巧用 Ansible 实现配置管理:多环境配置问题
配置管理是本书其他内容的基础。没有配置管理,根本谈不上持续集成、发布管理以及部署流水线。它对交付团队内部的协作也会起到巨大的促进作用

ansible logo

说在前面

在《持续交付》的第二章配置管理的小结里说到:

配置管理是本书其他内容的基础。没有配置管理,根本谈不上持续集成、发布管理以及部署流水线。它对交付团队内部的协作也会起到巨大的促进作用。

再怎么强调配置管理的重要性也不为过,特别是在多环境下。然而大家都知道重要,又少有人告诉我们具体如何做,所以实在难受。

本文总结了我在多环境配置管理实践方面的一点心得,希望对大家有帮助。

Ansible 介绍

你可以简单地把它理解为一个自动化运维工具。本文将会使用这个工具下 inventory 概念来实现多环境配置。简单一点来说,inventory是一个文本文件,你可以在这个文件里记录下所有的机器,并对这些机器进行分组(分类)。

当然,其它的自动化运维工具也可以使用同样的思路来实践。本文只以 Ansible 为例。

例子

比如我们有两个环境,分别有一台机器。使用Ansible的 inventory 来管理这些机器,就会像下面这样:

## inventory
[aws-prod-app]
10.171.32.158

[aws-test-app]
10.161.158.221

所有的 app 应用都是同一份代码,而且都会涉及操作数据库。当然,不同环境下的 app 读取的数据库的配置项的值是不样的。比如 aws-test 环境下配置是

db:
  url: test.mysql.url
  username: testu1
  password: passwordtest

而生产环境 aws-prod 环境下配置:

db:
  url: prod.mysql.url
  username: produ1
  password: passwordprod

这时,因为机器少,我们可以使用 Ansible 的 inventory 变量实现不同环境的配置隔离,比如:

## inventory
[aws-prod-app]
10.171.32.158

## [分组名:vars] 这样的写法是 Ansible inventory的约定
## 按照这个约定来写,Ansible就可以识别了
[aws-prod-app:vars]
db.url = test.mysql.url
db.username = testu1
db.password = passwordtest

[aws-test-app]
10.161.158.221

[aws-test-app:vars]
db.url = prod.mysql.url
db.username = produ1
db.password = passwordprod

接着,如果环境上要部署新应用呢?而且还是很多呢?我们的 inventory 就会变成这样:

## inventory
[aws-prod-app]
10.171.32.158

[aws-prod-appX]
10.171.32.159

## 还有更多的 aws-prod-app...

[aws-prod-app:vars]
db.url = prod.mysql.url
db.username = produ1
db.password = passwordprod


[aws-prod-appX:vars]
db.url = prod.mysql.url
db.username = produ1
db.password = passwordprod

## 还有更多的 aws-prod-app:vars ...

[aws-test-app]
10.161.158.221

[aws-test-appX]
10.161.158.222

## 还有更多的 aws-test-app...

[aws-test-app:vars]
db.url = test.mysql.url
db.username = testu1
db.password = passwordtest


## 还有更多的 aws-test-app:vars ...

好吧,面对这种配置冗余,后期维护会很恐怖。有两种办法解决:

  1. 不增加新应用
  2. 想办法解决这个问题

不要觉得第一种办法可笑,现实中真的存在,只是不同环境下的具体形态不一样。

解决这个问题的办法就是使用 Ansible 的分组的分组的变量。说起来是有点绕。简单的说就是对我们刚刚的分组,再进行一次分组,然后再给这一更高层次的分组设置变量。

接着我们上面的例子,我们使用分组的分组变量进行重写:

## inventory
[aws-prod-app]
10.171.32.158

[aws-prod-appX]
10.171.32.159

## 注意,我们将所有的生产环境的
## 分组又加入到 aws-prod分组下
[aws-prod:children]
aws-prod-app
aws-prod-appX

## 这样,aws-prod 分组的变量又可以
## 应用到所有的 aws-prod 环境下所有的机器
[aws-prod:vars]
db.url = prod.mysql.url
db.username = produ1
db.password = passwordprod

[aws-test-app]
10.161.158.221

[aws-test-appX]
10.161.158.222

[aws-test:children]
aws-test-app
aws-test-appX

[aws-test:vars]
db.url = test.mysql.url
db.username = testu1
db.password = passwordtest

Ansible 这个分组概念设计得非常妙。仔细看,你会发现,利用分组的概念,你可以轻松地、简单地实现多种环境的配置管理。

当然,所有的配置都放一个 inventory 里就不合适了,所以,我们使用了Ansible的 group_vars 文件夹来进行管理,重构后如下:

目录结构
.
├── group_vars
│   ├── aws-prod
│   └── aws-test
└── inventory
## inventory
[aws-prod-app]
10.171.32.158

[aws-prod-appX]
10.171.32.159

[aws-prod:children]
aws-prod-app
aws-prod-appX

[aws-test-app]
10.161.158.221

[aws-test-appX]
10.161.158.221

[aws-test:children]
aws-test-app
aws-test-appX
## group_vars/aws-prod
db.url = prod.mysql.url
db.username = produ1
db.password = passwordprod

到这里,我们简单的多环境管理的例子就算讲完了。

如果觉得不够直观,可以访问我在Github的代码样例 ansible-inventory-example

小结

当环境少的时候,开发人员和测试人员会争抢环境;当环境多的时候,配置管理又会成为一个头大的问题。不论当哪种情况,都会增加我们研发成本。

而利用 Ansible 的分组概念同时加上它的自动化,就可以很轻松地解决多环境的配置管理问题,同时又降低我们的研发成本。

扩展


Last modified on 2018-03-11