23.3 Ansible

Ansible和Saltstack比较类似,都是基于Python开发的,Ansible不需要安装客户端,通过ssh去通信。

Ansible有以下优点:

1. 基于模块工作,模块可以由任何语言开发;2. 支持命令行使用模块,支持编写yaml格式的playbook,易于编写和阅读;3. 安装简单,CentOS上可直接yum安装;4. 有提供UI(浏览器图形化),只是要收费,www.ansible.com/tower ;

官方文档 ,目前ansible已经被redhat公司收购,它在gitlab上是一个非常受欢迎的开源软件。gitlab地址

ansible入门电子书:https://ansible-book.gitbooks.io/ansible-first-book/ 。


安装Ansible

准备两台机器,

lzx192.168.100.150lzx1192.168.100.160

  • 只需要在lzx上安装ansible:
# yum list |grep ansibleansible.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     # yum install -y ansible

  • 密钥认证:

lzx上执行

# ls ~/.ssh/id_rsa  id_rsa.pub  known_hosts#有id_rsa和id_rsa.pub,没有的话执行ssh-keygen -t rsa,-t指定密钥类型# cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDqWlFPl3JwzR3AiJgolBthMJradp2r1UekJZnnU5hVjDb+pZ72YQUfNdatuUMr96avQYsF+V61sOc/cxa3YPn35n36TW8P+u7FMxZf31eqMatcHG/AWvjW0UsDw+zQrBr5414mj+AIYQgj0GtDIQJbfifGizK7i9UPLy7oW3Ss7+G2+fqhJ2hIo6qTSBHwSdN3rn9ypL0dPIEqJyaaBUpg5a5JKv3KHO5EyJt6Z787SPf3snKddQNpLkgoQ8yPcbZQ3BE5gt6DapMMpLEUUR2adIfe0rWqcDr4Gp9QTW0u+/LgFI6I1UKdTVYvU2UkpUf4WEp+6Q8AROasXxljrNC1 root@lzx# vim .ssh/authorized_keys#相当于给127.0.0.1做认证ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDqWlFPl3JwzR3AiJgolBthMJradp2r1UekJZnnU5hVjDb+pZ72YQUfNdatuUMr96avQYsF+V61sOc/cxa3YPn35n36TW8P+u7FMxZf31eqMatcHG/AWvjW0UsDw+zQrBr5414mj+AIYQgj0GtDIQJbfifGizK7i9UPLy7oW3Ss7+G2+fqhJ2hIo6qTSBHwSdN3rn9ypL0dPIEqJyaaBUpg5a5JKv3KHO5EyJt6Z787SPf3snKddQNpLkgoQ8yPcbZQ3BE5gt6DapMMpLEUUR2adIfe0rWqcDr4Gp9QTW0u+/LgFI6I1UKdTVYvU2UkpUf4WEp+6Q8AROasXxljrNC1 root@lzx

lzx1上执行

# mkdir .ssh # vim .ssh/authorized_keysssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDqWlFPl3JwzR3AiJgolBthMJradp2r1UekJZnnU5hVjDb+pZ72YQUfNdatuUMr96avQYsF+V61sOc/cxa3YPn35n36TW8P+u7FMxZf31eqMatcHG/AWvjW0UsDw+zQrBr5414mj+AIYQgj0GtDIQJbfifGizK7i9UPLy7oW3Ss7+G2+fqhJ2hIo6qTSBHwSdN3rn9ypL0dPIEqJyaaBUpg5a5JKv3KHO5EyJt6Z787SPf3snKddQNpLkgoQ8yPcbZQ3BE5gt6DapMMpLEUUR2adIfe0rWqcDr4Gp9QTW0u+/LgFI6I1UKdTVYvU2UkpUf4WEp+6Q8AROasXxljrNC1 root@lzx

lzx上执行

# ssh lzx1#要先配置/etc/hosts文件才能识别The authenticity of host 'lzx1 (192.168.100.160)' can't be established.ECDSA key fingerprint is SHA256:teKu3atU+OByPeXXD2xXhyb30vg6nW8ETqqCr785Dbc.ECDSA key fingerprint is MD5:13:a4:f1:c0:1f:62:65:d4:f4:4e:42:ab:40:f1:36:60.Are you sure you want to continue connecting (yes/no)? yes#输入yesWarning: Permanently added 'lzx1' (ECDSA) to the list of known hosts.Enter passphrase for key '/root/.ssh/id_rsa':#没设置密钥的密码就直接回车,有就输入root@lzx1's password:#输入lzx1机器上的root密码Last login: Tue Sep 11 10:12:52 2018 from 192.168.100.1# logoutConnection to lzx1 closed.

  • lzx上修改配置文件:
# vim /etc/ansible/hosts#添加下面内容[testhost]#自定义主机组名字127.0.0.1lzx1#这两行可以是ip或主机名


远程执行命令

  • lzx上执行命令:
# ansible testhost -m command -a 'w'#-m,指定模块;-a,指定命令Enter passphrase for key '/root/.ssh/id_rsa':#输入生成密钥时设置的密码127.0.0.1 | SUCCESS | rc=0 >>           10:28:34 up  1:47,  2 users,  load average: 0.17, 0.07, 0.06USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHATroot     pts/0    192.168.100.1    08:41    2.00s  0.81s  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-1536676113.66-66256136181906/command.py && sleep 0'root     pts/3    127.0.0.1        10:28    1.00s  0.12s  0.04s wEnter passphrase for key '/root/.ssh/id_rsa':#输入生成密钥时设置的密码  lzx1 | SUCCESS | rc=0 >> 10:28:42 up 16 min,  2 users,  load average: 0.04, 0.03, 0.05USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHATroot     pts/0    192.168.100.1    10:12   13:06   0.01s  0.01s -bashroot     pts/1    192.168.100.150  10:28    1.00s  0.06s  0.00s w

正常输出为绿色显示,出错为红色显示。

# ansible testhost -m command -a 'hostname'Enter passphrase for key '/root/.ssh/id_rsa': Enter passphrase for key '/root/.ssh/id_rsa':127.0.0.1 | SUCCESS | rc=0 >>lzxlzx1 | SUCCESS | rc=0 >>lzx1

也可以指定单独一台机器,不指定主机组

# ansible lzx1 -m command -a 'hostname'Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS | rc=0 >>lzx1

如果执行命令时遇到报错:"msg":"Aborting,target uses selinux but python bindings (libselinux-python) aren't installed",直接yum install -y libselinux-python

另外,还可以用shell模块来执行命令,多用于远程执行脚本

# ansible lzx1 -m shell -a 'date'Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS | rc=0 >>Tue Sep 11 10:39:03 EDT 2018


拷贝文件或目录

拷贝目录时,如果目标指定的目录不存在,它会自动创建;如果存在,源目录会放到目标目录下面。

拷贝文件时,dest指定的名字和源如果不同,并且它不是已经存在的目录,相当于拷贝过去后又重命名;如果目录存在,则会把文件放在目标目录下面。

  • 拷贝目录:
#copy表示copy模块;src表示源目录;dest表示目标目录;owner指定属主;group指定属组;mode指定权限# ansible lzx1 -m copy -a "src=/etc/ansible dest=/tmp/ansible_test owner=root group=root mode=0755"Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS => {    "changed": true,     "dest": "/tmp/ansible_test/",     "src": "/etc/ansible"}

到lzx1上查看

# ls /tmp/ansible_test#刚刚拷贝的目录mongodb-27019.socksystemd-private-645901bd56d24e14989826d0df1dc26e-chronyd.service-6UuejOsystemd-private-645901bd56d24e14989826d0df1dc26e-systemd-hostnamed.service-H4iKJysystemd-private-a6ad68ff8ed74d66ad66a5232a07dab2-chronyd.service-ElmwW4systemd-private-c40d86d5546d46c68cbb031445b13d64-chronyd.service-LsRxBQsystemd-private-f43349b80b2a416d9ea1b177669c618f-chronyd.service-sBY7OV# ls -lt /tmp/ansible_test/total 0drwxr-xr-x 3 root root 51 Sep 13 08:51 ansible#属主属组权限都能对应

  • 拷贝文件:
# ansible lzx1 -m copy -a "src=/etc/passwd dest=/tmp owner=root group=root mode=0755"Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS => {    "changed": true,     "checksum": "eb0190ef77febf56f7950c9d54c5799cdfa32ee4",     "dest": "/tmp/passwd",     "gid": 0,    "group": "root",     "md5sum": "55996731e2df563a71a4b9d66094c96c",     "mode": "0755",     "owner": "root",     "size": 1042,     "src": "/root/.ansible/tmp/ansible-tmp-1536843628.27-199330051688323/source",     "state": "file",     "uid": 0}

到lzx1上查看

# ls /tmp/ansible_testmongodb-27019.sockpasswd#刚刚拷贝的文件systemd-private-645901bd56d24e14989826d0df1dc26e-chronyd.service-6UuejOsystemd-private-645901bd56d24e14989826d0df1dc26e-systemd-hostnamed.service-H4iKJysystemd-private-a6ad68ff8ed74d66ad66a5232a07dab2-chronyd.service-ElmwW4systemd-private-c40d86d5546d46c68cbb031445b13d64-chronyd.service-LsRxBQsystemd-private-f43349b80b2a416d9ea1b177669c618f-chronyd.service-sBY7OV# ls -lt /tmp/passwd -rwxr-xr-x 1 root root 1042 Sep 13 09:00 /tmp/passwd


远程执行脚本

  • 编辑脚本:
# vim /tmp/1.sh#!/bin/bashecho `date` > /tmp/123.txt

  • 分发脚本:
# ansible testhost -m copy -a "src=/tmp/1.sh dest=/tmp/test.sh mode=0755"#拷贝脚本到各机器上Enter passphrase for key '/root/.ssh/id_rsa':19lzx1 | SUCCESS => {    "changed": true,     "checksum": "605c9fa9907b29503e55e10a40e5edf313dda056",     "dest": "/tmp/test.sh",     "gid": 0,     "group": "root",     "md5sum": "8877086180b43853c86af1d55989a0b6",     "mode": "0755",     "owner": "root",     "size": 39,     "src": "/root/.ansible/tmp/ansible-tmp-1536844193.91-149423054827561/source",     "state": "file",     "uid": 0}Enter passphrase for key '/root/.ssh/id_rsa':127.0.0.1 | SUCCESS => {    "changed": true,     "checksum": "605c9fa9907b29503e55e10a40e5edf313dda056",     "dest": "/tmp/test.sh",     "gid": 0,     "group": "root",     "md5sum": "8877086180b43853c86af1d55989a0b6",     "mode": "0755",     "owner": "root",     "size": 39,     "src": "/root/.ansible/tmp/ansible-tmp-1536844193.91-3493264441468/source",     "state": "file",     "uid": 0}# ls /tmp/ |grep testtest.sh#拷贝成功

到lzx1上查看

# ls /tmp/ |grep testansible_testtest.sh#拷贝成功

  • 执行脚本:
# ansible testhost -m shell -a "/tmp/test.sh"#shell表示shell模块Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS | rc=0 >>Enter passphrase for key '/root/.ssh/id_rsa':127.0.0.1 | SUCCESS | rc=0 >>

  • 查看结果:
# cat /tmp/123.txt Thu Sep 13 09:15:17 EDT 2018

lzx1上查看

# cat /tmp/123.txt Thu Sep 13 09:15:12 EDT 2018

shell模块除了支持执行脚本之外,还可以带管道,而command模块不支持带管道

  • 使用command模块测试:
# ansible testhost -m command -a "cat /etc/passwd|wc -l"Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | FAILED | rc=1 >>cat: invalid option -- 'l'Try 'cat --help' for more information.non-zero return codeEnter passphrase for key '/root/.ssh/id_rsa':127.0.0.1 | FAILED | rc=1 >>cat: invalid option -- 'l'Try 'cat --help' for more information.non-zero return code

  • 使用shell模块测试:
# ansible testhost -m shell -a "cat /etc/passwd|wc -l"Enter passphrase for key '/root/.ssh/id_rsa':127.0.0.1 | SUCCESS | rc=0 >>22Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS | rc=0 >>23


管理任务计划

ansible用来管理任务计划的模块是cron。

  • 创建任务计划:
#创建任务计划,name指定任务计划名;job指定任务计划具体操作;weedday指定任务计划执行日期,有对应分时日月周# ansible lzx1 -m cron -a "name='test cron' job='/bin/touch /tmp/aaa.txt' weekday=6"Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS => {    "changed": true,     "envs": [],     "jobs": [        "test corn"    ]}

带lzx1上查看

# crontab -l#Ansible: test cron#这一行不能改动,否则管理时会出错* * * * 6 /bin/touch /tmp/aaa.txt#创建成功,与上面一一对应

  • 删除任务计划:
# ansible lzx1 -m cron -a "name='test cron' state=absent"#删除任务计划Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS => {    "changed": true,#如果是false表示没有发生变化    "envs": [],     "jobs": []}

到lzx1上查看

# crontab -l#没有任务计划

其他的时间表示:

分钟 minute  小时 hour  日期 day  月份 month


安装包和管理服务

ansible安装包使用的是yum模块,管理服务的是service模块。

  • 安装包:
# ansible testhost -m yum -a "name=httpd"#安装httpdEnter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS => {    "changed": true,     "msg": "",     "rc": 0,     "results": [        "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.cn99.com\n * epel: mirror01.idc.hinet.net\n * extras: mirrors.cn99.com\n * updates: mirrors.shu.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--> Processing Dependency: httpd-tools = 2.4.6-80.el7.centos.1 for package: httpd-2.4.6-80.el7.centos.1.x86_64\n--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-80.el7.centos.1.x86_64\n--> Running transaction check\n---> Package httpd-tools.x86_64 0:2.4.6-80.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-80.el7.centos.1       updates       2.7 M\nInstalling for dependencies:\n httpd-tools       x86_64       2.4.6-80.el7.centos.1       updates        90 k\n mailcap           noarch       2.1.41-2.el7                base           31 k\n\nTransaction Summary\n================================================================================\nInstall  1 Package (+2 Dependent packages)\n\nTotal download size: 2.8 M\nInstalled size: 9.6 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal                                              1.1 MB/s | 2.8 MB  00:02     \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Installing : httpd-tools-2.4.6-80.el7.centos.1.x86_64                     1/3 \n  Installing : mailcap-2.1.41-2.el7.noarch                                  2/3 \n  Installing : httpd-2.4.6-80.el7.centos.1.x86_64                           3/3 \n  Verifying  : mailcap-2.1.41-2.el7.noarch                                  1/3 \n  Verifying  : httpd-tools-2.4.6-80.el7.centos.1.x86_64                     2/3 \n  Verifying  : httpd-2.4.6-80.el7.centos.1.x86_64                           3/3 \n\nInstalled:\n  httpd.x86_64 0:2.4.6-80.el7.centos.1                                          \n\nDependency Installed:\n  httpd-tools.x86_64 0:2.4.6-80.el7.centos.1    mailcap.noarch 0:2.1.41-2.el7   \n\nComplete!\n"    ]}

到lzx1上查看

# rpm -qa |grep httpdhttpd-tools-2.4.6-80.el7.centos.1.x86_64httpd-2.4.6-80.el7.centos.1.x86_64

  • 卸载包:
# ansible lzx1 -m yum -a "name=httpd state=removed"#卸载lzx1上面的httpdEnter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS => {    "changed": true,     "msg": "",     "rc": 0,     "results": [        "Loaded plugins: fastestmirror\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-80.el7.centos.1 will be erased\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package      Arch          Version                       Repository       Size\n================================================================================\nRemoving:\n httpd        x86_64        2.4.6-80.el7.centos.1         @updates        9.4 M\n\nTransaction Summary\n================================================================================\nRemove  1 Package\n\nInstalled size: 9.4 M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Erasing    : 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\nRemoved:\n  httpd.x86_64 0:2.4.6-80.el7.centos.1                                          \n\nComplete!\n"    ]}

到lzx1上查看

# rpm -qa |grep httpdhttpd-tools-2.4.6-80.el7.centos.1.x86_64#httpd已经被卸载

  • 启动服务:
# ansible lzx1 -m yum -a "name=httpd"#为了测试启动服务再次给lzx1装上httpd# ansible lzx1 -m service -a "name=httpd state=started enabled=yes"#给lzx1启动httpd服务,并且设置为开机启动Enter passphrase for key '/root/.ssh/id_rsa':lzx1 | SUCCESS => {    "changed": true,     "enabled": true,     "name": "httpd",     "state": "started",     "status": {        "ActiveEnterTimestampMonotonic": "0",         "ActiveExitTimestampMonotonic": "0",         "ActiveState": "inactive",         "After": "-.mount basic.target system.slice systemd-journald.socket network.target remote-fs.target nss-lookup.target tmp.mount",         "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": "3828",         "LimitRSS": "18446744073709551615",         "LimitRTPRIO": "0",         "LimitRTTIME": "18446744073709551615",         "LimitSIGPENDING": "3828",         "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"    }}

到lzx1上查看

# ps aux |grep httpdroot       1345  0.0  0.4 221972  4972 ?        Ss   09:05   0:00 /usr/sbin/httpd -DFOREGROUNDapache     1346  0.0  0.2 221972  2964 ?        S    09:05   0:00 /usr/sbin/httpd -DFOREGROUNDapache     1347  0.0  0.2 221972  2964 ?        S    09:05   0:00 /usr/sbin/httpd -DFOREGROUNDapache     1348  0.0  0.2 221972  2964 ?        S    09:05   0:00 /usr/sbin/httpd -DFOREGROUNDapache     1349  0.0  0.2 221972  2964 ?        S    09:05   0:00 /usr/sbin/httpd -DFOREGROUNDapache     1351  0.0  0.2 221972  2964 ?        S    09:05   0:00 /usr/sbin/httpd -DFOREGROUNDroot       1362  0.0  0.0 112704   972 pts/0    R+   09:07   0:00 grep --color=auto httpd#httpd服务已经启动# systemctl list-unit-files |grep httpd#centos7上查看开机启动项httpd.service                                 enabled#httpd服务已经开机启动

  • 列出ansible的所有模块:
# ansible-doc -l#列出ansible的所有模块

  • 查看某个模块的文档:
# ansible-doc service#查看service模块的文档> SERVICE    (/usr/lib/python2.7/site-packages/ansible/modules/system/service.py)        Controls services on remote hosts. Supported init systems include BSD init,        OpenRC, SysV, Solaris SMF, systemd, upstart. For Windows targets, use the        [win_service] module instead.  * note: This module has a corresponding action plugin.OPTIONS (= is mandatory):- arguments        Additional arguments provided on the command line        (Aliases: args)[Default: (null)]- enabled        Whether the service should start on boot. *At least one of state and enabled        are required.*        [Default: (null)]        type: bool= name        Name of the service.- pattern        If the service does not respond to the status command, name a substring to        look for as would be found in the output of the `ps' command as a stand-in for        a status result.  If the string is found, the service will be assumed to be        running.        [Default: (null)]        version_added: 0.7- runlevel        For OpenRC init scripts (ex: Gentoo) only.  The runlevel that this service        belongs to.        [Default: default]- sleep        If the service is being `restarted' then sleep this many seconds between the        stop and start command. This helps to workaround badly behaving init scripts        that exit immediately after signaling a process to stop.        [Default: (null)]        version_added: 1.3- state        `started'/`stopped' are idempotent actions that will not run commands unless        necessary.  `restarted' will always bounce the service.  `reloaded' will        always reload. *At least one of state and enabled are required.* Note that        reloaded will start the service if it is not already started, even if your        chosen init system wouldn't normally.        (Choices: reloaded, restarted, running, started, stopped)[Default: (null)]- use        The service module actually uses system specific modules, normally through        auto detection, this setting can force a specific module.        Normally it uses the value of the 'ansible_service_mgr' fact and falls back to        the old 'service' module when none matching is found.        [Default: auto]        version_added: 2.2        NOTES:      * For Windows targets, use the [win_service] module instead.AUTHOR: Ansible Core Team, Michael DeHaan        METADATA:          status:          - stableinterface          supported_by: core        EXAMPLES:- name: Start service httpd, if not running  service:    name: httpd    state: started- name: Stop service httpd, if running  service:    name: httpd    state: stopped- name: Restart service httpd, in all cases  service:    name: httpd    state: restarted- name: Reload service httpd, in all cases  service:    name: httpd    state: reloaded- name: Enable service httpd, and not touch the running state  service:    name: httpd    enabled: yes- name: Start service foo, based on running process /usr/bin/foo  service:    name: foo    pattern: /usr/bin/foo    state: started- name: Restart network service for interface eth0  service:    name: network    state: restarted    args: eth0


使用ansible playbook

playbook相当于把模块写入到配置文件里面,这样就避免我们在命令行下频繁地敲命令。

  • 编辑一个简单的playbook:
# cd /etc/ansible/# vim test.yml#playbook以.yml作为后缀名,注意空格---#表示开头,不可忽略- hosts: lzx1#指定针对哪些主机操作,多个主机用逗号分隔,也可以使用主机组  remote_user: root#指定执行用户  tasks:#指定任务    - name: test_playbook#描述任务,后面执行过程中会显示出来           shell: touch /tmp/lzxlzx.txt#具体任务内容,shell表示shell模块

  • 执行上面的playbook:
# ansible-playbook test.yml#执行playbookPLAY [lzx1] ************************************************************************************************TASK [Gathering Facts] *************************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [test_playbook] *************************************************************************************** [WARNING]: Consider using the file module with state=touch rather than running touch.  If you need to use#这里提示使用file module的state=touch选项更好command because file is insufficient you can add warn=False to this command task or setcommand_warnings=False in ansible.cfg to get rid of this message.changed: [lzx1]PLAY RECAP *************************************************************************************************lzx1                       : ok=2    changed=1    unreachable=0    failed=0#执行成功

到lzx1上查看

# ls -lt /tmp/lzxlzx.txt -rw-r--r-- 1 root root 0 Sep 18 09:33 /tmp/lzxlzx.txt#文件已生成


playbook中的变量

  • 编辑一个创建用户的playbook:
# vim create_user.yml---- name: create_user#作用描述,后面执行过程中会显示出来  hosts: lzx1#指定执行主机  user: root#指定执行用户  gather_facts: false#gather_facts指定在下面任务执行前是否执行setup模块获取主机相关信息,false表示不获取  vars:#指定变量    - user: "test"#定义user变量  tasks:#指定任务    - name: create user#描述任务      user: name= "{{ user }}"#变量名要用引号括起来;user指定调用user模块,name是user模块里面的参数,增加的用户名字调用了上面user变量的值

  • 执行上面的playbook:
# ansible-playbook create_user.yml PLAY [create_user] *****************************************************************************************TASK [create user] *****************************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]changed: [lzx1]PLAY RECAP *************************************************************************************************lzx1                       : ok=1    changed=1    unreachable=0    failed=0#表示执行成功

到lzx1上查看

# tail /etc/passwdpolkitd:x:999:997:User for polkitd:/:/sbin/nologinpostfix:x:89:89::/var/spool/postfix:/sbin/nologinchrony:x:998:996::/var/lib/chrony:/sbin/nologinsshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologinadmin:x:1000:1000:admin:/home/admin:/bin/bashmongod:x:997:995:mongod:/var/lib/mongo:/bin/falsetss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologingit:x:1001:1001::/home/git:/usr/bin/git-shellapache:x:48:48:Apache:/usr/share/httpd:/sbin/nologintest:x:1002:1002::/home/test:/bin/bash#有test用户


playbook中的循环

  • 编辑一个带循环的playbook:
# vim while.yml---- hosts: lzx1  user: root  tasks:    - name: change mode for files#描述任务      file: path=/tmp/{{ item }} state=touch mode=600#使用file模块,指定路径和要操作的文件名和权限;state=touch 创建文件;items为变量名      with_items:                - 1.txt        - 2.txt        - 3.txt

  • 执行上面的playbook:
# ansible-playbook while.yml PLAY [lzx1] ************************************************************************************************TASK [Gathering Facts] *************************************************************************************#Gathering Facts表示在收集信息,不禁掉会自动收集信息Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [change mode for files] *******************************************************************************changed: [lzx1] => (item=1.txt)changed: [lzx1] => (item=2.txt)changed: [lzx1] => (item=3.txt)PLAY RECAP *************************************************************************************************lzx1                       : ok=2    changed=1    unreachable=0    failed=0

到lzx1上查看

# ls -l /tmp/total 12-rw-r--r-- 1 root   root     29 Sep 13 09:15 123.txt-rw------- 1 root   root      0 Sep 20 08:18 1.txt-rw------- 1 root   root      0 Sep 20 08:18 2.txt-rw------- 1 root   root      0 Sep 20 08:18 3.txt#有刚刚创建的文件,且权限均为600drwx------ 2 root   root     61 Sep 18 08:50 ansible_KZIszYdrwxr-xr-x 3 root   root     21 Sep 13 08:51 ansible_test-rw-r--r-- 1 root   root      0 Sep 18 09:33 lzxlzx.txtsrwx------ 1 mongod mongod    0 Sep 20 07:23 mongodb-27019.sock-rwxr-xr-x 1 root   root   1042 Sep 13 09:00 passwddrwx------ 3 root   root     17 Sep 20 07:20 systemd-private-3f6f6b8540bb4821baa29cc8d067029b-chronyd.service-ATfvsadrwx------ 3 root   root     17 Sep 20 07:21 systemd-private-3f6f6b8540bb4821baa29cc8d067029b-httpd.service-B5HtVKdrwx------ 3 root   root     17 Sep 20 07:20 systemd-private-3f6f6b8540bb4821baa29cc8d067029b-systemd-hostnamed.service-sfZTSGdrwx------ 3 root   root     17 Sep 20 07:23 systemd-private-48497924bb434b52bc8db3b05c607623-chronyd.service-cFxvoEdrwx------ 3 root   root     17 Sep 20 07:23 systemd-private-48497924bb434b52bc8db3b05c607623-httpd.service-PGzvnWdrwx------ 3 root   root     17 Sep 13 08:41 systemd-private-c40d86d5546d46c68cbb031445b13d64-chronyd.service-LsRxBQ


playbook中的条件判断

  • 编辑一个带条件判断的playbook:
# 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.100.160"#when模块,代表条件判断,这里判断的内容是在gather_facts收集的信息里

  • 执行上面的playbook:
# ansible-playbook when.yml PLAY [testhost] ********************************************************************************************TASK [Gathering Facts] *************************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]Enter passphrase for key '/root/.ssh/id_rsa':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 usecommand because file is insufficient you can add warn=False to this command task or setcommand_warnings=False in ansible.cfg to get rid of this message.changed: [lzx1]PLAY RECAP *************************************************************************************************127.0.0.1                  : ok=1    changed=0    unreachable=0    failed=0   lzx1                       : ok=2    changed=1    unreachable=0    failed=0#lzx未发生变化,lzx1发生了变化

到lzx1上查看

# ls -l /tmp/total 12-rw-r--r-- 1 root   root     29 Sep 13 09:15 123.txt-rw------- 1 root   root      0 Sep 20 08:18 1.txt-rw------- 1 root   root      0 Sep 20 08:18 2.txt-rw------- 1 root   root      0 Sep 20 08:18 3.txtdrwx------ 2 root   root     61 Sep 18 08:50 ansible_KZIszYdrwxr-xr-x 3 root   root     21 Sep 13 08:51 ansible_test-rw-r--r-- 1 root   root      0 Sep 18 09:33 lzxlzx.txtsrwx------ 1 mongod mongod    0 Sep 20 07:23 mongodb-27019.sock-rwxr-xr-x 1 root   root   1042 Sep 13 09:00 passwddrwx------ 3 root   root     17 Sep 20 07:20 systemd-private-3f6f6b8540bb4821baa29cc8d067029b-chronyd.service-ATfvsadrwx------ 3 root   root     17 Sep 20 07:21 systemd-private-3f6f6b8540bb4821baa29cc8d067029b-httpd.service-B5HtVKdrwx------ 3 root   root     17 Sep 20 07:20 systemd-private-3f6f6b8540bb4821baa29cc8d067029b-systemd-hostnamed.service-sfZTSGdrwx------ 3 root   root     17 Sep 20 07:23 systemd-private-48497924bb434b52bc8db3b05c607623-chronyd.service-cFxvoEdrwx------ 3 root   root     17 Sep 20 07:23 systemd-private-48497924bb434b52bc8db3b05c607623-httpd.service-PGzvnWdrwx------ 3 root   root     17 Sep 13 08:41 systemd-private-c40d86d5546d46c68cbb031445b13d64-chronyd.service-LsRxBQ-rwxr-xr-x 1 root   root     39 Sep 13 09:10 test.sh-rw-r--r-- 1 root   root      0 Sep 20 08:40 when.txt#多了when.txt文件


playbook中的handlers

我们在命令行下,经常会用到这样的命令:command1 && command2,这表示command1执行成功后才执行command2,command1若执行失败,则不执行command2。

playbook中,handlers就类似与符号 && ,起到与它一致的作用。经常用于在执行task之后,服务器发生变化之后要执行的一些操作。比如在修改了配置文件后,需要重启一下服务。

  • 编辑一个带handlers的playbook:
# vim hand.yml---- name: handlers test  hosts: lzx1  user: root  tasks:    - name: copy file      copy: src=/etc/passwd dest=/tmp/aaa.txt#copy模块;src表示源文件,dest表示目标文件      notify: test handlers#与handlers关联,表示接下来要运行handlers,后面指定handlers名字  handlers:    - name: test handlers#定义handlers名字      shell: echo "111111" >> /tmp/aaa.txt#shell模块,执行后面具体操作

  • 执行上面的playbook:
# ansible-playbook hand.yml PLAY [handlers test] ***************************************************************************************TASK [Gathering Facts] *************************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [copy file] *******************************************************************************************changed: [lzx1]RUNNING HANDLER [test handlers] ****************************************************************************changed: [lzx1]PLAY RECAP *************************************************************************************************lzx1                       : ok=3    changed=2    unreachable=0    failed=0

到lzx1上查看

# tail /tmp/aaa.txtdbus:x:81:81:System message bus:/:/sbin/nologinpolkitd:x:999:997:User for polkitd:/:/sbin/nologinpostfix:x:89:89::/var/spool/postfix:/sbin/nologinchrony:x:998:996::/var/lib/chrony:/sbin/nologinsshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologinadmin:x:1000:1000:admin:/home/admin:/bin/bashmongod:x:997:995:mongod:/var/lib/mongo:/bin/falsetss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologinapache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin111111#上面handlers执行成功

需要注意的是,上面如果目标文件不存在,则copy时会失败,进而也不会执行后面的handlers。


playbook安装nginx

在学习了playbook的这些用法后,接下来我们尝试通过playbook去源码安装nginx。

首先在一台机器上编译安装好nginx、打包,然后再用ansible去分发。

  • 创建管理目录:
# mkdir nginx_install#创建nginx安装管理目录# cd nginx_install/# mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}#级联创建目录# ls roles# ls roles/common  install# ls roles/common/files  handlers  meta  tasks  templates  vars# ls roles/install/files  handlers  meta  tasks  templates  vars

files存放安装文件,handler存放handlers文件,meta存放说明信息、说明角色依赖等信息,tasks存放核心配置文件,templates存放配置文件、启动脚本等模板文件,vars存放定义的变量

如果机器没有安装nginx,需要先安装好才能进行下一步,nginx的安装步骤请参考这里:https://blog.csdn.net/miss1181248983/article/details/80890649l ,可以先安装好pcre-devel和zlib-devel依赖包,否则初始化会报错,这里就不再赘述。

  • 打包nginx:
# ls /usr/local/nginx/#nginx程序主目录client_body_temp  conf  fastcgi_temp  html  logs  proxy_temp  sbin  scgi_temp  uwsgi_temp# ls /etc/init.d/nginx#nginx启动脚本/etc/init.d/nginx# ls /usr/local/nginx/conf/nginx.conf#nginx配置文件/usr/local/nginx/conf/nginx.conf

# cd /usr/local/# tar czvf nginx.tar.gz --exlude "nginx.conf" --exclude "vhost" nginx/#打包程序主目录,除配置文件和虚拟主机目录外nginx/nginx/sbin/nginx/sbin/nginxnginx/conf/nginx/conf/koi-winnginx/conf/koi-utfnginx/conf/win-utfnginx/conf/mime.typesnginx/conf/mime.types.defaultnginx/conf/fastcgi_paramsnginx/conf/fastcgi_params.defaultnginx/conf/fastcgi.confnginx/conf/fastcgi.conf.defaultnginx/conf/uwsgi_paramsnginx/conf/uwsgi_params.defaultnginx/conf/scgi_paramsnginx/conf/scgi_params.defaultnginx/conf/nginx.conf.defaultnginx/logs/nginx/logs/error.lognginx/logs/nginx.pidnginx/logs/nginx_error.lognginx/logs/access.lognginx/html/nginx/html/50x.htmlnginx/html/index.htmlnginx/client_body_temp/nginx/proxy_temp/nginx/fastcgi_temp/nginx/uwsgi_temp/nginx/scgi_temp/

  • 移动打包文件到ansible中nginx对应的安装管理目录中:
#将nginx目录放到files下面,将启动脚本和配置文件放到templates下面# mv nginx.tar.gz /etc/ansible/nginx_install/roles/install/files/# cp nginx/conf/nginx.conf /etc/ansible/nginx_install/roles/install/templates/# cp /etc/init.d/nginx /etc/ansible/nginx_install/roles/install/templates/

  • 定义common目录下的tasks,nginx是需要一些依赖包:
# cd /etc/ansible/nginx_install/roles/common/# lsfiles  handlers  meta  tasks  templates  vars# vim tasks/main.yml- name: install initializtion require software  yum: name={{ item }} state=installed#采用循环安装依赖包  with_items:    - pcre-devel    - zlib-devel

  • 定义变量:
# vim /etc/ansible/nginx_install/roles/install/vars/main.ymlnginx_user: wwwnginx_port: 80nginx_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#copy模块,拷贝nginx.tar.gz;src写的是相对路径,这里它会自动去files目录查找对应文件- name: Uncompression Nginx Software  shell: tar zxvf /tmp/nginx.tar.gz -C /usr/local#shell模块,用来解压- name: Copy Nginx Start Script  template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755#template模块,拷贝启动脚本;src写的是相对路径,这里它会自动去template目录查找对应文件- name: Copy Nginx Config        template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=0644#template模块,拷贝配置文件;src写的是相对路径,这里它会自动去template目录查找对应文件

  • 建立用户,启动服务,删除压缩包:
# 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#user模块,创建nginx用户,定义shell,之前vars里面已定义用户- name: Start Nginx Service  shell: /etc/init.d/nginx start#shell模块,启动nginx服务- name: Add Boot Start Nginx Service  shell: chkconfig --level 345 nginx on#shell模块,将nginx服务加入开机启动,这里CentOS7也支持该命令- name: Delete Nginx compression files  shell: rm -rf /tmp/nginx.tar.gz#shell模块,删除压缩包

  • 创建main.yml来调用copy.yml和install.yml:
# vim /etc/ansible/nginx_install/roles/install/tasks/main.yml- include: copy.yml- include: install.yml

  • 定义入口配置文件:
# vim /etc/ansible/nginx_install/install.yml---#入口配置文件,上面都是子配置文件,所以不需要加---,但这里不可省略- hosts: lzx1#通常生产环境下,为一组机器,例如testhost  remote_user: root#定义远程执行用户  gather_facts: True#收集信息  roles:    - common    - install

  • 查看lzx1上是否有/usr/local/nginx目录:
# ls /usr/local/bin  etc  games  include  lib  lib64  libexec  sbin  share  src# netstat -lntpActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    tcp        0      0 192.168.100.160:27019   0.0.0.0:*               LISTEN      869/mongod          tcp        0      0 127.0.0.1:27019         0.0.0.0:*               LISTEN      869/mongod          tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      751/sshd            tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      842/master          tcp6       0      0 :::22                   :::*                    LISTEN      751/sshd            tcp6       0      0 ::1:25                  :::*                    LISTEN      842/master

在执行playbook之前,我们必须要保证目标机器上没有/usr/local/nginx目录,没有安装nginx。同时,80端口必须没有占用,否则执行下面的playbook会报错。

  • 执行入口配置文件:
# ansible-playbook /etc/ansible/nginx_install/install.yml#执行该playbookPLAY [lzx1] ********************************************************************************************TASK [Gathering Facts] *********************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [common : install initializtion require software] *************************************************ok: [lzx1] => (item=[u'pcre-devel', u'zlib-devel'])TASK [install : Copy Nginx Software] *******************************************************************ok: [lzx1]TASK [install : Uncompression Nginx Software] ********************************************************** [WARNING]: Consider using the unarchive module rather than running tar.  If you need to use commandbecause unarchive is insufficient you can add warn=False to this command task or setcommand_warnings=False in ansible.cfg to get rid of this message.changed: [lzx1]TASK [install : Copy Nginx Start Script] ***************************************************************ok: [lzx1]TASK [install : Copy Nginx Config] *********************************************************************ok: [lzx1]TASK [install : Create Nginx User] *********************************************************************ok: [lzx1]TASK [install : Start Nginx Service] *******************************************************************changed: [lzx1]TASK [install : Add Boot Start Nginx Service] **********************************************************changed: [lzx1]TASK [install : Delete Nginx compression files] ******************************************************** [WARNING]: Consider using the file module with state=absent rather than running rm.  If you need touse command because file is insufficient you can add warn=False to this command task or setcommand_warnings=False in ansible.cfg to get rid of this message.changed: [lzx1]PLAY RECAP *********************************************************************************************lzx1                       : ok=10   changed=4    unreachable=0    failed=0#执行成功

到lzx1上查看

# ps aux |grep nginxroot       2595  0.0  0.0  20556   628 ?        Ss   23:33   0:00 nginx: master process /usr/local/ngin/sbin/nginx -c /usr/local/nginx/conf/nginx.confnobody     2597  0.0  0.3  23044  3212 ?        S    23:33   0:00 nginx: worker processnobody     2598  0.0  0.3  23044  3212 ?        S    23:33   0:00 nginx: worker processroot       2724  0.0  0.0 112704   968 pts/0    R+   23:39   0:00 grep --color=auto nginx# netstat -lntpActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    tcp        0      0 192.168.100.160:27019   0.0.0.0:*               LISTEN      869/mongod          tcp        0      0 127.0.0.1:27019         0.0.0.0:*               LISTEN      869/mongod          tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      2595/nginx: master  tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      751/sshd            tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      842/master          tcp6       0      0 :::22                   :::*                    LISTEN      751/sshd            tcp6       0      0 ::1:25                  :::*                    LISTEN      842/master  # dateFri Sep 21 23:40:50 EDT 2018

目标机器lzx1上已经启动了nginx服务,并监听了80端口。


playbook管理配置文件

生产环境中大多时候是需要配置文件的,安装软件包只是在初始化环境的时候用到。下面来写个管理nginx配置文件的playbook。

  • 创建管理nginx配置文件的目录:
# mkdir -p /etc/ansible//nginx_config/roles/{new,old}/{files,handlers,vars,tasks}# cd /etc/ansible/# lsansible.cfg        create_user.yml  hosts         nginx_install  test.yml  while.ymlcreate_user.retry  hand.yml         nginx_config  roles          when.yml# cd nginx_config/# lsroles# ls roles/new  old# ls roles/new/files  handlers  tasks  vars# ls roles/old/files  handlers  tasks  vars

new目录用来更新配置文件,old用来回滚配置文件;files下面为nginx.conf和vhost目录,handlers为重启nginx服务的命令。另外,关于回滚,需要在更新之前备份旧的配置,要保证new/files下面的配置文件和线上的配置一致

  • 先拷贝nginx.conf和vhost目录放到files目录下:
# ls /usr/local/nginx/conf/fastcgi.conf            koi-utf             nginx.conf           uwsgi_paramsfastcgi.conf.default    koi-win             nginx.conf.default   uwsgi_params.defaultfastcgi_params          mime.types          scgi_params          vhostfastcgi_params.default  mime.types.default  scgi_params.default  win-utf# cd /usr/local/nginx/conf/# cp -r nginx.conf vhost /etc/ansible/nginx_config/roles/new/files/

  • 定义变量:
# vim /etc/ansible/nginx_config/roles/new/vars/main.ymlnginx_basedir: /usr/local/nginx

  • 定义重新加载nginx服务:
# vim /etc/ansible/nginx_config/roles/new/handlers/main.yml- name: restart nginx  shell: /etc/init.d/nginx reload#shell模块,重新加载nginx服务

  • 定义任务:
# 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#copy模块,拷贝配置文件和vhost目录;有两个循环对象,而这里nginx_basedir是前面定义的变量  with_items:    - { src: nginx.conf,dest: conf/nginx.conf }    - { src: vhost,dest: conf/ }  notify: restart nginx#调用handlers,handlers名字是restart nginx

  • 定义入口配置文件:
# vim /etc/ansible/nginx_config/update.yml---- hosts: lzx1  user: root  roles:    - new

  • 执行入口配置文件:
# ansible-playbook /etc/ansible/nginx_config/update.ymlPLAY [lzx1] ********************************************************************************************TASK [Gathering Facts] *********************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [new : copy conf file] ****************************************************************************ok: [lzx1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})changed: [lzx1] => (item={u'dest': u'conf/', u'src': u'vhost'})RUNNING HANDLER [new : restart nginx] ******************************************************************changed: [lzx1]PLAY RECAP *********************************************************************************************lzx1                       : ok=3    changed=2    unreachable=0    failed=0#执行成功

到lzx1上查看

# ps aux |grep nginxroot       2595  0.0  0.1  20688  1424 ?        Ss   Sep21   0:00 nginx: master process /usr/local/ngin/sbin/nginx -c /usr/local/nginx/conf/nginx.confnobody     3203  0.0  0.3  23176  3324 ?        S    00:39   0:00 nginx: worker processnobody     3204  0.0  0.3  23176  3324 ?        S    00:39   0:00 nginx: worker processroot       3217  0.0  0.0 112704   968 pts/0    R+   00:43   0:00 grep --color=auto nginx# dateSat Sep 22 00:43:14 EDT 2018# ls /usr/local/nginx/conf/fastcgi.conf            koi-utf             nginx.conf           uwsgi_paramsfastcgi.conf.default    koi-win             nginx.conf.default   uwsgi_params.defaultfastcgi_params          mime.types          scgi_params          vhostfastcgi_params.default  mime.types.default  scgi_params.default  win-utf

  • 做点变更验证:
# cd /etc/ansible/nginx_config/roles/new/files/ # lsnginx.conf  vhost# vim nginx.conf#做下面变更#       include vhost/*.conf#注释这行,前面加上#

# ansible-playbook /etc/ansible/nginx_config/update.ymlPLAY [lzx1] ********************************************************************************************TASK [Gathering Facts] *********************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [new : copy conf file] ****************************************************************************changed: [lzx1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})ok: [lzx1] => (item={u'dest': u'conf/', u'src': u'vhost'})RUNNING HANDLER [new : restart nginx] ******************************************************************changed: [lzx1]PLAY RECAP *********************************************************************************************lzx1                       : ok=3    changed=2    unreachable=0    failed=0#执行成功

到lzx1上查看

# cat /usr/local/nginx/conf/nginx.confuser nobody nobody;worker_processes 2;error_log /usr/local/nginx/logs/nginx_error.log crit;pid /usr/local/nginx/logs/nginx.pid;worker_rlimit_nofile 51200;events{    use epoll;    worker_connections 6000;}http{    include mime.types;    default_type application/octet-stream;    server_names_hash_bucket_size 3526;    server_names_hash_max_size 4096;    log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_local]'    ' $host "$request_uri" $status'    ' "$http_referer" "$http_user_agent"';    sendfile on;    tcp_nopush on;    keepalive_timeout 30;    client_header_timeout 3m;    client_body_timeout 3m;    send_timeout 3m;    connection_pool_size 256;    client_header_buffer_size 1k;    large_client_header_buffers 8 4k;    request_pool_size 4k;    output_buffers 4 32k;    postpone_output 1460;    client_max_body_size 10m;    client_body_buffer_size 256k;    client_body_temp_path /usr/local/nginx/client_body_temp;    proxy_temp_path /usr/local/nginx/proxy_temp;    fastcgi_temp_path /usr/local/nginx/fastcgi_temp;    fastcgi_intercept_errors on;    tcp_nodelay on;    gzip on;    gzip_min_length 1k;    gzip_buffers 4 8k;    gzip_comp_level 5;    gzip_http_version 1.1;    gzip_types text/plain application/x-javascript text/css text/htm     application/xml;    server    {        listen 80;        server_name localhost;        index index.html index.htm index.php;        root /usr/local/nginx/html;        location ~ \.php$         {            include fastcgi_params;            fastcgi_pass unix:/tmp/php-fcgi.sock;            fastcgi_index index.php;            fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;        }        }#include vhost/*.conf#注释掉了,说明没问题}

更新是没问题的,下面来配置回滚。

回滚操作就是把旧的配置覆盖,然后重新加载nginx服务,每次改动nginx配置文件之前先备份到old中files目录里。

  • 备份配置文件:
# rsync -av /etc/ansible/nginx_config/roles/new/ /etc/ansible/nginx_config/roles/old/sending incremental file list#拷贝配置文件,-av 保证两边完全一致files/files/nginx.conffiles/vhost/files/vhost/default.confhandlers/handlers/main.ymltasks/tasks/main.ymlvars/vars/main.ymlsent 2,815 bytes  received 131 bytes  5,892.00 bytes/sectotal size is 2,249  speedup is 0.76

  • 定义入口配置文件:
# vim /etc/ansible/nginx_config/rollback.yml---- hosts: lzx1  user: root  roles:  - old

  • 进行更改:
# vim nginx.conf#做下面更改        include vhost/*.conf#去掉前面#

# ansible-playbook /etc/ansible/nginx_config/update.ymlPLAY [lzx1] ********************************************************************************************TASK [Gathering Facts] *********************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [new : copy conf file] ****************************************************************************changed: [lzx1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})ok: [lzx1] => (item={u'dest': u'conf/', u'src': u'vhost'})RUNNING HANDLER [new : restart nginx] ******************************************************************changed: [lzx1]PLAY RECAP *********************************************************************************************lzx1                       : ok=3    changed=2    unreachable=0    failed=0#执行成功

到lzx1上查看

# cat /usr/local/nginx/conf/nginx.confuser nobody nobody;worker_processes 2;error_log /usr/local/nginx/logs/nginx_error.log crit;pid /usr/local/nginx/logs/nginx.pid;worker_rlimit_nofile 51200;events{    use epoll;    worker_connections 6000;}http{    include mime.types;    default_type application/octet-stream;    server_names_hash_bucket_size 3526;    server_names_hash_max_size 4096;    log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_local]'    ' $host "$request_uri" $status'    ' "$http_referer" "$http_user_agent"';    sendfile on;    tcp_nopush on;    keepalive_timeout 30;    client_header_timeout 3m;    client_body_timeout 3m;    send_timeout 3m;    connection_pool_size 256;    client_header_buffer_size 1k;    large_client_header_buffers 8 4k;    request_pool_size 4k;    output_buffers 4 32k;    postpone_output 1460;    client_max_body_size 10m;    client_body_buffer_size 256k;    client_body_temp_path /usr/local/nginx/client_body_temp;    proxy_temp_path /usr/local/nginx/proxy_temp;    fastcgi_temp_path /usr/local/nginx/fastcgi_temp;    fastcgi_intercept_errors on;    tcp_nodelay on;    gzip on;    gzip_min_length 1k;    gzip_buffers 4 8k;    gzip_comp_level 5;    gzip_http_version 1.1;    gzip_types text/plain application/x-javascript text/css text/htm     application/xml;    server    {        listen 80;        server_name localhost;        index index.html index.htm index.php;        root /usr/local/nginx/html;        location ~ \.php$         {            include fastcgi_params;            fastcgi_pass unix:/tmp/php-fcgi.sock;            fastcgi_index index.php;            fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;        }        }include vhost/*.conf#前面的#消失}

假如上面更新的操作是有问题的操作,那么我们需要回滚

  • 执行回滚的playbook:
# ansible-playbook /etc/ansible/nginx_config/rollback.ymlPLAY [lzx1] ********************************************************************************************TASK [Gathering Facts] *********************************************************************************Enter passphrase for key '/root/.ssh/id_rsa':ok: [lzx1]TASK [old : copy conf file] ****************************************************************************changed: [lzx1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})ok: [lzx1] => (item={u'dest': u'conf/', u'src': u'vhost'})RUNNING HANDLER [old : restart nginx] ******************************************************************changed: [lzx1]PLAY RECAP *********************************************************************************************lzx1                       : ok=3    changed=2    unreachable=0    failed=0#执行成功

到lzx1上查看

# cat /usr/local/nginx/conf/nginx.confuser nobody nobody;worker_processes 2;error_log /usr/local/nginx/logs/nginx_error.log crit;pid /usr/local/nginx/logs/nginx.pid;worker_rlimit_nofile 51200;events{    use epoll;    worker_connections 6000;}http{    include mime.types;    default_type application/octet-stream;    server_names_hash_bucket_size 3526;    server_names_hash_max_size 4096;    log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_local]'    ' $host "$request_uri" $status'    ' "$http_referer" "$http_user_agent"';    sendfile on;    tcp_nopush on;    keepalive_timeout 30;    client_header_timeout 3m;    client_body_timeout 3m;    send_timeout 3m;    connection_pool_size 256;    client_header_buffer_size 1k;    large_client_header_buffers 8 4k;    request_pool_size 4k;    output_buffers 4 32k;    postpone_output 1460;    client_max_body_size 10m;    client_body_buffer_size 256k;    client_body_temp_path /usr/local/nginx/client_body_temp;    proxy_temp_path /usr/local/nginx/proxy_temp;    fastcgi_temp_path /usr/local/nginx/fastcgi_temp;    fastcgi_intercept_errors on;    tcp_nodelay on;    gzip on;    gzip_min_length 1k;    gzip_buffers 4 8k;    gzip_comp_level 5;    gzip_http_version 1.1;    gzip_types text/plain application/x-javascript text/css text/htm     application/xml;    server    {        listen 80;        server_name localhost;        index index.html index.htm index.php;        root /usr/local/nginx/html;        location ~ \.php$         {            include fastcgi_params;            fastcgi_pass unix:/tmp/php-fcgi.sock;            fastcgi_index index.php;            fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;        }        }#include vhost/*.conf#可以看到,前面有#,已经回滚为之前的版本}

能够进行回滚操作的关键是,在更新之前做一次备份,使用rsync -av能够保证两边配置一致,再进行更新。如果更新出现问题,这时我们再执行回滚操作即可。


更多资料参考:

Ansible之playbook的使用

Ansible 系列之 Playbooks 剧本(1)

©著作权归作者所有:来自51CTO博客作者80民工的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 自动化运维Saltstack
  2. MySQL使用mysqldump+binlog完整恢复被删除的数据库
  3. IIS7设置http跳转到https重定向的方法
  4. Linux 下数据库定时备份
  5. mysql执行计划查看工具explain
  6. Spring-AOP
  7. Kubernetes 中定时任务的实现
  8. 智慧公安情指勤一体化指挥调度系统开发解决方案
  9. java中Future的使用

随机推荐

  1. 如何验证数据帮助类?验证数据帮助类的方法
  2. C++是什么
  3. C#中正则表达式有什么作用?匹配字符有什么
  4. c#如何使用?c#的基本语法
  5. C#中二分法查找的入门(代码介绍)
  6. C#与.net框架之间的关系是什么?C#程序的开
  7. .NET Core中如何使用Entity Framework操
  8. c#是什么?有什么用?
  9. 浅谈.NET Core开发日志中Edge.js是什么?如
  10. 如何用C语言计算矩形的周长和面积?(附代码)