【编者的话】本次主要分享DockerCon上的见闻,分享所有内容大致可以分为三个部分:1. Docker 1.7.0深度解析;2.DockerCon Hackathon见闻;3. DockerCon盛典。
第一环节:Docker 1.7.0深度解析
从Docker的版本变更日志来看,Docker 1.7.0在四个方面会有或多或少的变动,分别是:Docker运行时(Runtime),Docker的代码变化,Docker的builder模块,以及Docker的bug修复。此次分享主要涉及Docker 1.7.0的runtime。
1.1.增添了一个仍然处于试验阶段的特性:支持out of process的数据卷插件
何为试验性质的特性,换言之Docker的这部分特性还不支持在生产环境中采用,这些特性更多的希望用户仅仅在测试环境,以及沙箱环境中采用。试验性特性完全是Docker 1.7.0的一大亮点。
在以上的基础上理解out-of-process,就容易很多,插件本身与Docker Daemon无耦合,即插即用,在Docker Daemon范畴之外发挥作用。
目前Docker的试验性特性可以从两个方面来描述,首先Docker目前已经支持用户自定义第三方插件的使用;另外在这基础上,Docker自身支持了容器数据卷volume插件。此外,Docker还定义了一整套与插件相关的API,方便用户使用。当然,相信后续在该领域,不论是Docker官方,还是整个社区,都会不断有新的插件诞生。值得一提的,在数据卷volume插件方面,出现了Flocker的身影,这也意味着容器的数据存储问题,真正被提上台面,并有相应合理的解决方案。
1.2.从docker daemon的角度,添加了userland-proxy的起停开关
首先介绍userland-proxy一直以来的作用。众所周知,在Docker的桥接bridge网络模式下,Docker容器时是通过宿主机上的NAT模式,建立与宿主机之外世界的通信。然而在宿主机上,一般情况下,进程可以通过三种方式访问容器,分别为:<eth0IP>:<hostPort>, <containerIP>:<containerPort>,以及<0.0.0.0>:<hostPort>。实际上,最后一种方式的成功访问完全得益于userland-proxy,即Docker Daemon在启动一个Docker容器时,每为容器在宿主机上映射一个端口,都会启动一个docker-proxy进程,实现宿主机上0.0.0.0地址上对容器的访问代理。
当时引入userland-proxy时,也许是因为设计者意识到了0.0.0.0地址以及localhost对容器访问上的功能缺陷。然而,在docker-proxy加入Docker之后相当长的一段时间内。Docker爱好者普遍感受到,很多场景下,docker-proxy并非必需,甚至会带来一些其他的弊端。
影响较大的场景主要有两种。
第一,单个容器需要和宿主机有多个端口的映射。此场景下,若容器需要映射1000个端口甚至更多,那么宿主机上就会创建1000个甚至更多的docker-proxy进程。据不完全测试,每一个docker-proxy占用的内存是4-10MB不等。如此一来,直接消耗至少4-10GB内存,以及至少1000个进程,无论是从系统内存,还是从系统CPU资源来分析,这都会是很大的负担。
第二,众多容器同时存在于宿主机的情况,单个容器映射端口极少。这种场景下,关于宿主机资源的消耗并没有如第一种场景下那样暴力,而且一种较为慢性的方式侵噬资源。
如今,Docker Daemon引入- -userland-proxy这个flag,将以上场景的控制权完全交给了用户,由用户决定是否开启,也为用户的场景的proxy代理提供了灵活性。
1.3. docker exec命令增加- -user参数,用户控制docker exec在容器中执行命令时所处的用户
自从docker 1.3.0引入docker exec之后,用户对容器的操纵能力被大大释放,容器对用户而言不再是一个运行的黑盒。然而,docker exec带来巨大好处的同时,我们也能看到这其中的一些瑕疵,当然Docker社区也在不断地完善docker exec。
首先,docker exec在容器中运行的进程会以root权限运行,在权限方面缺乏灵活性的同时,容器的安全很有可能失控。参数- -user恰好弥补了这方面的不足。其次,docker exec的存在打破了容器内进程呈现树状关系的现状,而设计初期Docker容器的很多概念均以树的思想从init process入手,因此目前docker exec的进程并不能和原生态容器进程完全一样地被Docker Daemon管理。
1.4. 增强Docker容器网关地址的配置广度
Docker 1.7.0发布之前,在bridge桥接模式下,Docker容器的网关地址是默认生成的,一般为Docker环境中的docker0网桥地址。从容器通信的角度而言,默认的方式已经可以满足需要。但是,我们依然可以发现,这种模式存在一些弊端,比如网络配置的灵活性以及网络安全性。
Docker容器的网络一直广受关注,缺乏可配置的特性,在如今的软件发展中,几乎就意味着封闭。 –default-gateway 以及–default-gateway-v6 这两个参数,很大程度上提高了用户自定义容器网络的灵活性,用户更多场景的覆盖,似乎从Docker的发展中若影若现。结合最近几次新版本,功能的增强与丰富,不难猜测,Docker的企业化以及生产化,已经更上一层楼。
默认网关的设置,为什么说会和容器的网络安全相关呢?过去很长一段时间内,docker0作为容器的网关地址,这种方式将容器与宿主机的耦合关系体现的很彻底。docker0作为宿主机上的网络接口,充当容器与宿主机的桥梁。然而,也正是桥梁的存在,使得容器内部进程很容易穿过网关,到达宿主机,此过程并非对用户透明。
1.5. 容器CFS quota的支持
完善Docker对内核cgoups的支持,指的是对于一个组内的进程组在一个周期内被内核CFS调度算法调度的时间限额,单位为微秒。该配置项在cgroups中相应的文件为/sys/fs/cgroup/cpu/cpu.cfs_quota_us。
1.6. 容器磁盘IO限制的支持
众所周知,容器将会为用户提供一个隔离的运行环境,容器内部的进程或者进程组使用资源时将受到限制,这样的资源,包括:内存资源(物理内存以及swap),CPU资源(CPU时间片以及CPU核等),磁盘空间资源等,以上这部分内容或多或少,Docker的新版本之前或多或少都可以实现,然而隔离维度依旧不够完美,这次Docker添加了—blkio-weight参数,实现对容器磁盘IO限制的支持。隔离更加完备,用户也不再需要担心容器间磁盘IO资源的竞争。
1.7. ZFS支持
Docker 1.7.0 正式宣布支持ZFS文件系统。此举也意味着Docker容器文件系统的支持从原先的5种增加到6种。此前,Docker支持aufs,devmapper,btrfs,ovelayfs,vfs(用于支持volume),如今添加对ZFS的支持。ZFS的支持,不禁让人联想到与Docker的数据卷volume插件的Flocker。错进错出,似乎关系较为微妙。
值得一提的是,除了支持ZFS之外,笔者发现在负责容器文件系统的graph模块中,添加了driver_windows.go,虽然内容极其简易,并非完全实现对windows的全盘支持,但是至少让大家看到Docker支持windows的步伐在不断迈进。
1.8. docker logs的功能扩展
查看容器日志,相信很多Docker爱好者都体验过,这也是用户查看容器运行状态的重要依据。
可以简单了解Docker容器日志的原理:对于每一个创建的Docker容器,Docker Daemon均会在内部创建一个goroutine来监听容器内部进程的标准输出stdout以及标准错误stderr,并将内容传递至日志文件中。每当用户发通过Docker Client发起查看容器日志的请求docker logs之后,Docker Daemon会将日志文件的内容传递至Docker Client显示。
docker logs的发展,几乎可以分为4个阶段:Docker诞生初期的原生态日志打印;允许用户follow容器的日志;开启容器日志的tail功能,以及容器日志的since功能,打印从某一个时间戳开始之后的容器日志。
虽然容器日志的功能在逐渐增强,但是不可否认的是,容器日志是容器本身与Docker Daemon耦合最大的模块之一,而这涉及Docker设计之初的计划,绝非完美,但的确是短时间内最易用的方案。
1.9. 容器与宿主机共享UTS命名空间的支持
不同的场景下,容器与宿主机可以完全隔离,容器也可能与宿主机存在共享信息的情况,Docker网络的host模式就是一个很好的例子,该模式下的容器共享宿主机的网络命名空间。
共享UTS命名空间的支持,意味着容器与宿主机的关系越来越微妙。也许目前很多Docker爱好者已经习惯容器与宿主机完全隔离的运行,当然也会有一些用户曾经抱怨完全隔离的运行环境并不能平滑的将传统遗留业务容器化。那么,目前Docker在兼顾两者的情况下,更多地在满足后者的需求,不久的将来,Docker容器的运用场景必将更加丰富,这也是Docker走向企业化以及生产化必须要趟的路。
总体而言,Docker 1.7.0给笔者的感受是:功能上逐渐向企业需求靠拢,在production-ready的路上不断优化,另外在安全方面在不涉及内核基础上也不断完善。
就在发布1.7.0之后没几天的DockerCon上,Docker宣布production-ready并严肃看待安全,其实从1.7.0的变更来看,完全可以感受到这一点。
另外,需要提及的是:以上的3、5、6三点均是国内公司华为的大力推动下完成的,作为一个Docker开发者,由衷的感谢华为以及众多的docker committer的贡献。
第二环节:DockerCon Hackathon
6月7号8号,咱们中国的开发者在北京举办了一次Golang&Docker Hackathon,DockerCon前夕旧金山也举办了一次Docker Hackathon。这次黑客马拉松诞生了很多新颖的想法,鲸鱼粉的Geek精神发挥得淋漓尽致。由于内容过于丰富,我仅仅给大家介绍两个我印象非常深刻的项目。
2.1.参赛项目:Swarm-SEC
这是一个Swarm集群安全评估工具
通过Swarm、预先定义的安全规范来扫描整个集群。评估的安全维度有主要有三点:Swarm中docker daemon的安全配置,Swarm集群中Docker Node的具体安全策略使用情况,Swarm集群的运行时安全情况。
这是swarm-sec的启动方式:
docker run -it --net host --pid host --cap-add audit_control \
-v /var/lib:/var/lib \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib/systemd:/usr/lib/systemd \
-v /etc:/etc --label swarm-sec \
swarm-sec <token-id>
网络命名空间,Pid命名空间,几乎将所有的Docker信息都挂载到容器内部了,另外还添加了一个Capability能力audit_control,用以获取audit守护进程的信息。
我主要介绍一下Swarm-sec关注了Swarm Daemon以及Docker Node上Docker Daemon的哪些安全问题。
Swarm Daemon
1.查看Swarm是否运行在容器之中,
2.查看Swarm是否是一个最新的稳定版本
3.查看Swarm的日志级别,不建议使用debug模式
4.验证是否占用Docker的默认端口
5.验证Swarm Daemon是否启用了TLS安全传输协议
6.验证容器调度驱动是否是mesos,目前mesos驱动仍处于试验阶段
7.查看类似于SELinux和AppArmor是否启用
……
Docker Daemon
验证Docker Node的label设置是否规范,验证docker daemon的配置手否符合安全,比如不建议使用AUFS等。
项目源码:https://github.com/snrism/swarm-sec
2.2.参赛项目:Sherdock RancherOS的作品
主要的特征有:
基于正则表达式,对Docker镜像进行自动回收。
镜像GC的的原因主要还是因为在build失败的时候会产生一系列的none镜像,这些镜像未必有用。此时就可以基于给定的正则表达式,将这样的镜像清理掉。
基于docker 1.7.0做孤儿数据卷的清理工作。(孤儿数据卷:有data volume的容器在删除时没有指定-v参数)
提供UI界面。
Hackathon的报道分享得太多容易占篇幅,如果大家感兴趣,可以查阅:DockerCon之黑客马拉松见闻
第三环节:DockerCon盛典
分享DockerCon见闻,DockerCon两天发生的内容自然是重头戏。这部分的分享,我主要分为两部分:第一,keynotes的内容,并通过几个关键字进行介绍;第二,介绍我参加的几个分会场的topic内容。3.1 keynotes关键字
3.1.1 OCPDocker联合众多IT巨头,共建完全开放的容器标准,名为OCP,意为“开放式容器项目”,我国的公司华为也赫然在列。OCP是全球首个容器技术界开放并统一的标准。
OCP的诞生意味着Docker与CoreOS之间曾有的容器标准之争,暂告一段落。OCP的开放性使得容器的标准能够得到更好的完善。
OCP使得容器的发展能够被广泛认同并支持,个人或团队伸直企业对容器技术的共享能够更多的被思考,能够更多的被实践,其发展对容器的影响绝对不可小估。
3.1.2 新项目
Experimental binary
Docker的experimental binary是那种功能非常强大、但不可能被加入Docker官方版本的功能组件。这种实验性质的构建允许用户自行体现Docker的新功能,并且给Docker的维护者提供反馈。通过这种方式,Docker官方希望可以将一些新功能预先暴露给全球的开发者,从而让大家在实践以及反馈中重塑这些重要功能。
目前,Docker的网络插件以及数据卷volume插件是最先问世与大家见面的试验性功能插件。
Docker plugins
Docker的可扩展性再次被Solomom及其团队提上议程并实践。目前,Docker的network模块,数据库volume模块,swarm中的调度模块以及服务发现模块,均已经逐渐被插件化,体现Docker生态中软件强大的扩展性能力之外,更体现了Docker生态的开放性。当然除了以上这些已经支持的插件之外,未来的插件必定会更多。
此外,插件的使用,对于Docker Daemon以及其他的软件模块没有其他的patch引入,然而目前仍然需要重启Docker Daemon或者其他软件。另外,插件的支持,对于Docker应用而言是全盘透明的,插件的引入不会改变原有Docker应用的使用方式。
Docker Notary for security
Notary由server端和client端组成,Server端主要运行并维护一个容器的受信集合,Client端用以与Server交互最终实现安全任务的分发。
总体而言,Notary希望提供一种简单的方式,便于用户更安全的发布以及验证网络数据。原则上,我们可以通过TLS安全传输层协议保障通信双方的安全性,然而这本质上存在缺陷,原因很简单,Server端的任何疏忽,都将导致恶意内容替换合法内容,从而前者危及网络通信。
在Notary的帮助下,网络内容的发布者可以通过强安全的key对用户内容进行签名加密。一旦完成并准备发布,则内容首先被推送至Notary受信的集合中。访问者只有通过安全隧道获取了发布者的公钥之后,才能和Notary中的任意server建议通信,并访问到合适准确的资源。
runC.io
runC是一个OS层面通用的运行时环境,而且仅仅是OS层面的运行时。项目地址:[https://runc.io]
Docker官方宣称runC以及通过全面测试,并且production-ready。
在功能方面,runC支持Linux所有的安全特性,比如:SELinux,apparmor,cgroups,seccomp等。
- 支持目前连docker都不支持的user namespace
- 支持容器的热迁移。
- 微软正在积极开展windows对runC的支持。
- ARM体系的支持也正在积极进展中。
- Intel也在对DPDK贡献
- 明确了标准化、可移植、可运行的格式
- 兼容于命令行形式以及编程方式
3.1.3 生产化
Docker Hub线上服务的增强和改进
升级到V2 open source registry
优化后端,实现了更快的下载速度,更少的客服端/服务器端的交互次数
提高稳定性、整体用户体验提升
新的UI界面
提升安全性方面Docker做了很多努力,包括
authentication micro services
content-addressable images
one time use build hosts
on-ging scanning and audits等等。
Ocra
Project Orca的愿景是提供一套自上而下的整合栈,能够抓取所有的工具和plumbing(Docker Engine、Docker Swarm、Networking、GUI、Docker Compose、安全、安装工具、部署、配置等)。Project Orca非常适合“build-ship-run”中“run”的部分。
代表着Docker开始真正的进军企业市场,私有化容器管理解决方法Docker推出解决方案。
3.2 分会场分享
3.2.1Docker的安全
Docker能提供的安全保障将涵盖以下7点:
- namespace保障系统资源的隔离
- cgroup完成进程组资源的限制
- Linux的安全模块提供MAC(apparmor, SELinux)
- capabilities将root的权限细分为多种类型
- ulimit的功能更多维度的限制资源(docker 1.6之后支持)
- user namespace保障容器内部的root在host上并非root(预计docker 1.8支持)
- seccomp使得容器内进程受到系统调用权限的控制
Docker在安全方面还做了以下工作:
降低镜像带来的安全风向
设置更为精简的Linux发行版:
移除不需要的package、用户以及二进制工具文件
提出Tailored Profiles
容器可以创建least-privildge的文件
文件有能力随容器传递
通过独立的文件配置表明所有的权限
已经规划入runC
描述所有的隔离特性
值得提及的是:DockerCon安全话题的分享者,感谢了来自中国的华为公司。
3.2.2 Netflix的Docker企业级实践
为什么选择Docker?
1. 在netflix内部进程隔离的需求很大
2. Docker有能力将众多功能集一身,并打包成一个Docker二进制文件,用户完成无需关心与linux内核与其他特性之间的依赖关系,只需操纵Docker简易的API即可
3. Docker的周边工具链的发展以及集群间应用发布的可扩展性大大吸引了Netflix
Q&A
1.之前的docker-proxy这个进程似乎仅仅为了实现端口映射,而且还是每个容器占一个进程,是否有可能让daemon仅有一个进程,负责维护这个daemon上所有的端口映射?答:关闭userland-proxy之后,对于容器间的通信,以及容器与外界的访问不会有任何影响。但是影响总是存在的,docker-proxy的存在总是有价值的。影响就是:在单host上通过0.0.0.0和localhost已经不能访问容器的端口,但是通过主机IP还是可以通信的。单个进程来维护的,负载会非常大,而且使得该进程与所有容器产生很大的耦合,会有一些弊端。
2.“增添了一个仍然处于试验阶段的特性:支持out of process的数据卷插件” 这个具体提供什么功能?
答:简单说就是这个插件有能力对容器的数据卷data volume进行管理,包括存储备份,恢复等功能
3.请问experimental binary的最终呈现就是docker plugin么?
答:我的理解是“不完全是”, experimental binary也可以是docker daemon内部的一些功能,然后宣布说是experimental binary,让所有的docker用户去体验,去测试,帮助完善docker;插件也是一种形式。
4.能否介绍下windows平台上,容器支持情况的进展,貌似看到微软有展示?
答:微软自己也有容器解决方案,当然不是Docker,现在的情况是微软要开始慢慢支持Docker,这个计划完全看的到在进行了,从一开始的windows支持Docker的API,到现在Docker的具体实现也出现了windows的身影,但是到完全实现,可能还需要走一段比较长的时间。
5.请问下default gateway是1.7.0新增的功能么,能否稍微详细介绍下?
答:原先Docker容器的网关地址一般是固定的,都为docker0网桥地址,docker0位于宿主机,这样容器和宿主机之间的桥梁docker0很容易被利用,打通从容器到宿主机的通路。为容器设定default-gateway,可以绕过docker0,尽管物理上流量还是要经过docker0,至少用户是不可见了。
了解更多DockerCon现场精彩内容->
1.Docker 1.7.0 深度解析
2. DockerCon之黑客马拉松见闻
3. 除了OCP,DockerCon的主题演讲还说了些什么?
4. 有图有真相:DockerCon之Netflix的Docker企业级实践
5. 美国金融行业的Docker实践
6. DockerCon Day 2: 进军生产环境!
7. DockerCon Day 2:安全至上
8. DockerCon Day 2:城里人玩镜像
9. DockerCon Day2:闭幕+彩蛋
=====================================================
以上内容根据2015年7月2日晚微信群分享内容整理。分享人孙宏亮,DaoCloud软件工程师,InfoQ《Docker源码分析》专栏作者。接触Docker近两年,爱钻研系统实现原理,懂一点Linux操作系统。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学请加微信:liyingjiesx参与分享与学习。
有疑问加站长微信联系(非本文作者)