用 Ansible 玩转批量运维

Ansible 是个什么东西呢?官方的 title 是 “Ansible is Simple IT Automation” ——简单的自动化IT工具。这个工具的目标有这么几项:让我们自动化部署 APP;自动化管理配置项;自动化的持续交付;自动化的(AWS)云服务管理。

所有的这几个目标本质上来说都是在一个台或者几台服务器上,执行一系列的命令而已。

Ansible 基于 paramiko 开发的。这个 paramiko 是什么呢?它是一个纯 Python 实现的 ssh 协议库。因此 ansible 还有一个特点就是不需要在远程主机上安装 client/agents,因为它们是基于 ssh来和远程主机通讯的。

用 Ansible 的必要性

假如目前我们已经有超过 10 台的 Jenkins slave 机器,但是 slave 的环境配置却是需要统一,所以想要维护多台 slaves 就是一项需要做很多重复性机械性工作的体力活。

既然 Ansible 是一个能够在多台目标机器上批量执行命令的工具,那么用它来统一维护 slaves 无疑是一个省时省力的方式。

怎么安装呢?

既然它是 Python 实现的 ssh 协议库,那么就用 Python package Manager——pip 进行安装就好了,如果没有装过 pip,那就先需要安装这个

1
$ sudo easy_install pip

安装 pip 后,我们就能安装 Ansible 了

1
$ sudo pip install ansible

官方还特别温馨的提示了这句话

If you are installing on OS X Mavericks, you may encounter some noise from your compiler. A workaround is to do the following:
$ sudo CFLAGS=-Qunused-arguments CPPFLAGS=-Qunused-arguments pip install ansible

更多详细内容,可以参阅 官方文档

如果在 OS X El Capitan 下安装 pycrypto 遇到

1
configure: error: C compiler cannot create executables

请参考此篇文章:El Captainでmacportsでinstallしたpython3.4上でpycryptoのinstallに失敗する場合

需要注意的一点,因为这是通过 ssh 来实现的,所使用的 remote_user 要能够 ssh 无密码登录到所有机器,so,我们可能还需要把想要操作的 slave 的机器(一般是本机)的公钥传到 slave 上,这个比较简单:

1
$ ssh-copy-id [user@]hostname

快速上手

ansible 执行的时候会按照以下顺序查找配置项:

1
2
3
4
* ANSIBLE_CONFIG # 环境变量
* ansible.cfg # 当前目录下
* .ansible.cfg # 用户家目录下
* /etc/ansible/ansible.cfg

还有一个重要的配置是 hosts 的配置,所有的远程主机需要在 hosts 中配置,可以分组。当然 hosts 也可以执行是指定。先来一个简单的例子,目录下新建一个 hosts 文件:

1
2
3
# hosts
[slave]
slave1.ci.ios.com ansible_ssh_user=jenkins

然后在终端执行

1
$ ansible -i ./hosts all -a 'who'

你就会得到如下的反馈

1
2
3
4
# 输出结果
slave1.ci.ios.com | success | rc=0 >>
jenkins console Sep 6 13:10
jenkins ttys000 Sep 8 14:51 (你的 IP)

这是一条 ad-hoc 命令,也就是临时执行命令,ad-hoc 是 ansible 里的一个概念, 在上面命令中就是 -a ,下面会提到。命令中的 all 是值 host 中的所有服务器,当然也可以通过 $ ansible -i ~/hosts slave -a 'who' 这样根据组名指定服务器。

再说到 ansible.cfg 的配置,默认 ansible 执行时会从该配置中加载 hosts 配置,因此可以通过修改 .ansible.cfg 来指定默认的 hosts 文件地址:

1
2
3
# .ansible.cfg
[defaults]
hostfile=/Projects/jenkins-ansible/hosts # 这就是我hosts文件的路径

然后再执行的话,就不需要-i命令了

ad-hoc 命令

上面你看到的就是个简单的 ad-hoc 命令,当你想临时执行一个小命令的时候,例如看下 slave 上的 IP ,重启一下, ping 一下 slave 是否能 pong 回来(打个乒乓),这个命令就最适合啦。

那么这个 ad-hoc 命令怎么用呢?上面已经简单的示范了下。在 ansible 中还有一个 Module(模块)的概念,这个模块可以理解为一个库,所有的命令都需要通过模块来执行,比如上面的那个命令:

1
$ ansible -i ./hosts all -a 'who'

其实是调用了默认的 command 模块

1
$ ansible -i ./hosts all -m command -a 'who'

除了 command 模块还有其他很多模块,比如就像刚才我说的你就想 ping 下这个 slave 是不是还联通可以通过 ping 模块:

1
$ ansible -i ./hosts all -m ping

然后就会看到……

1
2
3
4
slave1.ci.ios.com | success >> {
"changed": false,
"ping": "pong"
}

其实还有以下几个有用的参数

1
2
3
-u username # 指定ssh连接的用户名
-f 10 # 指定并发数
--sudo [-K] # 如果需要root权限执行的话,-K参数是用来输入root密码的

你可以通过各种模块来批量完成某个包的安装,或者其他什么需要的操作。 更多模块可以看 官网文档

一次要执行很多任务?Playbook出场!

如果你想装一个包,配置N多个环境,升级下库,拉一下代码等众多任务,那么一条一条 ad-hoc 命令能把你累死,怎么办?

1
$ ansible-playbook

playbook,顾名思义,就是个剧本,你写好,它们照着演。先写个简单的剧情让它们试试镜?

1
2
3
4
5
6
# test.yml
- hosts: slave
user: jenkins
tasks:
- name: update homebrew
homebrew: update_homebrew=yes

上面的剧情就是让 slave 升级下 homebrew ,剧本写的好奇怪是么?那可能是你第一次见到 YAML 格式的文件,啥是 YAML戳这里!

简单解释下上面的 playbook ,hosts 后面根据 slave 是从 hosts 中读取的,tasks 是是关键词,指明了要执行哪些任务;下面的 name 是任务的名称,homebrew 是前面提到的 module(模块),后面跟的是命令。(点我看下 官方文档 理解更清楚)

然后,保存下,执行

1
$ ansible-playbook -i ./hosts test.yml

哎呀,好戏开场了!

1
2
3
4
5
6
7
8
9
10
11
PLAY [slave] ******************************************************************
GATHERING FACTS ***************************************************************
ok: [slave1.ci.ios.com]
TASK: [allow debugging] *******************************************************
changed: [slave1.ci.ios.com]
PLAY RECAP ********************************************************************
slave1.ci.ios.com : ok=2 changed=1 unreachable=0 failed=0

这就是个简单的 playbook ,结合 hostsModule ,可以演绎出各种惊天动地的凄美爱情剧目(play),有关详细的 playbook的官方介绍,可以 戳这里