前言
先做个自我介绍,本人毕业于香港科技大学,然后回国先后在IBM与微软工作,后加入了云络公司做架构师和解决方案顾问工作。
云络公司是一家致力于系统自动化运维的公司,我们拥有DevOps的项目经验和一些DevOps的运维积累。回到此次分享,这次的分享将主要涵盖以下几点内容:DevOps的现状,我们认为的DevOps的四个阶段,DevOps的基础,DevOps的案例分析,Docker的优势、挑战与相对应的策略,以及DevOps的未来。最后,通过这些分享,希望大家可以了解我们建议的目前大多数公司应该达到的DevOps的程度以及在实际案例中这个程度的DevOps是什么样子的。
首先,先来概述一下什么是DevOps。我认为DevOps是一种在促进开发与运维的交流与合作的条件下,以自动化工具与流程为基础,更快速,高效和稳定的实现环境搭建,应用测试,软件发布的一种文化和趋势。
当下DevOps无疑是一个很火的概念,很多公司都在尝试在他们的开发运维环境中使用DevOps。但是现状是这并不容易,很多公司在尝试的过程中都失败了,有的是因为将DevOps使用在了错误的场合,有的是因为使用了错误的方法,还有的是因为没有做好充足的准备。这些失败终将导致系统更复杂,有很多潜在风险,或者花费很多时间和精力在故障排查上,适得其反。
那么,到底该如何实现DevOps并且做好准备呢?
我们认为DevOps应该有以下四个阶段:简单的自动化,CI与静态Docker,增强与动态Docker,以及全面CI和自动化。我们定义的第一个DevOps阶段呢,是偏向传统的,只是使用了一些简单的自动化工具完成版本更新发布而已,那么第二个阶段呢,使我们认为目前大多数公司应该去实现达到的一个阶段,在这个阶段里应该拥有了自己的CI,使用了Docker但可以是静态的模式,即手动部署;然后在这个基础上,我们来到了第三个阶段,这时候我们希望可以对第二个阶段做全方位的加强,包括很多细节比如系统架构,如何实现CI,如何实现自动化的测试,并且可以拥有一个动态的Docker部署;最后,在第四个阶段就是一个全自动的阶段,一切尽在掌握,一切万无一失。
我们定义的第一个DevOps阶段呢,是偏向传统的,只是编写了一些脚本,或者利用一些简单的自动化工具,如Ansible,执行一些简单重复的命令,完成版本更新发布而已;
那么第二个阶段呢,是我们认为目前大多数公司应该去实现达到的一个阶段,在这个阶段里应该拥有了自己的支持交付的工具和流程,使用了Docker但可以是静态的模式,没有调度,扩展等的自动化机制,还是需要人工决定资源的调配,系统对于动态负载的弹性较弱;
然后在这个基础上,我们来到了第三个阶段,这时候我们希望可以对第二个阶段做全方位的加强,包括很多细节,比如不断改进持续交付以及实现自动化测试,支持更复杂的应用架构,并且可以拥有一个动态的Docker部署和调度,利用Swarm,Kubernete等工具;
最后,在第四个阶段就是一个全自动的阶段,完全实现infrastructure-as-code,整个系统和应用就是在Git中的一系列文件,包括云(底层基础设施),服务器,应用,等等等等,所有一切。当然这是非常理想化也非常困难的。
那么在了解了如何一步步一个阶段一个阶段实现DevOps之后,我们再来看一下DevOps需要哪些技术基础。
基于我们定义的这四个DevOps的阶段,在这里我给出了大家实现DevOps的四个技术基础,分别是:版本控制,环境抽象,全自动化测试以及完全持续部署。在没有这四个基础的准备之下,DevOps就是空中楼阁。
版本控制指的是代码的开发,复查,版本控制,代码集成等能够在DevOps中更加自动化;
抽象环境是指开发的代码可以匹配兼容各种环境,比如在一个Docker image里,我们的代码可以根据image所处的不同环境,调取不同的环境变量如IP,域名,文件,存储,密码等;一个docker image 满足多环境部署,配置独立且动态化
全自动化测试,是指所有版本,变更与其他版本的兼容性都可以得到自动的测试;
完全的持续集成是指无论在什么时间,或者什么人做的变更,都会与当前的版本代码进行持续的兼容测试,以保证所有的变更都可以最终整合在一起,实现最终版本的发布并部署到各个环境中。
在介绍了如何一步步实现DevOps以及实现DevOps的基础技术之后,下面我将会拿一个我们云络科技与客户合作完成的一个DevOps为例子,给大家分享一下我们是如何做到DevOps的。
这个案例的基本背景呢是这样。我们实现了之前提到的DevOps的第二阶段,整体环境是在AWS上,开发需求是每两周做一次版本迭代,每日推送更新3-4次。根据之前讲到的DevOps实现的四个基础,在这个项目中我们用了以下一些技术去实现:
使用GITLAB实现版本控制,Docker实现抽象环境,
自动化测试目前是半自动需要人为干预,
然后利用Jenkins 实现了持续集成。
客户具体的系统架构信息是这样使用了java/Node.js,CoreOS,Redis做了session的缓存,AWS RDS 中的 MYSQL 和 Postgres,MongoDB,ELK日志分析系统,Hadoop以及Solr则搭建在了自建的EC2虚拟机上,同时还是用了ELB,S3, SQS,SNS等AWS的辅助功能。
那么这个环境的大体架构是什么样子呢?首先应用请求会来通过AWS的ELB负载均衡然后分配到不同的API Gateway(这是在不同EC2 VM上的某一个Docker container中),之后API GATEWAY会通过Redis做session的缓存,通过Redis拿到中间键值然后再通过Internal的ELB去联系不同VM上的应用Docker container。所有的联系都会通过指定好的IP和端口去完成,并且在VM的docker上都是没有session存在的,这样可以实现更灵活的扩张或者变更。
在了解了这个项目的背景和架构之后,我们再来看一下我们是如何实现持续集成(CI)的。这个过程如屏幕上所示一样,CI是基于Jenkins的调度与docker的灵活度来实现。可以说Jenkins与Docker是一对很好的搭档。Docker在这个过程中扮演了一个极为称职的对代码打包的角色,通过RMPS技术或者其他机制我们又可以实现自动化的打包,更新到docker container registry, 然后利用Jenkins的调度功能,实现在不同的环境下进行测试以及处理。如图中所示,在commit代码后,利用RMPS打包docker image,然后分别发往本地以及AWS上的registry。在本地的image通过testing环境的部署与测试好之后,AWS上再调取相对应的已经测试好的版本进行Staging的部署与测试,然后再进行生产环境的部署与测试,之后完成最终的发布。
在commit代码后,在build服务器上完成编译,程序代码发送到Docker引擎,自动化打包至新的应用镜像,然后将docker image发送至docker registry完成注册。此刻的已准备好了对下一步的多环境部署动作。Docker在这个过程中扮演了一个极为称职的对代码打包的角色。整个过程如图所示。
上一步完成后,我们就可以开始在stage环境上部署,以便开始测试。利用Jenkins的调度发布功能,发布到本地Stage环境,同时会在基于AWS的UAT docker环境部署。实现在不同的环境下进行测试以及处理。在这个过程中,Docker可以帮助实现环境抽象化。(-e)
那么问题来了,如果我们有50个开发人员,10个IDC环境,4个不同开发环境,20个应用,我们该如何实现环境配置的管理?在这里就需要引入etcd服务发现功能来统一管理多环境多配置的集合。一套应用的镜像可以轻松应用于多个集合环境,实现了数据和配置的解耦。整个过程如图所示。
另外Jenkins在整个过程中,起到了任务调度执行的关键作用,从而实现了整个流程的自动化。从调度打包到垮环境部署等。如图所示。
介绍完一个真实的DevOps案例之后,我们可以看出Docker是实现DevOps的一个重要的技术手段,那么Docker的使用有什么优势以及挑战呢?面对这些挑战我们该如何应对呢?下面也是这次分享的最后一个大部分就来给大家介绍一下Docker的优势与挑战。
Docker的优势呢,总结起来主要有以下几点:首先,他是高效的,没有OS这一层可以极大提高运行性能;其次他是一个工具化的完整技术,Docker中包含了许多工具去管理docker container包括环境,发现服务,存储等;他又是极为灵活的,将应用和系统“容器化”可以更加便捷的部署应用;他的敏捷度很高,可以快速的复原和更新;同时,他也很轻量,在一个虚拟机上可以部署很多个容器;此外,他还具有成本优势以及是目前开发这个生态环境中受广大用户欢迎支持的一种技术。
这么棒的一种技术,受到开发者欢迎的,但对于运维工程师来说,在维护掌控这个技术的时候却面临了很多的挑战,这里我列出了如下几点在我们实践中碰到的挑战:监控,日志,排障,安全以及网络。
在监控方面,最基本的监控是做到监控docker service是否在正常运行,但这是远远不够的,我们需要对Docker运行有更多的了解,比如CPU,内容,硬盘空间,I/O,网络情况。更深层次的监控可以通过三种技术手段实现:读取container里的CGROUP文件再经过分析拿到Docker运行信息,通过调用docker API 直接拿去信息,或者通过命令行拿到信息但这种方式所获得的信息较少。于是,在Cgroup和API的基础上,我们建议去使用Cgroup直接拿到文件然后通过分析获得参数输出,因为相比API,这种手段可以获得更多有价值的信息并且对Docker的性能影响最低。
此外,对于Docker占用的disk问题也是个挑战,因为我们在VM上只可以看到所有containers整体占用的磁盘空间,所以为了了解到各个Docker的使用情况,我们需要链接到各个container然后通过命令行调取各自占用disk的信息。
再之,监控container内部的service也是一个难点,对于service的监控,我们有两种策略:一种是在container内部部署agent,但是这种手段需要其他的service辅助在启动container是控制启动这个agent。这里需要提醒大家的是,Docker的部署标准规范是一个container中只是用一个service。此外使用这种方法监控service的话,还有一个问题就是针对agent的更新只能在打包这个image时候完成,这样也对真个image的创建增加了复杂度。
就上述多种原因,我们在这里建议使用第二种方式,即在container外部对内部service进行监控。虽然这种方法中有一个难点是如何连接到内部的service获取数据,不过借助Zabbix的Low level Discovery技术,我们成功地可以找到内部的service并且获取我们需要的参数信息,完成对内部服务的监控。当然,对于不同的应用,我们仍需要对我们的监控脚本做一些定制化的修改。
Docker的日志对于运维人员也是一个挑战,尤其是当我们想集中管理这些日志的时候。
Docker产生的日志主要为应用日志,系统日志是很少数的,而我们面临的最大的挑战则是去搞清楚某一个日志是来自哪里,是来自按一个host,哪一个host上的哪一个container。此外,但我们部署可一个新的container或者删除一个container的时候,如何相应的对其日志进行相应的增加或减少的操作。针对上述问题,一个选择使用GELF收集Docker的日志到ELK系统,GELK是Docker自带的一个工具,在1.8版本中出现。但问题是它使用的UDP方式去传输日志,由于UDP的不稳定性以及GELK不会记录日志在本地,所以他很容易造成日志的丢失。所以看上去这个策略可靠性不高,于是我们又想到另一种方法,即通过创建一个专用的container作为logstash的forwarder。这样所有的日志都会被存在这个host上并且这个container可以对log进行读取,标记,然后发到ELK日志系统。
排障曾经是Docker面临的一个问题,因为我们无法SSH到container,需要在内部启动service使用console登录,并且我们很难对container进行修改和测试因为他的部署都是在image生成阶段完成的。后来Docker新版本有了Bash Shell工具可以实现对container的登录控制,但是对于及时即可的修改由于他的天性,我们仍然无法按照过去的习惯去完成故障排查。
安全和网络也是痛点。从安全角度讲,由于container的灵活性,image的安全补丁是不断地变化的。此外,隔离性也是个问题,不像VM与VM之间的用户权限是隔离,VM上的container的用户权限是与host VM一致的,这样不好完成权限管理。同时,由于docker的技术还在发展的阶段,他并没有很完善成熟的安全规则。不过docker也带来了很多安全方面的最佳实践文档,包括建议容器间开启LINKS从而保护了应用端口的不必要暴露,建议使用客户端和服务器端证书认证方式,使用非root用户运行服务,使用SELINUX来增强容器安全等等方法。
最后,聊完了DevOps以及实现它的重要工具Docker之后,我们再来展望一下DevOps的未来。我们希望,我们可以在不远的时间内实现 DevOps中的自动伸缩,是全自动化的scalling,然后可以完善动态的Docker ,而非现在还需要手动去部署和发布,以及实现Green/Blue rolling ,即对于不同VM不同container的变更可以在负载均衡后可以做到无缝的链接,为使用者提供持续稳定的服务。
自动伸缩:创建AWS的CloudWatch并设定阈值,在AWS的AutoScaling中的Launch Configuration 中集中制定各类弹性伸缩配置,包括AMI,安全策略等等,启动一个实例需要的所有信息(Launch Configuratio n是的朋友)。一旦弹性伸缩配置完成后,阈值一旦触发即可自动扩展性能,反之也可以自动收缩性能,做到完全的自动化。
集群化,自动化调度:通过一系列Docker工具,诸如Swarm, Fleet,Kubernete, Meso等等实现。
严格执行蓝绿发布:
在系统架构中,设定主备负载均衡。
当需要新发布时,把绿色集群的状态改为’备用’. 从负载均衡的池里把这些地址去掉,这样,绿色的集群就不再回接收到来自用户的请求了.转而进入备用负载均衡的池里。
在绿色集群里部署新的代码,直到应用启动成功。使用备用负载均衡简单测试一下备用集群的部署情况。
将流量引到绿色集群,对蓝色集群做同样部署和测试操作。这里需要注意的是,会有一段时间蓝绿集群两者运行了新老版本,所以程序兼容性也是受到考验的。
以上就是本次DevOps和Docker的案例分享,希望大家可以一起在中国把DevOps做的越来越好!
Q&A
Q1:动态Docker是怎么设计的?
A1:动态Docker可以利用一些工具实现,比如Swarm,Kubernete,实现可视化的一种Docker资源池,就不必像静态的Docker一样还需要人为参与去部署某一个docker container,然后安装在某一个VM上,而是一种资源池的感觉。
Q2:DevOps需要什么开发基础?
A2:DevOps其实对于开发来说,并没有带来多大的挑战,主要对于Ops带来了一些麻烦,所以说开发基础的话其实是在原有的开发基础上多一些注意点吧。
Q3:关于Docker,现在在数据库层面的实践多不多,可否指点一二?
A3:Docker是实现DevOps的一个重要技术手段,他实现的是对环境的抽象,即为不同的版本代码可以自由的兼容不同的环境然后部署交付测试发布,所以Docker中主要还是以应用代码为主,而数据库的话还是在外部的,即数据库不会放在Docker中,还是在VM上,Docker去调取。
Q4:DevOps是过程,方法,系统的一种组合,因为是跨部门协作,核心应该是是数据交付吧,我看文章里面也提到了QA型,开发型,运维型融合工具,是从工具角度来说吧,很多大公司都有独立的数据交付部门,这种也算是DevOps的一种实践方式吗?
A4:首先,你说的没错,DevOps是一种趋势,跨部门的合作,核心还是为了能提高版本迭代更新的速度。其次,就像我之前提到的DevOps有不同的四个阶段,简单的实现自动化部署和发布也是一个阶段,而我们希望的是大家达到第二个阶段,详细可以看之前的部分,及实现静态Docker和有CI的流程控制。
Q5:近年来DevOps、自动化运维都提得很热,两者的区别和联系是?
A5:关于第二个问题,DevOps是一种趋势和概念,自动化运维可以是实现DevOps的一种技术基础。
Q6:想从普通运维转行到病毒分析行业,像病毒分析行业,安全行业,百度安全,抗DDOS攻击,WAF这些,不知前景如何?
A6:安全行业的话从发展到现在从传统防火墙到WAF到DDOS,然后现在已经到了一种基于大数据的采集分析定位攻击者或者预先判断可能的攻击的阶段了,并且互联网安全现在变得越发重要,什么都上互联网,重要数据的保护异常关键,所以做安全还是蛮有发展的。
Q7:我觉得在云计算的背景下,DevOps是强调了开发和运维的合作模式的改变,感觉也是在弱化运维的独立性,而把运维层面,基础架构,系统级别的优化都交给云平台去做,或者是做平台统一,DevOps的核心逐步会是DEV,而OPS会逐渐弱化。我的这种担心老师怎么看?
A7:运维从始至今都是一件繁琐的,底层的工作,所以运维行业本身也在不断的发展从工具化,到标准化再到平台化,把工作变得更加有效率,从运营维护到运筹帷幄,所以我认为把运维工作工具平台化并不是一件坏事。然后关于DevOps核心是DEV弱化OPS这一部分的话,我觉得即使没有DevOps,OPS的工作也是服务DEV,帮助公司业务迅速发展,而有了DevOps虽然给OPS带来了挑战,但也是一个新的机遇吧。
作者介绍 王寒
毕业于香港科技大学;
曾就职于IBM、微软;
现就任云络科技(CHINA NET CLOUD)架构师。
本文来自云栖社区合作伙伴"DBAplus",原文发布时间:2016-05-11