Когда я разговариваю с Linux инженерами и говорю им о проблемах Kubernetes кластера на Windows, на меня смотрят очень подозрительно. Некоторые даже не верят что
это законно
такое бывает. Контейнеры на Windows не так распространены и востребованы, как на Linux. Но я думаю, что поговорить об этой теме стоит, хотя бы для того, что бы понимать общую концепцию и основные отличия контейнеров Windows и Linux. Первой записью я пройдусь по полотну широкой кистью, а затем, в последующих постах, попробую постепенно углубиться в нюансы.
Контейнеры в Windows
Согласно данной статье:
Многие разработчики, пишущие на .NET или под SQL Server, кусали локти и завидовали своим коллегам по цеху из мира Linux
Действительно, контейнеры в Windows до недавнего времени были экзотикой. А хуже всего то, что документацию приходилось собирать по крохам, на каждом ресурсе будь то официальный сайт Docker или Microsoft, всё представлялось в обзорном виде без описания «как и почему», а через месяц-два и существующая информация устаревала. И в этом нет ничего сверхъестественного – контейнеры и технологии с ними связанные развиваются с какой-то нереальной скоростью.
В настоящий момент с документацией все стало лучше и что бы погрузится в мир контейнеров для Windows достаточно почитать официальную документацию от Microsoft и следить за её изменениями. Что интересно, документация написана хорошо и на русском языке, хотя при глубоком изучении вам не избежать переходов по ссылкам на различные ресурсы по типу https://www.docker.com/ или https://kubernetes.io/ где всё написано на старом добром английском языке.
Сейчас ответы на любые вопросы можно найти в официальной документации, но есть некоторые нюансы, которые лучше знать заранее. Возможно вам это будет полезно и сэкономит время при погружении в контейнерные технологии под флагом Microsoft.
Вы не можете запускать контейнеры Windows на Linux и на Windows*
Контейнерные технологии позволяют легко обращаться с окружением благодаря наличию переконфигурированных образов приложений. Это как Apple Appstore или Google Play, но только для инженеров и разработчиков. Как и в магазинах для мобильных приложений вы не можете поставить приложение из Google Play на iOS. Так и на Docker хосте с операционной системой Linux вы не можете запустить контейнер с операционной Windows. Верно и обратное утверждение, правда с некоторыми «но», так как Docker хост с Windows всё же может предоставить Linux окружение для запуска контейнеров.
Так же вы не можете запустить контейнер Windows в среде Windows не убедившись в совместимости версий операционной системы. Работая с контейнерами от Microsoft вам придется оглядываться на Windows Container Version Compatibility и периодически открывать данный документ.
Говоря о версионности — Microsoft с приходом контейнеров приняла решение о выпуске новых полугодовых версий Windows semi-annual. Это такие версии как windows server 1703, 1709, 1803, 1809, 1903. Цифры означают год и месяц выхода, а поддерживаются они по 18 месяцев. Первые две уже покоятся с миром и находятся в end of service. Кроме того, существуют версии LTS такие как Windows Server 2016 и Windows Server 2019. Список версий.
Так вот, если вы собрали контейнер на хосте с версией Windows 1803, то и запустить данный контейнер вы можете только на хостах с Windows 1803. Соответственно, чтобы не пересобирать каждый раз сам контейнер вам придется использовать LTS версию Windows, что при современных скоростях развития технологий не всегда оправдано. Либо всё же думать о версионности и таки постоянно пересобирать контейнеры следуя шаг в шаг за программой semi-annual.
Тэг latest в Dokerfile для Windows контейнеров присутствует не всегда и вообще он deprecated. По-хорошему вам всегда надо знать, что у вас за версия Windows и вносить соответствующие правки в Dockerfile.
Контейнеры — это часть подхода «Инфраструктура как код». Пересобирать контейнеры нужно постоянно, это не только просто и весело, но в этом и заключается основная магия, которая позволяет приложениям всегда работать на свежем улучшенном софте. Но в нашем случае мы сталкиваемся с ограничением: не получится держать универсальный Dockerfile под все системы Windows. Это необходимо учитывать.
Всё вышесказанное справедливо для контейнеров, запущенных в режиме process isolation. В режиме Hyper-V isolation действует обратная совместимость – вы можете запускать все контейнеры, которые собраны на текущей и предыдущей версиях. В общем-то с помощью Hyper-V isolation можно на хосте Windows запускать и Linux контейнеры. Но такой режим пока что поддерживает меньше плюшек, чего только стоит отсутствие Kubernetes.
Отличие process isolation и Hyper-V isolation это тема отдельной статьи. Сейчас скажу только то, что сценарии с Hyper-V isolation мне не совсем очевидны, а по умолчанию в Windows используется process isolation.
Отдельной головной болью является поиск правильных по версии образов на Docker Hub. Некоторые образы вообще отсутствуют для Windows. Например, официальной сборки Nginx, MySQL, Nodejs, как и сотни других приложений под Windows вы не найдете и вам придется собирать контейнеры самостоятельно либо использовать контейнеры, собранные и предоставленные участниками сообщества.
Windows стоит денег.
Не стоит забывать и о том, что Windows это по-прежнему платная штука. К примеру, Semi-annual версии доступны по подписке Visual Studio или при наличии Software Assurance в действующем лицензионном контракте Microsoft. Ссылка.
Но у Microsoft есть большое количество способов получит платное за бесплатно. Это и программа BizSpark и всякие trial версии Windows Server 2019 на 180 дней и прочее и прочее.
Контейнеры Windows не легковесны.
Принято считать, что контейнеры легковесны, но что правда для Linux не всегда правда для Windows. Подавляющее большинство контейнеров Windows, на первый взгляд весит непозволительно много. Да и на второй взгляд впечатление не меняется. Например, базовый образ aspnet:4.8 весит порядка 7.5 Гб.
Даже если вы будете размещать базовые образы в локальном репозитории, первоначальная загрузка образа на хост будет занимать довольно продолжительное время, что уж говорить про удаленные репозиторий типа Docker Hub.
Да вы можете в некоторых сценариях использовать легковесный Windows Nano Server, но увы он имеет кучу ограничений. И тем более вам не по пути с Windows Nano Server если вы разрабатываете под .Net Framework.
Для управления надо хорошо знать CMD и Powershell.
Скорее всего работать вам придется с core версией Windows Server на Docker хостах. Windows Server имеет огромное количество возможностей по удаленному управлению. Общий подход такой, что имея Windows Server с графическим интерфейсом вы можете подключатся всеми графическими оснастками к любому core серверу.
Данный подход не работает в сценариях с контейнерами, хотя в контейнере и находится полноценная версия Windows Server. Внутрь контейнера Windows теоретически можно подключится по WMI, но это не так просто, хотя бы потому что хостовая ОС будет перехватывать данный трафик на себя. Контейнеров на хосте может быть несколько десятков и сотен, и в таком случае направлять трафик в нужный контейнер это целое дело.
CMD и Powershell понадобятся как для администрирования контейнеров так и самого хоста на котором установлен Docker. Так же знание данных оболочек необходимо для написания Dockerfile, так как все инструкции RUN будут выполнятся в вышеупомянутых командных оболочках.
Запомнить все длинные командлеты Powershell довольно сложно. Это вам не лаконичные команды bash. Хотя сейчас большинство командлетов имеет понятные любому Linux инженеру алиасы. В powershell можно использовать:
rm вместо Remove-Item
pwd вместо Get-Location.
cat вместо Get-Content
touch вместо New-Item
etc.
# ключи данных команд из Linux вам тут без пользы. Команда rm –rf не прокатит.
# но в Powershell есть аналог man в котором можно всё посмотреть
Get-Help <командлет>
Из крайне полезных вещей, это то, что с помощью Powershell можно запустить в контейнере простой веб сервер для целей тестирования. В Powershell всё представляется в виде объектов. Если вы сторонник ООП, то вы быстро оцените преимущества этой командной оболочки.
В качестве заключения вводной статьи хочу сказать что я нарочно не касался вопроса оркестрации и управления кластерам. Docker на Windows находится в роли догоняющего и приложения по оркестрации такие как Swarm и Kubernetes на Windows реализуют не полный свой функционал.
Так же на текущий момент если вы хотите поднять кластер Docker, то он скорее всего будет мульти платформенный. То есть вам придется иметь в кластере один или более хостов с операционной системой Linux. Например, для Kubernetes, мастер ноды обязаны быть на Linux. А в Swarm, Linux контейнеры понадобятся, например, для реализации балансировщика на Nginx или запуска других популярных приложений для кластера, которые доступны только для Linux.
P.S. Использование Windows в контейнерах имеет весьма ограниченный набор сценариев для применения. Тем не менее эти сценарии могут оказаться крайне продуктивными. Конечно, первое что приходит на ум это web приложения на IIS, но мой опыт показывает, что в контейнерах хорошо изолируются самописные службы Windows и некоторые сервисы такие как MSMQ.
UPD. В статье есть небольшая неточность, кластер Docker на одних только Windows хостах собрать можно. Причем, это не только Swarm, но и развиваемый самим Micrisoft продукт для оркестрации кластера Service Fabric
UPD2. Docker контейнеры для Windows 10 доступны только в режиме Hyper-V isolation и используют отличные от Windows Server базовые образы.
Tags:
Windows, Docker, Linux
Когда вы начнете работать с контейнерами, вы увидите много сходства между контейнером и виртуальной машиной; но, по сути, это два совершенно разных понятия. Контейнеры собираются изменить способ разработки Windows-разработок в следующем году, и они уже лежат в основе большой работы по ускорению процесса доставки. Мы объясним, как использовать функцию Windows Containers.
Введение
Контейнеры Windows революционизируют виртуализацию и процесс DevOps.
С Windows Server 2016 Microsoft представляет новую функцию под названием Windows Containers. Организации, которые обновляют свои серверы до этой новой операционной системы, смогут использовать контейнеры прямо из разработки в производственную среду.
Мы не будем углубляться в концепцию контейнеров, но в этой серии расскажем, как создавать, запускать, конвертировать и управлять вашими контейнерами Windows.
Основы Windows Containers
Прежде чем начать практическую сторону Windows Containers, мы должны вкратце осветить основы этой новой функции.
Контейнеры упаковывают программное обеспечение внутри полной файловой системы, которая содержит все, что нужно для запуска: код, среда выполнения, системные инструменты и системные библиотеки. Это гарантирует, что он всегда будет работать одинаково, независимо от среды, в которой он работает. Для достижения этой цели Windows использует изоляцию пространства имен, управление ресурсами и технологические процессы, чтобы ограничить файлы, сетевые порты и запущенные процессы, к которым может обращаться каждый контейнер, чтобы приложения, работающие в контейнерах, не могли взаимодействовать или видеть другие запущенные приложения в ОС хоста или в других контейнерах.
Виртуальные машины против контейнеров
Виртуальная машина является автономной и имеет собственную операционную систему, собственные приложения и собственные ресурсы (память, процессор и т. д.). Следующая схема показывает три виртуальных машины, размещенных на одном и том же физическом узле. Каждая виртуальная машина использует свою собственную ОС, библиотеки и т. Д. В результате они занимают значительное количество памяти.
Архитектура виртуальных машин
Довольно часто разработчикам приходится очень быстро тестировать приложения с разными версиями. Затем они должны попросить команду IT Ops развернуть одну или несколько машин (виртуальных или физических): это трудоемкий процесс. VM также потребляют значительные ресурсы, такие как память и пространство для хранения. Вот почему контейнеры удивительно полезны для процесса DevOps:
Архитектура контейнеров
Контейнеры, напротив, не содержат никакой операционной системы, поэтому они потребляют меньше ресурсов, чем виртуальные машины на физическом хосте. Контейнеры просто используют хост-операционную систему, включая ядро и библиотеки, поэтому им не нужно загружать полную ОС.
Таким образом, преимущества контейнеров Windows заключаются в следующем:
- Когда вы развертываете контейнер в рабочей среде, процесс отката очень прост. Вам просто нужно изменить сценарий развертывания и переустановить образ контейнера. Представьте себе процесс отката с виртуальными машинами? Вы должны перестроить всю машину (или вернуться к предыдущему состоянию или резервной копии).
- Время запуска для контейнера Windows короче, чем у виртуальной машины.
- Компактность использования облачных сценариев
Наконец, философия контейнера — это «одна услуга на контейнер»,
Windows Server Containers против Hyper-V Containers
Microsoft включает два разных типа контейнера. Первый тип основан на образовании Windows Server Core и называется контейнером Windows Server. Второй называется контейнером Hyper-V и основана на образовании Windows Nano Server. Контейнеры Hyper-V расширяют изоляцию, предоставляемую контейнерами Windows Server, запустив каждый контейнер в высоко оптимизированной виртуальной машине, чтобы обеспечить полную безопасную изоляцию. Ядро хоста контейнера не используется совместно с другими контейнерами Hyper-V. Если весь код, запущенный на хосте, надежен, то изоляция, предоставляемая контейнерами Windows, скорее всего, будет адекватной. Но если мы не доверяем коду, то контейнеры Hyper-V обеспечивают тот же уровень изоляции, что и виртуальные машины, но со многими преимуществами стандартных контейнеров.
Обратите внимание, что контейнеры Hyper-V управляются только Docker, а виртуальные машины Hyper-V управляются традиционными инструментами, такими как Hyper-V Manager. На практике загрузка Hyper-V контейнеров занимает больше времени, чем контейнеры Windows Server, но они намного быстрее, чем виртуальная машина с полной ОС (даже на Nano Server).
Docker
В октябре 2014 года Microsoft Corp и Docker объявили о стратегическом партнерстве, которое обеспечит гибкость, переносимость и безопасность платформы Docker для Windows Server.
Контейнеры Windows Server 2016, работающие от Docker Engine
Необходимо понимать, что Windows Server 2016 не может запускать контейнеры Linux в формате Docker, а только контейнеры Windows. Зачем? Поскольку для Linux-контейнеров требуются API-интерфейсы Linux из ядра-хозяина, а для контейнеров Windows Server требуются API-интерфейсы Windows для ядра Windows-хоста.
Однако процесс управления контейнерами Linux и Windows строго идентичен. Следующая схема описывает платформу Docker:
Платформа Docker
Ниже приведен краткий обзор жаргонов Windows Containers с их значением:
- Container Host: физическая или виртуальная компьютерная система, настроенная с использованием функции Windows Containers
- Container Image: Изображение контейнера содержит базовую операционную систему, приложение и все зависимости приложения, которые необходимы для быстрого развертывания контейнера.
- Container OS Image: Изображение операционной системы контейнера — это среда операционной системы.
- Container Registry: изображения контейнеров хранятся в реестре контейнеров и могут быть загружены по требованию. Это место, где публикуются изображения контейнеров. Реестр может быть удаленным или локальным.
- Docker Engine: Это ядро платформы Docker. Облегченное время выполнения контейнера, которое создает и запускает ваш контейнер.
- Docker file: файлы Docker используются разработчиками для создания и автоматизации создания изображений контейнеров. С файлом Docker демон Docker может автоматически создавать образ контейнера.
Docker предоставляет центральный репозиторий, называемый Docker Hub (https://hub.docker.com/), общедоступный реестр контейнерных приложений, поддерживаемый Docker. Контейнерные изображения могут быть опубликованы непосредственно в этом репозитории для совместного использования с сообществом Docker. На Docker Hub уже много изображений. Например:
- SQL
- WordPress
- IIS
- …
Вы можете запустить частный репозиторий локально. Посредством этого URL-адреса Microsoft имеет собственный публичный и официальный репозиторий: https://hub.docker.com/u/microsoft/
Контейнеры Windows на практике
Перед развертыванием контейнеров Windows вы должны подготовить свою среду с некоторыми предварительными условиями. Для этого вы можете использовать физическую или виртуальную машину, это зависит от вас. В нашем случае мы будем использовать виртуальную машину со следующими характеристиками:
- Система под управлением Windows Server 2016 (или Windows 10). Это самая важная предпосылка. Советуем вам работать с версией Datacenter из-за лицензирования (больше информации в конце статьи). Вы можете использовать Windows Server Core для своего контейнера, а не версию Windows, которая включает полный пользовательский интерфейс.
- Разрешения администратора на хосте контейнера
- Минимальное свободное пространство для хранения изображений и сценариев развертывания
- Ваш сервер должен быть современным
Хорошо, давайте начнем с установки функции Windows Containers на хосте контейнера. Для выполнения этой задачи запустите следующую команду PowerShell:
PS C:UsersAdministrator> Install-WindowsFeature Containers
Success Restart Needed Exit Code Feature Result
———— ——————— ————— ———————
True Yes SuccessRest... {Containers}
WARNING: You must restart this server to finish the installation process.
Чтобы применить изменения с помощью командлета Restart-Computer, необходимо перезапустить:
PS C:UsersAdministrator> Restart-Computer
Затем проверьте, что новая функция включена:
PS C:UsersAdministrator> Get-WindowsFeature containers
Display Name Name Install State
—————— —— ———————
[X] Containers Containers Installed
Контейнеры Windows тесно связаны с Docker; вы должны установить Docker Engine на хост контейнера. Для достижения этой цели у вас есть две возможности:
Первым из них является развертывание Docker из репозитория PSGallery:
PS C:UsersAdministrator> Install-Module -Name DockerMsftProvider -Repository PSGallery -Force
NuGet provider is required to continue
PowerShellGet requires NuGet provider version ‘2.8.5.201’ or newer to interact with NuGet-based repositories. The NuGet
provider must be available in ‘C:Program FilesPackageManagementProviderAssemblies’ or
‘C:UsersAdministratorAppDataLocalPackageManagementProviderAssemblies’. You can also install the NuGet provider by
running ‘Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force’. Do you want PowerShellGet to install
and import the NuGet provider now?
[Y] Yes [N] No [S] Suspend [?] Help (default is «Y»):
PS C:UsersAdministrator> Install-Package -Name docker -ProviderName DockerMsftProvider
The package(s) come(s) from a package source that is not marked as trusted.
Are you sure you want to install software from ‘DockerDefault’?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is «N»): Y
Install-Package : KB3176936 or later is required for docker to work
At line:1 char:1
+ Install-Package -Name docker -ProviderName DockerMsftProvider
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Microsoft.Power....InstallPackage:InstallPackage) [Install-Package],
Exception
+ FullyQualifiedErrorId : RequiredWindowsUpdateNotInstalled,Install-Package,Microsoft.PowerShell.PackageManagement
.Cmdlets.InstallPackage
Докер для Windows Server 2016 требует обновления «KB3176936». Его можно загрузить с веб-сайта Центра обновления Windows, а затем установить вручную:
http://www.catalog.update.microsoft.com/search.aspx?q..
Или вы можете выполнить эту задачу с помощью утилиты sconfig. Затем выберите число 6:
===============================================================================
Server Configuration
===============================================================================
1) Domain/Workgroup: Domain: get-cmd.Local
2) Computer Name: SRV1
3) Add Local Administrator
4) Configure Remote Management Enabled
5) Windows Update Settings: DownloadOnly
6) Download and Install Updates
7) Remote Desktop: Enabled (more secure clients only)
8) Network Settings
9) Date and Time
10) Telemetry settings Basic
11) Windows Activation
12) Log Off User
13) Restart Server
14) Shut Down Server
15) Exit to Command Line
Windows загрузит и установит обновления:
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
Search for for (A)ll updates or (R)ecommended updates only? a
Searching for all applicable updates...
Downloading updates...
Второй способ — установить версию Docker для разработки, чтобы иметь новейшие функции. Вы должны скачать Docker прямо с официального сайта. Используйте командлет Invoke-WebRequest:
PS > Invoke-WebRequest «https://master.dockerproject.org/windows/amd64/docker-1.14.0-dev.zip» -OutFile «$env:TEMPdocker.zip» –UseBasicParsing
Затем извлеките архив с помощью командлета Expand-Archive:
PS > Expand-Archive -Path «$env:TEMPdocker.zip» -DestinationPath $env:ProgramFiles
Теперь вы можете создать переменную окружения:
PS > $env:path += «;$env:ProgramFilesDocker» PS > $existingMachinePath = [Environment]::GetEnvironmentVariable(«Path»,[System.EnvironmentVariableTarget]::Machine) PS > [Environment]::SetEnvironmentVariable(«Path», $existingMachinePath + «;$env:ProgramFilesDocker», [EnvironmentVariableTarget]::Machine) |
Чтобы закончить, установите Docker в качестве службы Windows. Итак, запустите следующую команду для регистрации файла dockerd.exe:
PS > dockerd —register-service |
После установки сервис может быть запущен:
PS > Start-Service Docker
WARNING: Waiting for service ‘Docker Engine (Docker)’ to start...
PS > Get-Service -name «docker*»
Status Name DisplayName
——— —— ——————
Running docker Docker Engine
Чтобы отобразить информацию о докере, выполните следующие действия:
PS C:> docker info Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 1.14.0-dev Storage Driver: windowsfilter Windows: Logging Driver: json-file Plugins: Volume: local Network: l2bridge l2tunnel nat null overlay transparent Swarm: inactive Default Isolation: process Kernel Version: 10.0 14393 (14393.0.amd64fre.rs1_release.160715-1616) Operating System: Windows Server 2016 Datacenter OSType: windows Architecture: x86_64 CPUs: 1 Total Memory: 1.933 GiB Name: SRV1 ID: VB3B:IGYN:GEFL:6ML7:OQJM:GMCJ:HDNU:Z57W:SWYI:Z2I3:WZKG:O2L4 Docker Root Dir: C:ProgramDatadocker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false |
Итак, хост контейнера запущен и работает, поэтому мы можем развернуть наш первый Windows Container! В первом примере мы будем развертывать контейнер IIS, запускаем следующую команду:
PS > Docker run -d -p 8080:80 —name iis microsoft/iis
Unable to find image ‘microsoft/iis:latest’ locally
latest: Pulling from microsoft/iis
c480435b7cba: Downloading [==> ] 220.1 MB/4.175 GB
2acd7c473906: Downloading [=============> ] 240.1 MB/922.1 MB
a837699b27ea: Download complete
e4e8167eafc5: Download complete
0344b06e0e62: Download complete
Ниже приведен синтаксис команды Docker:
PS > docker run PUBLIC_PORT:PRIVATE_CONTAINER_PORT CONTAINER_NAME IMAGE
Контейнеры используют концепцию PAT (Port Address Translation). Это означает, что вы должны открывать порты контейнера через хост контейнера. В нашем примере Docker свяжет контейнер порта номер 80 с номером 8080 контейнера порта. Затем, когда мы попытаемся открыть веб-сайт IIS, расположенный внутри контейнера, я буду использовать открытый порт 8080.
Параметр «Name» добавляет дружественное имя в контейнер. Это не обязательно, но может быть полезно для последующего управления вашими контейнерами.
Наконец, вы должны указать имя образа контейнера. Здесь мы выбираем образ IIS, предоставленный Microsoft.
Когда я запускаю команду, Windows проверяет, доступно ли изображение локально (на хосте контейнера). Если нет, то Docker извлекает изображение из концентратора Docker.
PS > Docker run -d -p 8080:80 —name iis microsoft/iis
Unable to find image ‘microsoft/iis:latest’ locally
…
Когда это будет сделано, ваш Windows Container будет запущен. Наш хост контейнера имеет следующий IP-адрес: 192.168.0.132, поэтому мой веб-сайт IIS доступен с 192.168.0.132:8080
Контейнер IIS
Дальнейшая работа
Image2Docker
Допустим, у вас есть сервер, который был любовно собран вручную и который вы хотите контейнеризировать? Ну, вы можете использовать модуль PowerShell «Image2Docker», доступный в GitHub: https://github.com/docker/communitytools-image2docker.., который передает рабочие нагрузки приложений Windows из виртуальных машин на изображения Docker. Таким образом, вы можете легко конвертировать службы Windows в контейнеры Windows, такие как: сайты IIS, DNS, DHCP, …
Лицензирование
Официальный сайт содержит относительно небольшую информацию о лицензировании, но в соответствии с Техническим паспортом лицензирования Windows Server 2016 Standard Edition предоставляет права на до 2 контейнеров Hyper-V, когда все физические ядра на сервере лицензированы и контейнеры Windows Server неограничены для обоих выпусков.
Заключение
Контейнеры Windows уже меняют способы организации систем и предоставления услуг. Контейнеры начинают играть все более важную роль для разработчиков и операционных систем, чтобы не тратить слишком много времени на развертывание приложений.
Контейнерные технологии не новы в мире Linux, но для Microsoft это революция. Важно срочно найти время, чтобы понять все аспекты реализации контейнеров в вашей организации.
В этой статье мы видели, как развернуть наш первый контейнер Windows. Вы скоро заметите, что контейнеры замечательны для разработчиков и администраторов, поскольку контейнеризация обеспечивает большую гибкость в использовании и упрощает развертывание. Есть еще много вещей, которые нужно сказать о контейнерах, поэтому в следующих статьях мы объясним:
- Какие нужны команды Docker для начала работы с Docker,
- Как найти и загрузить изображения контейнеров,
- Как использовать контейнеры Hyper-V,
- Как создать собственное изображение Контейнера,
- Как конвертировать службы Windows для работы в контейнере Windows
Надеюсь, что эта статья поможет вам расширить свои знания о контейнерах Windows.
Содержание:
-
1.
Предыстория -
2.
Windows контейнер -
3.
В мире контейнеров Windows -
4.
Связь с Docker -
5.
Мир Windows
Начиная с Windows Server 2016 в операционной системе от Microsoft включена нативная поддержка контейнеров. Это не Linux контейнеры, это контейнеры, которые работают на Windows, и запускают Windows внутри себя.
Данный факт является результатом присоединения Microsoft к Open Container Initiative (OCI). Контейнеры в Windows позволяют запускать приложения, которые изолированы от остальной части системы в переносимых контейнерах. Эти контейнеры включают в себя все, чтобы ваше приложение было полностью функциональным. Так же как это произошло с Linux, Microsoft надеется, что контейнеры изменят характер поставки программного обеспечения для пользователей и в Windows.
Предыстория
Контейнеры являлись основой вычислений в Linux в течение целого ряда лет. Google, например, уже очень давно использует решения, основанные на контейнерах по всей своей империи, чтобы предоставлять распределенные приложения не только своим сотрудникам, но и своим пользователям по всему миру.
Тем не менее, Google не был долгое время одинок в своем увлечении контейнерными вычислениями. В какой-то момент из ниоткуда появился Docker, который в отличии от Google стандартизировал процессы доставки контейнеров, а также управления ими. Более того, Docker развивался сообществом энтузиастов в мире открытого исходного кода, что сделало его простым и очень популярным решением. С развитием проекта Docker буквально у каждого желающего появилась возможность получить скорость, гибкость и простоту управления программным обеспечением и инфраструктурой, которую предоставляют контейнеры.
Docker революция стала настолько значительной, что даже Microsoft присоединился к этой инициативе в первую очередь за счет поддержки Docker и Linux в Azure, а теперь и за счет интеграции этой технологии в Windows Server 2016. Самое интересное это то, что контейнеры Windows Server не основаны на Linux, это нечто совершенно новое. Windows контейнеры — это контейнеры, которые работают в Windows и запускают Windows внутри себя.
Причем Microsoft настолько серьезно стала относится к контейнерам, что сейчас активно участвует в Open Container Initiative (OCI), пытаясь перетягивать одеяло на себя так, как будто бы она сама придумала эту технологию.
Windows контейнер
Контейнер в Windows имеет много общего с его аналогом в Linux. Оба обеспечивают изолированную среду для запуска приложений. И там и там контейнеры используют передовые технологии изоляции для обеспечения портативной, но одновременно ограниченной среды, которая включает в себя практически все, чтобы приложение могло быть полностью функциональным.
Контейнер очень похож на виртуальную машину (ВМ) и часто рассматривается как отдельный тип виртуализации, но это два совершенно разные понятия. Да, каждый работает под управлением операционной системы (ОС), предоставляет внутри себя локальную файловую систему и может быть доступен по сети так же как физический компьютер. Тем не менее, при использовании ВМ вы имеете дело с полной и независимой ОС вместе с виртуальными драйверами устройств, управлением памятью и другими компонентами, которые добавляют к накладные расходы.
Контейнер переиспользует большее количество общих ресурсов хост-системы нежели виртуальная машина, а значит, он более легкий, быстрее разворачивается и проще масштабируется между различными датацентрами. Таким образом, контейнер может предложить более эффективный механизм для инкапсулирования приложения, обеспечивая ему при этом необходимые интерфейсы хост-системы — все из этого приводит к более эффективному использованию ресурсов и улучшению переносимости приложений.
Microsoft планирует предложить два типа контейнеров в Windows Server 2016: контейнер Windows Server и Hyper-V контейнер. Оба типа функционируют одинаковым образом, и могут быть созданы и управляются одинаково. Там, где они различаются — это в уровне изоляции, который каждый из них обеспечивает.
Контейнер Windows Server разделяет ядро с ОС работает на хост-машине, что означает, что все контейнеры, работающие на этой машине, разделяют одно и то же ядро. В то же время, каждый контейнер поддерживает свой собственный вид на операционную систему, реестр, файловую систему, IP-адреса и другие компоненты, сочетая это с изоляцией, предоставляемой каждому контейнеру при помощи процессов, пространства имен и технологий управления ресурсами.
Контейнер Windows Server хорошо подходит для ситуаций, в которых и основная ОС, и приложения в контейнерах лежат в пределах той же зоны доверия, например для приложений, которые охватывают несколько контейнеров или образуют общую службу. Тем не менее, контейнеры Windows Server обсуждаются в связи с их зависимостью от процесса обновления ОС хост-системы, который может осложнить обслуживание и препятствовать процессам. Например, патч примененный к хосту может сломать приложение, работающее в контейнере. Что еще более важно, в таких ситуациях, как многопользовательские среды, модель разделяемого ядра может раскрыть систему для уязвимостей приложений и кросс-контейнерных атак.
Hyper-V контейнер решает эти проблемы, предоставляя виртуальную машину, в которой нужно запустить контейнер Windows. При таком подходе контейнер больше не разделяет ядро хост-машины и не имеет зависимости от патчей ОС этой машины. Конечно, такой подход означает некоторую потерю скорости и эффективности упаковки, которые вы получаете с обычным контейнером в Windows Server, но взамен вы получаете более изолированную и безопасную среду.
Вне зависимости от типа контейнера, который вы используете, теперь у вас есть возможность использовать контейнеры с такими технологиями Windows как .NET или PowerShell, что не было возможно раньше. Контейнер для Windows предоставляет все необходимое для обеспечения работы приложения на любом компьютере под управлением Windows Server 2016, давая вам тот уровень переносимости, который был не доступен на протяжении большей части истории Windows. Вы можете создавать свои контейнеры локально, делать их доступными процессов для тестирования и контроля качества, а затем отправить их в команде, занимающейся продуктивом, без необходимости беспокоиться о сложных установках и конфигурациях на каждом шаге этого пути.
В мире контейнеров Windows
Ряд компонентов принимают участие в процессе создании и запуска контейнеров, начиная с хоста, на котором они должны работать. Хост может быть как физическим компьютером, так и ВМ с Windows 2016 Server. Единственное, что важно, чтобы была включена функция контейнеризации для Windows.
Вы можете разместить контейнеры на любой версии Windows: Server Full UI или же Core, которая устанавливается по умолчанию. Microsoft также представляет Nano издание для Windows Server 2016 — минимальную версию ОС, которая не включает в себя локальный графический пользовательский интерфейс или консоль.
Microsoft также добавила вложенную виртуализацию для Windows Server 2016, так что вы можете запустить Hyper-V контейнеры, если хостом является ВМ. Если вы планируете запускать такой тип контейнера, необходимо включить функцию Hyper-V на хост-ОС. Microsoft также добавляет поддержку контейнера для Windows 10, хотя только для Hyper-V контейнеров.
Как и с контейнерами Docker, вы разворачиваете контейнеры для Windows из образов. Каждый образ начинается с образа ОС контейнера — базового образа, включающего в себя операционную систему, которая будет работать внутри контейнера. В настоящее время Microsoft предоставляет два базовых образа: образ Server Core и образ Nano Server. Вы должны загрузить хотя бы один из этих образов ОС от Microsoft, прежде чем сможете развернуть контейнер.
Microsoft строго определяет, какие образы вы можете использовать с каким типом контейнера на основании хост-ОС, как описано в следующей таблице.
Хост-ОС |
Контейнер Windows Server |
Контейнер Hyper-V |
Windows Server Full UI |
Образ Server Core |
Образ Nano Server |
Windows Server Core |
Образ Server Core |
Образ Nano Server |
Windows Server Nano |
Образ Nano Server |
Образ Nano Server |
Windows 10 |
N/A |
Образ Nano Server |
Как вы можете видеть, Hyper-V контейнеры в настоящее время поддерживают только образ Nano сервера, но ваш выбор контейнеров Windows Server зависит от того, с какой версией Windows Server вы работаете.
Для этого типа контейнера, образ ОС должен также соответствовать хост-системы в отношении сборки и уровня обновления. Несоответствие может привести к непредсказуемому поведению как для контейнера, так и хоста. Это означает, что вы должны обновить образ базового контейнера ОС при обновлении ОС хоста. Это также означает, что вы не будете иметь возможность запускать Linux контейнер на Windows машине, или наоборот, и это также верно для Hyper-V контейнеров.
Образы обеспечивают высокую степень гибкости, когда речь идет о развертывании контейнеров. Вы можете создавать образы на основе существующего образа и обновлять новые образы так часто, как это необходимо. После этого вы можете развернуть один или несколько контейнеров из этого образа.
Например, предположим, что вы создаете образ, основанный на Server Core. В новый образ, вы устанавливаете приложение, которое в настоящее время находится в разработке вместе со всеми зависимостями этого приложения. Затем вы можете развернуть один или несколько контейнеров из этого образа. Каждый контейнер функционирует как песочница, которая включает все компоненты, необходимые для полной работоспособности приложения.
Образ может быть развернут так часто, как это необходимо, а также совместно использоваться любым количеством контейнеров. Вы создаете контейнеры по мере необходимости, а затем избавляетесь от них, когда вы с ними закончите. Но лучше всего то, что вы можете обновить и повторно развернуть образ в любое время, а затем создать из него новые контейнеры, которые содержат последние изменения.
Вам не нужно выбирать тип контейнера (Windows Server или Hyper-V) до тех пор, пока вы не будете готовы запустить фактический контейнер. Тип контейнера не имеет никакого отношения к тому, как вы собираете ваши образы. Образы хранятся в репозитории и доступны по запросу для разворачивания контейнеров, где и когда они необходимы, будь то контейнеры Windows Server или Hyper-V.
Связь с Docker
Помимо компании, Docker также является проектом с открытым кодом, которая облегчает процесс развертывания и управления контейнерами. Контейнеры Windows теперь являются частью этого проекта, и сообщество Docker интенсивно работает, чтобы полностью интегрировать контейнеры Windows в экосистему Docker. В рамках этой же инициативы Docker предлагает Docker Engine для Windows, и Docker Client для Windows.
Docker Engine обеспечивает функциональность, необходимую для управления Docker окружением. Например, Docker Engine позволяет автоматизировать создание контейнеров из образов. Хотя вы можете создавать образы вручную, Docker Engine предлагает целый ряд преимуществ, т.к. возможность хранения образов как кода, легкого пересоздания этих образов или включения их в цикл непрерывной интеграции в процессе разработки.
Тем не менее, Docker Engine не является частью установки Windows. Вы должны загрузить, установить и настроить его отдельно от Windows. Docker Engine работает как служба Windows. Можно настроить эту службу, используя файл конфигурации или Windows Service Control Manager (SCM). Например, вы можете установить отладку по умолчанию и параметры журнала или настроить, как Docker Engine принимает сетевые запросы. Microsoft рекомендует использовать файл конфигурации, а не SCM, но отмечает, что не каждый параметр конфигурации в файле применим к контейнерам Windows.
Docker Engine по существу делает всю рутинную работу по управлению контейнером за вас, расширяя API, необходимый для клиента Docker для взаимодействия Docker Engine. Клиент представляет собой интерфейс командной строки, который предоставляет набор команд для управления образами и контейнерами. Это те же самые команды, которые позволяют создавать и запускать контейнеры Docker в Linux. Хотя вы и не можете запустить контейнер для Windows на Linux или контейнер Linux на Windows, вы можете использовать один и тот же клиент для управления как Linux и Windows контейнерами, будь то контейнеры Windows Server или Hyper-V.
Как и с Docker Engine, вам необходимо загрузить и установить клиент Docker самостоятельно. Клиент может работать как на Windows 10 или Windows Server 2016. Вам нужно только указать клиенту Docker службу, которой необходимо начать управлять.
Мир Windows
Microsoft и Docker осталось сделать еще много работы, прежде чем контейнеры для Windows будут полностью функциональны, но то, что мы видим уже сейчас представляет собой значительный шаг вперед. Пользователям Windows, наконец, получат возможность пользоваться всеми преимуществами гибкости и переносимости, которые контейнеры предлагали миру Linux на протяжении более десяти лет.
Свершилось! То ли молитвы помогли, то ли жертвоприношения, но теперь можно запускать Docker контейнеры с Windows внутри. Прекрасная новость пришла одновременно с релизом Windows Server 2016. И речь не идёт о какой-нибудь хитро-спрятанной виртуальной машине, или эмуляции Windows на Linux ядре — запускается настоящая Windows в настоящем Docker, с работающими Dockerfile, docker-compose и прочими docker-приблудами.
Ограничения
Но это не значит, что теперь можно запускать любой контейнер где угодно. Из-за того, что Docker контейнеры «отдалживают» ядро операционной системы у своего хоста (а иначе им пришлось бы иметь свою ОС и превращаться в виртуальную машину), Windows контейнеры можно запускать только на свежих Windows 10 Pro Anniversary Update и Windows Server 2016.
Второй момент, запустить нативно Linux контейнер на Windows всё еще нельзя. В Anniversary Update есть собственная Linux подсистема (с помощью которой можно запустить настоящий Bash, например), но она не дотягивает для полноценного Linux-ядра, так что для того же контейнера с Убунтой на Windows всё еще нужна спрятанная виртуальная машина.
Наконец, одновременно запускать те и другие контейнеры на Windows машине можно, но с танцем. Если выполнить такую команду в Windows Server 2016 с установленным Docker (год назад я бы обозвал такое колдовством), оно сработает:
Но если после этой команды попробовать запустить Ubuntu контейнер, Docker взгрустнёт:
Проблема в том, что Windows и Linux контейнера обслуживаются разными Docker-демонами, которые, тем не менее, используют один и тот же канал для общения с командной строкой. То есть в каждый момент времени только один демон может быть активным. На официальном Докер-сайте есть бета «Docker for Windows«, которая пытается справиться проблемой (пока только на Windows 10 Pro и Enterprise). Но даже с ней, чтобы переключиться с Windows на Linux контейнеры, нужно либо лезть в меню настроек, либо общаться с командной строкой:
& ‘C:Program FilesDockerDockerDockerCli.exe’ -SwitchDaemon |
Пока есть только два базовых образа с контейнерной Windows:
- microsoft/windowsservercore
- microsoft/nanoserver
Сделать свой базовый образ (scratch image) — нельзя.
Образ Windows Server Core весит аж 10 гигов и в целом ведёт себя как полноценная Windows Server 2016. Например, MS SQL и полноценный .NET Framework устанавливаются там без проблем. Если ваше приложение не сильно зависит от UI, то установится и оно.
Nano Server слегка интереснее. Это очень оптимизированная и урезанная Windows Server, которая весит меньше гига. Но и ограничений хватает: нет 32-битных приложений, UI, RDP, порезаный PowerShell, и т.д. Но это не мешает поставить на Nano Server тот же IIS, .NET Core, и даже какой-нибудь MySQL.
И кто-нибудь мог представить пару лет назад, что в Dockerfile можно будет встретить сразу «Microsoft», «Windows» и «PowerShell»?
FROM microsoft/windowsservercore RUN powershell —Command.... |
Это же Windows в Докере! До сих пор звучит абсурдно.
Степени изоляции
Windows контейнера можно запускать в двух режимах изоляции:
- Windows Server Containers
- Hyper-V Containers
В первом режиме Windows контейнера ведут себя так же, как и все остальные контейнера в Docker: делят общее ядро с операционной системой, контейнерные процессы изолированы, но всё еще видны в хостовом дереве процессов, и т. п. Это дефолтный и самый быстрый способ запустить контейнер в Windows.
Во втором случае контейнера попадают особую Hyper-V виртуальную машину. Это, конечно, плохо сказывается на скорости запуска, но зато и изоляция полная.
Заключение
Windows в Докере — это просто отличные новости. Даже если не бросаться упаковывать свои продукты по контейнерам, это прекрасный инструмент для того, чтобы изолировать свои юнит-тесты, рабочие машины, сервера для демонстраций, песочницы — всё то, для чего раньше приходилось создавать виртуальную машину. Если Microsoft еще умудрится запустить nanoserver на Linux, то я им прощу недавнее снятие с производства Microsoft Band 2, неосмотрительно купленный за два месяца до этого.
Виртуализация, Из песочницы
Рекомендация: подборка платных и бесплатных курсов 3D-моделирования — https://katalog-kursov.ru/
Привет, Хабр! Представляю вашему вниманию перевод статьи Deep dive into Windows Server Containers and Docker – Part 2 – Underlying implementation of Windows Server Containers от автора Cornell Knulst.
В данной статье рассказывается об особенностях реализации Docker в Windows, а также об отличиях в реализации контейнеров между Windows и Linux.
Перед этим даётся общее представление, что такое контейнеры, чем они похожи и чем отличаются от виртуальных машин.
Вступление
Представив 3 августа 2015 года Windows Server 2016 Technical Preview 3, Microsoft внедрила технологию контейнеров в платформу Windows. В то время, как на Linux технология контейнеров появилась в августе 2008 года, подобная функциональность прежде не поддерживалась операционными системами Microsoft. Благодаря успеху Docker на Linux, Microsoft решила почти 3 года назад (оригинальная статья опубликована 6 мая 2017 — прим. перев.) начать работу над реализацией контейнеров для Windows. С сентября 2016 года мы смогли поработать с публично доступной версией этой новой технологии контейнеров в Windows Server 2016 и Windows 10. Но в чём разница между контейнерами и виртуальными машинами? И как внутренне реализованы контейнеры Windows? В этой статье мы погрузимся в реализацию контейнеров на Windows.
Контейнеры и виртуальные машины
Часто с контейнерами начинают знакомить с фразы “Контейнеры — это облегчённые виртуальные машины”. Хотя это может помочь людям дать фундаментальное понимание, что такое контейнеры, важно отметить, что это утверждение на 100% ошибочно и может сильно запутать. Контейнеры отличаются от виртуальных машин, и поэтому я всегда представляю контейнеры как “что-то, отличное от виртуальных машин” или даже говорю “контейнеры — это НЕ виртуальные машины”. Но в чём же разница? И почему она так важна?
Что общего между контейнерами и виртуальными машинами
Хотя контейнеры НЕ виртуальные машины, у них обоих есть три важные характеристики:
(Изображение Albund | Dreamstime.com)
Что общего между контейнерами и виртуальными машинами:
- Изолированное окружение: как и виртуальные машины, контейнеры гарантируют изоляцию файловой системы, переменных окружения, реестра и процессов между приложениями. Это значит, что, как и виртуальная машина, каждый контейнер создаёт изолированное окружение для всех приложений внутри себя. При миграции и контейнеры, и виртуальные машины сохраняют не только приложения внутри, но также и контекст этих приложений.
- Миграция между хостами: большое преимущество работы с виртуальными машинами в том, что можно перемещать слепки виртуальных машин между гипервизорами, при этом не нужно изменять их содержимое. Это справедливо и для контейнеров. Там, где виртуальные машины можно “перемещать” между разными гипервизорами, контейнеры можно “перемещать” между разными хостами контейнеров. При “перемещении” обоих видов артефактов между разными хостами содержимое виртуальной машины/контейнера остаётся точно таким же, как и на предыдущих хостах.
- Управление ресурсами: другая общая черта — это то, что доступные ресурсы (ЦП, ОЗУ, пропускная способность сети) как контейнеров, так и виртуальных машин могут быть ограничены до заданных значений. В обоих случаях это управление ресурсами может осуществляться только на стороне хоста контейнера или гипервизора. Управление ресурсами гарантирует, что контейнер получает ограниченные ресурсы, чтобы свести к минимуму риск того, что он повлияет на производительность других контейнеров, запущенных на том же самом хосте. К примеру, контейнеру можно задать ограничение, что он не может использовать больше 10% ЦП.
Разница между контейнерами и виртуальными машинами
Хотя между контейнерами и виртуальными машинами есть общие черты, также между ними есть некоторые важные различия.
Разница между контейнерами и виртуальными машинами:
- Уровень виртуализации: контейнеры — это новый уровень виртуализации. Если взглянуть на историю виртуализации, то она началась с таких понятий, как виртуальная память и виртуальные машины. Контейнеры — это новый уровень этой тенденции виртуализации. Там, где виртуальные машины обеспечивают виртуализацию аппаратного обеспечения, контейнеры обеспечивают виртуализацию ОС. Это значит, что если виртуализация аппаратного обеспечения позволяет виртуальной машине верить, что её аппаратные ресурсы принадлежат только ей, виртуализация ОС позволяет контейнеру верить, что вся ОС принадлежит только ему. Важно отметить эту разницу в виртуализации. У контейнеров, к примеру, нет собственного режима ядра. По этой причине контейнеры не видны как виртуальные машины и они также не распознаются, как виртуальные машины внутри операционной системы (можете попробовать самостоятельно выполнить команду PowerShell Get-VM). Хорошая аналогия для того, чтобы объяснить эту разницу — это дома (виртуальные машины) и квартиры (контейнеры). Дома (виртуальные машины) полностью самодостаточны и предоставляют защиту от непрошенных гостей. У каждого дома также есть собственная инфраструктура — водопровод, отопление, электричество и т. д. Квартиры (контейнеры) тоже предоставляют защиту от непрошенных гостей, но они строятся на основе общей инфраструктуры. В многоквартирном доме (Docker Host) водопровод, отопление, электричество и т. д являются общими. Хотя у них обоих могут быть общие характеристики, это разные сущности.
- Взаимодействие с ОС: другое важное отличие между контейнерами и виртуальными машинами заключается в способе, которым они взаимодействуют с режимом ядра. Тогда как у виртуальных машин есть полноценная ОС (и выделенный режим ядра), контейнеры разделяют “ОС (точнее, режим ядра)” с другими контейнерами и с хостом контейнеров. В результате контейнеры должны ориентироваться на ОС хоста контейнеров, в то время, как виртуальная машина может выбрать любую ОС (версию и тип), какую пожелает. Там, где виртуальные машины могут запускать ОС Linux на гипервизоре Windows, с технологией контейнеров невозможно запустить контейнер Linux на хосте контейнеров Windows, и наоборот. (В Windows 10 можно запускать контейнеры Linux, но они запускаются внутри виртуальной машины Linux — прим. перев.)
- Модель роста: контейнеры разделяют ресурсы хоста контейнера, и создаются на основе образа, который содержит ровно то, что нужно для запуска вашего приложения. Вы начинаете с основ и добавляете то, что необходимо. Виртуальные машины создаются в обратном порядке. Чаще всего мы начинаем с полной операционной системы и, в зависимости от приложения, убираем вещи, которые не нужны.
Контейнеры Windows Server
Теперь, когда мы знаем о различиях между виртуальными машинами и контейнерами, давайте нырнём глубже в архитектуру контейнеров Windows Server. Чтобы объяснить, как контейнеры внутренне реализованы в операционной системе Windows, нужно знать о двух важных понятиях: режиме пользователя и режиме ядра. Это два разных режима, между которыми постоянно переключается процессор, в зависимости от типа кода, который нужно выполнить.
Режим ядра
Режим ядра операционной системы был создан для драйверов, которым нужен неограниченный доступ к аппаратному обеспечению. Обычным программам (режима пользователя) приходится вызывать API операционной системы, чтобы получить доступ к аппаратному обеспечению или памяти. У кода, выполняющегося в режиме ядра, есть прямой доступ к этим ресурсам, и он разделяет те же области памяти/виртуальное адресное пространство, что и операционная система и другие драйверы в ядре. Поэтому выполнять код в режиме ядра очень рискованно, так как данные, принадлежащие операционной системе или другому драйверу могут быть повреждены, если ваш код режима ядра случайно запишет данные по неверному виртуальному адресу. Если драйвер режима ядра падает, то падает вся операционная система. Поэтому в режиме ядра нужно выполнять как можно меньше кода. По этой самой причине был создан режим пользователя.
Режим пользователя
В режиме пользователя код всегда выполняется в отдельном процессе (пользовательском пространстве), у которого есть свой собственный набор областей памяти (собственное виртуальное адресное пространство). Так как виртуальное адресное пространство каждого приложения является собственным, одно приложение не может изменить данные, принадлежащие другому приложению. Каждое приложение выполняется в изоляции, и если приложение падает, то падение ограничено только этим приложением. В дополнение к тому, что виртуальное адресное пространство является собственным, в режиме пользователя оно ограничено. Процессор, работающий в режиме пользователя, не может получить доступ к виртуальным адресам, зарезервированным для операционной системы. Ограничение виртуального адресного пространства приложения в режиме пользователя не позволяет ему изменять, и, возможно, повреждать, критические данные операционной системы.
Техническая реализация контейнеров Windows
Но что всем этим режимам процессора делать с контейнерами? Каждый контейнер — это всего лишь “режим пользователя” процессора с парой дополнительных возможностей, таких, как изоляция пространства имён, управление ресурсами и понятием каскадно-объединённой файловой системы. Это значит, что Microsoft нужно было адаптировать операционную систему Windows, чтобы она позволяла поддерживать множественные режимы пользователя. Что-то, что было очень трудно сделать, принимая во внимание высокий уровень интеграции между обоими режимами в предыдущих версиях Windows.
До выпуска Windows Server 2016 каждая операционная система Windows, которой мы пользовались, состояла из единственного “режима пользователя” и “режима ядра”. С появлением Windows Server 2016 стало возможным иметь несколько режимов пользователя, выполняющихся в одной операционной системе. Следующая диаграмма даёт общее представление об этой новой архитектуре мульти-режимов пользователя.
Взглянув на режимы пользователя в Windows Server 2016, можно выявить два различных типа: режим пользователя хоста и режимы пользователя контейнера (зелёные блоки на диаграмме). Режим пользователя хоста идентичен обычному режиму пользователя, с которым мы знакомы по предыдущим версиям Windows. Цель этого режима пользователя — размещать основные службы Windows и процессы, такие, как Session Manager, Event Manager и сеть. Более того, этот режим пользователя облегчает, в случае реализации Windows Server Core, взаимодействие пользователя с Windows Server 2016 при помощи пользовательского интерфейса.
Новая возможность Windows Server 2016 заключается в том, что как только вы включили компонент “Контейнеры”, этот режим пользователя хоста будет содержать некоторые дополнительные технологии управления контейнерами, которые гарантируют, что контейнеры будут работать в Windows. Основа этой технологии контейнеров — абстракция Compute Services (оранжевый блок), которая даёт доступ через публичный API к низкоуровневым возможностям контейнера, предоставляемым ядром. На самом деле, эти службы содержат лишь функциональность, чтобы запускать контейнеры Windows, отслеживать, запущены ли они, и управлять функциональностью, необходимой для их перезапуска. Остальные функции управления контейнером, такие, как отслеживание всех контейнеров, хранение образов контейнеров, томов и т. д., реализованы в Docker Engine. Этот движок напрямую общается с API контейнеров Compute Services и использует для этого “биндинг языка Go”, предложенный Microsoft.
Разница между контейнерами Windows и Linux
Одинаковые утилиты и команды Docker в контейнерах Windows и Linux
Хотя те же самые клиентские утилиты Docker (Docker Compose, Docker Swarm) могут управлять как контейнерами Windows, так и Linux, существуют некоторые важные отличия между реализациями контейнеров в Windows и в Linux.
Системные процессы
Там, где Linux предоставляет свою функциональность уровня ядра через системные вызовы, Microsoft решила контролировать доступную функциональность ядра при помощи DLL (это также является причиной того, почему Microsoft на самом деле не документировала свои системные вызовы). Хотя этот способ абстракции системных вызовов имеет свои преимущества, он привёл к сильно интегрированной операционной системе Windows со множеством взаимозависимостей между разными DLL Win32 и ожиданию от многих DLL, что будут запущены некоторые системные службы, на которые они (не)явно ссылаются. В результате запускать только процессы приложений, указанных в Dockerfile, внутри контейнера Windows не очень реалистично. Поэтому внутри контейнера Windows вы увидите кучу запущенных дополнительных системных процессов, в то время, как контейнерам Linux нужно запускать только указанные процессы приложений. Чтобы гарантировать, что необходимые системные процессы и службы выполняются внутри контейнера Windows, внутри каждого контейнера запускается так называемый процесс smss. Цель процесса smss — запустить нужные системные процессы и службы.
Процесс SMSS
Архитектура ОС
Не только в способе предоставления функциональности уровня ядра, но также и на уровне архитектуры существует важная разница в том, как обе операционные системы предоставляют функциональность контейнера клиентским утилитам Docker. В текущей реализации контейнеров в Windows Server 2016 представлен слой абстракции, называемый Compute Services, который абстрагирует низкоуровневые возможности контейнера извне. Причина этого в том, что Microsoft может менять низкоуровневый API контейнера без необходимости менять публичный API, вызываемый Docker Engine и другими клиентскими утилитами контейнеров. Кроме этого API Compute Services, вы можете написать свой собственный инструментарий управления контейнерами, используя биндинг языков C# или Go, которые доступны по адресам https://github.com/Microsoft/dotnet-computevirtualization и https://github.com/Microsoft/hcsshim.
Каскадно-объединённая файловая система?
Третье важное отличие между реализациями контейнеров Linux и Windows заключается в способе, которым обе операционные системы используют технологию Docker “копирование-при-записи”. Так как множество приложений Windows полагается на семантику NTFS, для команды Microsoft было сложно создать полноценную реализацию каскадно-объединённой файловой системы в Windows. Для таких функций, как журналы USN и транзакции, это, к примеру, потребовало бы совершенно новой реализации. Поэтому в текущей версии контейнеров в Windows Server 2016 нет настоящей каскадно-объединённой файловой системы. Вместо этого текущая реализация создаёт новый виртуальный диск NTFS для каждого контейнера. Чтобы эти виртуальные диски оставались небольшими, различные объекты файловой системы на этом виртуальном NTFS диске на самом деле являются символическими ссылками на настоящие файлы файловой системы хоста. Как только вы изменяете файлы внутри контейнера, эти файлы сохраняются на виртуальное блочное устройство, а в момент, когда вы хотите зафиксировать этот слой изменений, изменения забираются из виртуального блочного устройства и сохраняются в нужном месте файловой системы хоста контейнера.
Контейнеры Hyper-V
Последнее различие в реализации контейнеров Linux и Windows состоит в понятии контейнеров Hyper-V. Я напишу об этом интересном типе контейнеров в следующей статье этой серии. Оставайтесь с нами…
I wrote a blog post about running a Neo4j cluster in Windows Containers but I didn’t go into too much detail about setting them up. In this post, I’ll walk through setting up Windows Containers and some helpful tips to avoid some problems.
This post is mainly aggregated documentation from Docker, Microsoft, Stefan Scherer and other sources from when I was installing Windows Containers myself. Also, this is about Windows Containers, not Docker for Windows, which is a different product.
Before we start — Documentation
Like most things, it’s always a good idea to read up on them before diving in…
The documentation both on the Docker website and the Microsoft website is surprisingly good! It has some good examples and walk throughs as well some in depth documentation.
The Community and Support section also has a list of blog posts and videos for using Windows Containers
As Windows Containers are relatively new, and Linux Containers are not new, a lot of the documenation out there is targetted for Linux Containers. When searching for help and issues, I found it best to use the Windows Container
search term instead of Docker for Windows
to avoid links that were not relevant
What are Containers, Images and Docker?
The Microsoft Windows Containers website has a good introduction to Windows Containers
TLDR version
-
Images contain all the filesystem and registry changes for an application to run
-
Images can contain other images
-
All Images must, eventually, include an OS Image (Server Core or Nano)
-
Images are deployed and executed as Containers on Container Hosts
-
Many Containers can be deployed from the same Image but are all independent of each other
-
Docker wraps up the management of Containers, Images and Container Hosts in an easier to use format
Container Image
All the file and registry changes required to run an application are packaged into Container Images. For those that have used Application Virtualisation before (VMware ThinApp, Microsoft AppV etc.), this should sound familiar. An image can include other images so you can layer, or compose, them together, for example, if you have a website that ran on IIS, the website Image would include the IIS image. Indeed, all images must include at least a Container OS Image. For Windows Containers this is either the Windows Server Core or Nano Server OS Image.
The name Container Image can be confusing so they’re normally just called Images
Container OS Image
The Container OS image is the first layer in potentially many image layers that make up a container. This image provides the operating system environment. A Container OS Image is Immutable, it cannot be modified.
Container Host
Physical or Virtual computer system configured with the Windows Container feature. The container host will run one or more Windows Containers.
Container
Containers are created when you execute a Container Image, however each Container will have its own copy of the Image which means you can deploy many containers from the same Image safely.
Windows Containers has two isolation models, unlike Linux which has only one.
Windows Server Containers — provide application isolation through process and namespace isolation technology. A Windows Server container shares a kernel with the container host and all containers running on the host.
Hyper-V Containers – expand on the isolation provided by Windows Server Containers by running each container in a highly optimized virtual machine. In this configuration, the kernel of the container host is not shared with the Hyper-V Containers.
Server 2016 supports both isolation modes, while Windows 10 only supports the Hyper-V Containers. I could not find any documentation on the isolation modes supported by Nano Server but I suspect it is both isolation modes.
Docker
Docker is a management and packaging layer on top of Containers. This means we can use the Docker API on a Linux Container Host or a Windows Container Host with little change. Also, other tools which build upon Docker, for example, Docker Compose, Docker Swarm or Kubernetes can start to be used with Windows Containers.
While the Docker API is the same between Windows and Linux, there are some very different things between them such as volume mounting and networking which I will cover later.
What installation options are there?
So how do we install Windows Containers and Docker? This blog post is about creating a development environment so I won’t comment on how to deploy Windows Containers in production.
Windows Containers
For development environments, there are a few options:
- Install locally on Windows 10
- Install locally on Server 2016
- Install a Windows 10 or Server 2016 in Virtual Machine
I personally wouldn’t recommend Nano Server for development environment due to how tricky they can be to setup, however it’s possible to do.
Installing locally
The Microsoft documentation is very straightforward and is the same for Server 2016 and Windows 10
Windows Server 2016
Installation instructions
PS> Install-Module -Name DockerMsftProvider -Repository PSGallery -Force
PS> Install-Package -Name docker -ProviderName DockerMsftProvider
PS> Restart-Computer -Force
Windows 10
Installation instructions
PS> Enable-WindowsOptionalFeature -Online -FeatureName containers -All
PS> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
PS> Restart-Computer -Force
PS> Invoke-WebRequest "https://test.docker.com/builds/Windows/x86_64/docker-1.13.0-rc4.zip" -OutFile "$env:TEMPdocker-1.13.0-rc4.zip" -UseBasicParsing
PS> Expand-Archive -Path "$env:TEMPdocker-1.13.0-rc4.zip" -DestinationPath $env:ProgramFiles
PS> # Add path to this PowerShell session immediately
PS> $env:path += ";$env:ProgramFilesDocker"
PS> # For persistent use after a reboot
PS> $existingMachinePath = [Environment]::GetEnvironmentVariable("Path",[System.EnvironmentVariableTarget]::Machine)
PS> [Environment]::SetEnvironmentVariable("Path", $existingMachinePath + ";$env:ProgramFilesDocker", [EnvironmentVariableTarget]::Machine)
PS> dockerd --register-service
PS> Start-Service Docker
Install in a VM
This is basically the same as Installing Locally, but within a Virtual Machine.
Install in a VM using Vagrant
Stefan Scherer has created a Vagrant configuration which:
After provisioning the box has the following tools installed:
Windows Server 2016 with Docker Engine CS 1.12 and client
docker-machine 0.8.2
docker-compose 1.9.0
Docker Tab completion for PowerShell (posh-docker)
Chocolatey
Git command line
Git Tab completion for PowerShell (posh-git)
SSH client
Which means you can run Windows Containers in both isolation modes and Linux containers (docker-machine)! Stefan also has some Docker-Swarm examples too which I intend to look into further.
Docker Client
So now we have a Windows Container Host installed, and a Docker Engine running to manage the Host, now we need the docker client. Note if you installed Docker on Windows 2016 there should already be a client installed, but you may want to install an updated version.
Fortunately Chocolatey has a docker client package available at https://chocolatey.org/packages/docker which is maintained by Stefan Scherer and Ahmet Alp Balkan
If you would like the most release Docker Client, you can manually download it from the Github Docker Releases page. These zip files need to be extracted (like in the Windows 10 installation instructions) before use
Connecting to remote Docker Hosts
You don’t have to install the Docker client on the same host as the Docker server, the Docker API also runs over a network (TCP) connection.
Setting up the Docker Server for remote connections
By default, the Docker Server will only listen on a Named Pipe connection, which cannot be accessed remotely. However, it is fairly easy to add additional listeners:
-
Edit
C:ProgramDatadockerconfigdaemon.json
. If it does not exist, just create the text file -
Add or modify the hosts setting and append
tcp://0.0.0.0:2375
{
"hosts": ["tcp://0.0.0.0:2375","npipe://"]
}
- Save the file and restart the Docker Service
This configuration will listen on all IP addresses on port 2375 (Default Docker port). However, if you would like to restrict the manager to, say, a dedicated Management Network Interface (common in production environments), change the IP address appropriately.
More information on configuring the Docker Server on Windows is available on the Microsoft Windows Containers documentation website.
Setting up the Docker Client for remote connections
You can specify a remote Docker Server when using the Docker Client in two ways:
-
Use the
-H
or--host
command line parameter -
Set the
DOCKER_HOST
environment variable
For example, to connect to a remote Docker Server at IP Address 10.0.0.1
on the default port of `23751
PS> docker -H tcp://10.0.0.1:2375 info
or
PS> $ENV:DOCKER_HOST = 'tcp://10.0.0.1:2375'
PS> docker info
To use a local Docker Server over named pipes, use a host of npipe:////./pipe/docker_engine
.
Container OS Images
You can start the download of the two Container OS Images by running the appropriate docker pull
command;
Nano Server Container OS Image (600 MB or so)
PS> docker pull microsoft/nanoserver
Windows Server 2016 Server Core Container OS Image (9GB or so)
PS> docker pull microsoft/windowsservercore
File System information
Containers have an isolated file system from the host, which means any file you modify inside the container won’t affect the host. But what about log files or database files how do I mount them inside the container so they can modify them?
When you start a container, you can specify to mount directories on the host inside of the container. Any modifications to the files will be persisted on the host.
For example;
Let’s say I have log directory on my host called C:ContainerLogs
and my container writes to log files in the C:Logs
directory. When I start the container, I use a command line similar to below;
PS> docker run -it --volume C:ContainerLogs:C:Logs microsoft/nanoserver
...
C:>dir
Volume in drive C has no label.
Volume Serial Number is 7055-B6A6
Directory of C:
11/04/2016 09:04 AM 1,894 License.txt
01/14/2017 09:22 PM <SYMLINKD> logs [\?ContainerMappedDirectories24E62B19-4E1A-41B8-9B60-26DCC654A55F]
07/16/2016 04:20 AM <DIR> Program Files
07/16/2016 04:09 AM <DIR> Program Files (x86)
11/04/2016 09:05 AM <DIR> Users
01/14/2017 09:23 PM <DIR> Windows
1 File(s) 1,894 bytes
5 Dir(s) 21,205,929,984 bytes free
C:>
Note that there is a directory called logs
inside the container and that is a symlink, not a real directory like Users
or Windows
.
See the Docker documentation on volumes for more information
Containers and Images on the Host
By default, the images are stored in C:ProgramDatadockerwindowsfilter
and containers in C:ProgramDatadockercontainers
. To display this information run docker info
and look for the Docker Root Dir
PS> docker info
...
Docker Root Dir: C:ProgramDatadocker
...
Networking Information
Networking within Windows Containers can be a tricky to understand at first. If you come from a Virtual Machine background, it feels like normal Virtual Switches as used in HyperV (or VMware ESX). If you come from a Linux Container background, it feels like the usual NAT switches used there. But in both cases there are some subtle and infuriating differences.
Unlike Linux Containers, Windows Containers offer more networking options and I suggest reading the Windows Container Networking document for more detailed infomation.
Layer 2 Bridge and Layer 2 Tunnel
These are more complex networking options which I don’t feel most development environments will take advantage of.
Network Address Translation (NAT)
This is the most common networking option for Windows Containers. The Container Host will use the native WinNAT features of the operating system to assign an IP address to Containers and then use port mapping to redirect network traffic appropriately. However there are some limitations with the NAT network;
Only one NAT internal IP prefix is supported per container host, so ‘multiple’ NAT networks must be defined by partitioning the prefix
Container endpoints are only reachable from the container host using container internal IPs and ports
Issue — Only one NAT prefix
WinNAT will only allow one IP prefix (x.x.x.x/y) to be available for translation. This doesn’t mean you can’t have multiple NAT based Docker Networks, just that the setup for the WinNAT is more complicated, for example (taken from the documentation);
If you wanted two NAT networks, 172.16.0.0/16
and 172.17.0.0/16
, then the WinNAT prefix must encompass both of those networks: 172.0.0.0/8
, 172.16.0.0/12
or 172.16.0.0/15
are all examples of valid WinNAT prefixes.
Creating a custom NAT network
The Setup NAT Network documentation describes the setup process in detail.
For this example, I’ll walk through the high level steps for setting up two Container NAT Networks (172.16.0.0/16
and 172.17.0.0/16
) and WinNAT with a prefix of 172.16.0.0/12
, which encompases both of the smaller NAT networks. I also assume there is already an Internal vSwitch created.
PS> Stop-Service docker
PS> Get-ContainerNetwork | Remove-ContainerNetwork -force
PS> Get-NetNat | Remove-NetNat
- Stop the docker service as it will not allow the networks to be modified while running
- Remove the Docker NAT network using the
Remove-ContainerNetwork
cmdlet as this is not possible using the docker client - Remove the WinNAT configuration, but not remove the associated vSwitch
Edit the docker service daemon configuration file `C:ProgramDatadockerconfigdaemon.json` and add `bridge: none`.
- By default, the Docker service creates a default NAT network, which we don’t want. Add
bridge: none
tells docker not to create the default network
PS> New-ContainerNetwork –Name nat1 –Mode NAT –SubnetPrefix 172.16.0.0/16 -GatewayAddress 172.16.0.1
PS> Get-Netnat | Remove-NetNAT
PS> New-ContainerNetwork –name nat2 –Mode NAT –SubnetPrefix 172.17.0.0/16 -GatewayAddress 172.17.0.1
PS> Get-Netnat | Remove-NetNAT
For each NAT network you want to configure
-
Create a new NAT container network
-
Remove the created WinNAT allocation. We override that later with our larger prefix
PS> New-NetNat -Name SharedNAT -InternalIPInterfaceAddressPrefix 172.16.0.0/12
PS> Start-Service docker
- Configure WinNAT with our larger prefix
- Start the docker service
Issue — No localhost
People who have used Linux Containers before will find this issue very quickly. If you are on the Container Host, you cannot access NAT ports using localhost. Elton Stoneman has a good writeup in this blog post.
This is important to remember if you want to do container-to-container networking or you want to test a container resource.
To find the IP Address of container run:
PS> docker inspect --format '{{ .NetworkSettings.Networks.nat.IPAddress }}' <Container ID>
Where <Container ID>
is a tag or ID of running container.
Transparent Networks
This networking option should be quite familiar. The container has its own networking stack and appears as a network host in its own right, no hiding behind NAT devices!. You can create a transparent network using the docker client:
PS> docker network create -d transparent -o com.docker.network.windowsshim.interface="Ethernet 2" TransparentNet2
The -o com.docker.network.windowsshim.interface="Ethernet 2"
binds the transparent network to the network interface called Ethernet 2
on the Container Host
Assigning IP Addresses to containers can be done via DHCP, however I saw that the Container IP address is not shown when inspecting the container (docker inspec ....
). This means, while it’s easy to assign IPs the Host cannot coordinate resources when using tools such as Docker Compose.
You can assign Static IPs at container creation time using the --ip
option, for example
C:> docker run -it --network=TransparentNet2 --ip 10.123.174.105 microsoft/nanoserver cmdlet
This isn’t the most scalable solution but it’s just enough for development environments.
Portainer
While the docker client is very powerful, there is always a need for a more graphical view of managing containers. Portainer is a cross platform web based UI for managing a Docker Host, which is very simple to run and use. Which is great, but they also have a Windows Container deployment option and are actively working to make their product work better with Windows Containers. If you don’t want to run Portainer in a container, you can simply download the application and run it locally.
It’s also open source so you can lodge issues, or even fix bugs yourself!
Source Code
Documenation
Documentation Source