自动化运维—ansible
一、Ansible介绍
Ansilbe是一个部署一群远程主机的工具。远程的主机可以是远程虚拟机或物理机, 也可以是本地主机。
Ansilbe通过SSH协议实现远程节点和管理节点之间的通信,不需要安装客户端。
Ansible基于模块工作,模块可以由任何语言开发
Ansible不仅支持命令行使用模块,也支持编写yaml格式的playbook,易于编写和阅读
Ansible的安装十分简单,centos上可直接通过yum安装。
Ansible有提供命令行版本,免费。也有提供UI(浏览器图形化)版本,网址: www.ansible.com/tower,但是收费的。 官方文档: http://docs.ansible.com/ansible/latest/index.html
Ansible已经被redhat公司收购,它在github上是一个非常受欢迎的开源软件,github地址https://github.com/ansible/ansible
一本不错的入门电子书 https://ansible-book.gitbooks.io/ansible-first-book/
二、ansible安装和远程执行命令
查看ansible 的yum清单,安装ansible ansible-doc
[root@ying01 salt]# yum list | grep ansible
ansible.noarch 2.6.3-1.el7 epel
ansible-doc.noarch 2.6.3-1.el7 epel
ansible-inventory-grapher.noarch 2.4.4-1.el7 epel
ansible-lint.noarch 3.4.21-1.el7 epel
ansible-openstack-modules.noarch 0-20140902git79d751a.el7 epel
ansible-review.noarch 0.13.4-1.el7 epel
kubernetes-ansible.noarch 0.6.0-0.1.gitd65ebd5.el7 epel
python2-ansible-runner.noarch 1.0.1-1.el7 epel
python2-ansible-tower-cli.noarch 3.3.0-2.el7 epel
[root@ying01 salt]# yum -y install ansible ansible-doc
查看ying01 主机上是否有公钥存在,若不存在则要生成,生成秘钥命令: ssh-keygen
[root@ying01 ~]# ls /root/.ssh/
authorized_keys id_rsa id_rsa.pub known_hosts
[root@ying01 ~]# cat /root/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+X/2tfggcYIe/3qp98blHj4ySD0GbVmP5QfU7tXXMbE/+FnktHOA3l9+noxXxNXFpaDjc4k+R9TV1R4yG8U0+bx8zucaVTSQWgFCiwDlKhY4pUgfQePtNX+AVUo7yf0+ysz7P3cyUTIInHORB2R/DoKzcxMEM9AHkb//G/UtLaRBhLLWhNGz/R8S5ZhdsC3+X+yKKDVffua8RWkAqevntf4lWz6KEYbuTjxzM7cOXOrHx0/w3/qtvD/Vee+I7vZHkCdqwMfQxn9pTh6c3RwBwcx9jzbJJ7YLV5KmOx0QqSK8qHylgjuO2ZS1wF1+eTdO1D2zP2aEykF6dDNhzQRb5 root@ying01
把此公钥分别 存放在ying01、ying02、ying03机器 的authorized_keys 文件下;
#ansible
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+X/2tfggcYIe/3qp98blHj4ySD0GbVmP5QfU7tXXMbE/+FnktHOA3l9+noxXxNXFpaDjc4k+R9TV1R4yG8U0+bx8zucaVTSQWgFCiwDlKhY4pUgfQePtNX+AVUo7yf0+ysz7P3cyUTIInHORB2R/DoKzcxMEM9AHkb//G/UtLaRBhLLWhNGz/R8S5ZhdsC3+X+yKKDVffua8RWkAqevntf4lWz6KEYbuTjxzM7cOXOrHx0/w3/qtvD/Vee+I7vZHkCdqwMfQxn9pTh6c3RwBwcx9jzbJJ7YLV5KmOx0QqSK8qHylgjuO2ZS1wF1+eTdO1D2zP2aEykF6dDNhzQRb5 root@ying01
编辑/etc/ansible/hosts文件,添加以下语句
[root@ying01 ~]# vim /etc/ansible/hosts
[testhost] //主机名称
127.0.0.1 //主机IP
ying01 //主机的ID
ying02
ying03
以上写IP也可以,要是写ID,就需要在 /etc/hosts 里面定义;因为之前已经定义ID
[root@ying01 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 113.108.182.52 www.hao123.com www.baidu.com 127.0.0.1 ying.com 192.168.112.136 ying01 192.168.112.138 ying02 192.168.112.139 ying03
测试以下127.0.0.1主机是否联通
[root@ying01 ~]# ssh 127.0.0.1
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:ZQlXi+kieRwi2t64Yc5vUhPPWkMub8f0CBjnYRlX2Iw.
ECDSA key fingerprint is MD5:ff:9f:37:87:81:89:fc:ed:af:c6:62:c6:32:53:7a:ad.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '127.0.0.1' (ECDSA) to the list of known hosts.
Last login: Tue Sep 11 11:49:11 2018 from 192.168.112.1
[root@ying01 ~]# w
13:30:28 up 13:31, 2 users, load average: 0.12, 0.09, 0.07
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.112.1 11:49 4.00s 0.45s 0.01s ssh 127.0.0.1
root pts/1 127.0.0.1 13:30 4.00s 0.06s 0.00s w
[root@ying01 ~]# logout
Connection to 127.0.0.1 closed.
在行testhost主机上,执行命令
[root@ying01 ~]# ansible testhost -m command -a 'wc -l /etc/passwd'
ying03 | SUCCESS | rc=0 >>
25 /etc/passwd
ying02 | SUCCESS | rc=0 >>
30 /etc/passwd
127.0.0.1 | SUCCESS | rc=0 >>
53 /etc/passwd
ying01 | SUCCESS | rc=0 >>
53 /etc/passwd
[root@ying01 ~]# ansible 127.0.0.1 -m command -a 'wc -l /etc/passwd' //可以针对IP
127.0.0.1 | SUCCESS | rc=0 >>
53 /etc/passwd
[root@ying01 ~]# ansible 'ying03' -m command -a 'wc -l /etc/passwd' //可以针对单个定义ID
ying03 | SUCCESS | rc=0 >>
25 /etc/passwd
语句释义:ansible 批量执行命令,testhost 是主机的集合,-m后面接调用module的名字, -a后面接调用module的参数
shell模块也可以执行命令
[root@ying01 ~]# ansible testhost -m shell -a 'wc -l /etc/passwd'
127.0.0.1 | SUCCESS | rc=0 >>
53 /etc/passwd
ying03 | SUCCESS | rc=0 >>
25 /etc/passwd
ying02 | SUCCESS | rc=0 >>
30 /etc/passwd
ying01 | SUCCESS | rc=0 >>
53 /etc/passwd
[root@ying01 ~]# ansible testhost -m shell -a 'hostname'
ying01 | SUCCESS | rc=0 >>
ying01
127.0.0.1 | SUCCESS | rc=0 >>
ying01
ying03 | SUCCESS | rc=0 >>
ying03
ying02 | SUCCESS | rc=0 >>
ying02
[root@ying01 ~]# ansible 'ying01' -m shell -a 'wc -l /etc/passwd'
ying01 | SUCCESS | rc=0 >>
53 /etc/passwd
[root@ying01 ~]# ansible 127.0.0.1 -m shell -a 'wc -l /etc/passwd'
127.0.0.1 | SUCCESS | rc=0 >>
53 /etc/passwd
错误解决:
错误: "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
解决: yum install -y libselinux-python
三、 ansible拷贝文件或目录
ansible ying02 -m copy -a "src=/etc/ansible dest=/tmp/ansibletest owner=root group=root mode=0755"
- ying02 : 指定认证主机,可以是testhost集合,也可以是ying03、127.0.0.1等;
- copy -a "定义内容" :复制定义的内容
- src=/etc/ansible :定义复制的源目录及文件
- dest=/tmp/ansibletest :定义要复制到的位置
- owner=root :定义uid为root
- group=root :组为root
- mode=0755 :权限为755
整个语句意思为:把master机器的/etc/ansible目录复制到远程机器ying02上的/tmp/ansibletest目录,并指定所有者、所有组及其权限;
[root@ying01 ~]# ansible ying02 -m copy -a "src=/etc/ansible dest=/tmp/ansibletest owner=root group=root mode=0755"
ying02 | SUCCESS => {
"changed": true,
"dest": "/tmp/ansibletest/",
"src": "/etc/ansible"
}
在ying02上,查看复制结果
[root@ying02 ~]# ls -la /tmp/ansibletest
总用量 4
drwxr-xr-x 3 root root 21 9月 11 17:35 .
drwxrwxrwt. 17 root root 4096 9月 11 17:35 ..
drwxr-xr-x 3 root root 51 9月 11 17:35 ansible
[root@ying02 ~]# tree /tmp/ansibletest
/tmp/ansibletest
└── ansible
├── ansible.cfg
├── hosts
└── roles
2 directories, 2 files
ying02上未指定目录,会自动创建目录
[root@ying01 ~]# ansible ying02 -m copy -a "src=/etc/ansible dest=/tmp/ owner=root group=root mode=0755"
ying02 | SUCCESS => {
"changed": true,
"dest": "/tmp/",
"src": "/etc/ansible"
}
在ying02上,查看复制结果
[root@ying02 ~]# ls -ld /tmp/ansible
drwxr-xr-x 3 root root 51 9月 11 17:40 /tmp/ansible
[root@ying02 ~]# tree /tmp/ansible
/tmp/ansible
├── ansible.cfg
├── hosts
└── roles
1 directory, 2 files
注意:
- 源目录会放到目标目录下面去,
- 如果目标指定的目录不存在,它会自动创建。
- 如果拷贝的是文件,dest指定的名字和源如果不同,并且它不是已经存在的目录,相当于拷贝过去后又重命
- 但相反,如果desc是目标机器上已经存在的目录,则会直接把文件拷贝到该目录下面。
四、 ansible远程执行脚本
创建test.sh脚本
[root@ying01 ~]# vim /tmp/test.sh
#!/bin/bash
echo `date` > /tmp/ansible_test.txt //创建ansible_test.txt文件
把此脚本复制到ying03主机上,并改名为test1.sh
[root@ying01 ~]# ansible ying03 -m copy -a "src=/tmp/test.sh dest=/tmp/test1.sh owner=root group=root mode=0755"
ying03 | SUCCESS => {
"changed": true,
"checksum": "1a6e4af02dba1bda6fc8e23031d4447efeba0ade",
"dest": "/tmp/test1.sh",
"gid": 0,
"group": "root",
"md5sum": "edfaa4371316af8c5ba354e708fe8a97",
"mode": "0755",
"owner": "root",
"size": 48,
"src": "/root/.ansible/tmp/ansible-tmp-1536660710.3-139886566503496/source",
"state": "file",
"uid": 0
}
[root@ying01 ~]# ansible ying03 -m shell -a "/tmp/test1.sh" //远程执行test1.sh脚本
ying03 | SUCCESS | rc=0 >>
查看ansible_test.txt内容及相关情况
[root@ying03 ~]# cat /tmp/ansible_test.txt
2018年 09月 11日 星期二 18:12:56 CST
[root@ying03 ~]# ls -l /tmp/ansible_test.txt
-rw-r--r-- 1 root root 43 9月 11 18:12 /tmp/ansible_test.txt
注意:-m command 不支持管道符,而-m shell 支持管道
-m command 不支持管道
[root@ying01 ~]# ansible testhost -m command -a 'cat /etc/passwd |wc -l'
ying03 | FAILED | rc=1 >>
cat:无效选项 -- l
Try 'cat --help' for more information.non-zero return code
ying02 | FAILED | rc=1 >>
cat:无效选项 -- l
Try 'cat --help' for more information.non-zero return code
ying01 | FAILED | rc=1 >>
cat:无效选项 -- l
Try 'cat --help' for more information.non-zero return code
127.0.0.1 | FAILED | rc=1 >>
cat:无效选项 -- l
Try 'cat --help' for more information.non-zero return code
-m shell 支持管道
[root@ying01 ~]# ansible testhost -m shell -a 'cat /etc/passwd |wc -l'
ying02 | SUCCESS | rc=0 >>
30
ying03 | SUCCESS | rc=0 >>
25
127.0.0.1 | SUCCESS | rc=0 >>
53
ying01 | SUCCESS | rc=0 >>
53
五、ansible管理任务计划
- 新建管理任务计划
给ying02机器,创建名为test cron 的管理认为计划
[root@ying01 ~]# ansible ying02 -m cron -a "name='test cron' job='/bin/touch /tmp/1212.txt' weekday=6"
ying02 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"test cron"
]
用crontab -l查看此管理计划
[root@ying02 ~]# crontab -l
# Lines below here are managed by Salt, do not edit
#Ansible: test cron
* * * * 6 /bin/touch /tmp/1212.txt
- 管理计划任务
state=absent 定义状态为无,即可删除此计划任务
[root@ying01 ~]# ansible ying02 -m cron -a "name='test cron' state=absent"
ying02 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": []
}
在ying02上验证,此时已经无任务计划,说明删除成功
[root@ying02 ~]# crontab -l
# Lines below here are managed by Salt, do not edit
注意:由ansible管理的计划任务 (crontab -e),请不要手动修改,否则会导致ansible无法再管理相应的计划任务
六、ansible安装包和管理服务
删除httpd模块
[root@ying01 ~]# ansible ying02 -m yum -a "name=httpd state=removed"
ying02 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
"已加载插件:fastestmirror\n正在解决依赖关系\n--> 正在检查事务\n---> 软件包 httpd.x86_64.0.2.4.6-80.el7.centos.1 将被 删除\n--> 正在处理依赖关系 httpd = 2.4.6-80.el7.centos.1,它被软件包 httpd-devel-2.4.6-80.el7.centos.1.x86_64 需要\n--> 正在检查事务\n---> 软件包 httpd-devel.x86_64.0.2.4.6-80.el7.centos.1 将被 删除\n--> 解决依赖关系完成\n\n依赖关系解决\n\n================================================================================\n Package 架构 版本 源 大小\n================================================================================\n正在删除:\n httpd x86_64 2.4.6-80.el7.centos.1 @updates 9.4 M\n为依赖而移除:\n httpd-devel x86_64 2.4.6-80.el7.centos.1 @updates 749 k\n\n事务概要\n================================================================================\n移除 1 软件包 (+1 依赖软件包)\n\n安装大小:10 M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n 正在删除 : httpd-devel-2.4.6-80.el7.centos.1.x86_64 1/2 \n 正在删除 : httpd-2.4.6-80.el7.centos.1.x86_64 2/2 \n 验证中 : httpd-devel-2.4.6-80.el7.centos.1.x86_64 1/2 \n 验证中 : httpd-2.4.6-80.el7.centos.1.x86_64 2/2 \n\n删除:\n httpd.x86_64 0:2.4.6-80.el7.centos.1 \n\n作为依赖被删除:\n httpd-devel.x86_64 0:2.4.6-80.el7.centos.1 \n\n完毕!\n"
]
}
在ying02机器上,查看httpd是否删除
[root@ying02 ~]# rpm -qa httpd
[root@ying02 ~]# netstat -lnpt |grep httpd
安装httpd
[root@ying01 ~]# ansible ying02 -m yum -a "name=httpd"
ying02 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * epel: mirrors.aliyun.com\n * extras: mirrors.aliyun.com\n * updates: centos.ustc.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-80.el7.centos.1 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-80.el7.centos.1 updates 2.7 M\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 2.7 M\nInstalled size: 9.4 M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : httpd-2.4.6-80.el7.centos.1.x86_64 1/1 \n Verifying : httpd-2.4.6-80.el7.centos.1.x86_64 1/1 \n\nInstalled:\n httpd.x86_64 0:2.4.6-80.el7.centos.1 \n\nComplete!\n"
]
}
启动httpd
[root@ying01 ~]# ansible ying02 -m service -a "name=httpd state=started enabled=no"
ying02 | SUCCESS => {
"changed": true,
"enabled": false,
"name": "httpd",
"state": "started",
篇幅原因,省略
在ying02机器上,验证httpd是否启动
[root@ying02 ~]# netstat -lnpt |grep httpd
tcp6 0 0 :::80 :::* LISTEN 31897/httpd
[root@ying02 ~]# ps aux |grep httpd
root 31897 0.0 0.2 224020 4996 ? Ss 20:53 0:00 /usr/sbin/httpd -DFOREGROUND
apache 31898 0.0 0.1 224020 2952 ? S 20:53 0:00 /usr/sbin/httpd -DFOREGROUND
apache 31899 0.0 0.1 224020 2952 ? S 20:53 0:00 /usr/sbin/httpd -DFOREGROUND
apache 31900 0.0 0.1 224020 2952 ? S 20:53 0:00 /usr/sbin/httpd -DFOREGROUND
apache 31901 0.0 0.1 224020 2952 ? S 20:53 0:00 /usr/sbin/httpd -DFOREGROUND
apache 31902 0.0 0.1 224020 2952 ? S 20:53 0:00 /usr/sbin/httpd -DFOREGROUND
root 32086 0.0 0.0 112720 984 pts/0 S+ 21:01 0:00 grep --color=auto httpd
注意:这里的name是centos系统里的服务名,可以通过chkconfig --list查到。
ansible-doc -l : 列出所有的模块
[root@ying01 ~]# ansible-doc -l|grep httpd
apache2_mod_proxy Set and/or get members' attributes of an Apache httpd 2.4 mod_proxy balancer pool
bigip_device_httpd Manage HTTPD related settings on BIG-IP
ansible-doc cron :查看指定模块的文档
[root@ying01 ~]# ansible-doc cron
> CRON (/usr/lib/python2.7/site-packages/ansible/modules/system/cron.py)
Use this module to manage crontab and environment variables entries. This module allows you to create environment
variables and named crontab entries, update, or delete them. When crontab jobs are managed: the module includes one
line with the description of the crontab entry `"#Ansible: <name>"' corresponding to the "name" passed to the module,
which is used by future ansible/module calls to find/check the state. The "name" parameter should be unique, and
changing the "name" value will result in a new cron task being created (or a different one being removed). When
environment variables are managed: no comment line is added, but, when the module needs to find/check the state, it
uses the "name" parameter to find the environment variable definition line. When using symbols such as %, they must
be properly escaped.
OPTIONS (= is mandatory):
篇幅原因,下面内容省略
七、使用ansible playbook
- Playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.
- 如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.
- Playbooks 的格式是YAML。
[root@ying01 ~]# cd /etc/ansible/
[root@ying01 ansible]# ls
ansible.cfg hosts roles
[root@ying01 ansible]# vim test.yml
---
- hosts: ying02 //针对ying02主机,若果多个主机,可以用逗号隔开
remote_user: root //远程用户为root
tasks: //任务
- name: test_playbook //任务名 test_playbook
shell: touch /tmp/qqq.txt //用到shell模块
执行test.yml文件方案
[root@ying01 ansible]# ansible-playbook test.yml
PLAY [ying02] ***********************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [ying02]
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: [ying02]
PLAY RECAP **************************************************************************************************************************************************
ying02 : ok=2 changed=1 unreachable=0 failed=0
在ying02机器上验证
[root@ying02 ~]# ls -l /tmp/qqq.txt
-rw-r--r-- 1 root root 0 9月 11 21:24 /tmp/qqq.txt
[root@ying02 ~]# date
2018年 09月 11日 星期二 21:26:19 CST
八、playbook里的变量
创建create_user.yml文件
[root@ying01 ansible]# vim create_user.yml
---
- name: create_user
hosts: ying02
user: root
gather_facts: false //false 不收集主机相关信息;ture :与之相反
vars:
- user: "test"
tasks:
- name: create user
user: name="{{ user }}"
create_user.yml文件语句释义:
- name参数对该playbook实现的功能做一个概述,后面执行过程中,会打印name变量的值,可以省略;
- gather_facts参数指定了在以下任务部分执行前,是否先执行setup模块获取主机相关 信息,如果后面的task会使用到setup获取的信息时会用到;
- vars参数,指定了变量,这里指字一个user变量,其值为test,需要注意的是,变量值一定要用引号引住;
- user指定了调用user模块,name是user模块里的一个参数,而增加的用户名字调用了上面user变量的值。
执行此文件
[root@ying01 ansible]# ansible-playbook create_user.yml
PLAY [create_user] ******************************************************************************************************************************************
TASK [create user] ******************************************************************************************************************************************
changed: [ying02]
PLAY RECAP **************************************************************************************************************************************************
ying02 : ok=1 changed=1 unreachable=0 failed=0
在ying02上,测试执行结果
[root@ying02 ~]# id test
uid=1002(test) gid=1002(test) 组=1002(test)
九、playbook里的循环
创建while.yml文件
[root@ying01 ansible]# pwd
/etc/ansible
[root@ying01 ansible]# vim while.yml
---
- hosts: ying02 //针对ying02主机
user: root //用户为root
tasks:
- name: change mode for files //任务名称属性
file: path=/tmp/{{ item }} state=touch mode=600 //定义变量item ,先创建,再给予权限
with_items: //item文本集合
- 1.txt
- 2.txt
- 3.txt
执行 while.yml文件;Gathering Facts又出现,因为我们没有禁掉;
[root@ying01 ansible]# ansible-playbook while.yml
PLAY [ying02] ***********************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [ying02]
TASK [change mode for files] ********************************************************************************************************************************
changed: [ying02] => (item=1.txt)
changed: [ying02] => (item=2.txt)
changed: [ying02] => (item=3.txt)
PLAY RECAP **************************************************************************************************************************************************
ying02 : ok=2 changed=1 unreachable=0 failed=0
在ying02上,测试此循环试验成功,每个文件都创建,并授予600权限
[root@ying02 ~]# ls -l /tmp/?.txt
-rw------- 1 root root 0 9月 11 22:49 /tmp/1.txt
-rw------- 1 root root 0 9月 11 22:49 /tmp/2.txt
-rw------- 1 root root 0 9月 11 22:49 /tmp/3.txt
十、playbook里的条件判断
创建when.yml条件判断的yml文本
[root@ying01 ansible]# vim when.yml
---
- hosts: testhost
user: root
gather_facts: True
tasks:
- name: use when
shell: touch /tmp/when.txt //
when: ansible_ens33.ipv4.address == "192.168.112.138"
when: ansible_ens33.ipv4.address == "192.168.112.138" 释义:
- when: 为ansble模块
- ansible_ens33 :为一个1级范围
- ipv4:为ansible_ens33范围内的子集;
- address:为ipv4的一个子集;
- == "192.168.112.138" :匹配此IP
上面的when条件语句,就通过查看facter信息,来设置条件;
查看所有的facter信息: ansible ying02 -m setup
[root@ying01 ansible]# ansible ying02 -m setup
以下内容为节选,为了突出when条件
"ansible_ens33": { //此为1级条件
"active": true,
"device": "ens33",
"features": {
"busy_poll": "off [fixed]",
"fcoe_mtu": "off [fixed]",
"generic_receive_offload": "on",
"generic_segmentation_offload": "on",
"vlan_challenged": "off [fixed]"
},
"hw_timestamp_filters": [],
"ipv4": { //此为2级条件
"address": "192.168.112.138", //此为3级条件
"broadcast": "192.168.112.255",
"netmask": "255.255.255.0",
"network": "192.168.112.0"
},
"ipv6": [
{
"address": "fe80::43bd:36bd:3f01:f8e8",
"prefix": "64",
"scope": "link"
}
执行 when.yml方案
[root@ying01 ansible]# ansible-playbook when.yml
PLAY [testhost] *********************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [ying02]
ok: [ying03]
ok: [ying01]
ok: [127.0.0.1]
TASK [use when] *********************************************************************************************************************************************
skipping: [127.0.0.1]
skipping: [ying01]
skipping: [ying03]
[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: [ying02]
PLAY RECAP **************************************************************************************************************************************************
127.0.0.1 : ok=1 changed=0 unreachable=0 failed=0
ying01 : ok=1 changed=0 unreachable=0 failed=0
ying02 : ok=2 changed=1 unreachable=0 failed=0
ying03 : ok=1 changed=0 unreachable=0 failed=0
在ying02机器上,验证,有when.txt生成;因为只有ying02符合条件
[root@ying02 ~]# ls -l /tmp/when.txt
-rw-r--r-- 1 root root 0 9月 11 23:09 /tmp/when.txt
其他机器都没有,因为不符合when条件
[root@ying03 ~]# ls -l /tmp/when.txt
ls: 无法访问/tmp/when.txt: 没有那个文件或目录
十一、playbook中的handlers
Ansible playbook中的handlers可实现类似逻辑与的功能。(相当于shell中&&)
运用场景为:修改完配置文件后,重新加载配置文件;
创建handlers.yml文件
[root@ying01 ansible]# vim handlers.yml
---
- name: handlers test
hosts: ying02
user: root
tasks:
- name: copy file
copy: src=/etc/passwd dest=/tmp/bbb.txt //先复制
notify: test handlers
handlers:
- name: test handlers
shell: echo "111111" >> /tmp/bbb.txt //再写入内容
说明:此处必要copy步骤成功,handlers才能够继续执行;逻辑并且
执行 handlers.yml文件
[root@ying01 ansible]# ansible-playbook handlers.yml
PLAY [handlers test] ****************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [ying02]
TASK [copy file] ********************************************************************************************************************************************
changed: [ying02]
RUNNING HANDLER [test handlers] *****************************************************************************************************************************
changed: [ying02]
PLAY RECAP **************************************************************************************************************************************************
ying02 : ok=3 changed=2 unreachable=0 failed=0
在ying02机器上,测试bbb.txt文本有111111写入,试验成功
[root@ying02 ~]# tail /tmp/bbb.txt
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
zabbix:x:997:994:Zabbix Monitoring System:/var/lib/zabbix:/sbin/nologin
memcached:x:996:993:Memcached daemon:/run/memcached:/sbin/nologin
mongod:x:995:992:mongod:/var/lib/mongo:/bin/false
gitlab-www:x:994:990::/var/opt/gitlab/nginx:/bin/false
git:x:993:989::/var/opt/gitlab:/bin/sh
gitlab-redis:x:992:988::/var/opt/gitlab/redis:/bin/false
gitlab-psql:x:991:987::/var/opt/gitlab/postgresql:/bin/sh
gitlab-prometheus:x:990:986::/var/opt/gitlab/prometheus:/bin/sh
111111
十二、 playbook安装nginx
- 实战:批量安装源码nginx
- 思路:先在一台机器上编译安装好nginx、打包,然后再用ansible去下发
第一步:创建/etc/ansible/nginx_install目录及其子目录
[root@ying01 ~]# cd /etc/ansible
[root@ying01 ansible]# cd nginx_install/
[root@ying01 nginx_install]# mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}
[root@ying01 nginx_install]# tree
.
└── roles //install 此目录为安装nginx操作
├── common //此目录为一些准备操作
│ ├── files //此目录存放一些安装nginx时用到的文件
│ ├── handlers //当发生改变时要执行的操作,比如配置文件发生改变了,就要重启nginx服务
│ ├── meta //此目录存放说明信息
│ ├── tasks //存放核心的配置文件
│ ├── templates //存放一些配置文件,启动脚本等模块文件
│ └── vars //自定义变量
└── install //此目录为安装nginx操作
├── files
├── handlers
├── meta
├── tasks
├── templates
└── vars
第二步:确定需要打包的nginx目录文件
[root@ying01 nginx_install]# pwd
/etc/ansible/nginx_install
您在 /var/spool/mail/root 中有新邮件
[root@ying01 nginx_install]# ls /usr/local/nginx/
client_body_temp conf fastcgi_temp html logs proxy_temp sbin scgi_temp uwsgi_temp
[root@ying01 nginx_install]# ls /etc/init.d/nginx
/etc/init.d/nginx
[root@ying01 nginx_install]# ls /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/conf/nginx.conf
第三步:打包nginx目录下,除vhost的所有有关nginxd文件;把nginx配置文件、启动脚本复制到roles/install/templates/下;
[root@ying01 nginx_install]# cd /usr/local/
[root@ying01 local]# tar czf nginx.tar.gz --exclude "nginx.conf" --exclude "vost"
[root@ying01 local]# tar czf nginx.tar.gz --exclude "nginx.conf" --exclude "vhost" nginx/
[root@ying01 local]# mv nginx.tar.gz /etc/ansible/nginx_install/roles/install/files/
[root@ying01 local]# cp nginx/conf/nginx.conf /etc/ansible/nginx_install/roles/install/templates/
[root@ying01 local]# cp /etc/init.d/nginx /etc/ansible/nginx_install/roles/install/templates
[root@ying01 local]# cd /etc/ansible/nginx_install/roles/
[root@ying01 roles]# tree //查看已复制到位的文件
.
├── common
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
└── install
├── files
│ └── nginx.tar.gz
├── handlers
├── meta
├── tasks
├── templates
│ ├── nginx
│ └── nginx.conf
└── vars
14 directories, 3 files
第四步:定义普通的tasks,创建main.yml文件
[root@ying01 roles]# cd common/
[root@ying01 common]# vim tasks/main.yml
- name: Install initializtion require software
yum: name={{ item }} state=installed //循环安装所需包
with_items:
- zlib-devel
- pcre-devel
第五步:定义变量,创建/install/vars/main.yml 文件
[root@ying01 common]# vim /etc/ansible/nginx_install/roles/install/vars/main.yml
nginx_user: www //用户
nginx_port: 800 //端口
nginx_basedir: /usr/local/nginx //nginx目录
第六步:定义文件拷贝配置文件
[root@ying01 common]# vim /etc/ansible/nginx_install/roles/install/tasks/copy.yml
- name: Copy Nginx Software //把nginx包复制到指定目录
copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root
- name: Uncompression Nginx Software //用shell模块远程解压到/usr/local下
shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/
- name: Copy Nginx Start Script //复制启动nginx脚本
template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755
- name: Copy Nginx Config //复制nginx配置文件,通过变量,即/usr/local/nginx下
template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=0644
第七步:建立用户、启动服务。删除安装包
[root@ying01 ~]# 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 //远程启动nginx
shell: /etc/init.d/nginx start
- name: Add Boot Start Nginx Service //增加nginx服务,到启动项
shell: chkconfig --level 345 nginx on
- name: Delete Nginx compression files //删除nginx.tar.gz包
shell: rm -rf /tmp/nginx.tar.gz
第八步:创建main.yml,调用copy和install
[root@ying01 ~]# vim /etc/ansible/nginx_install/roles/install/tasks/main.yml
- include: copy.yml
- include: install.yml
第九步:创建入口文件
[root@ying01 ~]# vim /etc/ansible/nginx_install/install.yml
---
- hosts: ying03
remote_user: root
gather_facts: True
roles:
- common
- install
在认证主机ying03上,因为之前安装有nginx,因此把设计nginx改为nginx1,防止试验干涉;
[root@ying03 ~]# cd /usr/local/
[root@ying03 local]# mv nginx nginx1
[root@ying03 local]# ls
bin etc games include lib lib64 libexec mysql nginx1 sbin share src
[root@ying03 local]# ls /etc/init.d/
functions mysqld netconsole network nginx README
[root@ying03 local]# cd /etc/init.d/
[root@ying03 init.d]# ls
functions mysqld netconsole network nginx README
[root@ying03 init.d]# mv nginx nginx1
在ying01上,开始执行总入口的install.yml文件
[root@ying01 ~]# ansible-playbook /etc/ansible/nginx_install/install.yml
PLAY [ying03] ***********************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [ying03]
TASK [common : Install initializtion require software] ******************************************************************************************************
ok: [ying03] => (item=[u'zlib-devel', u'pcre-devel'])
TASK [install : Copy Nginx Software] ************************************************************************************************************************
changed: [ying03]
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: [ying03]
TASK [install : Copy Nginx Start Script] ********************************************************************************************************************
changed: [ying03]
TASK [install : Copy Nginx Config] **************************************************************************************************************************
changed: [ying03]
TASK [install : Create Nginx User] **************************************************************************************************************************
changed: [ying03]
TASK [install : Start Nginx Service] ************************************************************************************************************************
changed: [ying03]
TASK [install : Add Boot Start Nginx Service] ***************************************************************************************************************
changed: [ying03]
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: [ying03]
PLAY RECAP **************************************************************************************************************************************************
ying03 : ok=10 changed=8 unreachable=0 failed=0
到ying03机器上测试,有nginx的进程,说明是试验成功
[root@ying03 init.d]# ps aux |grep nginx
root 8748 0.0 0.1 45576 1076 ? Ss 01:01 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody 8749 0.0 0.3 47928 3704 ? S 01:01 0:00 nginx: worker process
nobody 8750 0.0 0.3 47928 3704 ? S 01:01 0:00 nginx: worker process
root 8887 0.0 0.0 112720 980 pts/0 S+ 01:02 0:00 grep --color=auto nginx
十三、 playbook管理配置文件
生产环境中安装软件包只是在初始化环境的时候用一下,大多时候是需要管理配置文件的。此时可以用playbook功能。
创建playbook配置目录结构
[root@ying01 ~]# mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}
[root@ying01 ~]# cd /etc/ansible/nginx_config/
[root@ying01 nginx_config]# tree
/etc/ansible/nginx_config/
└── roles
├── new
│ ├── files
│ ├── handlers
│ ├── tasks
│ └── vars
└── old
├── files
├── handlers
├── tasks
└── vars
11 directories, 0 files
把nginx虚拟主机,复制到nginx_config/roles/new/files/目录下
[root@ying01 nginx_config]# cd /usr/local/nginx/conf/
[root@ying01 conf]# cp -r nginx.conf vhost /etc/ansible/nginx_config/roles/new/files/
[root@ying01 conf]# cd -
/etc/ansible/nginx_config
[root@ying01 nginx_config]# tree
.
└── roles
├── new
│ ├── files
│ │ ├── nginx.conf
│ │ └── vhost
│ │ ├── aaa.com.conf
│ │ ├── load.conf
│ │ ├── proxy.conf
│ │ ├── ssl.conf
│ │ └── test.com.conf
│ ├── handlers
│ ├── tasks
│ └── vars
└── old
├── files
├── handlers
├── tasks
└── vars
12 directories, 6 files
定义变量文件
[root@ying01 nginx_config]# vim /etc/ansible/nginx_config/roles/new/vars/main.yml
nginx_basedir: /usr/local/nginx
定义nginx重新加载配置
[root@ying01 nginx_config]# vim /etc/ansible/nginx_config/roles/new/handlers/main.yml
- name: restart nginx
shell: /etc/init.d/nginx reload
定义主配置文件
[root@ying01 nginx_config]# 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=root group=root mode=0644
with_items:
- { src: nginx.conf, dest: conf/nginx.conf }
- { src: vhosts, dest: conf/ }
notify: restart nginx
定义总入口配置,创建update.yml文件
[root@ying01 nginx_config]# vim /etc/ansible/nginx_config/update.yml
---
- hosts: ying03
user: root
roles:
- new
执行update.yml文件
[root@ying01 nginx_config]# ansible-playbook /etc/ansible/nginx_config/update.yml
PLAY [ying03] ***********************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [ying03]
TASK [new : copy conf file] *********************************************************************************************************************************
ok: [ying03] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
changed: [ying03] => (item={u'dest': u'conf/', u'src': u'vhost'})
RUNNING HANDLER [new : restart nginx] ***********************************************************************************************************************
changed: [ying03]
PLAY RECAP **************************************************************************************************************************************************
ying03 : ok=3 changed=2 unreachable=0 failed=0
在客户端ying03测试,nginx服务重新加载
[root@ying03 ~]# ps aux |grep nginx
root 8945 0.0 0.2 45856 2900 ? Ss 01:07 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody 10713 0.0 0.3 48208 3964 ? S 02:11 0:00 nginx: worker process
nobody 10714 0.0 0.3 48208 3964 ? S 02:11 0:00 nginx: worker process
root 10724 0.0 0.0 112720 984 pts/0 R+ 02:12 0:00 grep --color=auto nginx
[root@ying03 ~]# ls /usr/local/nginx/conf/vhost/ //vhost也被复制到指定目录
aaa.com.conf load.conf proxy.conf ssl.conf test.com.conf
文件的回滚测试
在ying01机器上,把new文件夹备份到old文件夹
[root@ying01 nginx_config]# rsync -av roles/new/ roles/old/
sending incremental file list
files/
files/nginx.conf
files/vhost/
files/vhost/aaa.com.conf
files/vhost/load.conf
files/vhost/proxy.conf
files/vhost/ssl.conf
files/vhost/test.com.conf
handlers/
handlers/main.yml
tasks/
tasks/main.yml
vars/
vars/main.yml
sent 4,919 bytes received 207 bytes 10,252.00 bytes/sec
total size is 4,105 speedup is 0.80
[root@ying01 nginx_config]# tree
.
├── roles
│ ├── new
│ │ ├── files
│ │ │ ├── nginx.conf
│ │ │ └── vhost
│ │ │ ├── aaa.com.conf
│ │ │ ├── load.conf
│ │ │ ├── proxy.conf
│ │ │ ├── ssl.conf
│ │ │ └── test.com.conf
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── vars
│ │ └── main.yml
│ └── old
│ ├── files
│ │ ├── nginx.conf
│ │ └── vhost
│ │ ├── aaa.com.conf
│ │ ├── load.conf
│ │ ├── proxy.conf
│ │ ├── ssl.conf
│ │ └── test.com.conf
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── vars
│ └── main.yml
├── update.retry
└── update.yml
13 directories, 20 files
创建rollback.yml 文件
[root@ying01 nginx_config]# vim /etc/ansible/nginx_config/rollback.yml
---
- hosts: ying03
user: root
roles:
- old
在ying上,配置文件nginx.conf,在include前面加上#号
[root@ying01 nginx_config]# vim /etc/ansible/nginx_config/roles/new/files/nginx.conf
# include vhost/*.conf;
在ying02上测试,发现include前面有#号
[root@ying03 ~]# tail -5 /usr/local/nginx/conf/nginx.conf
gzip_http_version 1.1;
gzip_types text/plain application/x-javascript text/css text/htm
application/xml;
# include vhost/*.conf;
执行rollback.yml 文件
[root@ying01 nginx_config]# ansible-playbook /etc/ansible/nginx_config/rollback.yml
PLAY [ying03] ***********************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************
ok: [ying03]
TASK [old : copy conf file] *********************************************************************************************************************************
ok: [ying03] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
ok: [ying03] => (item={u'dest': u'conf/', u'src': u'vhost'})
PLAY RECAP **************************************************************************************************************************************************
ying03 : ok=2 changed=0 unreachable=0 failed=0
在ying02上测试,发现include的#消失了,试验成功
[root@ying03 ~]# tail -5 /usr/local/nginx/conf/nginx.conf
gzip_http_version 1.1;
gzip_types text/plain application/x-javascript text/css text/htm
application/xml;
include vhost/*.conf;
}