第三十九课 自动化运维之ansible
目录
十五、 ansible介绍
十六、 ansible安装
十七、 ansible远程执行命令
十八、 ansible拷贝文件或目录
十九、 ansible远程执行脚本
二十、 ansible管理任务计划
二十一、 ansible安装包和管理服务
二十二、 使用ansible playbook
二十三、 playbook里的变量
二十四、 playbook里的循环
二十五、 playbook里的条件判断
二十六、 playbook中的handlers
二十七、 playbook安装nginx
二十八、 playbook管理配置文件
十五、 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安装
环境:
ansiblemanager 192.168.1.51 CentOS Linux release 7.5.1804 (Core)
ansiblemanaged01 192.168.1.52 CentOS Linux release 7.5.1804 (Core)
ansiblemanaged02 192.168.1.53 CentOS Linux release 7.5.1804 (Core)
为三台主机配置hosts文件
[root@ansiblemanager ~]# vim /etc/hosts
// 添加如下内容
192.168.1.51 ansiblemanager
192.168.1.52 ansiblemanaged01
192.168.1.53 ansiblemanaged02
1.在ansiblemanager上安装ansible
// 查看源里自带的ansible版本
[root@ansiblemanager ~]# yum list | grep ansible
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
ansible.noarch 2.6.2-1.el7 epel
ansible-doc.noarch 2.6.2-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
// 安装ansible
[root@ansiblemanager ~]# yum -y install ansible ansible-doc.noarch
2.在ansiblemanager上生成密钥
[root@ansiblemanager ~]# 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:
SHA256:SelwQ1T30hy8SQxvHWlQ/0YmDvm0VNYvAR9qrVdqFb8 root@ansiblemanager
The key's randomart image is:
+---[RSA 2048]----+
| .o.. +*=+=|
| . . . X=O*|
| . = *.&+X|
| = o . X+O+|
| S . BEo|
| o . |
| |
| |
| |
+----[SHA256]-----+
[root@ansiblemanager ~]# ssh-copy-id 192.168.1.52
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.1.52 (192.168.1.52)' can't be established.
ECDSA key fingerprint is SHA256:F7bJ5VTokx6I6FGONg5glMgIm7xggOdBnDfnOz1WAm4.
ECDSA key fingerprint is MD5:d3:c0:12:84:40:a4:89:27:3f:bd:1a:2b:e5:2e:cc:27.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.1.52's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh '192.168.1.52'"
and check to make sure that only the key(s) you wanted were added.
[root@ansiblemanager ~]# ssh 192.168.1.52
Last login: Wed Sep 5 17:31:52 2018 from ansiblemanaged01
[root@ansiblemanaged01 ~]# logout
Connection to 192.168.1.52 closed.
[root@ansiblemanager ~]# ssh-copy-id 192.168.1.53
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.1.53 (192.168.1.53)' can't be established.
ECDSA key fingerprint is SHA256:F7bJ5VTokx6I6FGONg5glMgIm7xggOdBnDfnOz1WAm4.
ECDSA key fingerprint is MD5:d3:c0:12:84:40:a4:89:27:3f:bd:1a:2b:e5:2e:cc:27.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.1.53's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh '192.168.1.53'"
and check to make sure that only the key(s) you wanted were added.
[root@ansiblemanager ~]# ssh 192.168.1.53
Last login: Wed Sep 5 17:32:23 2018 from ansiblemanaged01
[root@ansiblemanaged02 ~]# logout
Connection to 192.168.1.53 closed.
3.新建配置被管理主机清单文件/etc/ansible/hosts
[root@ansiblemanager ~]# vim /etc/ansible/hosts
// 添加以下内容
[testhosts]
192.168.1.52
192.168.1.53
十七、 ansible远程执行命令
ansible命令的格式是:
ansible <host-pattern> [options]
演示:
// 批量执行命令,-m后面接调用module的名字, -a后面接调用module的参数
[root@ansiblemanager ~]# ansible testhosts -m command -a 'w'
192.168.1.52 | SUCCESS | rc=0 >>
17:49:21 up 59 min, 3 users, load average: 0.00, 0.01, 0.03
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root tty1 16:52 56:01 0.02s 0.02s -bash
root pts/0 192.168.1.9 16:52 3:13 0.32s 0.32s -bash
root pts/1 ansiblemanager 17:49 0.00s 0.11s 0.00s w
192.168.1.53 | SUCCESS | rc=0 >>
17:49:22 up 58 min, 3 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root tty1 16:53 55:46 0.01s 0.01s -bash
root pts/0 192.168.1.9 16:53 3:14 0.31s 0.31s -bash
root pts/1 ansiblemanager 17:49 1.00s 0.08s 0.00s w
// 也可以针对单主机执行命令
[root@ansiblemanager ~]# ansible 192.168.1.52 -m command -a 'uptime'
192.168.1.52 | SUCCESS | rc=0 >>
10:24:44 up 54 min, 2 users, load average: 0.00, 0.01, 0.03
// shell模块也可以执行命令
[root@ansiblemanager ~]# ansible testhosts -m shell -a 'w'
192.168.1.52 | SUCCESS | rc=0 >>
10:26:16 up 55 min, 2 users, load average: 0.00, 0.01, 0.03
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.1.9 09:31 3:52 0.01s 0.01s -bash
root pts/1 ansiblemanager 10:26 0.00s 0.05s 0.00s w
192.168.1.53 | SUCCESS | rc=0 >>
10:26:16 up 55 min, 2 users, load average: 0.00, 0.01, 0.02
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.1.9 09:31 55:08 0.01s 0.01s -bash
root pts/1 ansiblemanager 10:26 0.00s 0.08s 0.00s w
错误: "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
解决: yum install -y libselinux-python
十八、 ansible拷贝文件或目录
1.拷贝目录
// 源目录会放到目标目录下面去,如果目标指定的目录不存在,它会自动创建。
// 如果拷贝的是文件,dest指定的名字和源如果不同,并且它不是已经存在的目录,
// 相当于拷贝过去后又重命名。但相反,如果desc是目标机器上已经存在的目录,
// 则会直接把文件拷贝到该目录下面。
[root@ansiblemanager ~]# ansible 192.168.1.52 -m copy -a "src=/etc/ansible dest=/tmp owner=root group=root mode=755"
192.168.1.52 | SUCCESS => {
"changed": true,
"dest": "/tmp/",
"src": "/etc/ansible"
}
// 在192.168.1.52上查看
[root@ansiblemanaged01 ~]# ls -l /tmp/
total 0
drwxr-xr-x 3 root root 51 Sep 6 10:39 ansible
drwx------ 2 root root 6 Sep 6 09:14 vmware-root
[root@ansiblemanaged01 ~]#
2.拷贝文件
// 拷贝的行为类似于copy命令
[root@ansiblemanager ~]# ansible 192.168.1.52 -m copy -a "src=/etc/inittab dest=/tmp"
192.168.1.52 | SUCCESS => {
"changed": true,
"checksum": "e285e50c4dd88d8a2f644dd1750f60400ca60f94",
"dest": "/tmp/inittab",
"gid": 0,
"group": "root",
"md5sum": "66a88d6c4d693170753ea3382f8bc150",
"mode": "0644",
"owner": "root",
"size": 511,
"src": "/root/.ansible/tmp/ansible-tmp-1536201763.72-216741204056791/source",
"state": "file",
"uid": 0
}
// 在192.168.1.52上查看
[root@ansiblemanaged01 ~]# ls -l /tmp/
total 4
drwxr-xr-x 3 root root 51 Sep 6 10:39 ansible
-rw-r--r-- 1 root root 511 Sep 6 10:42 inittab
drwx------ 2 root root 6 Sep 6 09:14 vmware-root
十九、 ansible远程执行脚本
1.在AnsibkeManager端建立脚本文件
[root@ansiblemanaged01 sh]# vim who.sh
#!/bin/bash
echo $HOSTNAME
2.分发脚本到被管理机器
[root@ansiblemanager ~]# ansible testhosts -m copy -a "src=/root/script/sh/who.sh dest=/tmp mode=755"
192.168.1.52 | SUCCESS => {
"changed": true,
"checksum": "71b7b8522c1f41a69ce8f1e6671b028fdf849752",
"dest": "/tmp/who.sh",
"gid": 0,
"group": "root",
"md5sum": "2896d6645133ac0c98022eb61a5737cb",
"mode": "0755",
"owner": "root",
"size": 28,
"src": "/root/.ansible/tmp/ansible-tmp-1536202718.33-277007092121833/source",
"state": "file",
"uid": 0
}
192.168.1.53 | SUCCESS => {
"changed": true,
"checksum": "71b7b8522c1f41a69ce8f1e6671b028fdf849752",
"dest": "/tmp/who.sh",
"gid": 0,
"group": "root",
"md5sum": "2896d6645133ac0c98022eb61a5737cb",
"mode": "0755",
"owner": "root",
"size": 28,
"src": "/root/.ansible/tmp/ansible-tmp-1536202718.34-129515903004432/source",
"state": "file",
"uid": 0
}
3.批量执行脚本
[root@ansiblemanager ~]# ansible testhosts -m shell -a '/tmp/who.sh'
192.168.1.52 | SUCCESS | rc=0 >>
ansiblemanaged01
192.168.1.53 | SUCCESS | rc=0 >>
ansiblemanaged02
// shell模块与command模块的区别: shell模块,还支持远程执行命令并且带管道
[root@ansiblemanager ~]# ansible testhosts -m command -a 'who | grep root'
192.168.1.52 | FAILED | rc=1 >>
who: extra operand ‘root’
Try 'who --help' for more information.non-zero return code
192.168.1.53 | FAILED | rc=1 >>
who: extra operand ‘root’
Try 'who --help' for more information.non-zero return code
[root@ansiblemanager ~]# ansible testhosts -m shell -a 'who | grep root'
192.168.1.52 | SUCCESS | rc=0 >>
root pts/0 2018-09-06 09:31 (192.168.1.9)
root pts/1 2018-09-06 11:01 (ansiblemanager)
192.168.1.53 | SUCCESS | rc=0 >>
root pts/0 2018-09-06 09:31 (192.168.1.9)
root pts/1 2018-09-06 11:01 (ansiblemanager)
二十、 ansible管理任务计划
1.新建任务计划
// 其他的时间表示:分钟 minute 小时 hour 日期 day 月份 month
[root@ansiblemanager ~]# ansible testhosts -m cron -a "name='test cron' job='/bin/echo $(date +%F)>>/tmp/dd.txt' weekday=6"
192.168.1.52 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"test cron"
]
}
192.168.1.53 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"test cron"
]
}
// 在被管理端检查计划任务是否建立
[root@ansiblemanaged01 ~]# crontab -l
#Ansible: test cron
* * * * 6 /bin/echo 2018-09-06>>/tmp/dd.txt
// 由ansible管理的计划任务,请不要手动修改,否则会导致ansible无法再管理相应的计划任务
2.删除计划任务
[root@ansiblemanager ~]# ansible 192.168.1.52 -m cron -a "name='test cron' state=absent"
192.168.1.52 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": []
}
// 验证
[root@ansiblemanager ~]# ansible testhosts -m command -a "crontab -l"
192.168.1.52 | SUCCESS | rc=0 >>
192.168.1.53 | SUCCESS | rc=0 >>
#Ansible: test cron
* * * * 6 /bin/echo 2018-09-06>>/tmp/dd.txt
二十一、 ansible安装包和管理服务
1.通过yum模块安装包
// 在name后面还可以加上state=installed/removed来管理软件包
[root@ansiblemanager ~]# ansible testhosts -m yum -a "name=httpd"
192.168.1.52 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.cn99.com
* epel: mirrors.aliyun.com
* extras: mirrors.cn99.com
* updates: mirrors.163.com
Resolving Dependencies
--> Running transaction check
---> Package httpd.x86_64 0:2.4.6-80.el7.centos.1 will be installed
--> Processing Dependency: httpd-tools = 2.4.6-80.el7.centos.1 for package: httpd-2.4.6-80.el7.centos.1.x86_64
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-80.el7.centos.1.x86_64
--> Running transaction check
---> Package httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 will be installed
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
httpd x86_64 2.4.6-80.el7.centos.1 updates 2.7 M
Installing for dependencies:
httpd-tools x86_64 2.4.6-80.el7.centos.1 updates 90 k
mailcap noarch 2.1.41-2.el7 base 31 k
Transaction Summary
================================================================================
Install 1 Package (+2 Dependent packages)
Total download size: 2.8 M
Installed size: 9.6 M
Downloading packages:
--------------------------------------------------------------------------------
Total 3.8 MB/s | 2.8 MB 00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : httpd-tools-2.4.6-80.el7.centos.1.x86_64 1/3
Installing : mailcap-2.1.41-2.el7.noarch 2/3
Installing : httpd-2.4.6-80.el7.centos.1.x86_64 3/3
Verifying : mailcap-2.1.41-2.el7.noarch 1/3
Verifying : httpd-tools-2.4.6-80.el7.centos.1.x86_64 2/3
Verifying : httpd-2.4.6-80.el7.centos.1.x86_64 3/3
Installed:
httpd.x86_64 0:2.4.6-80.el7.centos.1
Dependency Installed:
httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 mailcap.noarch 0:2.1.41-2.el7
Complete!
"
]
}
192.168.1.53 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.163.com
* epel: mirrors.aliyun.com
* extras: mirrors.163.com
* updates: mirrors.163.com
Resolving Dependencies
--> Running transaction check
---> Package httpd.x86_64 0:2.4.6-80.el7.centos.1 will be installed
--> Processing Dependency: httpd-tools = 2.4.6-80.el7.centos.1 for package: httpd-2.4.6-80.el7.centos.1.x86_64
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-80.el7.centos.1.x86_64
--> Running transaction check
---> Package httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 will be installed
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
httpd x86_64 2.4.6-80.el7.centos.1 updates 2.7 M
Installing for dependencies:
httpd-tools x86_64 2.4.6-80.el7.centos.1 updates 90 k
mailcap noarch 2.1.41-2.el7 base 31 k
Transaction Summary
================================================================================
Install 1 Package (+2 Dependent packages)
Total download size: 2.8 M
Installed size: 9.6 M
Downloading packages:
--------------------------------------------------------------------------------
Total 3.1 MB/s | 2.8 MB 00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : httpd-tools-2.4.6-80.el7.centos.1.x86_64 1/3
Installing : mailcap-2.1.41-2.el7.noarch 2/3
Installing : httpd-2.4.6-80.el7.centos.1.x86_64 3/3
Verifying : mailcap-2.1.41-2.el7.noarch 1/3
Verifying : httpd-tools-2.4.6-80.el7.centos.1.x86_64 2/3
Verifying : httpd-2.4.6-80.el7.centos.1.x86_64 3/3
Installed:
httpd.x86_64 0:2.4.6-80.el7.centos.1
Dependency Installed:
httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 mailcap.noarch 0:2.1.41-2.el7
Complete!
"
]
}
2.服务管理
[root@ansiblemanager ~]# ansible testhosts -m service -a "name=httpd state=started enabled=yes"
192.168.1.52 | SUCCESS => {
"changed": true,
"enabled": true,
"name": "httpd",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "0",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "inactive",
"After": "systemd-journald.socket -.mount tmp.mount nss-lookup.target system.slice basic.target network.target remote-fs.target",
"AllowIsolate": "no",
"AmbientCapabilities": "0",
"AssertResult": "no",
"AssertTimestampMonotonic": "0",
"Before": "shutdown.target",
"BlockIOAccounting": "no",
"BlockIOWeight": "18446744073709551615",
"CPUAccounting": "no",
"CPUQuotaPerSecUSec": "infinity",
"CPUSchedulingPolicy": "0",
"CPUSchedulingPriority": "0",
"CPUSchedulingResetOnFork": "no",
"CPUShares": "18446744073709551615",
"CanIsolate": "no",
"CanReload": "yes",
"CanStart": "yes",
"CanStop": "yes",
"CapabilityBoundingSet": "18446744073709551615",
"ConditionResult": "no",
"ConditionTimestampMonotonic": "0",
"Conflicts": "shutdown.target",
"ControlPID": "0",
"DefaultDependencies": "yes",
"Delegate": "no",
"Description": "The Apache HTTP Server",
"DevicePolicy": "auto",
"Documentation": "man:httpd(8) man:apachectl(8)",
"EnvironmentFile": "/etc/sysconfig/httpd (ignore_errors=no)",
"ExecMainCode": "0",
"ExecMainExitTimestampMonotonic": "0",
"ExecMainPID": "0",
"ExecMainStartTimestampMonotonic": "0",
"ExecMainStatus": "0",
"ExecReload": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -k graceful ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStart": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -DFOREGROUND ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStop": "{ path=/bin/kill ; argv[]=/bin/kill -WINCH ${MAINPID} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"FailureAction": "none",
"FileDescriptorStoreMax": "0",
"FragmentPath": "/usr/lib/systemd/system/httpd.service",
"GuessMainPID": "yes",
"IOScheduling": "0",
"Id": "httpd.service",
"IgnoreOnIsolate": "no",
"IgnoreOnSnapshot": "no",
"IgnoreSIGPIPE": "yes",
"InactiveEnterTimestampMonotonic": "0",
"InactiveExitTimestampMonotonic": "0",
"JobTimeoutAction": "none",
"JobTimeoutUSec": "0",
"KillMode": "control-group",
"KillSignal": "18",
"LimitAS": "18446744073709551615",
"LimitCORE": "18446744073709551615",
"LimitCPU": "18446744073709551615",
"LimitDATA": "18446744073709551615",
"LimitFSIZE": "18446744073709551615",
"LimitLOCKS": "18446744073709551615",
"LimitMEMLOCK": "65536",
"LimitMSGQUEUE": "819200",
"LimitNICE": "0",
"LimitNOFILE": "4096",
"LimitNPROC": "1796",
"LimitRSS": "18446744073709551615",
"LimitRTPRIO": "0",
"LimitRTTIME": "18446744073709551615",
"LimitSIGPENDING": "1796",
"LimitSTACK": "18446744073709551615",
"LoadState": "loaded",
"MainPID": "0",
"MemoryAccounting": "no",
"MemoryCurrent": "18446744073709551615",
"MemoryLimit": "18446744073709551615",
"MountFlags": "0",
"Names": "httpd.service",
"NeedDaemonReload": "no",
"Nice": "0",
"NoNewPrivileges": "no",
"NonBlocking": "no",
"NotifyAccess": "main",
"OOMScoreAdjust": "0",
"OnFailureJobMode": "replace",
"PermissionsStartOnly": "no",
"PrivateDevices": "no",
"PrivateNetwork": "no",
"PrivateTmp": "yes",
"ProtectHome": "no",
"ProtectSystem": "no",
"RefuseManualStart": "no",
"RefuseManualStop": "no",
"RemainAfterExit": "no",
"Requires": "basic.target -.mount",
"RequiresMountsFor": "/var/tmp",
"Restart": "no",
"RestartUSec": "100ms",
"Result": "success",
"RootDirectoryStartOnly": "no",
"RuntimeDirectoryMode": "0755",
"SameProcessGroup": "no",
"SecureBits": "0",
"SendSIGHUP": "no",
"SendSIGKILL": "yes",
"Slice": "system.slice",
"StandardError": "inherit",
"StandardInput": "null",
"StandardOutput": "journal",
"StartLimitAction": "none",
"StartLimitBurst": "5",
"StartLimitInterval": "10000000",
"StartupBlockIOWeight": "18446744073709551615",
"StartupCPUShares": "18446744073709551615",
"StatusErrno": "0",
"StopWhenUnneeded": "no",
"SubState": "dead",
"SyslogLevelPrefix": "yes",
"SyslogPriority": "30",
"SystemCallErrorNumber": "0",
"TTYReset": "no",
"TTYVHangup": "no",
"TTYVTDisallocate": "no",
"TasksAccounting": "no",
"TasksCurrent": "18446744073709551615",
"TasksMax": "18446744073709551615",
"TimeoutStartUSec": "1min 30s",
"TimeoutStopUSec": "1min 30s",
"TimerSlackNSec": "50000",
"Transient": "no",
"Type": "notify",
"UMask": "0022",
"UnitFilePreset": "disabled",
"UnitFileState": "disabled",
"Wants": "system.slice",
"WatchdogTimestampMonotonic": "0",
"WatchdogUSec": "0"
}
}
192.168.1.53 | SUCCESS => {
"changed": true,
"enabled": true,
"name": "httpd",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "0",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "inactive",
"After": "remote-fs.target nss-lookup.target tmp.mount network.target systemd-journald.socket system.slice -.mount basic.target",
"AllowIsolate": "no",
"AmbientCapabilities": "0",
"AssertResult": "no",
"AssertTimestampMonotonic": "0",
"Before": "shutdown.target",
"BlockIOAccounting": "no",
"BlockIOWeight": "18446744073709551615",
"CPUAccounting": "no",
"CPUQuotaPerSecUSec": "infinity",
"CPUSchedulingPolicy": "0",
"CPUSchedulingPriority": "0",
"CPUSchedulingResetOnFork": "no",
"CPUShares": "18446744073709551615",
"CanIsolate": "no",
"CanReload": "yes",
"CanStart": "yes",
"CanStop": "yes",
"CapabilityBoundingSet": "18446744073709551615",
"ConditionResult": "no",
"ConditionTimestampMonotonic": "0",
"Conflicts": "shutdown.target",
"ControlPID": "0",
"DefaultDependencies": "yes",
"Delegate": "no",
"Description": "The Apache HTTP Server",
"DevicePolicy": "auto",
"Documentation": "man:httpd(8) man:apachectl(8)",
"EnvironmentFile": "/etc/sysconfig/httpd (ignore_errors=no)",
"ExecMainCode": "0",
"ExecMainExitTimestampMonotonic": "0",
"ExecMainPID": "0",
"ExecMainStartTimestampMonotonic": "0",
"ExecMainStatus": "0",
"ExecReload": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -k graceful ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStart": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -DFOREGROUND ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStop": "{ path=/bin/kill ; argv[]=/bin/kill -WINCH ${MAINPID} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"FailureAction": "none",
"FileDescriptorStoreMax": "0",
"FragmentPath": "/usr/lib/systemd/system/httpd.service",
"GuessMainPID": "yes",
"IOScheduling": "0",
"Id": "httpd.service",
"IgnoreOnIsolate": "no",
"IgnoreOnSnapshot": "no",
"IgnoreSIGPIPE": "yes",
"InactiveEnterTimestampMonotonic": "0",
"InactiveExitTimestampMonotonic": "0",
"JobTimeoutAction": "none",
"JobTimeoutUSec": "0",
"KillMode": "control-group",
"KillSignal": "18",
"LimitAS": "18446744073709551615",
"LimitCORE": "18446744073709551615",
"LimitCPU": "18446744073709551615",
"LimitDATA": "18446744073709551615",
"LimitFSIZE": "18446744073709551615",
"LimitLOCKS": "18446744073709551615",
"LimitMEMLOCK": "65536",
"LimitMSGQUEUE": "819200",
"LimitNICE": "0",
"LimitNOFILE": "4096",
"LimitNPROC": "1796",
"LimitRSS": "18446744073709551615",
"LimitRTPRIO": "0",
"LimitRTTIME": "18446744073709551615",
"LimitSIGPENDING": "1796",
"LimitSTACK": "18446744073709551615",
"LoadState": "loaded",
"MainPID": "0",
"MemoryAccounting": "no",
"MemoryCurrent": "18446744073709551615",
"MemoryLimit": "18446744073709551615",
"MountFlags": "0",
"Names": "httpd.service",
"NeedDaemonReload": "no",
"Nice": "0",
"NoNewPrivileges": "no",
"NonBlocking": "no",
"NotifyAccess": "main",
"OOMScoreAdjust": "0",
"OnFailureJobMode": "replace",
"PermissionsStartOnly": "no",
"PrivateDevices": "no",
"PrivateNetwork": "no",
"PrivateTmp": "yes",
"ProtectHome": "no",
"ProtectSystem": "no",
"RefuseManualStart": "no",
"RefuseManualStop": "no",
"RemainAfterExit": "no",
"Requires": "basic.target -.mount",
"RequiresMountsFor": "/var/tmp",
"Restart": "no",
"RestartUSec": "100ms",
"Result": "success",
"RootDirectoryStartOnly": "no",
"RuntimeDirectoryMode": "0755",
"SameProcessGroup": "no",
"SecureBits": "0",
"SendSIGHUP": "no",
"SendSIGKILL": "yes",
"Slice": "system.slice",
"StandardError": "inherit",
"StandardInput": "null",
"StandardOutput": "journal",
"StartLimitAction": "none",
"StartLimitBurst": "5",
"StartLimitInterval": "10000000",
"StartupBlockIOWeight": "18446744073709551615",
"StartupCPUShares": "18446744073709551615",
"StatusErrno": "0",
"StopWhenUnneeded": "no",
"SubState": "dead",
"SyslogLevelPrefix": "yes",
"SyslogPriority": "30",
"SystemCallErrorNumber": "0",
"TTYReset": "no",
"TTYVHangup": "no",
"TTYVTDisallocate": "no",
"TasksAccounting": "no",
"TasksCurrent": "18446744073709551615",
"TasksMax": "18446744073709551615",
"TimeoutStartUSec": "1min 30s",
"TimeoutStopUSec": "1min 30s",
"TimerSlackNSec": "50000",
"Transient": "no",
"Type": "notify",
"UMask": "0022",
"UnitFilePreset": "disabled",
"UnitFileState": "disabled",
"Wants": "system.slice",
"WatchdogTimestampMonotonic": "0",
"WatchdogUSec": "0"
}
}
// 被管理端检查
[root@ansiblemanager ~]# ansible testhosts -m shell -a "netstat -nltp | grep :80"
192.168.1.52 | SUCCESS | rc=0 >>
tcp6 0 0 :::80 :::* LISTEN 2542/httpd
192.168.1.53 | SUCCESS | rc=0 >>
tcp6 0 0 :::80 :::* LISTEN 2015/httpd
3.Ansible文档的使用
// 列出所有的模块
[root@ansiblemanager ~]# ansible-doc -l
a10_server Manage A10 Networks AX/SoftAX/Thunder/vThunder devices' server objec...
a10_server_axapi3 Manage A10 Networks AX/SoftAX/Thunder/vThunder devices
a10_service_group Manage A10 Networks AX/SoftAX/Thunder/vThunder devices' service grou...
a10_virtual_server Manage A10 Networks AX/SoftAX/Thunder/vThunder devices' virtual serv...
accelerate Enable accelerated mode on remote node
aci_aaa_user Manage AAA users (aaa:User)
aci_aaa_user_certificate Manage AAA user certificates (aaa:UserCert)
aci_access_port_to_interface_policy_leaf_profile Manage Fabric interface policy leaf profile interface selectors (inf...
aci_aep Manage attachable Access Entity Profile (AEP) objects (infra:AttEnti...
aci_aep_to_domain Bind AEPs to Physical or Virtual Domains (infra:RsDomP)
aci_ap Manage top level Application Profile (AP) objects (fv:Ap
...下略...
// 查看指定模块的文档
[root@ansiblemanager ~]# ansible-doc a10_server
> A10_SERVER (/usr/lib/python2.7/site-packages/ansible/modules/network/a10/a10_server.py)
Manage SLB (Server Load Balancer) server objects on A10 Networks devices via aXAPIv2.
OPTIONS (= is mandatory):
- client_cert
PEM formatted certificate chain file to be used for SSL client authentication. This file can
also include the key as well, and if the key is included, `client_key' is not required.
[Default: (null)]
- client_key
PEM formatted file that contains your private key to be used for SSL client authentication.
If `client_cert' contains both the certificate and key, this option is not required.
[Default: (null)]
- force
If `yes' do not get a cached copy.
(Aliases: thirsty)[Default: False]
type: bool
...下略...
二十二、 使用ansible playbook
Playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.
如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.
Playbooks 的格式是YAML。
第一个playbook
// 编写playbook文件
// 第一行需要有三个杠,hosts参数指定了对哪些主机进行参作,
// 如果是多台机器可以用逗号作为分隔,也可以使用主机组,在/etc/ansible/hosts里定义
// user参数指定了使用什么用户登录远程主机操作
// tasks指定了一个任务,其下面的name参数同样是对任务的描述,在执行过程中会打印出来,shell是ansible模块名字
[root@ansiblemanager ~]# vim /etc/ansible/test.yml
---
- hosts: ansiblemanaged01
remote_user: root
tasks:
- name: test_playbook
shell: echo $HOSTNAME >>/tmp/playbook_Test.txt
// 执行
[root@ansiblemanager ansible]# ansible-playbook test.yml
PLAY [testhosts] *************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [192.168.1.53]
ok: [192.168.1.52]
TASK [test playbook] *********************************************************************************************************
changed: [192.168.1.53]
changed: [192.168.1.52]
PLAY RECAP *******************************************************************************************************************
192.168.1.52 : ok=2 changed=1 unreachable=0 failed=0
192.168.1.53 : ok=2 changed=1 unreachable=0 failed=0
[root@ansiblemanager ansible]# ansible all -m shell -a "cat /tmp/playboogtest.txt"
192.168.1.53 | SUCCESS | rc=0 >>
ansiblemanaged02
192.168.1.52 | SUCCESS | rc=0 >>
ansiblemanaged01
二十三、 playbook里的变量
演示
// 创建playbook文件
[root@ansiblemanager ansible]# vim create_user.yml
---
- name: create user
hosts: testhosts
user: root
gather_facts: false
vars:
- user: "nico"
tasks:
- name: create user
user: name="{{ user }}"
// 执行
[root@ansiblemanager ansible]# ansible-playbook create_user.yml
PLAY [create user] ***********************************************************************************************************
TASK [create user] ***********************************************************************************************************
changed: [192.168.1.53]
changed: [192.168.1.52]
PLAY RECAP *******************************************************************************************************************
192.168.1.52 : ok=1 changed=1 unreachable=0 failed=0
192.168.1.53 : ok=1 changed=1 unreachable=0 failed=0
// 验证
[root@ansiblemanager ansible]# ansible all -m shell -a "grep nico /etc/passwd"
192.168.1.52 | SUCCESS | rc=0 >>
nico:x:5001:5001::/home/nico:/bin/bash
192.168.1.53 | SUCCESS | rc=0 >>
nico:x:5001:5001::/home/nico:/bin/bash
// name参数对该playbook实现的功能做一个概述,后面执行过程中,会打印name变量的值,
// 可以省略;gather_facts参数指定了在以下任务部分执行前,是否先执行setup模块获取主机相关
// 信息,如果后面的task会使用到setup获取的信息时会用到;vars参数,指定了变量,
// 这里指字一个user变量,其值为nico,需要注意的是,变量值一定要用引号引住;
// user指定了调用user模块,name是user模块里的一个参数,而增加的用户名字调用了上面user变量的值。
二十四、 playbook里的循环
演示
// 创建playbook文件
// with_items为循环的对象
[root@ansiblemanager ansible]# vim loop.yml
---
- hosts: 192.168.1.52
user: root
tasks:
- name: change mode for files
file: path=/tmp/{{ item }} state=touch mode=600
with_items:
- 1.txt
- 2.txt
- 3.txt
// 执行
[root@ansiblemanager ansible]# ansible-playbook loop.yml
PLAY [192.168.1.52] **********************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [192.168.1.52]
TASK [change mode for files] *************************************************************************************************
changed: [192.168.1.52] => (item=1.txt)
changed: [192.168.1.52] => (item=2.txt)
changed: [192.168.1.52] => (item=3.txt)
PLAY RECAP *******************************************************************************************************************
192.168.1.52 : ok=2 changed=1 unreachable=0 failed=0
二十五、 playbook里的条件判断
演示:
// 新建playbook文件
[root@ansiblemanager ansible]# vim when.yml
---
- hosts: testhosts
user: root
gather_facts: True
tasks:
- name: use when
shell: echo $HOSTNAME >>/tmp/tt.txt
when: ansible_ens32.ipv4.address=="192.168.1.52"
// 执行
[root@ansiblemanager ansible]# ansible-playbook when.yml
PLAY [testhosts] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.52]
ok: [192.168.1.53]
TASK [use when] ****************************************************************
skipping: [192.168.1.53]
changed: [192.168.1.52]
PLAY RECAP *********************************************************************
192.168.1.52 : ok=2 changed=1 unreachable=0 failed=0
192.168.1.53 : ok=1 changed=0 unreachable=0 failed=0
// 验证
[root@ansiblemanager ansible]# ansible all -m command -a 'cat /tmp/tt.txt'
192.168.1.53 | FAILED | rc=1 >>
cat: /tmp/tt.txt: No such file or directorynon-zero return code
192.168.1.52 | SUCCESS | rc=0 >>
ansiblemanaged01
// 当注释when这一句,则会对192.168.1.53
[root@ansiblemanager ansible]# vim when.yml
---
- hosts: testhosts
user: root
gather_facts: True
tasks:
- name: use when
shell: echo $HOSTNAME >>/tmp/tt.txt
#when: ansible_ens32.ipv4.address=="192.168.1.52"
// 执行
[root@ansiblemanager ansible]# ansible-playbook when.yml
PLAY [testhosts] *************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [192.168.1.52]
ok: [192.168.1.53]
TASK [use when] **************************************************************************************************************
changed: [192.168.1.53]
changed: [192.168.1.52]
PLAY RECAP *******************************************************************************************************************
192.168.1.52 : ok=2 changed=1 unreachable=0 failed=0
192.168.1.53 : ok=2 changed=1 unreachable=0 failed=0
[root@ansiblemanager ansible]# ansible all -m command -a 'cat /tmp/tt.txt'
192.168.1.52 | SUCCESS | rc=0 >>
ansiblemanaged01
ansiblemanaged01
192.168.1.53 | SUCCESS | rc=0 >>
ansiblemanaged02
//所有的facter信息可以通过 "ansible aming-02 -m setup" 查看
二十六、 playbook中的handlers
Ansible playbook中的handlers可实现类似逻辑与的功能。
演示
// 新建playbook文件
// 只有copy模块真正执行后,才会去调用下面的handlers相关的操作。
// 也就是说如果1.txt和2.txt内容是一样的,并不会去执行handlers里面的shell相关命令。 // 这种比较适合配置文件发生更改后,重启服务的操作。
[root@ansiblemanager ansible]# vim handlers.yml
---
- name: handlers test
hosts: testhosts
user: root
tasks:
- name: copy file
copy: src=/etc/inittab dest=/tmp/1.txt
notify: test handlers
handlers:
- name: test handlers
shell: echo "new line" >> /tmp/1.txt
// 执行
[root@ansiblemanager ansible]# ansible-playbook handlers.yml
PLAY [handlers test] *********************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [192.168.1.52]
ok: [192.168.1.53]
TASK [copy file] *************************************************************************************************************
changed: [192.168.1.52]
changed: [192.168.1.53]
RUNNING HANDLER [test handlers] **********************************************************************************************
changed: [192.168.1.52]
changed: [192.168.1.53]
PLAY RECAP *******************************************************************************************************************
192.168.1.52 : ok=3 changed=2 unreachable=0 failed=0
192.168.1.53 : ok=3 changed=2 unreachable=0 failed=0
// 检查
[root@ansiblemanager ansible]# ansible all -m command -a "tail -n 2 /tmp/1.txt"
192.168.1.52 | SUCCESS | rc=0 >>
#
new line
192.168.1.53 | SUCCESS | rc=0 >>
#
new line
二十七、 playbook安装nginx
思路:先在一台机器上编译安装好nginx、打包,然后再用ansible去下发
1.分发主机进入ansible配置文件目录
[root@ansiblemanager ~]# cd /etc/ansible/
2.为方便管理,创建一个nginx_install的目录
[root@ansiblemanager ansible]# mkdir nginx_install
[root@ansiblemanager ansible]# ls -ld !$
ls -ld nginx_install
drwxr-xr-x 2 root root 6 Sep 10 15:03 nginx_install
[root@ansiblemanager ansible]# cd !$
cd nginx_install
3.创建playbook目录结构
[root@ansiblemanager nginx_install]# mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}
[root@ansiblemanager 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下为定义的变量
4.在模板机安装nginx并打包
[root@lanquark sh]# cd /usr/local/
[root@lanquark local]# tar zcvf nginx.tar.gz nginx/ --exclude nginx.conf
// 打包好以后同步到分发主机
5.将打包的nginx文件,配置文件,启动脚本拷贝到相应的目录
[root@ansiblemanager nginx_install]# mv /usr/local/src/nginx.tar.gz roles/install/files/
[root@ansiblemanager nginx_install]# mv /usr/local/src/nginx.conf roles/install/templates/
[root@ansiblemanager nginx_install]# mv /usr/local/src/nginx roles/install/templates/
6.定义普通的tasks
[root@ansiblemanager nginx_install]# vim roles/common/tasks/main.yml
- name: Install initializtion require software
yum: name={{ item }} state=installed
with_items:
- zlib-devel
- pcre-devel
7.定义变量
[root@ansiblemanager nginx_install]# vim roles/install/vars/main.yml
nginx_user: nginx
nginx_port: 80
nginx_basedir: /usr/local/nginx
8.定义文件拷贝配置
[root@ansiblemanager nginx_install]# vim 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=0644
9.建立用户、启动服务。删除安装包
[root@ansiblemanager nginx_install]# vim 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
10.创建main.yml,调用copy和install
[root@ansiblemanager nginx_install]# vim roles/install/tasks/main.yml
- include: copy.yml
- include: install.yml
11.创建入口文件
[root@ansiblemanager nginx_install]# vim install.yml
---
- hosts: 192.168.1.52
remote_user: root
gather_facts: True
roles:
- common
- install
12.执行
[root@ansiblemanager nginx_install]# ansible-playbook install.yml
PLAY [192.168.1.52] **********************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [192.168.1.52]
TASK [common : Install initializtion require software] ***********************************************************************
ok: [192.168.1.52] => (item=[u'zlib-devel', u'pcre-devel'])
TASK [install : Copy Nginx Software] *****************************************************************************************
ok: [192.168.1.52]
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: [192.168.1.52]
TASK [install : Copy Nginx Start Script] *************************************************************************************
ok: [192.168.1.52]
TASK [install : Copy Nginx Config] *******************************************************************************************
changed: [192.168.1.52]
TASK [install : Create Nginx User] *******************************************************************************************
changed: [192.168.1.52]
TASK [install : Start Nginx Service] *****************************************************************************************
changed: [192.168.1.52]
TASK [install : Add Boot Start Nginx Service] ********************************************************************************
changed: [192.168.1.52]
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: [192.168.1.52]
PLAY RECAP *******************************************************************************************************************
192.168.1.52 : ok=10 changed=6 unreachable=0 failed=0
13.客户端检查
[root@ansiblemanaged01 ~]# lsof -i :80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 14441 root 6u IPv4 510103 0t0 TCP *:http (LISTEN)
nginx 14442 nginx 6u IPv4 510103 0t0 TCP *:http (LISTEN)
二十八、 playbook管理配置文件
生产环境中安装软件包只是在初始化环境的时候用一下,大多时候是需要管理配置文件的,下面我们来写个管理nginx配置文件的playbook
1.创建playbook配置目录结构
[root@ansiblemanager nginx_install]# mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}
[root@ansiblemanager nginx_install]# cd ../
[root@ansiblemanager ansible]# tree nginx_config/
nginx_config/
└── roles
├── new
│ ├── files
│ ├── handlers
│ ├── tasks
│ └── vars
└── old
├── files
├── handlers
├── tasks
└── vars
11 directories, 0 files
// 其中new为更新时用到的,old为回滚时用到的,files下面为nginx.conf和vhosts
// 目录,handlers为重启nginx服务的task
// 关于回滚,需要在执行playbook之前先备份一下旧的配置,所以对于老配置文件的管
// 理一定要严格,千万不能随便去修改线上机器的配置,并且要保证new/files下面的
// 配置和线上的配置一致
2.把当前线上的文件放到new/files下
11 directories, 0 files
[root@ansiblemanager ansible]# cp /usr/local/src/nginx.conf nginx_config/roles/new/files/
[root@ansiblemanager ansible]# ls -l !$
ls -l nginx_config/roles/new/files/
total 4
-rw-r--r-- 1 root root 2903 Sep 10 16:53 nginx.conf
3.定义变量
[root@ansiblemanager ansible]# vim /etc/ansible/nginx_config/roles/new/vars/main.yml
nx_basedir: /usr/local/nginx
4.定义重新加载nginx服务
[root@ansiblemanager ansible]# vim /etc/ansible/nginx_config/roles/new/handlers/main.yml
- name: restart nginx
shell: /etc/init.d/nginx reload
5.定义主配置文件
[root@ansiblemanager ansible]# 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
- 定义入口文件
---
- hosts: 192.168.1.52
user: root
roles:
- new
7.执行更新
// 修改了默认的配置文件,新建了vhosts文件夹,并在vhosts文件夹里添加了几个配置文件
-rw-r--r-- 1 root root 56 Sep 10 20:22 update.yml
[root@ansiblemanager nginx_config]# ansible-playbook update.yml
PLAY [192.168.1.52] *****************************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************************
ok: [192.168.1.52]
TASK [new : copy conf file] *********************************************************************************************************************************************
ok: [192.168.1.52] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
changed: [192.168.1.52] => (item={u'dest': u'conf/', u'src': u'vhosts'})
RUNNING HANDLER [new : restart nginx] ***********************************************************************************************************************************
changed: [192.168.1.52]
PLAY RECAP **************************************************************************************************************************************************************
192.168.1.52 : ok=3 changed=2 unreachable=0 failed=0
// 在192.168.1.52上检查,已经更新,不再是默认的那个配置文件了
[root@ansiblemanager nginx_config]# ansible 192.168.1.52 -m command -a "tail -n 5 /usr/local/nginx/conf/nginx.conf"
192.168.1.52 | SUCCESS | rc=0 >>
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
}
8.回滚操作
// 更新前一定要备份new下files中的内容,再行更新
// 同步new的内容到old,也相当于备份了一次
[root@ansiblemanager nginx_config]# rsync -av roles/new/ roles/old/
sending incremental file list
files/
files/nginx.conf
files/vhosts/
files/vhosts/bbs.yuankeedu.conf
files/vhosts/www.yuankeedu.conf
handlers/
handlers/main.yml
tasks/
tasks/main.yml
vars/
vars/main.yml
sent 3,910 bytes received 150 bytes 8,120.00 bytes/sec
total size is 3,270 speedup is 0.81
[root@ansiblemanager nginx_config]# tree
.
├── roles
│ ├── new
│ │ ├── files
│ │ │ ├── nginx.conf
│ │ │ └── vhosts
│ │ │ ├── bbs.yuankeedu.conf
│ │ │ └── www.yuankeedu.conf
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ └── main.yml
│ │ └── vars
│ │ └── main.yml
│ └── old
│ ├── files
│ │ ├── nginx.conf
│ │ └── vhosts
│ │ ├── bbs.yuankeedu.conf
│ │ └── www.yuankeedu.conf
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── vars
│ └── main.yml
├── update.retry
└── update.yml
13 directories, 14 files
// 对配置文件进行变更,注释掉对vhosts引用
# include vhost/*.conf;
//更新
[root@ansiblemanager nginx_config]# ansible-playbook update.yml
PLAY [192.168.1.52] *****************************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************************
ok: [192.168.1.52]
TASK [new : copy conf file] *********************************************************************************************************************************************
changed: [192.168.1.52] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
ok: [192.168.1.52] => (item={u'dest': u'conf/', u'src': u'vhosts'})
RUNNING HANDLER [new : restart nginx] ***********************************************************************************************************************************
changed: [192.168.1.52]
PLAY RECAP **************************************************************************************************************************************************************
192.168.1.52 : ok=3 changed=2 unreachable=0 failed=0
[root@ansiblemanager nginx_config]#
// 检查是否更新
[root@ansiblemanager nginx_config]# ansible 192.168.1.52 -m command -a "grep ^# /usr/local/nginx/conf/nginx.conf"
192.168.1.52 | SUCCESS | rc=0 >>
# include vhost/*.conf;
// 回滚
// 建立回滚入口文件
[root@ansiblemanager nginx_config]# vim rollback.yml
---
- hosts: 192.168.1.52
user: root
roles:
- old
//执行回滚
"rollback.yml" 5L, 56C written
[root@ansiblemanager nginx_config]# ansible-playbook rollback.yml
PLAY [192.168.1.52] *****************************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************************
ok: [192.168.1.52]
TASK [old : copy conf file] *********************************************************************************************************************************************
changed: [192.168.1.52] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
ok: [192.168.1.52] => (item={u'dest': u'conf/', u'src': u'vhosts'})
RUNNING HANDLER [old : restart nginx] ***********************************************************************************************************************************
changed: [192.168.1.52]
PLAY RECAP **************************************************************************************************************************************************************
192.168.1.52 : ok=3 changed=2 unreachable=0 failed=0
// 检查, 回滚成功
[root@ansiblemanager nginx_config]# ansible 192.168.1.52 -m command -a "grep vhost /usr/local/nginx/conf/nginx.conf"
192.168.1.52 | SUCCESS | rc=0 >>
include vhost/*.conf;