为什么要docker化?
/usr/local/tomcat
(或其它你喜欢的位置)下,对外端口是8080,debug端口是8000. 上述工作,原有的技术手段不是不可以做,可是太麻烦,可用性和扩展性都不够好。
总结一下,基于n台物理机搭建容器环境,整个工作的主线:一个项目一个主机 ==> 物理机资源不够 ==> 虚拟化 ==> 轻量级虚拟化 ==> docker ==> 针对docker容器带来的网络、存储等问题 ==> 集群编排 ==> 对CI/CD的影响。
虚拟化网络的两种思路:
经过对比,我们采用了macvlan,主要是因为:
关于macvlan,这涉及到lan ==> vlan => macvlan 的发展过程,请读者自行了解。网络部分参见 docker macvlan实践
ip分配问题
对于物理机、kvm等虚拟机来说,其生命周期很长,ip一经分配便几乎不变,因此通常由人工通过命令或web界面手动分配。而对于docker容器来说,尤其是测试环境,容器的创建和销毁非常频繁,这就涉及到频繁的ip分配和释放。因此,ip分配必须是自动的,并且有一个ip资源池来管理ip。
在docker网络中,CNM(Container Network Management)模块通过IPAM(IP address management)driver管理IP地址的分配。我们基于 TalkingData/Shrike 改写了自己的ipam插件,fix了在多实例部署模式(一个docker host部署一个ipam,以防止单实例模式出现问题时,整个系统不可用的问题)下的重复存取问题。
docker解决了单机的虚拟化,但当一个新部署任务到达,由集群中的哪一个docker执行呢?因此,docker之外,需要一个编排工具,实现集群的资源管理和任务调度。
这些工具均采用maser/slave架构,假设我们将物理机分为master和slave,这些工具在slave上运行一个agent(任务执行和数据上报),在master上运行一个manager(任务分发和数据汇总)。从功能上说,任务分发和容器资源汇总,这些工具基本都可以满足要求。就我的理解,其实这些工具的根本区别就是:发展历程的不同。
其中的不同,请大家自己体会一下。
到目前为止,根据我们测试环境的实践,发现我司有以下特点
因此,最终我们决定使用marathon + mesos 方案。当然,后面在实践的过程中,因为网络和编排工具的选择,ip变化的问题给我们带来很大的困扰,甚至专门开发了几个小工具,参见下文。
docker的厉害之处,不在于发明了一系列新技术,而在于整合了一系列老技术,比如aufs、lxc等,在docker之前,我司运维也经常使用cgroup来限制一些c项目进程使用的资源。阿里、腾讯等大厂在cgroup、namespace等基础上搞一套自己的容器工具,现在也广为人知。甚至在《尽在双11:阿里巴巴技术演进与超越》关于docker部分中提到,对于阿里,使用docker初衷是docker镜像化,也就是其带来的应用环境标准化,而不是容器化。
docker镜像的实践主要涉及到以下问题:
我们要对镜像的layer进行组织,以最大化的复用layer。
因为我们还只是在测试环境使用,镜像较慢的矛盾还不是太突出,这方面并没有做什么工作。
写到这里,我们可以看到一个技术之外的技术问题。阿里对于docker image feature的改造
本质上jenkins如何跟marathon结合的问题,现成的方案很多,本文不再赘述。
关键是提供几套不同的模板,以方便不同业务的童鞋使用。
使用docker后,容器在物理机之间自由漂移,物理机的角色弱化成了:单纯的提供计算资源。但带来的问题是,影响了许多系统的正常运行。
许多系统的正常运行依赖ip,ip不稳定带来一系列的问题。而解决ip的变化问题主要有以下方案
对于web服务,ip的变化导致要经常更改nginx配置,为此,我们专门改写了一个nginx插件来解决这个问题。参见一个大牛的工具 weibocom/nginx-upsync-module ,我为大牛的工具新增了zk支持,参见 qiankunli/nginx-upsync-module-zk
对于rpc服务,我司有自己独立开发的服务治理系统,实现服务注册和发现。但该系统有审核机制,系统认为服务部署在新的机器上时(通过ip识别新机器)应先审核才能对外使用。我们和开发同学协调,在服务上线时,进行额外处理来屏蔽掉这个问题。遗憾的是,对于跨语言调用,因为rpc客户端不通用,仍有很多不便。
有许多项目会将业务数据存储在文件中,这就意味着项目deploy进而容器重启之后,要能找到并访问这些文件。在docker环境下主要有以下两种方案:
我们当下主要采用第一种,将cluster fs mount到每台docker host的特定目录(例如/data),打通 container /data ==> docker host /data == cluster fs /data
,任意容器即可共享访问 /data
目录下的数据。
为了将日志持久化存储,我们将容器的日志目录映射到了物理机上。but,一个项目的日志分散在多个物理机中。
我司原有日志采集报警系统,负责日志采集、汇总、报警。因此容器化后,日志的采集和报警并不会有什么影响。但该系统只采集错误日志,导致开发人员要查看日志以调试程序时,比较麻烦。最初,我们提供了一个web console来访问容器,操作步骤为:login ==> find container ==> input console ==> op。但很多童鞋依然认为过于繁琐,并且web console的性能也不理想。而直接为每个容器配置ssh server,又会对safe shutdown等产生不良影响。因此
essh -i marathon_app_name
即可访问对应的ssh container实例并查看日志。 当然,日志的问题,也可以通过elk解决。
mesos + marathon + docker的文章很多,其实这才是本文的重点。
/etc/hosts
中ip和容器主机名的映射后,加上 /etc/sysconfig/network
的缺失,导致java代码 InetAddress.getLocalHost()
执行失败。参见 ava InetAddress.getLocalHost() 在linux里实现 这样带来的问题是
Q: 自动扩容缩容是按照什么策略进行的?
A: 因为我司还在快速发展,机器经常处于不够用状态,所以还没到扩容缩容那一步
Q: 镜像精炼影响很大吗?docker相同层不是只下载一次吗?
A: 我们绝大部分是java项目,通常一个war包五六十M,更大的也有,占用一个layer。频繁的发布和部署,仅仅是下载这一个layer,时间上还是有一点耗时的
Q: 网络对于k8s出来容易,进去很难。不知道你们说的物理机,和docker网络是怎么互通的?希望能详细说下。
A: 首先通过docker ipam driver我们为每个容器分配一个ip,docker 本身也支持macvlan,不准确的说,相当于每个容器有一个物理网卡,只是和物理机网段不同。我们通过交换机连通两个网段。
Q: 问一下,配置的统一管理是怎么做的?哪些配置信息做了统一管理,数据库的链接信息也是放到配置信息里吗?
A: 可能我文中用配置一词不太对,文中的配置更多指的是,tomcat的安装目录,tomcat的web端口、debug端口号,日志目录命名等约定。这个是做镜像时便已经确定的。
Q: 容器有了固定IP那么就不需要NAT了,那么在原mesos下的服务发现就不适用了,能详细介绍下这块怎么搞么?
A: 从根本上,不管容器ip变不变,因为以后做扩容缩容,我们认为服务的ip总是会变得。因此我们写了nginx插件等额外组件来屏蔽ip的变化,而不是尝试让ip不变。
Q: 怎么收集tomcat 启动时的log? 有没有想过用websocket
A: 我们公司有自己的日志采集系统,可以采集并分析业务日志。至于tomcat日志,我们业务上暂时还不需要采集。我们有自己的手段来采集tomcat运行状态。这里顺便说下,很多方案我们的选择,是基于公司目前已有的一些框架工具,大家要按照自己的情况因地制宜。
Q: jenkin 模板是job template吗
A: jenkins我只是简单会用,我是做了一个demo job,大家使用时copy整个demo job,并改一些变量即可。
Q: 将容器的应用端口映射到主机端口,能不能解决ip变化问题??
A: 因为容器会在主机之间漂移,我们通过“物理机ip:物理机port”来访问容器时,容器对应的物理机ip在deploy后,还是会变得。
Q: 使用macvlan 宿主机是不能直接访问到容器的ip吧。你们怎么解决的
A: 是的,我们通过设置外置的交换机来解决这个问题
来源: http://www.tuicool.com/articles/7n2U7vY