2016 年 9 月 10 日,又拍云 Open Talk NO.25 在成都举行。本次活动以“DevOps与持续交付实践”为主题,邀请了聚美优品高级运维工程师胡骏、ThoughtWorks 咨询师刘梓懿和咕咚DBA李锐三位技术高手,分享各自的运维经验。刘梓懿在演讲中边写代码边讲解“如何解决基础设施代码化”,并将此段代码上传到了Github(https://github.com/richardzone/ansible-training-workshop)。

本段讲解利用到了Ansible培训代码( http://ansible.richard.zone/)作为参考 。

image.png

以下是刘梓懿的分享全文。

各位下午好,我是刘梓懿,是ThoughtWorks的一名IT咨询师,目前专注于云技术和DevOps方面。

今天我带来的话题是“云环境下的基础设施即代码实践案例”。在这个案例中,我们从传统的基础设施管理遇到的问题出发,讲解了从最初手工创建/维护基础设施资源,到使用自动化配置管理工具管理基础设施,最后实现了利用CloudFormation、Terraform等现代基础设施管理工具进行版本化、代码化云资源管理的DevOps演化历程。

什么是基础设施?

我们在这个话题中讨论的基础设施主要有几类:

image.png

云服务器、云存储、DNS、CDN等都是基础设施。我们的应用程序具备真正的业务价值,但是应用程序跑的基础平台都是基础设施。云服务器包括应用程序服务器,数据库服务器和缓存服务器等。大家不要认为像 DNS、CDN 这种基础设施只能手工配置,实际上我们可以通过代码化的方式把它们自动化配置出来。

这种传统的基础设施管理具体存在着哪些问题? 

第一,咨询审批流程长,响应不及时。 这个基础设施从一个开发人员开始申请,逐级批准,然后运维总监签字批准,最后走采购的流程,这种审批流程非常繁琐,不但项目组等待非常耗时,而且等待的信息反馈适应不了瞬息万变的互联网时代需求。

第二,手工进行服务器的安装和配置的问题。这个地方可能会有几个问题:第一个是速度比较慢,发布前大家都要加班去做,因为服务器部署并非几分钟就可以搞定。第二个是难于版本化,难于追溯配置版本变更历史。这方面可以举个例子,之前我们服务器上遇到问题,或者需要新装任何东西,就需要登录服务器去手工的排错或部署,这样做造成的问题是我们完全不知道现在服务器是什么样的状态,也没有一个配置的版本,配置变更历史也很难去追溯。

第三,易出错,遗漏配项。这个其实也很容易理解,大家如果做过传统运维可能都有切身体会。如果配置项忘了一步很可能服务器跑不起来,要加班处理这个问题。

静态的基础设施造成的问题

那么,静态的基础设施会造成什么问题呢?实际上,我们在很多企业组织观察到,这些组织使用了云计算技术,但使用云计算本身,并不能确保资源被合理充分利用,这是由于基础设施资源是静态分配的,动态变化很少且变化成本较高,这样带来的问题主要有三个:

一是无法根据业务需求,随时动态增加环境; 

二是云资源利用率低; 这种静态的,手工的配置方式带来的后果是项目组一开始在立项的时候把基础设施申请好,而并不释放资源,比如说现在有四台服务器,不用也不会还给公司,为什么?之后要用再申请是非常麻烦的。现在云服务器并没有给我们带来资源动态分配和释放的好处,也就是说我们还是用旧时代的运维方式来解决云时代的问题,导致资源利用率低,成本增加。

三是手工部署的步骤有文档,但是文档维护起来很繁琐,而且常常更新不及时。 有的时候上线之前会做很多准备和手工配置的工作,做完之后我们的人员都很累了大家都去休息了,可能下周一过来我们也没有发现部署文档少了些什么东西,但是我们实际执行的部署步骤和文档已经不完全匹配了。

我们看到的问题主要是静态的基础设施导致没办法用云时代新的思维来解决问题,我们还是停留在旧的申请虚拟机的方式来解决问题。

为什么传统基础设施管理会遇到问题?

image.png

一、我总结概括的本质问题是:在倡导敏捷开发、精益企业的时代,基础设施也需要变得敏捷。我们的产品要适应瞬息万变的市场,各位的发布频率也从以前的3、4个月发布一次,到后来2-4周一次发布,到现在很多互联网公司每天可发布,这样的发布频率,这样快的市场变化,就需要基础设施有更快的响应速度。

二、我们可以用这种敏捷的基础设施支撑持续的创新和实验。有的时候产品经理有一个想法,没有人知道推向市场会怎么样,因为开发、运维,公司里面的人员可能并不是这个产品的真正用户。要快速的推向市场,快速的试错,这个时候也需要基础设施跟得上步伐。

三、持续交付、DevOps的实践要求团队对部署和运维有更高的自主性。我们现在在推广的一个实践是说我们会把运维的权利下放到每个团队。这种文化叫做:You build it, you own it. 谁构建一个App,谁就负责运维这个App。团队也由目前的项目团队(project team)在向产品团队(product team)转型。在这种转型的过程中,就要求团队对运维有更高的自主性。

四、技术的快速进步,使基础设施的配置不得不频繁变化,以前基于 Java 技术栈的企业级应用占应用开发的主流,然而现在我们有更多的选择了。像我们客户有些项目组会用Python写轻量级的Web应用,还有些项目组用Node.js来支持高并发的核心服务。这样的情况导致我们会有各种各样不同的服务器配置,使得传统的运维人员往往感到力不从心。这就是技术快速进步导致的基础设施频繁变化的需求。

五、最后在快速变化过程中,要求基础设施既要灵活、也要安全,可靠。我们开发人员,一线的产品人员肯定是希望基础设施越灵活越好,但是从企业的角度而言,尤其是大型的组织,他们对安全、可靠、可审计(Auditability)和合规性(Conformity)的要求也是非常强的。

那我们要怎么样解决这些问题呢?

image.png

实际上时下有一个热词(buzz word):基础设施即代码,我们演讲幻灯片上展示的同名书籍也是今年中文版上市的,有兴趣的话可以演讲后买来读一下。那么这个概念,我们是怎么理解并应用到客户项目上的呢?有两个原则:

image.png

代码化基础设施:把服务器、网络、工具和服务以及对基础设施的管理本身作为一个软件系统,采纳现代软件工程优秀实践以结构化、代码化、安全的方式来管理对系统的变更。比如对基础设施进行版本控制,持续集成,自动化测试,自动化部署等。

动态基础设施:使得基础设施及其配置可以按需动态地创建、释放和重建,并保持一致性,这些改变可以人为触发,比如测试人员需要一套新的环境用于测试,也可以由系统自动触发,比如资源不足时自动对其扩容。

如何解决基础设施代码化的问题?

刚刚引入自动化的时候,我们用的是Ansible,之前用配置管理工具做应用程序的部署和发布,我们在想基础设施的管理是不是也可以用它来做?我现在给大家做一个演示,使用 Ansible 创建亚马逊云 AWS 基础设施(刘梓懿在此开始边coding边演讲)。

首先定义软件包,然后配置服务器,把配置文件和安全设置应用到服务器上面去,最后把应用程序的外包发布到服务器上,我们用代码的方式进行自动化实现。 

我们在基础设施创建的时候,可以写一些简单的代码,比如说创建一台虚拟的服务器,创建一个自带的ec2,给它指定一些参数,操作系统的镜像是什么样的等等,之后加在主机的集合里面,等配置之后可以持续往下面的脚本去部署,现在看一下脚本是怎么样运行的。 

这时候在云上面创建一个云服务器,整个过程都是一个自动化的过程。当时我们在客户的组织内部做了一个培训,我写了一个完善的文档教大家怎么用Ansible,大家可以去看。

实现基础设施全生命管理

image.png

Ansible解决了创建基础设施资源的问题。但对于怎样记录基础设施资源分配,跟踪其使用,以及怎样追踪基础设施资源的变更,以及对于不需要的基础设施资源的回收,Ansible这种实践并没有给出答案。那么,有没有其他的解决方案和工具,能够帮助我们解决这些问题呢?

我们认为,基础设施的生命周期管理分两个部分,一个是构建(Formation),一个是配置(Provision)。构建就是创建资源,但不配置。配置的时候呢,就会做比如说在服务器上装 Java 运行环境,装 Tomcat,再比如在数据库服务器里导入用户初始数据,这些活动我们认为是配置。在配置方面我们已经有很成熟的解决方案了,像Ansible、Chef、Saltstack等等。在基础设施构建这一块,有没有更好的工具可以解决基础设施资源全生命周期管理问题呢?这里面我们推荐两个业界中的典型工具,亚马逊云AWS有一个原生工具叫CloudFormation。另外,推出Vagrant的公司Hashicorp也有一个Terraform工具,以及Openstack Heat工具等。

怎么样用现代的基础设施管理工具来构建现在的基础设施架构呢?我们来看接下来的演示。

这个是非常简单的演示,一个简单的功能,这里面一个是创建,一个是更新基础设施,然后如何销毁基础设施;我们把基础设施分解成一个一个技术栈(stack),每一个项目组可能有一个或者更多的应用程序架构,包括应用服务器,数据库服务器,云存储等云资源,这样的一个组就是一个stack。

CloudFormation给大家带来的是一个一个经典的技术栈。为了保证它的可用性,我们做了一个分区域的高可用部署,可以看到它现在调用API去实现,我相信所有的公有云都有这个API的接口,企业的私有云也有这样的API接口。这里面可以看到已经创建了一些安全组,然后逐渐创建我指定的所有的资源,创建之后会导入一些初始的数据,而且都是全部自动化的。

怎么样自动化?实际上代码也非常简单,首先定一些参数,比如数据库的名字,数据库里面的用户名,密码,还有一些服务器的大小,可以设置默认程序机构有几台服务器,可以动态扩容,但需要一个初始的值,后面是一些固定的企业码。

这里有一个Resources,之后会配置它的的特性,比如接在80端口上,有什么样的协议,我们定义了一组服务器,用自动扩容架构去创建了一个服务器,然后设置了一些updatepolicy的滚动发布的策略,还有一些具体服务器的配置。我们把代码写死在服务器里面,但实际上可以不用写死,可以指定在外部的文件里面。

最后给应用者一个新创建文件的访问地址,这样创建完之后就可以直接用了,相当于一键把整个应用程序的架构创建好了,而且是高扩展的。

Terrafom,这个公司的服务发现,本地虚拟机的启动,是比较有意思的。又拍云有一个云存储的服务,我在API上写一个拓展插件,非常容易,这样我可以把所有基础设施代码通过又拍云来创建。

那么我们来总结一下今天的分享内容。

image.png