《精通Docker第三版》完整目录:
第一章 Docker概览
第二章 创建容器镜像
第三章 存储和发布镜像
第四章 管理容器
第五章 Docker Compose
第六章 Windows容器
第七章 Docker Machine
第八章 Docker Swarm
第九章 Docker和Kubernetes
第十章 在公有云上运行Docker
第十一章 Portainer – 一个Docker的GUI
第十二章 Docker安全
第十三章 Docker工作流
第十四章 Docker进阶
本章中,我们将讨论并学习Windows容器。Microsoft以一种在新设备上部署老应用的方式拥抱容器技术。不同于Linux容器,Windows仅在基于Windows的Docker主机上可用。
本章将涵盖如下内容:
- Windows容器的介绍
- 为Windows容器设置Docker主机
- 运行Windows容器
- Windows容器的Dockerfile
- Windows容器和Docker Compose
技术准备
和此前章节一样,我们将继续使用本地Docker安装。同样,本章中的截图都取自我个人偏好的操作系统,macOS – 是的,虽然我们将要运行的是Windows容器,你还是可以使用macOS客户端。后面会详解。
我们所运行的Docker命令可以在所有的三种操作系统中运行。但时,在本章中我们将要启动的容器仅在Windows Docker主机上运行。我们将使用macOS或Linux机器上的VirtualBox和Vagrant来帮助我们启动和运行Windows Docker主机。
本章的的完整代码请参见https://github.com/alanhou/mastering-docker/tree/master/Chapter06。
访问如下视频来查看代码实时操作:
Windows容器简介
作者过去20年日常大多使用macOS和Linux电脑以及Linux服务器,事实上有关Microsoft Windows的体验仅停留在Windows XP和我曾拥有的Windows 10游戏机,还有就是在工作中未能避免而使用的古怪的Windows,Windows容器的出现是一个很有意思的开发。
我从不会将自己归类为Linux/UNIX迷弟。但Microsoft过去几年的运行着实惊到了我。早在2014年一个Azure的活动上,Microsoft声称”Microsoft ❤️ Linux”,之后就一发不可收拾:
- Linux是Microsoft Azure的一等公民
- .NET内核跨平台,意味着你可以在Linux和Windows上运行自己的.NET应用
- 现在Linux上可以使用SQL Server
- Windows 10专业版电脑上可以像Ubuntu一样运行 Linux shell
- Linux上已可安装PowerShell
- 它开发了很多跨平台工具,如Visual Studio Code,并对它们进行了开源
- 它斥资75亿美元收购了GitHub
很明显老的Microsoft时代已经一去不返了,那时其前CEO鲍尔默叫嚣着开源和Linux社区此处不宜复述的话(译者注:他曾称 Linux为“恶性肿瘤”)。
因此,在微软公开声明其对 Linux 的热爱后的数月,于2014年10月宣告Docker和Microsoft正在合作在一些基于Windows的操作系统上应用容器,比如Windows 10专业版和Windows Server 2016,这就不足为奇了。
那么什么是Windows容器呢?
表面上它们与 Linux 容器并无区别。Microsoft在Windows内核中引入了与Linux相同的进程隔离。同是类似 Linux 容器,这一隔离扩展为沙盒文件系统甚至是一个Windows仓库。
因为每一个容器都是一个新的Windows内核或Windows Nano,这相当于一个削减的Windows服务器镜像(如同Alpine Linux但是Windows版的),安装的系统管理员可以在同一台主机上运行多个容器化应用,而无需担心做作任何自定义仓库修改或带来崩溃和导致问题的软件安装。
结合Docker命令行客户端带来的轻松使用,以及系统管理员可以将老应用迁移到更新的硬件上,同时可以无忧地托管多个操作系统,也不必管理多台运行老的不再支持的Windows版本的虚拟机了。
Windows容器还提供另外一层隔离。Hyper-V隔离在启动容器时在迷你hypervisor上运行容器进程。这更一进步地将容器进程与宿主机进行隔离。但是为每个使用Hyper-V运行的容器分配额外的少量资源也会带来一些开销,容器的启动时间会因hypervisor需要在容器启动之前进行启动而上升。
虽然Hyper-V确实使用了Microsoft的hypervisor,这在Windows服务器和桌面版以及Xbox One系统软件中都可以找到,我们无法使用标准的Hyper-V 管理工具来管理用Hyper-V隔离的容器。这时需要使用Docker。
既然Microsoft投入了这么多工作和精力来在Windows内核中使用容器,为什么他们不创建自己的管理工具而选择Docker呢?
Docker已经通过一组已应用的 API 和强大的社区将其打造成管理容器的必选工具。同时,Docker是开源的,这意味着微软不仅可以将其适配到Windows上,还可以为Docker的开发做出贡献。
通过下图可以概览Windows上的Docker是如何运作的:
注意我说的是Windows上的Docker(Docker on Windows)而非Windows版Docker(Docker for Windows),这是两个不同的产品。Docker on Windows是原生版本的Docker引擎及客户端,与Windows内核进行交互来提供Windows容器。Docker for Windows为开发者在桌面上提供运行Linux和Windows容器尽可能原生的体验。
为Windows容器设置Docker主机
勿需多言,你需要一个Windows主机来运行Docker。如果你没有Windows 10专业版的机器也不必担心,有方式可以实现macOS和Linux上进行运行。在讨论这个之前,我们先来看如何通过Docker for Windows的安装来在Windows 10专业版上运行Windows容器。
Windows 10专业版
Windows 10专业版默认即支持Windows容器。但默认它配置用于运行Linux容器,要将Linux容器切换为Windows容器,在任务栏系统托盘处右击Docker图标并从菜单中选择Switch to Windows containers … :
这会跳出如下弹窗:
可通过如下输出进行查看:
TODO
Docker引擎中OS/Arch的值为windows/amd64,而非到目前我们所一直看到的linux/amd64。这就是Windows 10专业版的相关内容了。但对那些更喜欢使用macOS和Linux的用户怎么办呢?
MacOS和Linux
要在macOS和Linux机器上使用Windows,我们需要用到Stefan Scherer所整理的优秀资源,在本书配置的仓库的Chapter06 文件夹中,有一个Stefan的windows-docker-machine仓库,其中包含我们可以在macOS上启动和运行Windows容器的文件。
在开始之前,我们需要用到两个工具:Hashicorp的Vagrant和Oracle的Virtualbox。下载地址为:
在完成了下载和安装之后,打开Terminal,进入Chapter06/docker-machine 仓库文件夹,并运行如下命令:
1 |
$ vagrant up --provider virtualbox 2016-box |
这会下载一个VirtualBox Windows Server 2016核心eval镜像,它已包含我们用于启动和运行Windows容器的所有内容。下载内容略大于10 GB,所以请确保带宽和磁盘空间足够支撑。
Vagrant启动该镜像,并在虚拟机上配置Docker,拷贝本地Docker客户端与你本机交互所需的认证文件。要切换到新启动的Docker Windows主机,只需运行如下命令:
1 |
$ eval $(docker-machine env 2016-box) |
我们会在下一章中详细讨论Docker Machine。以上的命令是重新配置本地客户端来与Docker Windows主机进行对话。可运行如下命令进行查看:
1 |
$ docker version |
如果你没有照着一起操作,可以看看如下的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
C:\Users\vagrant>docker version Client: Version: 18.09.2 API version: 1.39 Go version: go1.10.6 Git commit: 1ac774dfdd Built: unknown-buildtime OS/Arch: windows/amd64 Experimental: false Server: Engine: Version: 18.09.2 API version: 1.39 (minimum version 1.24) Go version: go1.10.6 Git commit: 1ac774dfdd Built: 02/10/2019 04:13:25 OS/Arch: windows/amd64 Experimental: false |
译者注:我在测试时使用 eval 命令是无法识别到有任何 Docker Machine,以上操作均为在虚拟机内部的操作,从 GitHub 上看到与 Docker Machine 版本可能存在关系,由于这一仓库较老,本文中将大量采用原书截图来进行说明
可以看出,我们现在与运行在windows/amd64上的Docker引擎进行连接。要切换回去,可以重启终端会话或运行如下命令:
1 |
$ eval $(docker-machine env -unset) |
操作完Docker Windows主机后,可以运行如下命令来进行停止:
1 |
$ vagrant halt |
也可以运行如下命令来彻底删除:
1 |
$ vagrant destroy |
以上的这些命令都需要在Chapter06/windows-docker-machine 仓库目录下进行运行。
运行Windows容器
在本章的第一部分已经提到了,使用Docker命令行来启动和与Windows容器交互和此前我们运行的命令没有分别。那么我们来通过运行hello-world容器来进行下测试吧:
1 |
$ docker container run hello-world |
和此前一样,这会下载hello-world容器并返回一条消息:
此处唯一的不同是Docker拉取的不是Linux镜像,而是基于nanoserver-sac2016镜像的windows-amd64版本的镜像。
下面我们来看在前台运行一个容器,这次我们运行PowerShell:
1 |
$ docker container run -it microsoft/windowsservercore powershell |
在shell准备就绪时,运行如下命令将输出电脑名称,即容器ID:
1 |
$ Get-CimInstance -ClassName Win32_Desktop -ComputerName . |
前述命令在终端中的完整输出如下:
运行exit退出PowerShell之后,可以通过运行如下命令查看容器ID:
1 |
$ docker container ls -a |
所得到输出可参见下图:
Windows容器的Dockerfile
Windows容器镜像使用与Linux容器相同格式的Dockerfile命令。以下Dockerfile会下载、安装并在容器上启动IIS网站服务器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# escape=` FROM microsoft/nanoserver:sac2016 RUN powershell -NoProfile -Command ` New-Item -Type Directory C:\install; ` Invoke-WebRequest https://az880830.vo.msecnd.net/nanoserver-ga-2016/Microsoft-NanoServer-IIS-Package_base_10-0-14393-0.cab -OutFile C:\install\Microsoft-NanoServer-IIS-Package_base_10-0-14393-0.cab; ` Invoke-WebRequest https://az880830.vo.msecnd.net/nanoserver-ga-2016/Microsoft-NanoServer-IIS-Package_English_10-0-14393-0.cab -OutFile C:\install\Microsoft-NanoServer-IIS-Package_English_10-0-14393-0.cab; ` dism.exe /online /add-package /packagepath:c:\install\Microsoft-NanoServer-IIS-Package_base_10-0-14393-0.cab & ` dism.exe /online /add-package /packagepath:c:\install\Microsoft-NanoServer-IIS-Package_English_10-0-14393-0.cab & ` dism.exe /online /add-package /packagepath:c:\install\Microsoft-NanoServer-IIS-Package_base_10-0-14393-0.cab & ;` powershell -NoProfile -Command ` Remove-Item -Recurse C:\install\ ; ` Invoke-WebRequest https://dotnetbinaries.blob.core.windows.net/servicemonitor/2.0.1.3/ServiceMonitor.exe -OutFile C:\ServiceMonitor.exe; ` Start-Service Was; ` While ((Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\WAS\Parameters\ -Name NanoSetup -ErrorAction Ignore) -ne $null) {Start-Sleep 1} EXPOSE 80 ENTRYPOINT ["C:\\ServiceMonitor.exe", "w3svc"] |
可以使用如下命令来构建该镜像:
1 |
$ docker image build --tag local:dockerfile-iis . |
构建之后,运行docker image ls就该会显示如下内容:
TODO
你很快就会注意到Windows容器镜像都非常的大。这在Server 2019的发行版中努力克服的事情。
通过如下命令来运行容器会启动IIS镜像:
1 |
$ docker container run -d --name dockerfile-iis -p 8080:80 local:dockerfile-iis |
可通过打开浏览器查看新启动的容器正在运行。但使用的不是http://localhost:8080/,我们需要通过使用容器的NAT IP来对其进行访问。如果你运行的是Windows 10 专业版,可以通过运行如下命令来查看NAT IP:
1 |
$ docker inspect --format="{{.NetworkSettings.Networks.nat.IPAddress}}" dockerfile-iis |
这会显示IP地址,只需在后面加上8080/即可,比如http://172.31.20.180:8080/
macOS用户可运行如下命令来使用所启动的Vagrant虚拟机的IP地址打开浏览器:
1 |
$ open http://$(docker-machine ip 2016-box):8080/ |
不论你使用哪种操作系统来启动IIS容器,都可以看到如下的默认等待页面:
要停止和删除我们到现在所启动的容器,可运行如下命令:
1 2 |
$ docker container stop dockerfile-iis $ docker container prune |
到这里,我相信你也会同意它的体验与使用基于Linux的Docker容器 并没有什么区别。
Windows容器和Docker Compose
本章的最后一节,我们将来看一下Windows Docker主机上的Docker Compose。你可能已经猜到,我们并不需要对前面章节中的代码进行什么修改。仓库的Chapter06 文件中,有一个从 Docker Examples仓库复制的 dotnet-album-viewer应用,它带有docker-compose.yml文件。
Docker Compose文件是像这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
version: '2.1' services: db: image: microsoft/mssql-server-windows-express environment: sa_password: "DockerCon!!!" ACCEPT_EULA: "Y" healthcheck: test: [ "CMD", "sqlcmd", "-U", "sa", "-P", "DockerCon!!!", "-Q", "select 1" ] interval: 2s retries: 10 app: image: dockersamples/dotnet-album-viewer build: context: . dockerfile: docker/app/Dockerfile environment: - "Data:useSqLite=false" - "Data:SqlServerConnectionString=Server=db;Database=AlbumViewer;User Id=sa;Password=DockerCon!!!;MultipleActiveResultSets=true;App=AlbumViewer" depends_on: db: condition: service_healthy ports: - "80:80" networks: default: external: name: nat |
可以看到,它和我们之前看的Docker Compose文件使用了相同的结构、标记和命令,唯一的不同是使用Docker Hub中为Windows容器所设计的镜像。
要构建所需镜像,只要运行如下命令:
1 |
$ docker-compose build |
然后在完成构建后使用如下命令进行启动:
1 |
$ docker-compose up -d |
和前面一样,我们接下来可使用如下命令来查看Windows上的 IP地址:
1 |
$ docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" musicstore_web_1 |
要打开应用,你只需要在浏览器中输入Docker主机的 IP 地址。如果使用的是macOS,运行如下命令:
1 |
$ open http://$(docker-machine ip 2016-box)/ |
此时应该就会打开如下页面了:
完成应用的使用后,可以运行如下命令来进行删除:
1 |
$ docker-compose down --rmi all --volumes |
总结
本章中,我们简短地来看了下Windows容器。可以看到,借助于Microsoft采纳Docker作为其Windows容器的管理工具,其体验与使用 Docker 管理Linux管理是极其相似的。
下一章中我们将来深入的学习Docker Machine。
课后问题
- Docker on Windows引入了哪一附加的隔离层?
- 使用哪个命令来查看Windows容器的NAT IP地址?
- 是非题:Docker on Window引入一组额外的命令来管理Windows容器?
扩展阅读
你可以查看有关本章中所讨论话题的更多信息如下:
- Docker和Microsoft合作的声明:https://blog.docker.com/2014/10/docker-microsoft-partner-distributed-applications/
- Windows服务器与Docker – 将Docker和容器带向Windows的背后原理:https://www.youtube.com/watch?v=85nCF5S8Qok
- Stefan Scherer的GitHub:https://github.com/stefanScherer/
- dotnet-album-viewer仓库: https://github.com/dockersamples/dotnet-album-viewer