众所周知,Docker能打通开发和运维的任督二脉,所谓DevOps是也。有朋友说,这符合王阳明的"知行合一"之教。html
而Windows Server 2016内置的Windows Docker亦已经出来一段时间,这里就来和诸公汇报一下测试结果。docker
在安装配置Container Host的时候,常常报错Container OS Image下载失败(没办法,墙内的缘故)。ubuntu
什么是Container OS?顾名思义,是从容器角度看到的OS。windows
Container OS实际是应用所依赖的用户模式(User mode)OS组件,对于Windows容器来讲,例如ntdll.dll、kernel32.dll或者coresystem.dll之类的System DLL。主机上的全部容器共享内核模式(Kernel mode)OS组件,对于Windows,就是ntoskrnl.exe,还有驱动等。bash
例如对于如下命令,意味着Windows系统从docker映像中获取Windows Server Core的用户模式OS组件,并启动cmd得到Shell。架构
docker run -it windowsservercore cmd
Linux也是一理,若是运行如下命令,意味着从docker映像中获取Ubuntu的用户模式组件,而且启动Bash Shell。运维
docker run -it ubuntu /bin/bash
对于以上两个容器,Linux容器里的进程比较少,能够参考如下截图:工具
而Windows容器,则状况略有不一样。性能
在Windows主机上启动Process Explorer,能够看到这个Windows容器的进程相对多一些:测试
这是由于在Windows系统中,须要给应用提供一些用户模式的系统服务,例如DNS、DHCP、RPC等服务,这样从容器的角度来看,容器得到了本身独有的服务(通常是在各自的svchost或者其余服务宿主进程里运行),构成了所谓的Container OS。
咱们能够用PowerShell命令查看容器内部启动的Windows服务,大概有27个,参考附图。
很惋惜,这个版本的Windows docker里,虽然有远程桌面服务,可是目前还不支持远程桌面到容器,因此没法使用容器应用的图形化界面。
容器里的应用,到底应该启动多少Windows服务?因为Windows服务的具体做用是非文档化的,因此不像Linux能够作到最精简。可是因为这些服务几乎不占用什么额外的资源,对于容器性能没有影响。
因为在最新的测试版本里,容器对象的权限设置有了改变,只有SYSTEM权限才能查看。因此要查看Windows容器的进程隔离,须要用SYSTEM权限启动Winobj。这能够借助Psexec来实现:
Psexec -i -d -s winobj.exe
能够看到Windows对象空间里多了一个Containers的节点,其下有若干个GUID分支,这些GUID表明系统里的容器。其下每一个容器有本身独立的BaseNamedObjects等命名空间,包括互斥信号量、内存Section、事件等。 能够用PowerShell查看容器的GUID,参考附图。
每一个容器节点下,有本身的Session分支,例如该容器,占据了Windows系统的Session 2。如附图所示。
这就是为何,无论用任务管理器,仍是PowerShell,抑或是Process Explorer等工具,咱们都在Windows主机里看到容器里的全部进程都会标记Session为2。 借助Process Explorer,咱们能够看到容器里的进程,所打开的Handle,其中就指向先前所看到的Windows容器对象命名空间。
同时还能看到,容器进程所在的WindowStation并非WinSta0,而是Service-0x0-3e7$,3e7的10进制等于999,等于九五之尊,这是SYSTEM服务所在的窗口站。因此容器进程没法在Windows桌面上拥有图形化界面。
还能够查看一个有意义的对象,Windows容器所挂载的主机目录,相似于Linux容器的Volume。
和Linux同样,Windows容器映像采用分层的文件系统,基于映像建立容器后,至关于在只读的分层文件系统上再覆盖一层可读写的文件系统层。若是要修改的文件在最上层的可读写层里没有,则沿着分层的Layer找到目标文件后,将其用COW(Copy on write:写时复制)复制到可读写层再修改。
让咱们进入到Windows主机的如下目录:
C:\ProgramData\Microsoft\Windows\Hyper-V\Containers
该目录下列出全部经过PowerShell命令建立的容器文件。其下有文件夹和文件,都以容器的GUID来命名。
其中的926A300B-ACB7-4B28-9D86-45BF82C1211C.vhdx就是该容器的最上层的可读写层,是一个VHDX文件。 记住该可读写层并非一个完整的文件系统,它须要和Image的现有文件系统组成Union File System。若是尝试双击该VHDX(只能尝试挂载中止状态的容器VHDX),试图挂载到Windows系统,会弹出如下报错信息,提示该虚拟硬盘没法挂载。
Image的文件系统位于如下路径(Windows Server Core的Container OS文件):
C:\ProgramData\Microsoft\Windows\Images\CN=Microsoft_WindowsServerCore_10.0.10586.0\Files
若是用Process Explorer查看容器进程访问的Dll,能够看到其访问的路径为Container OS文件。
若是是用docker命令建立的进程,道理相似,可是其可读写层文件系统位于如下路径:
C:\ProgramData\docker\windowsfilter
和Linux不同,Windows容器还须要考虑注册表的隔离问题。和文件系统命名空间隔离同样,注册表命名空间隔离也采用相似Union FS形式。 下面让咱们进入PowerShell命令建立的Windows容器文件夹内部。
C:\ProgramData\Microsoft\Windows\Hyper-V\Containers\926A300B-ACB7-4B28-9D86-45B
在这个Hives文件夹下方,有不少命名为*_Delta的文件,这是容器所访问的注册表配置单元文件。
从命名方式中能够看到,容器的注册表和文件系统同样,也采用分层架构,最上层的是可读写的注册表命名空间。而Image映像也有只读部分的注册表空间,路径以下。
C:\ProgramData\Microsoft\Windows\Images\CN=Microsoft_WindowsServerCore_10.0.10586.0\Hives
在Process Explorer里能够看到可读写层、只读层注册表合并后所加载的内容。
Docker命令所建立的容器,方法相似,位于相似如下路径:
你们知道,Docker能够调用CGroup技术来限制Linux容器的CPU、内存等资源占用。而在Windows容器里,内存资源的限制,则是经过Windows的JO(做业对象)技术来实现。 能够参考如下技术来限定Windows容器的CPU、内存和磁盘IO。例如能够将容器的内存限定为最大占用为5GB。
https://msdn.microsoft.com/en-us/virtualization/windowscontainers/management/manage_resources?f=255&MSPPError=-2147217396
而后用Process Explorer打开任意一个容器进程的属性对话框,切换到Job标签页。
能够看到全部容器进程共享一个做业对象,并且该做业对象的内存限额(Job Memory Limit)为5GB。 来源:http://www.youruncloud.com/docker/1_65.html