写点什么

细说 Windows 与 Docker 之间的趣事

  • 2016-08-29
  • 本文字数:2892 字

    阅读完需:约 9 分钟

众所周知,Docker 能打通开发和运维的任督二脉,所谓 DevOps 是也。有朋友说,这符合王阳明的"知行合一"之教。

而 Windows Server 2016 内置的 Windows Docker 亦已经出来一段时间,这里就来和诸公汇报一下测试结果。

Linux 和 Windows,Docker 里各有多少进程

在安装配置 Container Host 的时候,经常报错 Container OS Image 下载失败 (没办法,墙内的缘故)。

什么是 Container OS?顾名思义,是从容器角度看到的 OS。

Container OS 实际是应用所依赖的用户模式 (User mode)OS 组件,对于 Windows 容器来说,例如 ntdll.dll、kernel32.dll 或者 coresystem.dll 之类的 System DLL。主机上的所有容器共享内核模式 (Kernel mode)OS 组件,对于 Windows,就是 ntoskrnl.exe,还有驱动等。

例如对于以下命令,意味着 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 可以做到最精简。但是由于这些服务几乎不占用什么额外的资源,对于容器性能没有影响。

Windows 容器的进程如何隔离

由于在最新的测试版本里,容器对象的权限设置有了改变,只有 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。

Windows 容器的文件系统如何隔离

和 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

Windows 容器还有注册表

和 Linux 不一样,Windows 容器还需要考虑注册表的隔离问题。和文件系统命名空间隔离一样,注册表命名空间隔离也采用类似 Union FS 形式。

下面让我们进入 PowerShell 命令创建的 Windows 容器文件夹内部。

复制代码
C:\ProgramData\Microsoft\Windows\Hyper-V\Containers\926A300B-ACB7-4B28-9D86-45BF82C1211C\Hives

在这个 Hives 文件夹下方,有很多命名为 *_Delta 的文件,这是容器所访问的注册表配置单元文件。

从命名方式中可以看到,容器的注册表和文件系统一样,也采用分层架构,最上层的是可读写的注册表命名空间。而 Image 映像也有只读部分的注册表空间,路径如下。

复制代码
C:\ProgramData\Microsoft\Windows\Images\CN=Microsoft_WindowsServerCore_10.0.10586.0\Hives

在 Process Explorer 里可以看到可读写层、只读层注册表合并后所加载的内容。

Docker 命令所创建的容器,方法类似,位于类似以下路径:

Windows 容器的资源限制

大家知道,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。

作者简介

彭爱华 网名盆盆,微软混合云技术顾问。11 届微软最有价值专家 (MVP),微软高级认证讲师。出版过近 20 本技术图书,2005 年创建 ITECN 博客 (09 年全国 IT 博客五十强)。微信公众号 (华来四笑侃 Windows):sysinternal。曾获得微软技术大会 TechEd 最佳讲师、中国首届 IT 管理技术大会 (2009) 最佳讲师的光荣称号。


感谢陈兴璐对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016-08-29 18:096887

评论

发布
暂无评论
发现更多内容

DataLeap的Catalog系统近实时消息同步能力优化

字节跳动数据平台

大数据 kafka 数据治理 实时同步 数据研发

融云云盘,不止于存储

融云 RongCloud

云盘 云存储

信用卡市场发展洞察:浦大喜奔APP探索大零售融合经营体系

易观分析

金融 银行 信用卡

年轻一代程序员:社牛、不卷、玩开源

腾源会

开源 腾源会

自学Java和java培训哪个好就业

小谷哥

Java培训学生可以学到哪些开发技术呢

小谷哥

计算机网络——数据链路层

StackOverflow

编程 计算机网络 9月月更

10CSS动画案例,学会了惊艳所有人

大师兄

CSS 前端 9月月更

常见堡垒机小知识汇总-行云管家

行云管家

安全 IT 堡垒机 IT运维

工赋开发者社区 | 从零开始的新跨平台浏览器:Ladybird 正式起飞

工赋开发者社区

参加Java培训能学到开发技术吗?

小谷哥

JAVA开发培训哪家比较好

小谷哥

会当“零”绝顶!天翼云零信任产品利刃出鞘

天翼云开发者社区

安全

天翼云全场景业务无缝替换至国产原生操作系统CTyunOS!

天翼云开发者社区

系统

企业上云安全感多“亿”点!

天翼云开发者社区

Java进阶(二十八)SimpleDateFormat格式化日期问题

No Silver Bullet

Java 9月月更

过等保是浪费钱吗?一定要过等保吗?

行云管家

等级保护 过等保 等保2.0

人工智能、机器学习与深度学习的区别在哪里?

Finovy Cloud

人工智能 深度学习

如何选择靠谱的西安培训机构?

小谷哥

限时开源!阿里P8架构师手写Spring全家桶核心知识学习笔记

了不起的程序猿

Java spring 编程 程序员 Spring全家桶

ApacheCon Asia 2022 精彩回顾 | 如何让更多人从大数据中获益?

白鲸开源

易观千帆 | 2022年7月银行APP活跃用户规模盘点:江浙沪城商行表现亮眼

易观分析

App 金融 银行

数据湖管理及优化

阿里云大数据AI技术

大数据 spark 数据湖 企业号九月金秋榜

Wallys /QCA9880 vs QCA9882/802.11ac Solution/MU-MIMO

wallys-wifi6

QCA9880 QCA9882

是什么引起数据库响应超时?

BUG侦探

MySQL AWS 云服务

Databend JSON 复杂数据类型的设计与使用 | Databend 特性系列

Databend

json

QA如何高效参与技术设计评审

转转技术团队

质量管理 测试 技术设计质量把控

阿里巴巴“高并发”天花板教程《基础+实战+源码+面试+架构》

程序知音

Java 高并发 阿里 多线程与高并发 java架构

100+大屏模板免费领!葡萄城BI行业应用方案重磅发布!

葡萄城技术团队

BI 发布会

CentOS时代即将结束 国产系统能否避免“受限”覆辙?

天翼云开发者社区

天翼云安全一体化纵深体系是怎么炼成的?

天翼云开发者社区

云安全

细说Windows与Docker之间的趣事_Windows_彭爱华_InfoQ精选文章