一个关于不可变基础设施的实践案例

不可变基础设施(Immutable Infrastructure)是由Chad Fowler于2013年提出的一个很有的预见性的构想 ,其核心思想为任何基础设施的实例一旦创建之后变成为只读状态,如需要修改和升级,则使用新的实例进行替换。
这种模式可以为我们减少配置管理的负担,并使得 DevOps 更加容易实践,基于 Packer、Terraform及Docker, 我们正在实践和完善这种构想,现在给大家分享。
当前的不可变基础设施实践的主要内容有:
生产与开发环境的一致性系统
利用 Terraform 构建基础设施
生产与开发环境的一致性系统
我们平时的开发和测试乃至部署中,最常出现的问题之一就是由于系统环境的不一致导致bug或者运行失败, 这在长时间运行的服务器进行缓慢升级时最为常见,而老旧的系统和软件则带来更多的问题和维护成本。
因此我们使用 Packer 及 Vagrant 来统一生产环境和开发环境,Packer 构建操作系统镜像,供 Vagrant 运行虚拟开发环境,这样所有的开发人员都会有一个统一并且持续更新的开发环境,更利于减少问题和协作。
Packer 构建的镜像还可用于各大虚拟化平台,如 KVM、Xen和ESXi,以及导入到 AWS 等云计算平台,我们这里使用的就是 AWS。
构建的基础镜像会预装好大部分需要的软件如 Docker、Consul,一些常见的 Docker 容器镜像也会拉取预装好。
这样我们在部署时就会有一个和开发环境几乎没有差别的统一基础设施可用。
我已经把我们镜像的构建脚本提取开源出来 zealic/packer-boxes(https://github.com/zealic/packer-boxes),构建的镜像有 CentOS 及 Debian,大家可以参考以此构建自己的镜像。
利用Terraform构建基础设施
上面说过我们使用 AWS 作为基础设施平台,基于不可变基础设施的理念,我们希望的是基础设施是可以快速销毁和重建的,
基于这个目的,我们使用了 Terraform 来完全托管 AWS 基础设施。
在此之前,我需要介绍一下部分架构。
首先我们会为基础设施分组,每个基础设施组对应一整套 VPC 环境。
每组基础设施我们根据功能场景分为两种;ops-center组 及应用基础设施组,ops-center 主要承载运维基础设施,如 Mesos Master,Docker Registry,持续集成服务,VPN接入以及管理后台都运行在 ops-center。
应用基础设施组则运行主要业务的微服务、反向代理及 Marathon 节点。
而这些体现到 AWS 中,每组基础设施组都会应对一个 VPC,通过 VPC Peering Connection 连接相关的基础设施组。
基于这样的前提,我们可以对此分出多个基础设施组,比方我们有国内和新加坡的业务,则可分出如下基础设施组:

ops-cn
prd-cn
ops-sg
prd-sg-master
prd-sg-slave

下面将介绍我们使用 Terraform 托管基础设施时的一些细节。
我们写了一套 Thor 脚本来管理多个基础设施组,每个组都是一个文件夹,文件夹中包含了对基础设施组的 Terraform 定义, 这些定义文件均被版本控制,可以进行对资源的快速回滚和改动。
当我们需要对 AWS 基础设施做一些修改时,只需要修改定义并运行如下命令。
thor exec:terraform apply
通过管理配置文件传递变量来关联多个基础设施组的关系。
目前通过 Terraform 托管了以下内容:

VPC
VPC Subnet
Route table
Security Groups
Route53 records

ELB
S3
Internet/NAT Gateways
以及上面提到的 ops-center 的中提供的各种功能服务器,在定义 aws_instance 时,我们会为其分配 tag,我们的管理程序在接收到服务器准备好的事件时,通过 tag 判断该服务器的角色,为其执行对应的 Ansible Playbook,从而完成自动化部署。
有时我们可能会有未受 Terraform 的资源需要纳入其托管范围,这里我们用了terraforming,可以将已经存在的 VPC、S3 或者 EC2 实例纳入 Terraform 的托管;当然Terraform 也承诺了将会在未来加入 import 功能以导入已有资源。
应用基础设施组则仅部署 Marathon 管理 Docker 容器集群,由其管理业务服务及其他相关内容,由于我们的业务服务均会构建为 Docker 容器进行发布,因此这里仅仅只需要管理应用服务的配置,这里我们使用了Consul和Confd来进行动态配置管理。
这样,我们的基础设施均以相同的模式运行和创建,均具有不可变性,系统更为简单和可靠,并具有快速回滚的能力。
通过实施这套方案,我们可以获得以下好处:
快速重建、销毁基础设施组,部署多个基础设施组来实现灾容、灰度发布及快速升级。

Q&A
Q:你们这套方案中遇到过哪些坑让你印象深刻,请举一两个具体实例说明?
A:使用 Packer 在国内进行构建时,因为众所周知的网络原因,经常会有失败的问题,这一点可以通过其他方式避免。此外由于 Terraform 并非完全支持所有的 AWS 资源管理,如 Cloudfront、Route53 Geo DNS,仍然需要手工管理这些,不过未来 Terraform 会加入这些的支持。
Q:每个vpc组是完全独立的提供服务?能说下这套技术应对的业务层是哪个方面的么?
A:每个 VPC 组提供的是一个完整的应用功能实现,上面也提高了我们会有 prd-sg-master,prd-sg-slave,可用于灾容。业务层提供的主要是 HTTP 服务及内部依赖的微服务。
Q:请问为什么选用Consul?很多类似方案用的etcd。
A:Consul 对于 agent 的节点的失效更友好,此外 Vagrant、Consul、Terraform 都是由 HashiCorp 公司开发的,其文档和技术栈都很全面,值得应用实践。
Q:如果我用了Kubernetes,对大数据Hadoop、Spark都没啥需求,是否还有用Mesos的必要呢?换句话说Mesos和Kubernetes结合针对纯容器平台有什么好处,使用场景是什么?
A:Kubernetes和Mesos都是容器管理调度的框架,Mesos的优势是更具可开发扩展性。
Q:请问对于PHP这种可以动态加载代码的服务,在这套系统里应该怎么应用呢?
A:动态加载代码的代码源建议使用微服务的方式提供。
Q:Vagrant在宿主机使用的是NAT模式还是bridge ?Packer相对于vagrant package 命令,优势是哪些?Vagrant 在宿主机使用 NAT 模式,这样可以减少 DNS 出问题的几率。
A:Packer 可以从ISO镜像开始构建你的系统,相对于Vagrant更纯粹;实际上Vagrant的大多数 box 都是从Packer打包过来的。
Q:我在上期分享时,介绍过类似的Packer+Terraform工具。在使用Terraform管理AWS资源时,你提到另外的脚本管理(thor exec:terraform apply)。请问,你为何不直接运行Terraform 的命令,用thor的目的是什么,你的哪个repo了有用到thor,我可以参考一下?
A:我们在运行Terraform时需要传递很多变量以及硬编码参数,同时我们使用了AWS国内区域和 AWS 国际区域,他们是分开的,对应的 AWS Access Key 及 SecretKey 不同,Thor 脚本的目的是讲这些内容通过配置文件和环境变量的的方式传递给 Terraform,使其能获取正确的参数和定位正确的执行环境。
Q:请问持续集成采用的是Jenkins加插件的方式吗?持续集成的代码采用了什么样的分支管理策略?
A:是的,持续集成采用Jenkins及插件,我们采用的分支是 Git Flow 的变种,基于pull的模型。
Q:单纯的用于AWS的话,亚马逊自家的CloudFormation支持的基础设施应该更全面,如果不考虑跨平台的能力,还有什么理由选择Terraform吗?
A:CloudFormation 的设计并不友好,基于 JSON 的语法非常晦涩且难于维护,不像 Terraform 一样一目了然。
Q:跨主机网络是咋解决的啊?是结合了Kubernetes和Mesos、Docker功能吗?
A:我们采用的方案是 Weave,没有使用Kubernetes。

你可能感兴趣的:(一个关于不可变基础设施的实践案例)