Вы когда-нибудь чувствовали себя прекрасной принцессой, которую злой волшебник превратил в лягушку? Как будто происходит что-то не то? У меня такое бывает. Я пользуюсь исключительно 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 Gaczkowski: How to set up Docker and Windows Subsystem for Linux: A Love Story.