现代软件开发对基础设施的管理提出了更苛刻的要求。产品要适应瞬息万变的市场,要求基础设施要有更快的响应速度。而持续交付和DevOps的推行要求产品团队对部署和运维要有更高的自主性。技术的快速进步和演化,也使得基础设施的配置不得不频繁变化。在这种快速变化的过程当中,要求基础设施既要灵活,也要安全、可靠。nginx
而传统的基础设施运维管理具备如下几个问题。apache
被动响应。 产品团队获取服务器资源采用的是申请制,中间存在若干审批过程,以及须要等待运维团队实施,响应不及时。ubuntu
自动化缺少串联。虽然有必定的自动化,但不能作到无人值守,须要执行一些临时命令介入。因为环境释放和重建的成本高,于是倾向于不释放,致使资源利用率低。安全
和产品团队脱节。很难根据需求随时动态增长环境。须要额外的文档来描述环境,可能更新不及时。服务器
产品团队是实施持续交付的过程当中,必须考虑将基础设施的维护归入进来,做为支持产品运行的一部分。如下是产品团队的持续交付流水线全景图。网络
从上图能够看出,产品团队除了管理项目自己代码外,还要管理环境定义脚本。环境定义脚本能够由基础设施自动化工具执行,动态建立和销毁和更新产品运行所需的环境(包括服务器、负载均衡器、防火墙配置、第三方依赖等)。架构
若是实现了这一点,那么就实现了基础设施即代码的雏形。Kief在《Infarftruce As Code》一书中对基础设施即代码定义以下:负载均衡
基础设施即代码是一种使用新的技术来构建和管理动态基础设施的方式。它把基础设施、工具和服务以及对基础设施的管理自己做为一个软件系统,采纳软件工程实践以结构化的安全的方式来管理对系统的变动。运维
基础设施即代码有四项关键原则。工具
- 再生性。
环境中的任何元素能够轻松复制。
一致性。 不管什么时候,建立的环境各个元素的配置是彻底相同的。
快速反馈。 可以频繁、容易地进行变动,并快速知道变动是否正确。
可见性。 全部对环境的变动应该容易理解,可审计,受版本控制。
基础设施即代码的目标是:
标准化。 以代码来定义环境,实现开发环境、测试环境、生产环境的标准化。
自动化。 以自动化工具来驱动代码准备环境。包括建立环境、更新环境以及销毁环境。
可视化。 以监控来可视化环境信息。环境当前状态可视、环境变动历史可视、可追溯。
基础设施即代码实践会产生高成熟度的持续交付和DevOps。
在实施基础设施即代码时,要遵照如下实践。
- 使用DSL描述环境。
Ansible、Chef、SaltStack、Terraform等基础设施自动化工具都有各自的描述性语言实现对基础设施的定义。使用DSL更容易经过描述性的语言定义基础设施,也有助于代码重用。团队成员能创建起共同理解,从而维护脚本。
如下是Ansible的一个playbook示例。
1 2 3 4 5 6 7 8 9 10 11 |
--- - hosts: local tasks: - name: Install Nginx apt: pkg=nginx state=installed update_cache=true notify: - Start Nginx handlers: - name: Start Nginx service: name=nginx state=started |
- 自测试系统。
在编写环境代码的配置时,也要编写对环境的测试。确保全部服务器都正确进行了配置,遵照了全部的安全规则,网络连通性等进行了验证。咱们通常提倡将测试代码和配置代码放在一块儿维护。这样配置代码更新的化,能保证测试代码也被及时更新。
一些典型的基础设施自动化测试工具备ServerSpec、Testinfra等。如下是一个ServerSpec的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
require 'spec_helper' describe package('httpd'), :if => os[:family] == 'redhat' do it { should be_installed } end describe package('apache2'), :if => os[:family] == 'ubuntu' do it { should be_installed } end describe service('httpd'), :if => os[:family] == 'redhat' do it { should be_enabled } it { should be_running } end describe service('apache2'), :if => os[:family] == 'ubuntu' do it { should be_enabled } it { should be_running } end describe service('org.apache.httpd'), :if => os[:family] == 'darwin' do it { should be_enabled } it { should be_running } end describe port(80) do it { should be_listening } end |
- 一切进行版本化。
一旦采用了环境定义脚本实现对环境的控制后,须要将环境定义脚本归入到版本管理中。而且以后全部的环境变动都应该先修改环境定义脚本,由环境定义脚本触发对环境的变动。登陆到服务器执行一些临时性命令是被坚定禁止的。由于这极有可能会破坏环境的一致性。当重建服务器时,也不能保证能应用全部须要的变动。
下图是基础设施即代码的一个典型使用场景。
除此以外,若是想要在生产环境中建立可伸缩性的服务的话,也须要借助机舱设施即代码这一实践。在高峰时期,系统能够根据定义的环境自动建立并加入新的节点实现动态扩容,并在低峰时将其销毁。当监控发现某节点失败,系统能够根据定义的环境自动建立新的节点来替换失败节点,实现自动灾难恢复。
最后是咱们在某团队实施基础设施即代码的案例解析。这张图是某团队的基础设施架构图。
该团队使用AWS做为基础设施平台。咱们选用ansible做为基础设施自动化工具,并结合AWS提供的cloudformation服务实现快速建立和销毁资源。全部网元都有清晰的角色划分,配套对应的配置脚本。从网络配置到网元配置以及应用配置都实现了全自动化。全部的配置脚本都和源代码一块儿托管在GitHub。团队全部成员均可以查看并修改。