Edwin & Xinyu's Blog  

查无此人,查有此地

Docker那些事(二)两个案例

上回谈到docker的意义,其中阐述docker存在的意义中最重要的一点就是“将软件包标准化和共享化,降低了管理复杂度”。这次就结合近期做过的两个简单案例,来看下docker具体是怎么标准化,共享化和降低管理复杂度的。

第一个案例我们来看看nginx。

首先看下传统习惯上nginx是如何部署的。根据官方描述(http://nginx.org/en/linux_packages.html),nginx安装一般基于预编译版本安装或源码自行编译安装。区别在于前者一般有OS版本对应和限定,且早期版本nginx插件模块需要额外安装或编译。而后者需要完整源码进行动态/静态编译,另外如果需要大批量部署服务器,除了一起打包nginx所使用的共享库外,还需要注意一些独有的坑,比如打包后的权限遗失等。

于是乎,经过漫长的编译(折腾),我们终于上生产了。不料,安全部门通报,CVE-2014-0160,SSL出现心脏出血漏洞(https://zh.wikipedia.org/wiki/%E5%BF%83%E8%84%8F%E5%87%BA%E8%A1%80%E6%BC%8F%E6%B4%9E),对于nginx而言,别无选择只能升级OpenSSL版本。怎么升级?重新编译。./configure … make & make install…于是,上文的漫长编译(折腾)再来了一遍。

那么,对docker而言nginx是怎么部署的呢?上次谈到docker是基于linux内核级的隔离来运行软件包“镜像”的。通过一个简单的“docker pulll nginx”命令,即可从指定的公共仓库中下载指定版本的nginx镜像。运行“docker run –name demo -p 8080:80 -d nginx”即可运行nginx。这里简单注明一下启动参数:–name表示启动实例名;-p 8080:80表示将容器内部端口映射至宿主机,也就是说原先nginx镜像(可以想象为虚拟机)是启动在80端口的,通过该命令即可通过宿主机8080端口访问到nginx的80端口;-d表示后台运行。具体可参考docker官方文档(https://docs.docker.com/engine/reference/commandline/run/)。

简不简单,方不方便?

看到这也许有人会疑问,nginx通过是用来做反向代理或http server的,如何进一步配置?比如修改nginx的nginx.conf?在镜像中,nginx的配置文件位于/etc/nginx/conf.d/nginx.conf。如何修改它?这里docker有两种解决方案:

  • docker file

大致思路就是基于官方nginx镜像创建一个新镜像,在创建新镜像时将自定义的配置文件放入镜像,这样运行nginx时所采用的配置文件就是新的自定义配置。具体我们可以参考官方案例定义一个Dockerfile(https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/),再通过docker build命令进行镜像构建。

  • volume mount

大致的思路是将宿主机的一个目录通过mount方式映射到容器镜像实例中。这里假定将宿主机/data/web/nginx/conf.d目录mapping到nginx镜像配置目录/etc/nginx/conf.d/,这样运行nginx时所采用的配置文件就在宿主机/data/web/nginx/conf.d了。具体启动命令就变为“docker run –name demo -p 8080:80 -d -v /data/web/nginx/conf.d:/etc/nginx/conf.d -v /data/web/nginx/content:/usr/share/nginx/html:ro -d nginx” 这里将配置文件和nginx的静态html页面均做了映射,且对页面文件夹做了只读权限。

方案上两者均可行,差异在于前者需要打包比较复杂,但提供黑盒运行环境;后者启动比较简单,但对宿主机的文件有一定依赖。

不管使用哪种方法,我们能通过docker轻松构建nginx的HTTP服务。接下来我们来看下HTTPS。

根据TLS协议(https://en.wikipedia.org/wiki/Transport_Layer_Security),服务器端需要一张由受信任的证书颁发机构(CA)颁发的证书,用于与客户端建立安全通讯,防止中间人窃听,数据篡改或伪造。一般而言,此证书为公信证书(因为客户端会进行检验验证其是自己信任的机构颁发的),需要根据域名找公信机构进行颁发。因为有背书的存在,一般证书需要购买,而这反过来成为HTTPS推广的阻力。

因此,一个由由Mozilla、Cisco等组织发起的免费开源项目Let’s Encrypt (https://letsencrypt.org/) 诞生了,旨在推进网站从HTTP向HTTPS过度的进程,目前已经有越来越多的商家加入和赞助支持。根据官方文档的描述(https://letsencrypt.org/getting-started/),Let’s Encrypt的大致工作原理为安装一个验证客户端,在服务器80/443端口起相应应用服务,并由Let’s Encrypt服务器端进行验证,确认能通过域名访问该服务器正常。在域名归属权确认无误后,自动颁发证书保存于服务器指定目录中。处于安全性考虑,证书的有效时间是90天,也就是说需要每隔90天手工或自动调用客户端命令刷新一次证书。

发现没,传统的Let’s Encrypt使用思路和上文nginx安装如出一辙,需要在服务器进行复杂的部署安装。这么如果用docker来做,会怎么样?

  • 申请证书:”docker run –rm -p 80:80 -p 443:443 -v /etc/letsencrypt:/etc/letsencrypt certbot/certbot auth –standalone -m 申请人邮箱 –agree-tos -d 主域名 -d 二级域名A -d 二级域名B“ 命令通过创建一个全新的镜像实例,接受申请证书的参数,并将产生的证书存放于宿主机/etc/letsencrypt目录。

  • 刷新证书:”docker run –rm -p 80:80 -p 443:443 -v /etc/letsencrypt:/etc/letsencrypt certbot/certbot renew –standalone“命令自动按需刷新存放于宿主机/etc/letsencrypt目录的证书。

  • Nginx HTTPS修改nginx.conf 增加ssl_certificate 和ssl_certificate_key指向/etc/letsencrypt中的证书。再通过命令”docker run –name demo -p 80:80 -p 443:443 –restart=always -v /data/web/nginx/conf.d:/etc/nginx/conf.d -v /etc/letsencrypt:/etc/letsencrypt -v /data/web/nginx/content:/usr/share/nginx/html:ro -d nginx“启动即可。

需要注意的是,由于Let’s Encrypt容器和应用容器均需要使用服务器80/443端口,故设置crontab计划任务定期renew证书时,需要docker stop应用容器,等docker run renew容器完成后再docker start应用容器。

总结一下,docker本身提供的就是一个黑盒子,一旦将软件包盒子化后,即可轻松实现共享化,同时也降低了管理复杂度。

validate