像JaCoCo这样的复杂功能,我们会抽象成服务,供用户使用。他们只要在构建镜像时选择对应的服务,和该服务起效的环境就可以了。
而实际系统要完成的任务则复杂得多,首先要通过改写Dockerfile完成以上所说的“勾选JaCoCo服务”,同时还要改写镜像中JVM的启动参数等,并完成对JaCoCo服务中心的注册。具体的操作各个服务有所不同,根据实际需求而定,原则就是把这些服务内容增加到对应的环境镜像中去。
通过这种方式构建的镜像,不同环境就拥有了不同的服务。比如,用户在构建镜像时,选择了JaCoCo服务起效的环境是测试环境,那么JaCoCo就只在测试环境的镜像中起效,而不会在生产环境中起效。
除了JaCoCo以外,携程还提供了许多其他与环境有关的服务,组成了一个服务集市,用户可以按照具体需求组合使用。
## 自定义镜像发布
**用户自定义环境脚本、平台化环境选项与服务集市,这两种方式有一个共同的缺点:自定义的部分都需要插到 Dockerfile中,因此每次打镜像时都需要运行一次。** 这对一些比较快的操作,没有问题,但如果需要安装很多软件,甚至需要编译一些软件时,每次发布都重复运行一次的效率就会非常低下。
为此,我们提供了用户自定义镜像的功能,该功能分为自定义Base镜像和完全自定义镜像发布两种。
1. **自定义 Base 镜像**
自定义 Base 镜像,就是如果基础镜像无法满足用户需求,并且自定义的部分非常重,运行比较久,我们就会建议用户使用自定义的 Base 镜像。但是,这个自定义的 Base 镜像,必须基于官方提供的 Base 镜像,因为很多工具和功能都是基于官方Base 镜像的。
虽然 Base 镜像是自定义的,但是应用还是标准的应用,因此发布方式和普通的发布方式没有区别。只是解决了自定义环境脚本与平台化环境选项的运行速度问题,反映到实际的 Dockerfile 上,就只是 FROM指令的指向改变了,变成了用户自定义的 Base 镜像地址。
1. **完全自定义镜像发布**
但是,用户的需求是永无止境的。比如,特殊启动方式的应用,自定义Base镜像就无法解决。
原则上来说,我不建议使用一些非标准的应用,因为这是不可控的,对生产环境非常危险。但是 Docker 的镜像是如此方便,用户如果只是想在测试环境中使用一些测试工具,虽然这个工具来自于社区,也不是标准的应用,但我们也没有理由全部拒绝。否则,用户很可能会以虚拟机上可以安装任何工具为由,要求退回到虚拟机时代。
但是,这样的退化怎么能被允许呢!
因此,一定要支持完全自定义镜像发布,也就是说用户可以发布任何镜像,只要这个镜像能够跑起来。对私有云来说,这应该是能接受的最大化的自由了。
对于完全自定义发布我们使用 Docker 多阶段构建(multi-stage build),也就是说用户可以将构建代码和构建镜像合并成一个步骤,在同一个 Dockerfile 中完成。
## 镜像安全合规检查
满足了用户对镜像的个性化需求,也就意味着会引入不可控因素,因此对镜像的安全合规检查也就变得尤为重要了。我们必须通过合规检查,来确认用户是否在容器里做了危险的事情。
只有这样,用户个性化的自由,才不会损害整个环境。毕竟,有克制的自由才是真正的自由。
**对自定义镜像,首先必须保证它是基于公司官方Base 镜像的,这是携程最不可动摇的底线。** 在其他情况下,就算真的不继承公司官方 Base 镜像,建议也必须要满足 Base 镜像的一些强制性规定,比如应用进程不能是 root 等类似的安全规范。
**关于自定义镜像是否继承了公司官方镜像,我们采取的方法是对比镜像 Layer,即自定义镜像的 Layer 中必须包含官方Base镜像的 Layer。**
但是,对比 Layer 也不是最靠谱的方式,因为用户虽然继承了 Base 镜像,但还是有可能在用户创建的上层 Layer中破坏镜像结构。目前,Docker 的部署流程中,还有许多潜在漏洞,有可能让一些有企图的人有机可乘,发起攻击。
因此,我们需要一些强制手段来确保镜像的安全,好的安全实践意味着要对可能出现的事故未雨绸缪 。
目前,市面上有很多工具可以为 Docker 提供安全合规检查,如 CoreOS Clair,Docker Security Scanning,Drydock 等等。
在安全合规检查方面,携程的方案是 Harbor 与 CoreOS Clair 结合使用:当构建系统 Push 一个新的镜像或者用户 Push 一个自定义镜像之后,Harbor 会自动触发 CoreOS Clair 进行镜像安全扫描。Clair 会对每个容器 Layer 进行扫描,并且对那些可能成为威胁的漏洞发出预警。
漏洞分严重级别,对于一些非破坏性的漏洞,我们是允许发布的。检查的依据是 Common Vulnerabilities and Exposures 数据库(常见的漏洞和风险数据库,简称 CVE),以及Red Hat、Ubuntu 、Debian 类似的数据库。
这些数据库中,包含了一些常见的软件漏洞检查。比如, libcurl 7.29.0-25.el7.centos 存在如下漏洞:
>
The curl packages provide the libcurl library and the curl utility for downloading files from servers using various protocols, including HTTP, FTP, and LDAP. Security Fix(es): * Multiple integer overflow flaws leading to heap-based buffer overflows were found in the way curl handled escaping and unescaping of data. An attacker could potentially use these flaws to crash an application using libcurl by sending a specially crafted input to the affected libcurl functions. (CVE-2016-7167) Additional Changes: For detailed information on changes in this release, see the Red Hat Enterprise Linux 7.4 Release Notes linked from the References section.
注:攻击者可以利用libcurl缓冲区溢出的漏洞,在应用的上下文中执行任意代码。
Clair 是一种静态检查,但对于动态的情况就显得无能为力了。所以,对于镜像的安全规则我还总结了如下的一些基本建议: