自动化运维工具-ansible

一、什么是ansible?

ansible是一个部署一群远程主机的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优势,它不须要安装客户端,经过SSH协议实现远程节点和管理节点之间的通讯,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于模块工做的,模块能够由任何语言开发,它不只支持命令行使用模块,也支持编写yaml格式的playbook。html

二、ansible的安装

两台主机,jin-10,jin-11,咱们只须要在jin-10上安装ansible便可。python

[root@jin-10 ~]# yum install -y ansible

而后把jin-10上的公钥文件id_rsa.pub复制到jin-11上的/root/.ssh/authorized_keys里,同时,对本机也进行密钥认证(把/root/.ssh/id_rsa.pub文件的内容复制到authorized_keys里)。linux

[root@jin-10 ~]# ssh jin-10
Last login: Tue Sep  3 12:27:50 2019 from jin-11
[root@jin-10 ~]# ssh jin-11
Last login: Tue Sep  3 12:24:22 2019 from jin-10

能够看到,jin-10用ssh的方式链接本机和jin-11都不用密码和密钥认证。nginx

而后咱们设置一个主机组,用来告诉Ansible须要管理哪些主机。编辑文件vim /etc/ansible/hosts,内容以下:docker

[testhost]
127.0.0.1
jin-11

其中,testhost为自定义的主机组名字,而后是两个主机的IP(或主机名)。shell

三、ansible的使用

ansible模块Module
bash不管在命令行上执行,仍是bash脚本中,都须要调用cd、ls、copy、yum等命令;module就是ansible的“命令”,module是ansible命令行和脚本中都须要调用的。经常使用的ansible module有yum、copy、template等。
在bash,调用命令时能够跟不一样的参数,每一个命令的参数都是该命令自定义的;一样,ansible中调用module也能够跟不一样的参数,每一个module的参数也都是由module自定义的。
在命令行中,-m后面接调用module的名字,-a后面接调用module的参数:apache

[root@jin-10 ~]# ansible all -m copy -a "src=/etc/hosts dest=/tmp/hosts"
jin-11 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "checksum": "843eede91ec66c16e38ddb67dee1bb173ea7fe9c", 
    "dest": "/tmp/hosts", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/tmp/hosts", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 182, 
    "state": "file", 
    "uid": 0
}
127.0.0.1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "checksum": "843eede91ec66c16e38ddb67dee1bb173ea7fe9c", 
    "dest": "/tmp/hosts", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/tmp/hosts", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 182, 
    "state": "file", 
    "uid": 0
}

在playbook脚本中,tasks中的每个action都是对module的一次调用。在每一个action中:冒号前面是module的名字,冒号后面是调用module的参数:编程

---
  tasks:
  - name: ensure apache is at the latest version
    yum: pkg=httpd state=latest
  - name: write the apache config file
    template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
  - name: ensure apache is running
    service: name=httpd state=started

下面是一些经常使用的module:

调试和测试类的module:json

  • ping - ping一下你的远程主机,若是能够经过ansible成功链接,那么返回pong
  • debug - 用于调试的module,只是简单打印一些消息,有点像linux的echo命令。

文件类的module:vim

  • copy - 从本地拷贝文件到远程节点
  • template - 从本地拷贝文件到远程节点,并进行变量的替换
  • file - 设置文件的属性

linux上经常使用的操做:

  • user - 管理用户帐户
  • yum - redhat系linux上的安装包管理
  • service - 管理服务
  • firewalld - 管理防火墙中的服务和端口

执行Shell命令:

  • shell - 在节点上执行shell命令,支持$HOME和"<", ">", "|", ";" and "&"
  • command - 在远程节点上面执行命令,不支持$HOME和"<", ">", "|", ";" and "&"

3.1 ansible远程执行命令

例:ansible testhost -m command -a 'w'
此处的testhost为主机组名(也能够直接写一个ip,针对某一台机器来执行命令),-m后边是模块名字,-a后面是命令

[root@jin-10 ~]# ansible testhost -m command -a 'w'
jin-11 | CHANGED | rc=0 >>
 09:07:34 up 21:59,  2 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.154.1    二11   20:39m  0.33s  0.33s -bash
root     pts/1    jin-10           09:07    1.00s  0.28s  0.02s w

127.0.0.1 | CHANGED | rc=0 >>
 09:07:34 up 23:03,  3 users,  load average: 0.27, 0.14, 0.19
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.154.1    二10    6.00s  6.63s  5.48s ssh jin-10
root     pts/1    fe80::d601:fb6f: 二12    6.00s  7.09s  0.00s ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/21f0e6a9ae -tt 127.0.0.1 /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1567559253.0-170559931011383/AnsiballZ_command.py && sleep 0'
root     pts/4    localhost        09:07    1.00s  0.51s  0.01s w

针对某一台机器来执行命令:

[root@jin-10 ~]# ansible jin-11 -m command -a 'hostname'
jin-11 | CHANGED | rc=0 >>
jin-11

模块shell也能够一样实现:

[root@jin-10 ~]# ansible testhost -m shell -a 'hostname'
jin-11 | CHANGED | rc=0 >>
jin-11

127.0.0.1 | CHANGED | rc=0 >>
jin-10

3.2 ansible拷贝文件或目录

ansible拷贝目录时,若是目标指定的目录不存在,它会自动建立:

[root@jin-10 ~]# ansible jin-11 -m copy -a "src=/etc/ansible dest=/tmp/ansible_test owner=root group=root mode=0755"
jin-11 | CHANGED => {
    "changed": true, 
    "dest": "/tmp/ansible_test/", 
    "src": "/etc/ansible"
}
[root@jin-11 ~]# ll /tmp/ansible_test
总用量 0
drwxr-xr-x. 3 root root 51 9月   4 09:24 ansible

能够看到目标目录被建立且源目录在目标目录下面。
操做时,要注意src和dest是文件仍是目录,拷贝文件时,若是目标目录已经存在同名目录,那么会把该文件放到同名目录里面:

[root@jin-11 /tmp]# ll -t
总用量 4
drwxr-xr-x. 2 root   root     6 9月   4 09:32 m_test
[root@jin-10 ~]# ansible jin-11 -m copy -a "src=/etc/passwd dest=/tmp/m_test"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "1db31b171f911344344ceb7cf8621d31be83ec07", 
    "dest": "/tmp/m_test/passwd", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "e1a0ce587167dc3587ee5f1b357dc3c4", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 1299, 
    "src": "/root/.ansible/tmp/ansible-tmp-1567560870.7-110358489604181/source", 
    "state": "file", 
    "uid": 0
}
[root@jin-11 /tmp]# ls m_test/
passwd

3.3 ansible远程执行脚本

在jin-10上编写一个test_ansible.sh的脚本,内容以下:

#!/bin/bash
echo `date` >/tmp/test_ansible.txt

而后分发到主机组testhost:

[root@jin-10 ~]# ansible testhost -m copy -a "src=/tmp/test_ansible.sh dest=/tmp/test.sh mode=0755"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "0dc6471ba363889d83d3bf98c4354d874c86bd19", 
    "dest": "/tmp/test.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "bfee9509a7066ca2e822dbe48b21fbe7", 
    "mode": "0755", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 48, 
    "src": "/root/.ansible/tmp/ansible-tmp-1567561704.9-93797175448931/source", 
    "state": "file", 
    "uid": 0
}
127.0.0.1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "0dc6471ba363889d83d3bf98c4354d874c86bd19", 
    "dest": "/tmp/test.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "bfee9509a7066ca2e822dbe48b21fbe7", 
    "mode": "0755", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 48, 
    "src": "/root/.ansible/tmp/ansible-tmp-1567561704.82-59120276764010/source", 
    "state": "file", 
    "uid": 0
}

而后批量执行该脚本:

[root@jin-10 ~]# ansible testhost -m shell -a "/tmp/test.sh"
jin-11 | CHANGED | rc=0 >>


127.0.0.1 | CHANGED | rc=0 >>
[root@jin-10 ~]# ls /tmp/test_ansible.txt 
/tmp/test_ansible.txt
[root@jin-10 ~]# cat !$
cat /tmp/test_ansible.txt
2019年 09月 04日 星期三 09:50:23 CST
[root@jin-11 /tmp]# ls /tmp/test_ansible.txt 
/tmp/test_ansible.txt
[root@jin-11 /tmp]# cat !$
cat /tmp/test_ansible.txt
2019年 09月 04日 星期三 09:50:23 CST

3.4 ansible管理任务计划

使用cron模块能够建立计划任务:

[root@jin-10 ~]# ansible jin-11 -m cron -a "name='test cron' job='/bin/touch /tmp/test_cron' weekday=6"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "test cron"
    ]
}
[root@jin-11 /tmp]# crontab -l
#Ansible: test cron
* * * * 6 /bin/touch /tmp/test_cron

使用cron模块删除计划任务:

[root@jin-10 ~]# ansible jin-11 -m cron -a "name='test cron' state=absent"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": []
}
[root@jin-11 /tmp]# crontab -l

能够看到,以前建立的计划任务已经被删除了。

3.5 ansible安装包和管理服务

ansible的yum模块能够安装包和管理服务(能够进行安装包的安装、卸载和远程启动等)。 咱们在jin-11上安装httpd为例:

[root@jin-11 ~]# rpm -qa httpd
[root@jin-11 ~]#

能够看到,jin-11是没有安装httpd的。
在jin-10上执行以下命令:

[root@jin-10 ~]# ansible jin-11 -m yum -a "name=httpd state=installed"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "changes": {
        "installed": [
            "httpd"
        ]
    }, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.tuna.tsinghua.edu.cn\n * epel: hkg.mirror.rackspace.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.tuna.tsinghua.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-89.el7.centos.1 will be installed\n--> Processing Dependency: httpd-tools = 2.4.6-89.el7.centos.1 for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Running transaction check\n---> Package apr.x86_64 0:1.4.8-3.el7_4.1 will be installed\n---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed\n---> Package httpd-tools.x86_64 0:2.4.6-89.el7.centos.1 will be installed\n---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package           Arch         Version                     Repository     Size\n================================================================================\nInstalling:\n httpd             x86_64       2.4.6-89.el7.centos.1       updates       2.7 M\nInstalling for dependencies:\n apr               x86_64       1.4.8-3.el7_4.1             base          103 k\n apr-util          x86_64       1.5.2-6.el7                 base           92 k\n httpd-tools       x86_64       2.4.6-89.el7.centos.1       updates        91 k\n mailcap           noarch       2.1.41-2.el7                base           31 k\n\nTransaction Summary\n================================================================================\nInstall  1 Package (+4 Dependent packages)\n\nTotal download size: 3.0 M\nInstalled size: 10 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal                                              260 kB/s | 3.0 MB  00:11     \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Installing : apr-1.4.8-3.el7_4.1.x86_64                                   1/5 \n  Installing : apr-util-1.5.2-6.el7.x86_64                                  2/5 \n  Installing : httpd-tools-2.4.6-89.el7.centos.1.x86_64                     3/5 \n  Installing : mailcap-2.1.41-2.el7.noarch                                  4/5 \n  Installing : httpd-2.4.6-89.el7.centos.1.x86_64                           5/5 \n  Verifying  : httpd-2.4.6-89.el7.centos.1.x86_64                           1/5 \n  Verifying  : mailcap-2.1.41-2.el7.noarch                                  2/5 \n  Verifying  : httpd-tools-2.4.6-89.el7.centos.1.x86_64                     3/5 \n  Verifying  : apr-util-1.5.2-6.el7.x86_64                                  4/5 \n  Verifying  : apr-1.4.8-3.el7_4.1.x86_64                                   5/5 \n\nInstalled:\n  httpd.x86_64 0:2.4.6-89.el7.centos.1                                          \n\nDependency Installed:\n  apr.x86_64 0:1.4.8-3.el7_4.1                  apr-util.x86_64 0:1.5.2-6.el7   \n  httpd-tools.x86_64 0:2.4.6-89.el7.centos.1    mailcap.noarch 0:2.1.41-2.el7   \n\nComplete!\n"
    ]
}

再在jin-11上查看,已经安装了httpd包,而且没有启动:

[root@jin-11 ~]# rpm -qa httpd
httpd-2.4.6-89.el7.centos.1.x86_64
[root@jin-11 ~]# ps aux |grep httpd
root       4256  0.0  0.1 112724   996 pts/0    S+   11:29   0:00 grep --color=auto httpd

咱们再远程启动httpd:

[root@jin-10 ~]# ansible jin-11 -m service -a "name=httpd state=started enabled=no"

再查看jin-11是否成功启动httpd服务:

[root@jin-11 ~]# ps aux |grep httpd
root       4355 19.0  0.5 230408  5184 ?        Ss   11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4356  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4357  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4358  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4360  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4361  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
root       4370  0.0  0.1 112724   996 pts/0    R+   11:31   0:00 grep --color=auto httpd

能够看到,httpd服务已经成功启动。

四、ansible playbook

playbook是指一个可被ansible执行的yml文件,最基本的playbook脚本分为三个部分:
一、在什么机器上以什么身份执行:

  • hosts:为主机的IP,或者主机组名,或者关键字all。
  • users:在远程以哪一个用户身份执行。
  • ...

二、执行的任务有哪些:

  • tasks
    • tasks是从上到下顺序执行,若是中间发生错误,那么整个playbook会停止。咱们能够改修文件后,再从新执行。
    • 每个task都是对module的一次调用,只是使用不一样的参数和变量而已。
    • 每个task最好有name属性(可选),这个是供人读的,没有实际的操做。而后会在命令行里面输出,提示用户执行状况。
    • task中每一个action会调用一个module,在module中会去检查当前系统状态是否须要从新执行。
      • 若是本次执行了,那么action会获得返回值changed。
      • 若是不须要执行,那么action获得返回值ok。

三、善后的任务有哪些:

  • handlers
    • handler也是对module的一次调用,与tasks不一样,tasks会默认的按定义顺序执行每个task,handlers则不会,它须要在tasks中被调用,才有可能被执行。
    • handler能够理解为playbook的event,在ansible中,只在task的执行状态为changed的时候,才会执行该task调用的handler,这也是handler与普通的event机制不一样的地方。
    • 若是有多个task notify同一个handler,那么只执行一次。
    • handler的使用场景:例如执行task以后,服务器状态发生变化以后要执行的一些操做,好比咱们修改了配置文件后,须要重启一下服务,这时候就能够用handler模块。

下面咱们来编写一个简单的playbook,vim /etc/ansible/test.yml:

---
- hosts: jin-11
  remote_user: root
  tasks:
   - name: test_playbook
     shell: touch /tmp/test_playbook.txt

而后执行:

[root@jin-10 /etc/ansible]# ansible-playbook /etc/ansible/test.yml 

PLAY [jin-11] ************************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]

TASK [test_playbook] *****************************************************************
 [WARNING]: Consider using the file module with state=touch rather than running
'touch'.  If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid
of this message.

changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
[root@jin-11 ~]# ll -t /tmp/
总用量 16
-rw-r--r--. 1 root   root      0 9月   4 14:49 test_playbook.txt

能够看到,在jin-11的/tmp/下生成了文件test_playbook.txt。

4.1 playbook的变量

  • 自定义变量

在playbook中,经过vars关键字自定义变量,使用时用{{ }}引用以来便可。
咱们以建立用户为例,编辑vim /etc/ansible/create_user.yml,内容以下:

---
- name: create_user
  hosts: jin-11
  user: root
  gather_facts: false
  vars:
   - user: "test"
  tasks:
   - name: create user
     user: name="{{ user }}"

而后执行:

[root@jin-10 /etc/ansible]# ansible-playbook /etc/ansible/create_user.yml 

PLAY [create_user] *******************************************************************

TASK [create user] *******************************************************************
changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在jin-11上查看:

[root@jin-11 ~]# id test
uid=1002(test) gid=1002(test) 组=1002(test)
  • 主机的系统变量(facts)

ansible会经过module setup来收集主机的系统信息,这些收集到的系统信息叫作facts,这些facts信息能够直接以变量的形式使用。

[root@jin-10 ~]# ansible all -m setup -u root
jin-11 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.154.11"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::c9a8:961e:9b39:d180"
        ], 
        "ansible_apparmor": {
            "status": "disabled"
        }, 
        "ansible_architecture": "x86_64",
		...
  • 文件模板中使用的变量

在playbook中定义的变量,能够直接在template中使用,facts变量也能够直接在template中使用,包含在inventory里面定义的host和group变量。只要是在playbook中能够访问的变量,均可以在template文件中使用。

  • 把运行结果当作变量使用-注册变量

把task的执行结果也能够做为一个变量值。这个时候就须要用到“注册变量”,将执行结果注册到一个变量中,待后面的action使用,注册变量常常和debug module一块儿使用,这样能够获得更多action的输出信息,帮助用户调试。

---

- hosts: all

  tasks:

     - shell: ls
       register: result
       ignore_errors: True

     - shell: echo "{{ result.stdout }}"
       when: result.rc == 5

     - debug: msg="{{ result.stdout }}"
  • 用命令行传递参数

为了使Playbook更灵活、通用性更强,容许用户在执行的时候传入变量的值,这个时候就须要用到“额外变量”。

在playbook中定义的变量,须要从命令行传递变量值。
下面是在命令行里面传值得的方法:

[root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "hosts=jin-11 user=root"

能够用json格式传递参数:

[root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "{ 'hosts': 'jin-11', 'user': 'root' }"

还能够把参数放在文件里面:

[root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "@vars.json"

4.2 playbook中的条件判断

when: 相似于编程语言中的if语句
编辑文件vim /etc/ansible/when.yml,内容以下:

---
- hosts: testhost
  user: root
  gather_facts: True
  tasks:
   - name: use when
     shell: touch /tmp/when.txt
     when: ansible_ens32.ipv4.address == "192.168.154.11"

执行:

[root@jin-10 ~]# ansible-playbook /etc/ansible/when.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [use when] **********************************************************************
skipping: [127.0.0.1]
 [WARNING]: Consider using the file module with state=touch rather than running
'touch'.  If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid
of this message.

changed: [jin-11]

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
jin-11                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

查看结果:

[root@jin-10 ~]# ll -t /tmp/
总用量 12
-rw-r--r--. 1 root root 43 9月   4 09:50 test_ansible.txt
-rwxr-xr-x. 1 root root 48 9月   4 09:48 test.sh
[root@jin-11 ~]# ll -t /tmp/
总用量 16
-rw-r--r--. 1 root   root      0 9月   5 09:33 when.txt
-rw-r--r--. 1 root   root      0 9月   4 14:49 test_playbook.txt

能够看到jin-10没有生成when.txt文件,而jin-11则生成了。

4.3 playbook循环

loop: 相似于编程语言中的while语句,在playbook脚本中通常写做with_...
编辑文件vim /etc/ansible/while.yml,内容以下:

---
- hosts: testhost
  user: root
  tasks:
   - name: change mode for files
     file: path=/tmp/{{ item }} state=touch mode=600
     with_items:
      - while1.txt
      - while2.txt
      - while3.txt

执行:

[root@jin-10 ~]# ansible-playbook /etc/ansible/while.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [change mode for files] *********************************************************
changed: [jin-11] => (item=while1.txt)
changed: [127.0.0.1] => (item=while1.txt)
changed: [jin-11] => (item=while2.txt)
changed: [jin-11] => (item=while3.txt)
changed: [127.0.0.1] => (item=while2.txt)
changed: [127.0.0.1] => (item=while3.txt)

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

查看结果:

[root@jin-10 ~]# ll -t /tmp/
总用量 12
-rw-------. 1 root root  0 9月   5 09:45 while3.txt
-rw-------. 1 root root  0 9月   5 09:45 while2.txt
-rw-------. 1 root root  0 9月   5 09:45 while1.txt
-rw-r--r--. 1 root root 43 9月   4 09:50 test_ansible.txt

[root@jin-11 ~]# ll -t /tmp/
总用量 16
-rw-------. 1 root   root      0 9月   5 09:45 while3.txt
-rw-------. 1 root   root      0 9月   5 09:45 while2.txt
-rw-------. 1 root   root      0 9月   5 09:45 while1.txt
-rw-r--r--. 1 root   root      0 9月   5 09:33 when.txt

4.4 用playbook安装nginx

思路:先在一台机器上编译安装好nginx、打包,而后再用ansible去下发。
- 建立相关的目录
进入ansible配置文件目录, 建立一个nginx_install的目录,方便管理,最终目录以下:

[root@jin-10 /var/lib/docker]# cd /etc/ansible/
[root@jin-10 /etc/ansible]# mkdir nginx_install
[root@jin-10 /etc/ansible]# cd !$
cd nginx_install
[root@jin-10 /etc/ansible/nginx_install]# mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}
[root@jin-10 /etc/ansible/nginx_install]# tree
.
└── roles
    ├── common
    │   ├── files
    │   ├── handlers
    │   ├── meta
    │   ├── tasks
    │   ├── templates
    │   └── vars
    └── install
        ├── files
        ├── handlers
        ├── meta
        ├── tasks
        ├── templates
        └── vars

说明:roles目录下有两个角色,common为一些准备操做,install为安装nginx的操做。
每一个角色下面又有几个目录,handlers下面是当发生改变时要执行的操做,一般用在配置文件发生改变,重启服务。files为安装时用到的一些文件,meta为说明信息,说明角色依赖等信息,tasks里面是核心的配置文件,templates一般存一些配置文件,启动脚本等模板文件,vars下为定义的变量。

  • 准备相关的文件
    以前已经在jin-10上编译安装了nginx,相关目录文件以下:
  1. nginx的目录:
[root@jin-10 /etc/ansible/nginx_install]# ls /usr/local/nginx/
client_body_temp  fastcgi_temp  logs        sbin       uwsgi_temp
conf              html          proxy_temp  scgi_temp
  1. nginx的启动脚本:
[root@jin-10 /etc/ansible/nginx_install]# ls /etc/init.d/nginx 
/etc/init.d/nginx
  1. nginx的配置文件:
[root@jin-10 /etc/ansible/nginx_install]# ls /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/conf/nginx.conf

把nginx的目录打包,并复制文件到以前建立的目录中:

[root@jin-10 /usr/local]# tar czf nginx.tar.gz --exclude "nginx.conf" --exclude "vhost" nginx/
[root@jin-10 /usr/local]# mv nginx.tar.gz /etc/ansible/nginx_install/roles/install/files/
[root@jin-10 /usr/local]# cp nginx/conf/nginx.conf /etc/ansible/nginx_install/roles/install/templates/
[root@jin-10 /usr/local]# cp /etc/init.d/nginx /etc/ansible/nginx_install/roles/install/templates/

定义common的tasks,安装nginx须要的一些依赖包:
进入/etc/ansible/nginx_install/roles/目录,并编写/etc/ansible/nginx_install/roles/common/tasks/main.yml文件,内容以下:

[root@jin-10 /etc/ansible/nginx_install/roles]# vim /etc/ansible/nginx_install/roles/common/tasks/main.yml

- name: Install initializtion require software
  yum: name={{ item }} state=installed
  with_items:
   - zlib-devel
   - pcre-devel

再编写一个定义变量的文件vim /etc/ansible/nginx_install/roles/install/vars/main.yml,内容以下:

nginx_user: www
nginx_port: 80
nginx_basedir: /usr/local/nginx

而后再建立一个配置文件vim /etc/ansible/nginx_install/roles/install/tasks/copy.yml ,用于拷贝文件到目标机器:

- name: Copy nginx software
  copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root
- name: Uncompression nginx software
  shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/
- name: Copy nginx start script
 template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755
- name: Copy nginx config
 template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=06
44

再建立一个文件vim /etc/ansible/nginx_install/roles/install/tasks/install.yml ,用于创建用户,启动服务,删除压缩包:

- name: Create nginx user
  user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin
- name: Start nginx service
  shell: /etc/init.d/nginx start
- name: Add boot start nginx service
  shell: chkconfig --level 345 nginx on
- name: Delete nginx compression files
  shell: rm -rf /tmp/nginx.tar.gz

再建立一个调用copy和install的文件 /etc/ansible/nginx_install/roles/install/tasks/main.yml,内容以下:

- include: copy.yml
- include: install.yml

最后,咱们再定义一个入口配置文件/etc/ansible/nginx_install/install.yml,内容以下:

---
- hosts: jin-11
  remote_user: root
  gather_facts: True
  roles:
   - common
   - install

最终目录文件以下:

[root@jin-10 /etc/ansible/nginx_install]# tree
.
├── install.yml
└── roles
    ├── common
    │   ├── files
    │   ├── handlers
    │   ├── meta
    │   ├── tasks
    │   │   └── main.yml
    │   ├── templates
    │   └── vars
    └── install
        ├── files
        │   └── nginx.tar.gz
        ├── handlers
        ├── meta
        ├── tasks
        │   ├── copy.yml
        │   ├── install.yml
        │   └── main.yml
        ├── templates
        │   ├── nginx
        │   └── nginx.conf
        └── vars
            └── main.yml
  • 执行脚本:
[root@jin-11 ~]# yum remove nginx
已加载插件:fastestmirror
参数 nginx 没有匹配
不删除任何软件包

若是目标机器上已安装了nginx,先用命令yum remove nginx删除已安装的nginx。
而后执行playbook脚本:

[root@jin-10 /etc/ansible/nginx_install]# ansible-playbook /etc/ansible/nginx_install/install.yml 

PLAY [jin-11] ************************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]

TASK [common : Install initializtion require software] *******************************
[DEPRECATION WARNING]: Invoking "yum" only once while using a loop via squash_actions
 is deprecated. Instead of using a loop to supply multiple items and specifying 
`name: "{{ item }}"`, please use `name: ['zlib-devel', 'pcre-devel']` and remove the 
loop. This feature will be removed in version 2.11. Deprecation warnings can be 
disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [jin-11] => (item=[u'zlib-devel', u'pcre-devel'])

TASK [install : Copy nginx software] *************************************************
changed: [jin-11]

TASK [install : Uncompression nginx software] ****************************************
 [WARNING]: Consider using the unarchive module rather than running 'tar'.  If you
need to use command because unarchive is insufficient you can add 'warn: false' to
this command task or set 'command_warnings=False' in ansible.cfg to get rid of this
message.

changed: [jin-11]

TASK [install : Copy nginx start script] *********************************************
ok: [jin-11]

TASK [install : Copy nginx config] ***************************************************
ok: [jin-11]

TASK [install : Create nginx user] ***************************************************
changed: [jin-11]

TASK [install : Start nginx service] *************************************************
changed: [jin-11]

TASK [install : Add boot start nginx service] ****************************************
changed: [jin-11]

TASK [install : Delete nginx compression files] **************************************
 [WARNING]: Consider using the file module with state=absent rather than running
'rm'.  If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid
of this message.

changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=10   changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在jin-11主机上查看是否有nginx的进程:

[root@jin-11 ~]# ps aux|grep nginx
root       4040  0.0  0.0  20540   628 ?        Ss   08:32   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody     4042  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
nobody     4043  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
root       4192  0.0  0.1 112724   996 pts/0    S+   09:45   0:00 grep --color=auto nginx

4.5 playbook管理配置文件

安装软件通常是在初始化环境的时候,而在生产环境中,咱们大多数是要管理配置文件。
下面咱们来写一个管理nginx配置文件的playbook。
首先先建立所须要的目录:

[root@jin-10 ~]# mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}

最终目录以下:

[root@jin-10 ~]# tree /etc/ansible/nginx_config/
/etc/ansible/nginx_config/
└── roles
    ├── new
    │   ├── files
    │   ├── handlers
    │   ├── tasks
    │   └── vars
    └── old
        ├── files
        ├── handlers
        ├── tasks
        └── vars

其中,new目录更新时用到,old回滚时用到,files下面为nginx.conf,handlers为重启nginx服务的命令。
关于回滚,须要在执行playbook以前先备份旧的配置,因此对于旧的配置文件的管理必定要谨慎,千万不要随便去修改线上机器的配置,并且要保证new/files下面的配置和线上的配置保持一致。
拷贝nginx.conf文件到/etc/ansible/nginx_config/roles/new/files/目录下:

[root@jin-10 /usr/local/nginx/conf]# cp -r nginx.conf /etc/ansible/nginx_config/roles/new/files/

编辑一个定义变量的文件vim /etc/ansible/nginx_config/roles/new/vars/main.yml,内容以下:

nginx_basedir: /usr/local/nginx

再编写一个从新加载nginx服务的文件vim /etc/ansible/nginx_config/roles/new/handlers/main.yml,内容以下:

- name: restart nginx
  shell: /etc/init.d/nginx reload

再编写一个核心任务的文件vim /etc/ansible/nginx_config/roles/new/tasks/main.yml ,内容以下:

- name: copy conf file
  copy: src={{ item.src }} dest={{ nginx_basedir }}/{{ item.dest }} backup=yes owner=r
oot group=root mode=0644
  with_items:
   - { src: nginx.conf, dest: conf/nginx.conf }
  notify: restart nginx

最后,咱们定义一个总入口配置文件vim /etc/ansible/nginx_config/update.yml,内容以下:

---
- hosts: testhost
  user: root
  roles:
  - new

执行update.yml

[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [new : copy conf file] **********************************************************
ok: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
ok: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

能够看到,nginx服务已经从新加载了:

[root@jin-11 ~]# ps aux|grep nginx
root       4040  0.0  0.0  20540   628 ?        Ss   08:32   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody     4042  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
nobody     4043  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
root       4570  0.0  0.1 112724   996 pts/0    S+   10:43   0:00 grep --color=auto nginx
[root@jin-11 ~]# date
2019年 09月 09日 星期一 10:44:12 CST

咱们编辑nginx.conf,加上一行注释内容:# test for the rollback,而后再执行update.yml脚本:

[root@jin-10 ~]# cat /etc/ansible/nginx_config/roles/new/files/nginx.conf|grep test
# test for the rollback
[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [new : copy conf file] **********************************************************
ok: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
ok: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在jin-11上查看nginx.conf是否备份成功:

[root@jin-11 ~]# cat /usr/local/nginx/conf/nginx.conf|grep test
# test for the rollback

以上的操做是针对于更新、修改配置文件的,下面来介绍一下回滚操做:
回滚操做就是把旧的配置覆盖,而后从新加载nginx服务, 每次改动nginx配置文件以前先备份到old里,对应目录为/etc/ansible/nginx_config/roles/old/files。
拷贝new目录里的文件到old目录里,至关于把当前nginx配置文件备份到old里,如需回滚就将备份还原。

[root@jin-10 ~]# rsync -av /etc/ansible/nginx_config/roles/new/ /etc/ansible/nginx_config/roles/old/
sending incremental file list
files/
files/nginx.conf
handlers/
handlers/main.yml
tasks/
tasks/main.yml
vars/
vars/main.yml

sent 2,535 bytes  received 108 bytes  5,286.00 bytes/sec
total size is 2,080  speedup is 0.79

编写一个一个总入口配置文件vim /etc/ansible/nginx_config/rollback.yml,内容以下:

---
- hosts: jin-11
  user: root
  roles:
  - old

下面咱们来进行一个简单的回滚操做:
一、先将配置文件同步到old目录下:

[root@jin-10 ~]# rsync -av /etc/ansible/nginx_config/roles/new/files/nginx.conf /etc/ansible/nginx_config/roles/old/files/nginx.conf 
sending incremental file list

sent 49 bytes  received 12 bytes  122.00 bytes/sec
total size is 1,772  speedup is 29.05

二、修改配置文件/etc/ansible/nginx_config/roles/new/files/nginx.conf,文件末尾增长一行注释内容:

#test the ansible playbook rollback

三、执行update.yml文件向客户端更新文件:

[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [new : copy conf file] **********************************************************
changed: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
changed: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

RUNNING HANDLER [new : restart nginx] ************************************************
changed: [jin-11]
changed: [127.0.0.1]

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

四、在jin-11上查看,文件是否同步:

[root@jin-11 ~]# tail -n1 /usr/local/nginx/conf/nginx.conf
#test the ansible playbook rollback

五、能够看到,同步成功,而后咱们执行rollback.yml文件进行回滚操做:

[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/rollback.yml 

PLAY [jin-11] ************************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]

TASK [old : copy conf file] **********************************************************
changed: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

RUNNING HANDLER [old : restart nginx] ************************************************
changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

六、在jin-11上查看是否已恢复:

[root@jin-11 ~]# tail -n1 /usr/local/nginx/conf/nginx.conf
}
[root@jin-11 ~]#

能够看到,以前文件末尾增长的那一行没有了。 因此,所谓的回滚就是在操做改动前,先把文件备份一份,若是出现误操做,就将以前备份的文件还原回去,这样就起到了一个回滚的效果。

相关文章
相关标签/搜索