Вы когда-нибудь чувствовали себя прекрасной принцессой, которую злой волшебник превратил в лягушку? Как будто происходит что-то не то? У меня такое бывает. Я пользуюсь исключительно UNIX и боюсь закрыть уютную командную строку. Мой терминал — моя крепость. Но так как иногда мне все-таки приходится пользоваться Microsoft Windows, я узнал о некоторых трюках, которые помогают мне справиться с таким стрессом.

Для ежедневной работы в терминале я установил Windows Subsystem for Linux вместе с дистрибутивом Ubuntu. Кроме того у меня установлен Linuxbrew, который помогает мне с установкой приложений сторонних производителей. Такое сочетание функционирует просто отлично! У меня есть следующая ссылка ко «внешним» (хранящимся на Windows) данным: ln -s ~/external /mnt/c/Users/DoomHammer. Почти все необходимое можно осуществить подобным образом. Но до тех пор, пока не нужно использовать Docker.

Что такого особенного в Docker?

В отличие от многих приложений, используемых мной ежедневно, Docker является системным. То есть он находится глубоко в системе и для его работы на хост-компьютере необходим демон. В данном случае под хост-компьютером я подразумеваю Microsoft Windows.

Значит ли это, что мы не можем использовать Docker изнутри WSL? Можем, но нужно постараться, чтобы добраться до него. Во-первых, нужно установить Docker под Windows. Для этого есть Docker Enterprise Editions для Windows Server 2016 (и новее), Community Edition для Windows 10 Professional и Enterprise. У меня установлена Windows 10 Home.

Docker на Windows 10 Home

Настройка Docker в Windows 10 Home кажется более сложной. Для Docker Community Edition необходима поддержка системы Hyper-V, которая недоступна для версии Home. То есть мне надо было найти Docker Toolbox— более раннюю версию на основе Docker Machine и Virtualbox. Но после установки Virtualbox выдал окно с ошибкой о том, что запустить виртуальную машину невозможно.

Как оказалось, в BIOS у меня была выключена функция виртуализации. Видимо для безопасности. После включения функции, я снова запускаю Virtualbox. Проблема осталась. В интернете посоветовали проверить systeminfo. Хорошо. Там показано, что работает какой-то гипервизор. Но ведь не Virtualbox или, тем более, Hyper-V, верно?

К моему удивлению, все это время работал именно Hyper-V. Похоже в версии Home нет инструментов для использования Hyper-V, но это не означает, что гипервизор не работает. К счастью, чтобы выключить его, нужно просто ввести в команду bcdedit /set hypervisorlaunchtype off. После перезагрузки Virtualbox заработал. Ура!

Docker и WSL — лучшие друзья навеки?

С работающим Virtualbox я открыл Docker Quickstart Terminal. Во время первого запуска он создает Docker Machine (вот зачем нужен Virtualbox) для функционирования в качестве хоста для всех контейнеров. Далее ввожу команду docker run --rm hello-world и наблюдаю за индикатором выполнения загрузки подходящего образа. Снова ура!

Теперь вместо cmd.exe я использую Docker в WSL. Как так получилось? К счастью, у WSL есть доступ к бинарным файлам Windows. То есть я могу ввести команду docker-machine.exe ls для того, чтобы увидеть машину, созданную Docker Toolbox. Она будет называться просто default. Если не указан статус «Running», то можно запустить машину с помощью команды docker-machine.exe start. Каждый раз при запуске Docker Machine помните, что в отличие от cmd.exe,выполнение ( .exe) является обязательным.

Чтобы указать переменные окружения, вызывается docker-machine.exe env.

К сожалению, они выводятся в формате для cmd.exe, а не Bourne shell (bash или zsh). Но мы можем изменить это с помощью docker-machine.exe env — shell sh.

Почти готово. Нужно сделать кое-что еще. Путь к сертификату написан как путь Windows. Как перевести это во что-то понятное для WSL? В WSL есть хорошая утилита wslpath, благодаря которой можно ввести команду export DOCKER_CERT_PATH=$(wslpath $DOCKER_CERT_PATH). Готово!

Но нам все еще нужны инструменты пользовательского пространства. Итак, с помощью диспетчера пакетов установите Docker Engine и Docker Compose. В моем случае нужно ввести команду brew install docker docker-compose. После нее вводим команду docker run --rm hello-world. На этом все, мои поздравления!

На этом все?

Конечно же нет. Как видим, bind-mount работает некорректно, потому что Docker-демон ожидает подходящего пути Windows, а пути WSL не переводятся автоматически. Но есть несколько приемов, которые помогут нам в данной ситуации.

Выбор конкретного метода зависит от вашей версии Windows. Нажмите Win+R и введите команду winver. Появится сообщение, в котором указана версия. Наример:

Microsoft Windows
Version 18.03 (OS Build 17133.73)

Если версия будет 18.03 или новее, то можно отредактировать /etc/wsl.conf следующим образом:

[automount]
root = /
options = "metadata"

То есть WSL смонтирует диск С: под /c/ вместо обычного /mnt/c. Почему это важно? Потому что этого ожидает Docker-демон от путей Windows. Кстати, после сохранения файла необходимо перезайти (re-login), чтобы изменения вступили в силу.

Осторожно! Если вы используете WSL-терминал, то это изменение сломает его. Тогда можно сделать следующее.

Если вы не хотите перезагружать систему или версия Windows более ранняя, то можно примонтировать одну точку монтирования к другой следующим образом:

sudo mkdir /c
sudo mount --bind /mnt/c /c

Так быстрее, но функция будет доступна только до тех пор, пока вы не выйдете из системы. После перезапуска нужно повторять процедуру или добавить ее в конфигурацию среды выполнения shell (например, ~/.bashrc или ~/.zshrc). Это происходит из-за того, что /etc/fstab не работает на WSL так, как требуется.

Теперь можно запускать Docker с монтированием, но только если приложение находится в файловой системе WIndows. У вас не должно возникнуть проблем с командной строкой docker, которая ожидает абсолютные пути, но с Docker Compose нужно быть максимально внимательным. Он позволяет использовать относительные пути, и все, что начинается с ./ не будет работать.

Если вы все-таки решили монтировать файловую систему WSL с помощью Docker, то можете попробовать заменить все ./ и $PWD на /c/Users/$USERNAME/AppData/Local/lxss. Здесь $USERNAMEозначает не имя пользователя WSL, а имя пользователя Windows.

Я также хотел написать оболочку для Docker Compose, чтобы изменить рабочий каталог на lxss, но у WSL нет к нему доступа. И думаю, это правильно!

И последнее

Мы можем запускать Docker и связывать каталоги данных. Что еще нам нужно? Может рабочая переадресация портов? В отличие от Native solutions, ипользуя Docker через Docker Machine, необходимо вызывать все службы через $(docker-machine ip):$PORT вместо обычного localhost:$PORT. Существует способ обойти все это, хотя и не очень элегантный:

#!/bin/sh

# This script uses Virtualbox Port Forwarding to make all Docker services
# available on Windows host under `localhost`

VBXMGMT=/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe

# List all the running container ids
docker ps -q | while read -r i; do
  # List all the ports bound by this container<Paste>
  for port in $(docker port "$i" | cut -d'-' -f1); do
    port_num=$(echo "${port}" | cut -d'/' -f1)
    port_type=$(echo "${port}" | cut -d'/' -f2)
    echo "Create rule natpf1 for ${port_type} port ${port_num}"
    "$VBXMGMT" controlvm "default" natpf1 "${port_type}-port${port_num},${port_type},,${port_num},,${port_num}"
  done
done

Думаю, можно написать оболочку для Docker, чтобы выполнять все эти манипуляции при каждом запуске нового контейнера. Но я лично еще не проверял данный метод, потому что мне достаточно переадресации одного порта.

Надеюсь, данные советы облегчат работу с Docker на WSL. Лично мне они очень помогли.

 

Перевод статьи Piotr GaczkowskiHow to set up Docker and Windows Subsystem for Linux: A Love Story.

Предыдущая статьяОвладей Python, создавая реальные приложения. Часть 2
Следующая статьяХитрости объектно-ориентированного программирования. Часть 2: Закон Деметры