Just For Coding

Keep learning, keep living …

Ansible入门

Ansible是一个自动化配置管理系统,主要用于简化运维人员对大量服务器上配置及服务等内容的管理工作。在自动化配置管理领域内,除了ansible, 比较著名的还有Puppet,SaltStack, Chef等项目。Ansible与这些同类项目相比,部署和使用更简单。Puppet等项目都是C/S架构,需要在被管理服务器上安装agent程序,agent程序与配置管理中心服务器通信拉取相应的配置或文件。而ansible无论是获取主机信息,发送命令还是拷贝文件等操作都是直接使用SSH通道来完成。

我们在CentOS7环境中来演示ansible使用,首先安装ansible:

1
2
yum install -y epel-release
yum install -y ansible

Ansible默认使用SSH Key登录被管理服务器。为了简化使用,我们首先配置ansible所在服务器能够以SSH key免密钥登录被管理服务器。

一路直接回车生成SSH key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@centos4 ansible]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
81:86:f6:45:c4:5d:ac:3b:81:16:45:bf:c0:99:5d:72 root@centos4
The key's randomart image is:
+--[ RSA 2048]----+
|       oo+ooo E  |
|     . oo..=.+   |
|    o o oo=.o    |
|   . o .o.o. .   |
|      ..S  o.    |
|          o      |
|           .     |
|                 |
|                 |
+-----------------+

再将SSH公钥拷贝到被管理服务器,以192.168.33.14为例:

1
ssh-copy-id root@192.168.33.14

Ansible使用Inventory文件来管理被管理服务器,默认为/etc/ansible/hosts。在Inventory文件中,我们可以将服务器划分为组,或者直接以单机的形式来记录,可以划分为多个组。比如:

1
2
3
4
5
6
7
8
9
10
192.168.100.1
192.168.100.10

[group1]
192.168.100.20
192.168.100.30

[group2]
192.168.100.20
192.168.100.30

其中前两条为未分组服务器,之后划分了两个组。Inventory文件中有非常多的注释,具体内容格式可以参考注释。

在我们的示例中,我们将被管理服务器192.168.33.13192.168.33.14划分为一组,组名定为test, 并给每台服务器定义一个别名,文件内容如下:

1
2
3
[test]
centos4 ansible_ssh_host=192.168.33.13
centos5 ansible_ssh_host=192.168.33.14

Ansible的使用方式主要有两种: 一种直接命令行调用;另一种是通过叫做playbook的配置脚本来定义需要执行的任务。

首先,我们直接以命令行执行ansible:

1
2
3
4
5
6
7
8
9
[root@centos3 ansible]# ansible -m ping all
centos5 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
centos4 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Ansible的基本逻辑为在指定的服务器上运行Ansible模块,配置管理相关内容由模块来完成。Ansible内置实现了大量的模块,具体模块可以参考官方文档。 上述命令中的-m ping表示使用ping模块, 它会连接到被管理服务器并检测是否有可用的python,检测成功时返回pong

命令中的all表示Inventory文件中所有服务器。在命令行中我们也可以指定某个组或者服务器:

1
2
3
4
5
6
7
8
9
[root@centos3 ansible]# ansible -m ping test
centos4 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
centos5 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
1
2
3
4
5
[root@centos3 ansible]# ansible -m ping centos4
centos4 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

也可以以”:”分隔来指定多个服务器:

1
2
3
4
5
6
7
8
9
[root@centos3 ansible]# ansible -m ping centos4:centos5
centos4 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
centos5 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

内置的shell模块可以在服务器上执行命令,比如,我们要查看centos4机器的内存情况, 可以这样运行:

1
2
3
4
5
[root@centos3 ansible]# ansible -m shell -a 'free -m' centos4
centos4 | SUCCESS | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            457          75         252           2         130         306
Swap:          1015           9        1006

命令行方式适合用于一次性任务,而日常繁琐的配置管理,使用playbook脚本更为方便。Playbook脚本为YAML格式, 在脚本中,我们需要指明被管理的服务器或组,以及需要执行的任务等信息。在Playbook中可以定义许多任务,每个任务需要指明运行的模块及参数。任务以在脚本文件中的先后顺序运行。

下面,我们以在CentOS7上通过ansible安装NGINX并管理NGINX的配置文件为例来说明Playbook脚本的编写与执行。

创建demo.yml, 内容如下:

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
30
31
32
---
- hosts: test
  vars:
    nginx_port: 8080
    nginx_root: /var/www/html
  tasks:
    - name: Install NGINX repo rpm
      yum:
        name: http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
        state: present

    - name: Install NGINX
      yum: name=nginx state=latest

    - name: create directory
      file: path= state=directory owner=nginx group=nginx

    - name: populate file
      copy: src=index.html dest=/index.html owner=nginx group=nginx mode=0440

    - name: generate conf
      template: src=demo.conf.tpl dest=/etc/nginx/conf.d/demo.conf owner=nginx group=nginx
      notify: Restart NGINX

    - name: Stop and disable firewalld
      service: name=firewalld state=stopped enabled=false
    - name: Staring NGINX
      service: name=nginx state=started

  handlers:
    - name: Restart NGINX
      service: name=nginx state=restarted

其中,hosts指明需要执行任务的服务器或组,vars用于定义变量,这些变量可以在playbook脚本和模板文件中引用。tasks定义了需要执行的所有task,这些task会按先后顺序执行。前两个tasks使用YUM模块来安装NGINX。第三个task使用file模块创建NGINX的Document ROOT目录。第四个task执行copy模块将index.html文件拷贝到被管理服务器的NGINX的Document Root目录下。第五个task使用了template模块,它将模板文件内容中的变量替换为相应的值来生成目标文件。

比如,我们的NGINX配置文件模板demo.conf.tpl内容如下,使用了nginx_portnginx_root两个变量:

1
2
3
4
5
6
7
8
server {
    listen ;

    location / {
        root ;
        index index.html;
    }
}

最后两个tasks分别是关闭和禁用firewalld服务。

handlers是Playbook中的事件机制,它需要由task使用notify指令触发。task执行都有状态结果,只有状态结果为changed, 才会触发相应的handler

在上述示例中,生成NGINX配置文件的task: generate conf完成后,状态为changed, 此时会触发handler: Restart NGINX来重启NGINX令我们的配置文件生效。再次执行该playbook脚本时,NGINX配置文件没有改动,任务状态结果为ok,则不会触发handler: Restart NGINX

上述示例的index.html内容如下:

1
hello index.html.

我们示例的所有文件结构如下:

1
2
3
4
5
6
7
[root@centos3 ansible]# tree .
.
├── demo.conf.tpl
├── demo.yml
└── index.html

0 directories, 3 files

第一次执行demo.yml的结果:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
[root@centos3 ansible]# ansible-playbook demo.yml

PLAY [test] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [centos4]
ok: [centos5]

TASK [Install NGINX repo rpm] **************************************************
changed: [centos5]
changed: [centos4]

TASK [Install NGINX] ***********************************************************
changed: [centos5]
changed: [centos4]

TASK [create directory] ********************************************************
changed: [centos4]
changed: [centos5]

TASK [populate file] ***********************************************************
changed: [centos4]
changed: [centos5]

TASK [generate conf] ***********************************************************
changed: [centos5]
changed: [centos4]

TASK [Stop and disable firewalld] **********************************************
ok: [centos5]
ok: [centos4]

TASK [Staring NGINX] ***********************************************************
changed: [centos5]
changed: [centos4]

RUNNING HANDLER [Restart NGINX] ************************************************
changed: [centos5]
changed: [centos4]

PLAY RECAP *********************************************************************
centos4                    : ok=9    changed=7    unreachable=0    failed=0
centos5                    : ok=9    changed=7    unreachable=0    failed=0

再次执行demo.yml的结果如下:

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
30
31
32
33
34
35
36
37
38
39
[root@centos3 ansible]# ansible-playbook demo.yml

PLAY [test] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [centos5]
ok: [centos4]

TASK [Install NGINX repo rpm] **************************************************
ok: [centos5]
ok: [centos4]

TASK [Install NGINX] ***********************************************************
ok: [centos5]
ok: [centos4]

TASK [create directory] ********************************************************
ok: [centos5]
ok: [centos4]

TASK [populate file] ***********************************************************
ok: [centos5]
ok: [centos4]

TASK [generate conf] ***********************************************************
ok: [centos5]
ok: [centos4]

TASK [Stop and disable firewalld] **********************************************
ok: [centos5]
ok: [centos4]

TASK [Staring NGINX] ***********************************************************
ok: [centos4]
ok: [centos5]

PLAY RECAP *********************************************************************
centos4                    : ok=8    changed=0    unreachable=0    failed=0
centos5                    : ok=8    changed=0    unreachable=0    failed=0

可以看到第一次执行时,task: generate conf结果状态为changed, handler: Restart NGINX被触发。而第二次执行时,task结果状态为ok, handle: Restart NGINX没有被触发。

最后,我们测试NGINX配置是否已经生效:

1
2
[root@centos3 ansible]# curl http://192.168.33.13:8080/
hello index.html.

在Playbook中还可以定义循环执行、条件执行等各种情况,可以非常灵活的满足我们的业务需求。具体内容本文不再详述。