张春源
作者张春源2017-06-26 11:18
技术总监, 希云cSphere

关于实践Docker过程中应用配置文件管理经验分享

字数 2783阅读 2749评论 0赞 13

前言:在以Docker为代表的容器技术普及之前,CFEngine、Puppet、Chef、Ansible之类的配置管理工具曾是运维的神器。在容器化以后,这些传统的配置管理工具还是否适用?用了容器后还需要配置管理吗?容器中的服务该如何运维?本次分享将对这些问题进行逐一探讨。

传统的配置管理工具对容器是否适用?

Docker开源的早期,确实有不少人尝试使用Puppet、Ansible之类的配置管理工具来管理容器。

比如Puppet的Docker模块,可以完成Docker Daemon的安装配置、容器的创建等操作,这个模块相当于对yum/apt等包管理工具和Docker CLI的封装。

Ansible也有Docker模块,相当于对docker run命令的封装。

由此可见,通过传统的配置管理工具确实可以在一定程度上管理Docker。

但问题是Docker的命令行本身已经足够简单,再用各种基于DSL的配置文件封装一层有必要吗?这不是简单问题复杂化了吗?

也许有人可能会说通过这些配置管理工具可以批量管理多台机器上的Docker。但我觉得与其学习那些繁琐的DSL配置文件,还不如果直接写个简单的脚本批量在多台机器上执行Docker命令来的快。

说到用Puppet管理Docker,以前还有人尝试通过Puppet来制作Docker镜像。

大致做法是先制作个安装了Puppet的镜像作为Base镜像,然后基于这个Base镜像创建容器,把现有的Puppet配置文件添加进去,然后在容器里执行puppet apply,最后把容器commit成镜像。

这种做法的问题是制作出来的镜像会非常大,不利于存储和传输。而且镜像的详细构建过程无法通过docker history命令查看到。

通过Puppet之类的工具确实可以批量完成Docker Daemon的部署,但仍然存在问题:
安装完操作系统后先装个Puppet,再通过Puppet模块安装Docker,安装Puppet的成本其实已经大于直接通过执行yum install或者apt-get install安装Docker的成本了。
系统中多了个Puppet软件,Puppet本身也需要维护,无疑增加了维护成本。

以上案例说明用传统配置管理工具管理容器确实有些鸡肋。

用了容器以后,还需要配置管理吗?

起初我们跟Docker官方一样,属于理想主义派。天真的认为容器就应该是inmutable的,当需要配置变更的时候,重新构建镜像重新部署。

基于这一思路,我们在cSphere中添加了个镜像自动构建模块,用户可以配置代码仓库的地址。服务的配置文件保存于Git或者SVN库中,需要配置变更时,向版本库中Push一下,自动通过hook触发镜像构建,并自动完成线上容器的重建。
c164f0581b71485a0139ec555d0628af.png

c164f0581b71485a0139ec555d0628af.png

通过这套系统,用户可以非常方便的批量更新线上的服务,并不局限于配置文件的变更,代码的变更也天生支持。

经过实际使用,这套系统能够很好的满足开发和测试环境的需求,提升工作效率。

但是,在生产环境中使用的时候,我们发现这种流程其实并不那么完美,主要表现在:
镜像构建和部署虽然自动化了,但构建是针对VCS中的某个仓库的,改一行配置就得整体重新构建一下,在更新容器时还需要把镜像重新分发到所有机器上,配置变更速度太慢。
这种方式的配置变更会涉及到服务的重启,这在生产环境某些场景下是不可接受的 ,有可能引起短暂的服务中断。

综上,我们认为即使用了容器,对容器内部的配置文件的管理仍然需要一套自动化的工具来完成。

我们如何打造Docker Native的配置管理系统我们如何打造Docker Native的配置管理系统

前面提到用传统的配置管理工具来管理容器是鸡肋的,那么容器里的配置文件到底该如何管理呢?

根据我们一贯的作风,轮子不好用时,就创造个改良版的轮子。

下面我来简单介绍一下Docker平台的配置管理系统。

容器配置管理的需求:
一致性(用不用容器这都是个硬需求)
模板化(同上)
尽可能在配置变更时不重启容器
配置文件与容器的强绑定(容器销毁重建时,其配置文件应该自动跟随)
配置参数动态获取(如:数据库的域名、端口)
需要保证容器创建之后、启动之前配置文件已经Ready
易用性(包括配置变更成本、配置文件管理系统本身的维护成本)

一致性方面,我们通过一个分布式的中心存储来保存所有配置文件的模板。

配置文件下发时,统一由分布于每个Docker主机上的Agent从中心获取。

同时对每个Docker主机进行监控,在配置下发前确认每个agent的健康状态。

平台本身是全部使用go语言开发的,配置文件也采用go template进行模板化管理。

控制器收到Agent的“获取配置文件”请求后,先读取配置文件模板,然后加载相关的各种参数以及用户自定义参数,解析模板生成目标配置文件返回给Agent。

Agent收到控制器返回的配置文件内容后,把目标配置文件“装”到容器里并根据配置设置配置文件的权限、执行用户自定义的脚本或者内置动作让配置文件生效(如:向容器里的nginx发送HUP信号、重启容器,执行任意命令等)。

控制器会自动把与该容器相关的各种参数暴露给配置模板,用户可以在配置文件模板里引用包括容器所在主机的内存、与容器关联的服务的各种参数等

示例:
2.png

2.png

通过上图中的配置文件模板,可以生成一个智能的haproxy配置文件。

该配置模板下发时,会自动把haproxy这个容器环境变量中“BackendSrv”这个Key对应的服务下所有容器的IP添加到haproxy这个配置文件里,后端端口由{{.BACKEND_PORT}}这个用户自定义变量指定。
用户自定义变量在部署的时候,可以Web管理面板指定。

配置文件通过应用名+服务名与容器绑定,在新建或者重建容器时自动生效。

创建容器时,我们不直接使用Docker CLI的docker run命令来创建容器,而是通过三步完成:

Create -> 下发配置 -> Start
这样确保容器启动之前已经加载了正确的配置文件。

配置变更后,agent会自动通过docker exec到容器里执行用户定义的相关动作,如:killall -HUP nginx,尽可能避免了强制重启容器生成的服务中断。

这种容器原生的配置文件管理机制的优点:

通过利用编程语言自身的模板语法,让配置文件的编写像写代码一样简单,灵活度高,学习成本低。
与cSphere产品整合度高,无需安装额外的软件包,易维护。
可视化,包括配置文件的编辑、模板变量的定义、配置文件下发都通过可视化界面完成。
内置版本管理,方便一键回滚。
高效,可以在秒级完成成百上千个容器的配置变更。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

13

添加新评论0 条评论

Ctrl+Enter 发表

关于TWT  使用指南  社区专家合作  厂商入驻社区  企业招聘  投诉建议  版权与免责声明  联系我们
© 2019  talkwithtrend — talk with trend,talk with technologist 京ICP备09031017号-30