Docker на Windows: уже работает

Обратите внимание! Это статья про запуск Docker Engine нативно в Windows Server 2016. Не путайте с Docker Toolbox и Docker for Windows!

Что ж, прошёл год с того момента, как Docker и Microsoft пообещали совместными усилиями запустить Docker на Windows.

Сегодня уже можно с уверенностью сказать, что обещание они сдержали: доступна для скачивания четвёртая редакция Windows Server 2016 Technical Preview, существует практически полностью совместимая с Windows сборка Докера, написана документация, в интернете стали появляться красивые ролики и первые блог-посты, радостно сообщающие «Глядите! Я поднял докер под виндой!»

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

Пожалуйста, имейте в виду, что данная статья описывает пред-релизное состояние. Если вы читаете её спустя год после публикации, то, вероятно, некоторые детали успели поменяться, недостатки уйти, а критика потерять актуальность!

Windows Server 2016 Technical Preview

Нам понадобится виртуальная машина с Windows Server 2016. ISO-образ можно скачать из Evaluation Center или воспользоваться прямой ссылкой https://aka.ms/tp4/serveriso.

Запаситесь свободным местом на диске и почаще делайте снапшоты!

Типы контейнеров

Microsoft реализовала два типа контейнеров:

  • Windows Server Containers — это настоящие контейнеры, позволяющие запускать процессы в изолированном окружении с использованием общего ядра, без виртуализации аппаратных ресурсов.

  • Hyper-V Containers — виртуалки, «притворяющиеся» контейнерами. Позиционируются как более безопасные.

Интересен, конечно же, первый тип, потому что виртуальные машины под Windows мы все видели, а контейнеры ещё нет.

Docker vs. PowerShell

В Windows предлагается два способа работы с контейнерами: через PowerShell и через Docker (кажется, в Microsoft решили делать всё в двух вариантах). При этом контейнеры, созданные одним способом, будут недоступны через другой.

Понятно, что Microsoft не хочет класть все яйца в одну корзину и попадать в полную зависимость от Докера и его планов. В итоге мы имеем фрагментацию. Но нас сегодня интересует только Docker!

Step by step

В документации советуют воспользоваться длинным автоматизированным скриптом Install-ContainerHost.ps1, который сам всё проверит и установит.

Я, в свою очередь, предлагаю всё сделать вручную. Так вы лучше прочувствуете процесс, а у меня будет возможность вставить пояснения и авторские комментарии.

Все команды, которые встретятся ниже в тексте, следует выполнять из-под административной учётной записи.

Windows Server Containers

Поддержка контейнеризации выключена по-умолчанию. Включить её можно либо через установку компонентов Windows (Programs and Features и так далее), либо командой PowerShell:

Install-WindowsFeature Containers

После этого надо будет (вы правильно догадались) перезагрузить систему. Докер-докером, а мы всё ещё в Windows 🙂

Настройка сети

Следующим шагом нужно создать виртуальную сеть для контейнеров. Если вы использовали Docker на Linux, то наверняка видели сетевой мост под названием docker0. Сделаем такой же в Windows.

Выполните две команды в PowerShell:

New-VMSwitch -Name docker0 -SwitchType NAT -NATSubnetAddress "172.17.0.0/16"
New-NetNat -Name ContainerNAT -InternalIPInterfaceAddressPrefix "172.17.0.0/16"
Вместо docker0 можно использовать любое удобное имя, а ContainerNAT (имя NAT-объекта) менять не стоит, т.к. нет возможности легко его передавать в docker daemon (см. код на GitHub).

Убедитесь, что сеть добавилась:

ipconfig

Windows IP Configuration

Ethernet adapter vEthernet (docker0):

   IPv4 Address. . . . . . . . . . . : 172.17.0.1
   Subnet Mask . . . . . . . . . . . : 255.255.0.0

Если вы запускаете Windows Server внутри Hyper-V, то нужно дополнительно включить «MAC address spoofing». Из внешней операционной системы выполните PowerShell-команду:

Get-VMNetworkAdapter -VMName <имя виртуальной машины> | Set-VMNetworkAdapter -MacAddressSpoofing On

либо сделайте это мышью:

docker.exe

Скачайте docker.exe и поместите в System32:

wget https://get.docker.com/windows/tp4/docker.exe -OutFile c:\Windows\System32\docker.exe

(можно попытать счастья с ночными билдами: master.dockerproject.org)

Docker Daemon

В отдельной консоли запустите Docker в режиме демона:

docker daemon -b docker0

(параметр -b задает имя созданного ранее сетевого моста)

Убедимся, что всё завелось:

docker info

Storage Driver: windowsfilter
Execution Driver:
 Name: Windows 1854
 Build: 1.10.0-dev e852959
 Default Isolation: process
Kernel Version: 10.0 10586 (10586.11.amd64fre.th2_release.151112-1900)
Operating System: Windows Server 2016 Technical Preview 4
OSType: windows

В официальной документации есть инструкции по оборачиванию docker.exe в Windows-сервис с помощью NSSM. Сейчас не будем этим заниматься, так как это не критично.

Ситуация с образами

Всё шло гладко, и вот мы подошли к первой кочке, о которую будем спотыкаться.

docker.exe пока не умеет работать с DockerHub (реестром образов). Соответствующие команды (docker search, docker pull) обращаются к другому адресу (см. код на GitHub).

Любой поисковый запрос выводит одно и то же:

docker search anyshit

NAME                 DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
microsoft/aspnet     ASP.NET 5 framework installed in a Windows...   1         [OK]       [OK]
microsoft/django     Django installed in a Windows Server Core ...   1                    [OK]
microsoft/dotnet35   .NET 3.5 Runtime installed in a Windows Se...   1         [OK]       [OK]
microsoft/golang     Go Programming Language installed in a Win...   1                    [OK]
microsoft/httpd      Apache httpd installed in a Windows Server...   1                    [OK]
microsoft/iis        Internet Information Services (IIS) instal...   1         [OK]       [OK]
microsoft/mongodb    MongoDB installed in a Windows Server Core...   1                    [OK]

Попытка «затянуть» любой из образов потерпит неудачу:

docker pull microsoft/iis

Using default tag: latest
Pulling repository docker.io/microsoft/iis
Invalid base layer "6801d964fda5b67eb36e005261c1529ec96974bb02dfad52ee249638a18a93d1"
Error: image microsoft/iis not found

Базовый слой (то есть слой с файлами операционной системы) нужно загружать особым образом, причём он должен содержать версию Windows в точности соответствующую версии внешней системы. В противном случае контейнеры не будут запускаться с сообщением:

The operating system of the container does not match the operating system of the host.

В документации это обосновывается так:

A mismatch will lead to potential instability and/or unpredictable behavior for the container and/or the host.

Хочется верить, что это временное положение дел: с таким ограничением Docker на Windows вряд ли «взлетит».

Загрузка базового образа

В PowerShell:

Install-PackageProvider ContainerProvider -Force

затем:

Install-ContainerImage -Name WindowsServerCore

Последует нудное скачивание трёх гигабайт данных через Background Intelligent Transfer Service. Затем образ будет распакован и «осядет» в папке C:\ProgramData\Microsoft\Windows\Images.

Теперь перезапустите docker daemon и дайте команду:

docker images

REPOSITORY          TAG               IMAGE ID          CREATED           SIZE
windowsservercore   10.0.10586.0      efc12fd2d2ec      4 weeks ago       9.653 GB

(обратите внимание на графу SIZE)

IIS внутри контейнера

Предпримем попытку запустить контейнер из образа microsoft/iis:

docker run --rm -ti -p 80:80 microsoft/iis cmd

Дождитесь сливок появления командной строки.

В Windows по-умолчанию все порты закрыты, поэтому надо добавить разрешающее правило в Firewall. Откройте ещё одну (третью по счёту) консоль и выполните в PowerShell:

if (!(Get-NetFirewallRule | where {$_.Name -eq "TCP80"})) {
    New-NetFirewallRule -Name "TCP80" -DisplayName "HTTP on TCP/80" -Protocol tcp -LocalPort 80 -Action Allow -Enabled True
}

Интересная деталь: фаервол у хоста и всех контейнеров общий.

Теперь если вбить в адресную строку браузера внешний IP-адрес машины (в нашем случае, виртуальной), на которой бежит Windows Server 2016 с контейнерами, то IIS должен нам сказать «Привет»:

Для уничтожения контейнера достаточно набрать «exit» в его консоли (потому что мы использовали флаг --rm).

docker build

Теперь испытаем функциональность сборки образов. Создайте какую-нибудь папку, а в ней файл Dockerfile следующего содержания:

FROM microsoft/iis
RUN echo "Hello from container!" > c:\inetpub\wwwroot\index.html
CMD waitfor nothing

(конструкция "waitfor nothing" мне определённо нравится!)

Затем:

docker build -t hello .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM microsoft/iis
 ---> 39b8f98ccaf1
Step 2 : RUN echo "Hello from container!" > c:\inetpub\wwwroot\index.html
 ---> Running in 646aafe92a7d
 ---> 3e75f2f2153d
Removing intermediate container 646aafe92a7d
Step 3 : CMD waitfor nothing
 ---> Running in 6c27fc49004a
 ---> eea7a40e56a0
Removing intermediate container 6c27fc49004a
Successfully built eea7a40e56a0

И запустим, на этот раз в фоновом режиме:

docker run -d -p 80:80 hello

3b1cc1492049763c1b60d8643466254eab9d92fd808c593b70f46f1bebb4886a
docker ps -q

CONTAINER ID        IMAGE               COMMAND                  CREATED
3b1cc1492049        hello               "cmd /S /C 'waitfor n"   11 seconds ago

Обновляем браузер:

Как будто бы все действительно работает!

Что внутри?

Я воспользовался утилитой Process Explorer, чтобы выяснить, как выглядит работающий контейнер с точки зрения процессов:

Видим wininit, от которого порождена дюжина служб. IIS работает по-обычному (то есть как сервис). Команда waitfor запущена через некий посредник CExecSvc.

Если подождать минуту, то зародится ещё больше жизни:

К нашим услугам тут и KMS Connection Broker, и WMI Provider Host, и Distributed Transaction Coordinator…

Windows-контейнер больше похож на «винду внутри винды» нежели на «программу, запущенную в изолированном окружении».

Что на диске?

Файлы контейнеров (слои) находятся в C:\ProgramData\docker\windowsfilter. Для файловой системы используются VHDX-диски. Кроме того, каждый слой хранит дельту ключей реестра. Даже реестр в контейнерах есть!

Выводы

Безусловно, Docker и Microsoft продемонстрировали очень плодотворное сотрудничество «на ниве опен-сорса».

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

Требует серверной редакции ОС. Неясно, будет ли добавлена поддержка контейнеров в Windows 10.

Windows-контейнеры оказались весьма тяжеловесными: 10 Гб базового образа, два десятка процессов внутри контейнера, VHDX-диски для хранения данных — всё это выглядит «толстовато» по сравнению с Docker на Linux.

Будем следить за дальнейшим развитием событий!

Обновление (июль 2016). На DockerCon 2016 был доклад от представителей Microsoft (видео на YouTube), в котором рассказали интересные детали: почему в Windows-контейнере необходимо иметь дюжину запущенных служб, зачем на самом деле понадобились Hyper-V Containers и как приходится бороться с возникающими накладными расходами.

Обновление (октябрь 2016). Windows Server 2016 зарелизился, появилась официальная документация для Windows 10 (Pro и Enterprise). Но стабильных сборок Windows-native Docker Engine всё ещё нет. По-прежнему предлагается скачивать master-билды, которые не всегда работают


Все материалы по теме Docker:

Видео:

Статьи:

Устаревшее:

Комментариев: 8

  1. Звучит-то красиво…
    Посмотрим, как удастся на этом что-нибудь энтерпрайзненькое запустить 🙂

    И, кстати, вот к этой фразе вопрос:
    «версию Windows, в точности соответствующую версии внешней системы»
    В точности — это как? Вплоть до мажорной версии? Или вплоть до сервис-пака? Или вплоть до апдейтов винды?

  2. Отличная статья. А на ажуре это ещё нет?

  3. Алексей:

    @Mike Vitik, есть: Azure Quick Start

  4. Алексей:

    @Kuleshov, в настоящее время требуется совпадение вплоть до апдейтов:

    If you install updates against the Windows container host OS you will need to update the container base OS image to have the matching updates.

    из Work in Progress

  5. Антон:

    Привет. Не подскажешь, возможно ли такое:
    Имеем систему Windows, например Windows 10. Имеем машину линукс в сети удаленную. Можно ли как-то с помощью клиента docker.exe работать на линуксе удаленном? то есть писать команды в cmd на Windows, а они исполняются на удаленной машине?

  6. Алексей:

    @Антон
    Можно, с помощью флага -H. Но проще и практичнее подключаться к удаленной машине по SSH с помощью PuTTY.

  7. Александр:

    Все прочитал, посмотрел видяшки, но так и не могу понять что происходит. На странице https://docs.docker.com/docker-for-windows/ указаны два способа использования контейнеров под виндой: «native Docker binary» и «Docker for Windows». При этом второй способ рекомендуемый, но на мсдн https://msdn.microsoft.com/virtualization/windowscontainers/containers_welcome как я понял, описан только первый. Что должно определять выбор между вариантами? И как если я настроил систему под первый вариант мне мигрировать на второй?

  8. Алексей:

    @Александр
    Смело выбирайте второй вариант, Docker for Windows.

Ваш комментарий