在咱们微信群里听一位兄弟提到,Docker能将DevOps(意即”开发”和”运维”)整合在一起,暗合王阳明先生的“知行合一”之教,这真是一种有趣的说法。
话说从头,盆盆在《Windows Docker深入原理分析》里曾经提到微软Build大会后,会第一时间给大家介绍Windows Docker技术。
还没看过Build在线视频的朋友,您可以泡杯咖啡,带上耳机,静静地欣赏以下由Taylor Brown主讲的Windows Docker讲座,我们的文章就以此为蓝本。
这里需要注意的是:以下的论述,大多是盆盆根据Taylor的demo效果所做的推论,并不是Taylor本人的陈述,所以并不一定正确。由于能力所限,必然谬误不少,还望大家能及时指出哈。
拿大家熟悉的Linux Docker来看,其涉及到Linux内核所提供的Namespace隔离技术和资源控制的CGroup技术。
这里推荐大家阅读浙大SEL研究生孙建波老师的文章《Docker背后的内核知识——Namespace资源隔离》。
孙建波老师提到了一张表格,其中列出了Linux内核所支持的6种隔离:主机名、IPC、进程ID、网络、文件系统、账号。
先来看看浙大SEL的另一位大牛孙宏亮老师的文章《Docker源码分析(九):Docker镜像 》。这篇文章清晰地描述了Linux Docker的文件系统隔离,多层的可叠加文件系统。
孙宏亮老师指出,假设我们下拉了Ubuntu:14.04映像,并通过命令docker run –it ubuntu:14.04 /bin/bash将其启动运行。则Docker为其创建的rootfs以及容器可读写的文件系统参见下图。从容器的视角来看,虽然只有一个逻辑的完整文件系统,但该文件系统由“2层”组成,分别为读写文件系统和只读文件系统(按只读层还可以再逻辑分层,所以极大地节省磁盘空间)。
视频里演示了一个demo。用一段简单的代码,在Docker Client的console里显示“This is a pretty cool app”。
第1行:表明该映像基于windowsservercore这个Base映像,可以将其理解为rootfs
第2行:表示工作目录是C盘根目录
第3行:将应用目录复制到容器映像里
第4行:启动该应用程序
和Linux Docker容器一样,Windows容器也采用IPC隔离机制。Windows容器使用Windows自己的session隔离机制。
会话(session)隔离机制,最初是用在Windows终端服务和快速用户切换中,以便这些不同用户的进程不会互相干扰,确保安全。从Windows Vista开始,也采用这种技术对系统会话进行隔离,Windows系统自己的服务和进程会占用原来的控制台会话(会话0),而后续的用户会依次使用会话1、会话2等等,这就是我们不能再使用mstsc /console进行控制台登录的原因。
从《Windows Internals》里我们可以学习到:不同会话里的应用,不能够发送窗口消息(Window Message),以防止粉碎攻击。每个会话拥有自己专用的对象命名空间。同样每个Windows容器,也会有自己的独立会话,有自己专用的BaseNamedObjects等对象命名空间,以便隔离事件、互斥信号和内存段等对象。这样不同容器在同一个Windows主机上访问同一个命名对象,就不会导致冲突。以下的WinObj对话框是在盆盆自己的Windows 10上截图的,虽然不是取自Windows Docker系统,但是道理是一样的,可以看到不同的会话,拥有自己专用的对象命名空间。
视频里演示了Docker容器的会话隔离能力。Taylor启动了两个容器,都是从同一个windowsservercore映像里派生出来的。其中一个容器,可以运行Tasklist命令,看到该容器运行在会话14中。而且还能看到两个系统进程,一个是System进程,代表操作系统本身,另一个是空闲进程,这两个进程都运行在会话0里。
和Linux容器一样,Windows容器也可以有自己的独立网络配置。
由于传统的Windows应用大多是有GUI的,所以这些应用可能需要通过图形化方式进行远程操控。
视频里Taylor举了一个sysinternals容器的例子。有趣的是,这个demo本来是Mark Russsinovich的保留曲目,可惜Build大会Keynote的时间十分宝贵,Mark没有足够的时间去演示,而由Taylor代劳。
Taylor演示直接在docker client上下文里启动Sysinternals Suite里的经典工具Process Explorer,由于该工具带GUI,所以虽然进程已经在容器里启动,但是在Docker Client里无法直接远程显示。
如何才能正常显示呢?Taylor用了一个CC命令,直接连接到该容器的IP地址(192.168.0.23)。从demo里我们可以看出,实际上这个CC命令连接到容器的RDP服务上,这样就相当于直接通过终端服务连接到容器里的会话里,哈哈,有点类似RemoteApp(或者Citrix XenApp)的效果!
在Linux容器里,容器里的PID有自己的独立命名空间。从演示的情况来看,Windows容器的PID隔离方法看上去略有不同。
在前面IPC隔离一节,我们可以通过tasklist命令确认不同的容器,其CSRSS、Lsass、SVCHOST等重要进程的PID有所不同,用户进程的PID也不一样,可见彼此之间是完全隔离的。
那么从宿主机的角度来看呢?
我们可以用Process Explorer的例子来确认,这需要观看Ignite大会上由Taylor所主讲的视频,由于Process Explorer是在终端会话里打开的,所以我们可以在容器的任务管理器里看到有两个会话:
1.会话14是Docker客户端访问生成
2.会话15则是通过RDP访问生成
可以看到Process Explorer的进程有两个版本。显然,会话14是Taylor在Docker客户端里运行的结果(但是我们无法看到图形化界面),而会话15则是RDP访问的结果。
两者的运行账户不一样,RDP登录的运行身份为Administrator(应该和Docker History一致),而会话14则是System账户。
以下是从容器视角所看到的任务管理器。这个任务管理器是从容器的角度来看的,我们可以记下其中的若干SVCHOST进程的PID。
Linux内核拥有账户隔离能力,可以让容器里的进程以root身份运行,而在宿主机上,该账户实际上是普通用户权限,这样可以极大地改进安全性。
在Taylor的这个演示中,我们也能“察觉”到一些蛛丝马迹。在PID隔离一节的两个任务管理器截图里,从容器的视角来看,可以看到Process Explorer的运行账户为Administrator,但是从宿主机上查看,对应进程的运行账户为空。所以Windows容器可能也实现了类似的账户隔离技术(抱歉这只是推测,我们现在还拿不到Windows Docker的测试版本)。
Windows容器拥有自己的计算机名和域名隔离能力,这样在网络上,Windows容器看上去类似于一台独立的虚拟机。
不过由于共享内核,所以Windows容器目前应该不支持活动目录,毕竟同一台宿主机上所有容器应该都具有同一个SID,这样就无法加域(无法验证计算机账户)。
盆盆推测,到了Windows容器时代,类似于活动目录这类比较笨重的验证协议可能会逐渐退出历史舞台。毕竟活动目录需要开放那么多端口,需要借助ADFS等手段才能穿透Internet。
不过Windows容器的验证并不会存在问题,Azure AD和证书等都是很合适的办法。
容器非常适合开发的快速迭代、快速回滚。Taylor做了一个简单的演示,对前面所述的代码进行修改,调用私有的msvcr120.dll文件里的_snwprintf函数,以显示”Now it’s really cool”。
在Build大会的Keynote上,Mark Russinovich演示了用Visual Studio把同一个电商网站的代码签入到Windows容器和Linux容器里,并且可以用Visual Studio来调试Linux容器里的代码。
联系客服