Windows Docker第一时间揭秘-盆盆跑微软两会

【编者的话】这是盆盆谈微软两会(Build/Iginte)系列之一。文章引用孙建波老师关于Linux内核的6大命名空间隔离,看Windows Docker如何实现相似隔离,同时又有哪些不一样。文章素材取自Build和Ignite大会视频,但主要展现盆盆本身的分析和研究,还望你们指正为谢。html


今天在微信群里听一位兄弟提到,Docker能将DevOps(意即"开发"和"运维")整合在一块儿,暗合王阳明先生的“知行合一”之教,这真是一种有趣的说法。linux


话说从头,盆盆在《Windows Dcoker深刻原理分析》里曾经提到Build大会后,您能够在华来四公众号里回复docker8,阅读这篇文章(能够在微信里搜索并关注公众号:sysinternal),会第一时间给你们介绍Windows Docker技术。docker


还没看过Build在线视频的朋友,您能够泡杯咖啡,带上耳机,静静地欣赏如下由Taylor Brown主讲的Windows Docker讲座,咱们的文章就以此为蓝本。这里须要注意的是,如下的论述,大可能是盆盆根据Taylor的demo效果所作的推论,并非Taylor本人的陈述,因此并不必定正确。若有问题,还望你们多ubuntu

多指点哈。windows

http://channel9.msdn.com/Events/Build/2015/2-704sass


容器即隔离bash


拿你们熟悉的Linux Docker来看,其涉及到Linux内核所提供的Namespace隔离技术和资源控制的CGroup技术。微信


这里推荐你们阅读浙大SEL研究生孙建波老师的文章《Docker背后的内核知识——Namespace资源隔离》:网络

http://www.infoq.com/cn/articles/docker-kernel-knowledge-namespace-resource-isolation?from=timeline&isappinstalled=0session


孙建波老师提到了一张表格,其中列出了Linux内核所支持的6种隔离:曰主机名、曰IPC、曰进程ID、曰网络、曰文件系统、曰帐号。


尽管Windows内核实现和Linux不一样,可是二者仍是有很多可比拟处。因此盆盆根据Build大会上Mark Russinovich这位大神以及Taylor Brown的讲座,来条分缕析。


文件系统隔离


先来看看浙大SEL另外一位大牛孙宏亮老师的文章《Docker源码分析(九):Docker镜像 》。这篇文章清晰地描述了Linux Docker的文件系统隔离,多层的可叠加文件系统。

http://blog.daocloud.io/docker-source-code-analysis-part9/


孙宏亮老师指出:假设咱们下拉了Ubuntu:14.04映像,并经过命令docker run –it ubuntu:14.04 /bin/bash将其启动运行。则Docker为其建立的rootfs以及容器可读写的文件系统参见下图。从容器的视角来看,虽然只有一个逻辑的完整文件系统,但该文件系统由“2层”组成,分别为读写文件系统和只读文件系统(按只读层还能够再逻辑分层,因此极大地节省磁盘空间)。

wKiom1Vhv2jzEwo1AACi-9Fcksw515.jpg


Windows Docker一样如此,顶层的沙盒层(sandbox layer)是可读写的,只容许该容器本身占用,而其余层则是只读的,可供不一样容器共享。在下图中,底层的基础OS层和中间的应用程序框架层都是只读的,而顶层的沙盒层则可读写,在容器的视角看来,它独占了完整的OS。这有点相似于Hyper-V的差别磁盘链(顶部的子盘才能读写,其上方的全部父盘和Base盘都是只读的)。

wKioL1VhwQOxUWXpAAGdUvZCbHE961.jpg


为了说明文件系统隔离的魔力,Taylor得意地在Windows Container里执行删除C盘根目录下全部文件和注册表键值,尽管这个容器被毁了,可是根本不会影响其余容器,更不会影响主机。

wKiom1Vhv4bw0Y-SAAHdz1pYCIc531.jpg


盆盆猜想,在容器的视角里,若是只是读取一个文件,该文件在最顶端的沙盒层里只有重解析点(reparse point);只有在修改该文件时,才会用copy-on-writer的方法从下方的只读层中把文件内容复制到可读写的沙盒层。


建立Windows Container


视频里演示了一个很棒的demo。有一段简单的代码,在console里显示“This is a pretty cool app”。

wKioL1VhwSGy-eYpAADZmNs2ZaA806.jpg


这是用来构建Windows Docker映像的Dockerfile。这个文件由如下4行命令组成:

  • 第1行:代表该映像基于windowsservercore这个Base映像,能够将其理解为rootfs

  • 第2行:表示工做目录是C盘根目录

  • 第3行:将应用目录复制到容器映像里

  • 第4行:启动该应用程序

wKiom1Vhv6fBToHaAAClhkuH2W8974.jpg


很快用docker build命令将其构建为容器映像,Tag是1。从命令结果中能够看到Dockerfile里的每一个命令都被执行,在执行第4个命令时,会生成一个临时的容器。

wKioL1VhwUGDwnqOAAG9Z1-E6SY488.jpg


Docker映像构建完成后,只需运行docker run命令便可快速启动该映像,并成功显示"This is a pretty cool app..."。

wKiom1Vhv7-wh6I7AADveoCZYAM167.jpg


经过使用docker history命令,咱们能够查看容器映像的构建历史,这甚至能够用来逆向生成Dockerfile。例如视频里演示了sysinternals这个映像的构建历史。从中咱们能够看到:首先记录维护人员是谁;而后指定工做目录是C盘根目录;再者是将sysinternals suite这个工具软件目录拷贝到容器映像里;而后设定容器的运行帐户;最后设置启动Ipconfig以便显示容器的IP地址。

wKioL1VhwVnicR6nAADvz1IJEyE289.jpg


IPC隔离


和Linux Docker Container同样,Windows Server Container也采用IPC隔离机制。这其实是利用Windows本身的session隔离机制。


会话(session)隔离机制,最初是用在Windows终端服务和快速用户切换中。可是从Windows Vista开始,Windows也采用这种技术对系统会话进行隔离,Windows系统的服务和进程会占用原来的控制台会话(会话0),然后续的用户会依次使用会话一、会话2等等。


从《Windows Internals》里咱们能够学习到,不一样会话里的应用,不可以发送窗口消息(Window Message,以防止粉碎***)。不一样会话里拥有不一样的对象命名空间,例如不一样容器,有本身独立的BaseNamedObjects目录,包含事件、互斥信号和内存段等对象。这样不一样容器在同一个Windows主机上访问同一个命名对象,就不会致使冲突。如下的WinObj截图虽然不是取自Windows Docker系统,可是道理是同样的。

wKiom1Vhv9qDwdwxAAJdagMAcS4426.jpg


有兴趣的朋友能够参考盆盆在9年前发表在ITECN博客上的文章,介绍会话隔离技术:

http://blogs.itecn.net/blogs/winvista/archive/2006/06/09/SrvSession0.aspx


视频里演示了Docker容器的会话隔离能力,Taylor启动了两个容器,都是从同一个windowsservercore映像里建立出来。其中一个容器,能够运行Tasklist命令,看到该容器运行在会话14中。并且还能看到两个系统进程,一个是System进程,表明操做系统自己,另外一个是空闲进程,这两个进程都运行在会话0里。

wKioL1VhwXHysexjAAGpKjhgR5o804.jpg


在同一个映像所建立的另外一个容器里,咱们能够看到该容器运行在会话15中,一样能够看到System和空闲进程。Taylor的解释是因为容器是共享Windows Kernel的,因此容易能够看到System进程的PID是同样的,都是4。其实在全部Windows主机上,System进程的PID都是4。

wKiom1Vhv-_zB9D_AAHSSL_-Hw4832.jpg


网络隔离+图形化访问


和Linux容器同样,Windows容器也能够有本身的独立网络配置。

wKioL1VhwZHhfeLzAAE29cREuQ8686.jpg


因为传统的Windows应用大可能是有GUI的,因此这些应用可能须要经过图形化方式进行远程操控。


视频里Taylor举了一个sysinternals容器的例子。有趣的是,这个demo原本是Mark Russsinovich的保留曲目,惋惜Keynote的时间十分宝贵,最Mark没能有足够的时间去演示。


Taylor演示启动Sysinternals Suite里的经典工具Process Explorer,因为该工具带GUI,因此虽然进程已经在容器里启动,可是在Docker Client里没法直接远程显示。


如何才能正常显示呢?Taylor用了一个CC命令,直接链接到该容器的IP地址。从demo里咱们能够看出,实际上这个CC命令链接到容器的RDP服务上,这样就至关于直接经过终端服务链接到容器里的会话里。

wKioL1VhwbLzEHx7AAI9V74brwI268.jpg


盆盆在《Windows Dcoker深刻原理分析》里曾经提到Windows Docker的前身DrawBridge在其沙盒里实现了RDP服务(请在华来四公众号里回复docker8,阅读这篇文章),Windows Docker的原理应该相似。

wKiom1VhwDCBV5zVAADl8b8wTpI349.jpg


Linux Docker也能访问图形化界面,在如下的这篇文章《在 Docker 中运行 OpenOffice》里介绍,只需在Dockerfiles里添加安装X Server的命令,就能借助VNC客户端链接到OpenOffice图形化界面。

http://linux.cn/article-5305-weibo.html


PID隔离


在Linux容器里,容器里的PID有本身的独立命名空间。从演示的状况来看,Windows容器的PID隔离方法看上去略有不一样。


在前面IPC隔离一节,咱们能够经过Tasklist命令确认不一样的容器,其CSRSS、Lsass、SVCHOST等系统进程的PID有所不一样,可见彼此之间是彻底隔离的。


那么从宿主机的角度来看呢?


咱们能够看Process Explorer的例子(该例子是在Ignite大会上由Taylor所演示的),因为Process Explorer是在终端会话里打开的,因此咱们能够在容器的任务管理器里看到有两个会话

  • 14是Docker客户端访问的会话

  • 而15则是经过RDP访问的会话


能够看到Process Explorer的进程有两个版本。显然,会话14是Taylor在Docker客户端里运行的结果(可是咱们没法看到图形化界面),而会话15则是RDP访问的结果。


二者的运行帐户不同,RDP登陆的运行身份为Administrator(应该和Docker History一致),而会话14则是System帐户。


如下是容器里的任务管理器。

wKioL1VhwciCfYlMAAIjFougUmY378.jpg


这个任务管理器是从容器的角度来看的,咱们能够记下其中的若干SVCHOST进程的PID。接下来咱们打开宿主机的任务管理器,从全局的角度来查看。能够发现,从宿主机的角度来看,能看到每一个容器里的进程,其PID和容器里面的版本是同样的。

wKiom1VhwFfSjakCAAJ8PBbciQ4316.jpg


用户帐户隔离


Linux内核拥有帐户隔离能力,可让容器里的进程以root身份运行,可是在宿主机上,该帐户其实是普通用户权限。


在Taylor的这个演示中,咱们也能“察觉”到一些蛛丝马迹。在PID隔离一节的两个任务管理器截图里,容器里的版本能够看到Process Explorer的运行帐户为Administrator,可是从宿主机上查看,该帐户为空。因此Windows容器有可能也实现了相似的帐户隔离技术。


计算机名和域名隔离


Windows容器拥有本身的计算机名和域名隔离能力,这样在网络上,Windows容器看上去相似于一台独立的虚拟机。


不过因为共享内核,因此Windows容器目前应该不支持活动目录,毕竟同一台宿主机上全部容器应该都具备同一个SID,这样就没法加域(没法验证计算机帐户)。


盆盆推测,到了Windows容器时代,相似于活动目录这类比较笨重的验证协议可能会逐渐退出历史舞台。毕竟活动目录须要开放那么多端口,须要借助ADFS等手段才能穿透Internet。

不过Windows容器的验证并不会存在问题,Azure AD和证书等都是很合适的办法。


容器的优点


容器很是适合开发的快速迭代、快速回滚。Taylor作了一个简单的演示,对前面所述的代码进行修改,调用私有的msvcr120.dll文件里的_snwprintf函数。

wKioL1VhwhnwYqW_AAC5W_oOXgE378.jpg


可是在docker build的时候,Taylor没有修改Dockerfile,没有像Mark以前的demo那样把私有的msvcr120.dll拷贝到容器映像中,生成新的映像Layer。

wKioL1VhwjLxJDDYAADtSLmnNpM049.jpg


结果因为容器的目标宿主机上没有安装Visual Studio,因此新Build的容器运行失败,提醒缺乏msvcr120.dll文件。

wKiom1VhwLPC-RVmAAERGGVks1A250.jpg


解决办法很简单,要么修复这个Bug,要么根据先前的映像快速生成新的容器,这只须要花费几秒钟时间!


解决这个问题很简单,能够根据先前的映像快速生成新的容器,这大概只须要几秒钟时间。这样就能够有充足的时间去调试修改了。

相关文章
相关标签/搜索