自动化运维工具-ansible
< 返回列表时间: 2019-10-15来源:OSCHINA
1、什么是ansible?
ansible是一个部署一群远程主机的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,它不需要安装客户端,通过SSH协议实现远程节点和管理节点之间的通信,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于模块工作的,模块可以由任何语言开发,它不仅支持命令行使用模块,也支持编写yaml格式的playbook。
2、ansible的安装
两台主机,jin-10,jin-11,我们只需要在jin-10上安装ansible即可。 [root@jin-10 ~]# yum install -y ansible
然后把jin-10上的公钥文件id_rsa.pub复制到jin-11上的/root/.ssh/authorized_keys里,同时,对本机也进行密钥认证(把/root/.ssh/id_rsa.pub文件的内容复制到authorized_keys里)。 [root@jin-10 ~]# ssh jin-10 Last login: Tue Sep 3 12:27:50 2019 from jin-11 [root@jin-10 ~]# ssh jin-11 Last login: Tue Sep 3 12:24:22 2019 from jin-10
可以看到,jin-10用ssh的方式连接本机和jin-11都不用密码和密钥认证。
然后我们设置一个主机组,用来告诉Ansible需要管理哪些主机。编辑文件vim /etc/ansible/hosts,内容如下: [testhost] 127.0.0.1 jin-11
其中,testhost为自定义的主机组名字,然后是两个主机的IP(或主机名)。
3、ansible的使用
ansible模块Module
bash无论在命令行上执行,还是bash脚本中,都需要调用cd、ls、copy、yum等命令;module就是ansible的“命令”,module是ansible命令行和脚本中都需要调用的。常用的ansible module有yum、copy、template等。
在bash,调用命令时可以跟不同的参数,每个命令的参数都是该命令自定义的;同样,ansible中调用module也可以跟不同的参数,每个module的参数也都是由module自定义的。
在命令行中,-m后面接调用module的名字,-a后面接调用module的参数: [root@jin-10 ~]# ansible all -m copy -a "src=/etc/hosts dest=/tmp/hosts" jin-11 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "checksum": "843eede91ec66c16e38ddb67dee1bb173ea7fe9c", "dest": "/tmp/hosts", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "path": "/tmp/hosts", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 182, "state": "file", "uid": 0 } 127.0.0.1 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "checksum": "843eede91ec66c16e38ddb67dee1bb173ea7fe9c", "dest": "/tmp/hosts", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "path": "/tmp/hosts", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 182, "state": "file", "uid": 0 }
在playbook脚本中,tasks中的每一个action都是对module的一次调用。在每个action中:冒号前面是module的名字,冒号后面是调用module的参数: --- tasks: - name: ensure apache is at the latest version yum: pkg=httpd state=latest - name: write the apache config file template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf - name: ensure apache is running service: name=httpd state=started
下面是一些常用的module:
调试和测试类的module: ping - ping一下你的远程主机,如果可以通过ansible成功连接,那么返回pong debug - 用于调试的module,只是简单打印一些消息,有点像linux的echo命令。
文件类的module: copy - 从本地拷贝文件到远程节点 template - 从本地拷贝文件到远程节点,并进行变量的替换 file - 设置文件的属性
linux上常用的操作: user - 管理用户账户 yum - redhat系linux上的安装包管理 service - 管理服务 firewalld - 管理防火墙中的服务和端口
执行Shell命令: shell - 在节点上执行shell命令,支持$HOME和"<", ">", "|", ";" and "&" command - 在远程节点上面执行命令,不支持$HOME和"<", ">", "|", ";" and "&"
3.1 ansible远程执行命令
例:ansible testhost -m command -a 'w'
此处的testhost为主机组名(也可以直接写一个ip,针对某一台机器来执行命令),-m后边是模块名字,-a后面是命令 [root@jin-10 ~]# ansible testhost -m command -a 'w' jin-11 | CHANGED | rc=0 >> 09:07:34 up 21:59, 2 users, load average: 0.00, 0.01, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.154.1 二11 20:39m 0.33s 0.33s -bash root pts/1 jin-10 09:07 1.00s 0.28s 0.02s w 127.0.0.1 | CHANGED | rc=0 >> 09:07:34 up 23:03, 3 users, load average: 0.27, 0.14, 0.19 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.154.1 二10 6.00s 6.63s 5.48s ssh jin-10 root pts/1 fe80::d601:fb6f: 二12 6.00s 7.09s 0.00s ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/21f0e6a9ae -tt 127.0.0.1 /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1567559253.0-170559931011383/AnsiballZ_command.py && sleep 0' root pts/4 localhost 09:07 1.00s 0.51s 0.01s w
针对某一台机器来执行命令: [root@jin-10 ~]# ansible jin-11 -m command -a 'hostname' jin-11 | CHANGED | rc=0 >> jin-11
模块shell也可以同样实现: [root@jin-10 ~]# ansible testhost -m shell -a 'hostname' jin-11 | CHANGED | rc=0 >> jin-11 127.0.0.1 | CHANGED | rc=0 >> jin-10
3.2 ansible拷贝文件或目录
ansible拷贝目录时,如果目标指定的目录不存在,它会自动创建: [root@jin-10 ~]# ansible jin-11 -m copy -a "src=/etc/ansible dest=/tmp/ansible_test owner=root group=root mode=0755" jin-11 | CHANGED => { "changed": true, "dest": "/tmp/ansible_test/", "src": "/etc/ansible" } [root@jin-11 ~]# ll /tmp/ansible_test 总用量 0 drwxr-xr-x. 3 root root 51 9月 4 09:24 ansible
可以看到目标目录被创建且源目录在目标目录下面。
操作时,要注意src和dest是文件还是目录,拷贝文件时,如果目标目录已经存在同名目录,那么会把该文件放到同名目录里面: [root@jin-11 /tmp]# ll -t 总用量 4 drwxr-xr-x. 2 root root 6 9月 4 09:32 m_test [root@jin-10 ~]# ansible jin-11 -m copy -a "src=/etc/passwd dest=/tmp/m_test" jin-11 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "checksum": "1db31b171f911344344ceb7cf8621d31be83ec07", "dest": "/tmp/m_test/passwd", "gid": 0, "group": "root", "md5sum": "e1a0ce587167dc3587ee5f1b357dc3c4", "mode": "0644", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 1299, "src": "/root/.ansible/tmp/ansible-tmp-1567560870.7-110358489604181/source", "state": "file", "uid": 0 } [root@jin-11 /tmp]# ls m_test/ passwd
3.3 ansible远程执行脚本
在jin-10上编写一个test_ansible.sh的脚本,内容如下: #!/bin/bash echo `date` >/tmp/test_ansible.txt
然后分发到主机组testhost: [root@jin-10 ~]# ansible testhost -m copy -a "src=/tmp/test_ansible.sh dest=/tmp/test.sh mode=0755" jin-11 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "checksum": "0dc6471ba363889d83d3bf98c4354d874c86bd19", "dest": "/tmp/test.sh", "gid": 0, "group": "root", "md5sum": "bfee9509a7066ca2e822dbe48b21fbe7", "mode": "0755", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 48, "src": "/root/.ansible/tmp/ansible-tmp-1567561704.9-93797175448931/source", "state": "file", "uid": 0 } 127.0.0.1 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "checksum": "0dc6471ba363889d83d3bf98c4354d874c86bd19", "dest": "/tmp/test.sh", "gid": 0, "group": "root", "md5sum": "bfee9509a7066ca2e822dbe48b21fbe7", "mode": "0755", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 48, "src": "/root/.ansible/tmp/ansible-tmp-1567561704.82-59120276764010/source", "state": "file", "uid": 0 }
然后批量执行该脚本: [root@jin-10 ~]# ansible testhost -m shell -a "/tmp/test.sh" jin-11 | CHANGED | rc=0 >> 127.0.0.1 | CHANGED | rc=0 >> [root@jin-10 ~]# ls /tmp/test_ansible.txt /tmp/test_ansible.txt [root@jin-10 ~]# cat !$ cat /tmp/test_ansible.txt 2019年 09月 04日 星期三 09:50:23 CST [root@jin-11 /tmp]# ls /tmp/test_ansible.txt /tmp/test_ansible.txt [root@jin-11 /tmp]# cat !$ cat /tmp/test_ansible.txt 2019年 09月 04日 星期三 09:50:23 CST
3.4 ansible管理任务计划
使用cron模块可以创建计划任务: [root@jin-10 ~]# ansible jin-11 -m cron -a "name='test cron' job='/bin/touch /tmp/test_cron' weekday=6" jin-11 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "envs": [], "jobs": [ "test cron" ] } [root@jin-11 /tmp]# crontab -l #Ansible: test cron * * * * 6 /bin/touch /tmp/test_cron
使用cron模块删除计划任务: [root@jin-10 ~]# ansible jin-11 -m cron -a "name='test cron' state=absent" jin-11 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "envs": [], "jobs": [] } [root@jin-11 /tmp]# crontab -l
可以看到,之前创建的计划任务已经被删除了。
3.5 ansible安装包和管理服务
ansible的yum模块可以安装包和管理服务(可以进行安装包的安装、卸载和远程启动等)。 我们在jin-11上安装httpd为例: [root@jin-11 ~]# rpm -qa httpd [root@jin-11 ~]#
可以看到,jin-11是没有安装httpd的。
在jin-10上执行如下命令: [root@jin-10 ~]# ansible jin-11 -m yum -a "name=httpd state=installed" jin-11 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "changes": { "installed": [ "httpd" ] }, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.tuna.tsinghua.edu.cn\n * epel: hkg.mirror.rackspace.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.tuna.tsinghua.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-89.el7.centos.1 will be installed\n--> Processing Dependency: httpd-tools = 2.4.6-89.el7.centos.1 for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Running transaction check\n---> Package apr.x86_64 0:1.4.8-3.el7_4.1 will be installed\n---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed\n---> Package httpd-tools.x86_64 0:2.4.6-89.el7.centos.1 will be installed\n---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n httpd x86_64 2.4.6-89.el7.centos.1 updates 2.7 M\nInstalling for dependencies:\n apr x86_64 1.4.8-3.el7_4.1 base 103 k\n apr-util x86_64 1.5.2-6.el7 base 92 k\n httpd-tools x86_64 2.4.6-89.el7.centos.1 updates 91 k\n mailcap noarch 2.1.41-2.el7 base 31 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package (+4 Dependent packages)\n\nTotal download size: 3.0 M\nInstalled size: 10 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal 260 kB/s | 3.0 MB 00:11 \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : apr-1.4.8-3.el7_4.1.x86_64 1/5 \n Installing : apr-util-1.5.2-6.el7.x86_64 2/5 \n Installing : httpd-tools-2.4.6-89.el7.centos.1.x86_64 3/5 \n Installing : mailcap-2.1.41-2.el7.noarch 4/5 \n Installing : httpd-2.4.6-89.el7.centos.1.x86_64 5/5 \n Verifying : httpd-2.4.6-89.el7.centos.1.x86_64 1/5 \n Verifying : mailcap-2.1.41-2.el7.noarch 2/5 \n Verifying : httpd-tools-2.4.6-89.el7.centos.1.x86_64 3/5 \n Verifying : apr-util-1.5.2-6.el7.x86_64 4/5 \n Verifying : apr-1.4.8-3.el7_4.1.x86_64 5/5 \n\nInstalled:\n httpd.x86_64 0:2.4.6-89.el7.centos.1 \n\nDependency Installed:\n apr.x86_64 0:1.4.8-3.el7_4.1 apr-util.x86_64 0:1.5.2-6.el7 \n httpd-tools.x86_64 0:2.4.6-89.el7.centos.1 mailcap.noarch 0:2.1.41-2.el7 \n\nComplete!\n" ] }
再在jin-11上查看,已经安装了httpd包,并且没有启动: [root@jin-11 ~]# rpm -qa httpd httpd-2.4.6-89.el7.centos.1.x86_64 [root@jin-11 ~]# ps aux |grep httpd root 4256 0.0 0.1 112724 996 pts/0 S+ 11:29 0:00 grep --color=auto httpd
我们再远程启动httpd: [root@jin-10 ~]# ansible jin-11 -m service -a "name=httpd state=started enabled=no"
再查看jin-11是否成功启动httpd服务: [root@jin-11 ~]# ps aux |grep httpd root 4355 19.0 0.5 230408 5184 ? Ss 11:31 0:00 /usr/sbin/httpd -DFOREGROUND apache 4356 0.0 0.3 230408 3004 ? S 11:31 0:00 /usr/sbin/httpd -DFOREGROUND apache 4357 0.0 0.3 230408 3004 ? S 11:31 0:00 /usr/sbin/httpd -DFOREGROUND apache 4358 0.0 0.3 230408 3004 ? S 11:31 0:00 /usr/sbin/httpd -DFOREGROUND apache 4360 0.0 0.3 230408 3004 ? S 11:31 0:00 /usr/sbin/httpd -DFOREGROUND apache 4361 0.0 0.3 230408 3004 ? S 11:31 0:00 /usr/sbin/httpd -DFOREGROUND root 4370 0.0 0.1 112724 996 pts/0 R+ 11:31 0:00 grep --color=auto httpd
可以看到,httpd服务已经成功启动。
4、ansible playbook
playbook是指一个可被ansible执行的yml文件,最基本的playbook脚本分为三个部分:
1、在什么机器上以什么身份执行: hosts:为主机的IP,或者主机组名,或者关键字all。 users:在远程以哪个用户身份执行。 ...
2、执行的任务有哪些: tasks tasks是从上到下顺序执行,如果中间发生错误,那么整个playbook会中止。我们可以改修文件后,再重新执行。 每一个task都是对module的一次调用,只是使用不同的参数和变量而已。 每一个task最好有name属性(可选),这个是供人读的,没有实际的操作。然后会在命令行里面输出,提示用户执行情况。 task中每个action会调用一个module,在module中会去检查当前系统状态是否需要重新执行。 如果本次执行了,那么action会得到返回值changed。 如果不需要执行,那么action得到返回值ok。
3、善后的任务有哪些: handlers handler也是对module的一次调用,与tasks不同,tasks会默认的按定义顺序执行每一个task,handlers则不会,它需要在tasks中被调用,才有可能被执行。 handler可以理解为playbook的event,在ansible中,只在task的执行状态为changed的时候,才会执行该task调用的handler,这也是handler与普通的event机制不同的地方。 如果有多个task notify同一个handler,那么只执行一次。 handler的使用场景:例如执行task之后,服务器状态发生变化之后要执行的一些操作,比如我们修改了配置文件后,需要重启一下服务,这时候就可以用handler模块。
下面我们来编写一个简单的playbook,vim /etc/ansible/test.yml: --- - hosts: jin-11 remote_user: root tasks: - name: test_playbook shell: touch /tmp/test_playbook.txt
然后执行: [root@jin-10 /etc/ansible]# ansible-playbook /etc/ansible/test.yml PLAY [jin-11] ************************************************************************ TASK [Gathering Facts] *************************************************************** ok: [jin-11] TASK [test_playbook] ***************************************************************** [WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [jin-11] PLAY RECAP *************************************************************************** jin-11 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@jin-11 ~]# ll -t /tmp/ 总用量 16 -rw-r--r--. 1 root root 0 9月 4 14:49 test_playbook.txt
可以看到,在jin-11的/tmp/下生成了文件test_playbook.txt。
4.1 playbook的变量 自定义变量
在playbook中,通过vars关键字自定义变量,使用时用{{ }}引用以来即可。
我们以创建用户为例,编辑vim /etc/ansible/create_user.yml,内容如下: --- - name: create_user hosts: jin-11 user: root gather_facts: false vars: - user: "test" tasks: - name: create user user: name="{{ user }}"
然后执行: [root@jin-10 /etc/ansible]# ansible-playbook /etc/ansible/create_user.yml PLAY [create_user] ******************************************************************* TASK [create user] ******************************************************************* changed: [jin-11] PLAY RECAP *************************************************************************** jin-11 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在jin-11上查看: [root@jin-11 ~]# id test uid=1002(test) gid=1002(test) 组=1002(test) 主机的系统变量(facts)
ansible会通过module setup来收集主机的系统信息,这些收集到的系统信息叫做facts,这些facts信息可以直接以变量的形式使用。 [root@jin-10 ~]# ansible all -m setup -u root jin-11 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.154.11" ], "ansible_all_ipv6_addresses": [ "fe80::c9a8:961e:9b39:d180" ], "ansible_apparmor": { "status": "disabled" }, "ansible_architecture": "x86_64", ... 文件模板中使用的变量
在playbook中定义的变量,可以直接在template中使用,facts变量也可以直接在template中使用,包含在inventory里面定义的host和group变量。只要是在playbook中可以访问的变量,都可以在template文件中使用。 把运行结果当做变量使用-注册变量
把task的执行结果也可以作为一个变量值。这个时候就需要用到“注册变量”,将执行结果注册到一个变量中,待后面的action使用,注册变量经常和debug module一起使用,这样可以得到更多action的输出信息,帮助用户调试。 --- - hosts: all tasks: - shell: ls register: result ignore_errors: True - shell: echo "{{ result.stdout }}" when: result.rc == 5 - debug: msg="{{ result.stdout }}" 用命令行传递参数
为了使Playbook更灵活、通用性更强,允许用户在执行的时候传入变量的值,这个时候就需要用到“额外变量”。
在playbook中定义的变量,需要从命令行传递变量值。
下面是在命令行里面传值得的方法: [root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "hosts=jin-11 user=root"
可以用json格式传递参数: [root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "{ 'hosts': 'jin-11', 'user': 'root' }"
还可以把参数放在文件里面: [root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "@vars.json"
4.2 playbook中的条件判断
when: 类似于编程语言中的if语句
编辑文件vim /etc/ansible/when.yml,内容如下: --- - hosts: testhost user: root gather_facts: True tasks: - name: use when shell: touch /tmp/when.txt when: ansible_ens32.ipv4.address == "192.168.154.11"
执行: [root@jin-10 ~]# ansible-playbook /etc/ansible/when.yml PLAY [testhost] ********************************************************************** TASK [Gathering Facts] *************************************************************** ok: [jin-11] ok: [127.0.0.1] TASK [use when] ********************************************************************** skipping: [127.0.0.1] [WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [jin-11] PLAY RECAP *************************************************************************** 127.0.0.1 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 jin-11 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查看结果: [root@jin-10 ~]# ll -t /tmp/ 总用量 12 -rw-r--r--. 1 root root 43 9月 4 09:50 test_ansible.txt -rwxr-xr-x. 1 root root 48 9月 4 09:48 test.sh [root@jin-11 ~]# ll -t /tmp/ 总用量 16 -rw-r--r--. 1 root root 0 9月 5 09:33 when.txt -rw-r--r--. 1 root root 0 9月 4 14:49 test_playbook.txt
可以看到jin-10没有生成when.txt文件,而jin-11则生成了。
4.3 playbook循环
loop: 类似于编程语言中的while语句,在playbook脚本中一般写作with_...
编辑文件vim /etc/ansible/while.yml,内容如下: --- - hosts: testhost user: root tasks: - name: change mode for files file: path=/tmp/{{ item }} state=touch mode=600 with_items: - while1.txt - while2.txt - while3.txt
执行: [root@jin-10 ~]# ansible-playbook /etc/ansible/while.yml PLAY [testhost] ********************************************************************** TASK [Gathering Facts] *************************************************************** ok: [jin-11] ok: [127.0.0.1] TASK [change mode for files] ********************************************************* changed: [jin-11] => (item=while1.txt) changed: [127.0.0.1] => (item=while1.txt) changed: [jin-11] => (item=while2.txt) changed: [jin-11] => (item=while3.txt) changed: [127.0.0.1] => (item=while2.txt) changed: [127.0.0.1] => (item=while3.txt) PLAY RECAP *************************************************************************** 127.0.0.1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 jin-11 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
查看结果: [root@jin-10 ~]# ll -t /tmp/ 总用量 12 -rw-------. 1 root root 0 9月 5 09:45 while3.txt -rw-------. 1 root root 0 9月 5 09:45 while2.txt -rw-------. 1 root root 0 9月 5 09:45 while1.txt -rw-r--r--. 1 root root 43 9月 4 09:50 test_ansible.txt [root@jin-11 ~]# ll -t /tmp/ 总用量 16 -rw-------. 1 root root 0 9月 5 09:45 while3.txt -rw-------. 1 root root 0 9月 5 09:45 while2.txt -rw-------. 1 root root 0 9月 5 09:45 while1.txt -rw-r--r--. 1 root root 0 9月 5 09:33 when.txt
4.4 用playbook安装nginx
思路:先在一台机器上编译安装好nginx、打包,然后再用ansible去下发。
- 创建相关的目录
进入ansible配置文件目录, 创建一个nginx_install的目录,方便管理,最终目录如下: [root@jin-10 /var/lib/docker]# cd /etc/ansible/ [root@jin-10 /etc/ansible]# mkdir nginx_install [root@jin-10 /etc/ansible]# cd !$ cd nginx_install [root@jin-10 /etc/ansible/nginx_install]# mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars} [root@jin-10 /etc/ansible/nginx_install]# tree . └── roles ├── common │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ ├── templates │ └── vars └── install ├── files ├── handlers ├── meta ├── tasks ├── templates └── vars
说明:roles目录下有两个角色,common为一些准备操作,install为安装nginx的操作。
每个角色下面又有几个目录,handlers下面是当发生改变时要执行的操作,通常用在配置文件发生改变,重启服务。files为安装时用到的一些文件,meta为说明信息,说明角色依赖等信息,tasks里面是核心的配置文件,templates通常存一些配置文件,启动脚本等模板文件,vars下为定义的变量。 准备相关的文件
之前已经在jin-10上编译安装了nginx,相关目录文件如下: nginx的目录: [root@jin-10 /etc/ansible/nginx_install]# ls /usr/local/nginx/ client_body_temp fastcgi_temp logs sbin uwsgi_temp conf html proxy_temp scgi_temp nginx的启动脚本: [root@jin-10 /etc/ansible/nginx_install]# ls /etc/init.d/nginx /etc/init.d/nginx nginx的配置文件: [root@jin-10 /etc/ansible/nginx_install]# ls /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf
把nginx的目录打包,并复制文件到之前创建的目录中: [root@jin-10 /usr/local]# tar czf nginx.tar.gz --exclude "nginx.conf" --exclude "vhost" nginx/ [root@jin-10 /usr/local]# mv nginx.tar.gz /etc/ansible/nginx_install/roles/install/files/ [root@jin-10 /usr/local]# cp nginx/conf/nginx.conf /etc/ansible/nginx_install/roles/install/templates/ [root@jin-10 /usr/local]# cp /etc/init.d/nginx /etc/ansible/nginx_install/roles/install/templates/
定义common的tasks,安装nginx需要的一些依赖包:
进入/etc/ansible/nginx_install/roles/目录,并编写/etc/ansible/nginx_install/roles/common/tasks/main.yml文件,内容如下: [root@jin-10 /etc/ansible/nginx_install/roles]# vim /etc/ansible/nginx_install/roles/common/tasks/main.yml - name: Install initializtion require software yum: name={{ item }} state=installed with_items: - zlib-devel - pcre-devel
再编写一个定义变量的文件vim /etc/ansible/nginx_install/roles/install/vars/main.yml,内容如下: nginx_user: www nginx_port: 80 nginx_basedir: /usr/local/nginx
然后再创建一个配置文件vim /etc/ansible/nginx_install/roles/install/tasks/copy.yml ,用于拷贝文件到目标机器: - name: Copy nginx software copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root - name: Uncompression nginx software shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/ - name: Copy nginx start script template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755 - name: Copy nginx config template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=06 44
再创建一个文件vim /etc/ansible/nginx_install/roles/install/tasks/install.yml ,用于建立用户,启动服务,删除压缩包: - name: Create nginx user user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin - name: Start nginx service shell: /etc/init.d/nginx start - name: Add boot start nginx service shell: chkconfig --level 345 nginx on - name: Delete nginx compression files shell: rm -rf /tmp/nginx.tar.gz
再创建一个调用copy和install的文件 /etc/ansible/nginx_install/roles/install/tasks/main.yml,内容如下: - include: copy.yml - include: install.yml
最后,我们再定义一个入口配置文件/etc/ansible/nginx_install/install.yml,内容如下: --- - hosts: jin-11 remote_user: root gather_facts: True roles: - common - install
最终目录文件如下: [root@jin-10 /etc/ansible/nginx_install]# tree . ├── install.yml └── roles ├── common │   ├── files │   ├── handlers │   ├── meta │   ├── tasks │   │   └── main.yml │   ├── templates │   └── vars └── install ├── files │   └── nginx.tar.gz ├── handlers ├── meta ├── tasks │   ├── copy.yml │   ├── install.yml │   └── main.yml ├── templates │   ├── nginx │   └── nginx.conf └── vars └── main.yml 执行脚本: [root@jin-11 ~]# yum remove nginx 已加载插件:fastestmirror 参数 nginx 没有匹配 不删除任何软件包
如果目标机器上已安装了nginx,先用命令yum remove nginx删除已安装的nginx。
然后执行playbook脚本: [root@jin-10 /etc/ansible/nginx_install]# ansible-playbook /etc/ansible/nginx_install/install.yml PLAY [jin-11] ************************************************************************ TASK [Gathering Facts] *************************************************************** ok: [jin-11] TASK [common : Install initializtion require software] ******************************* [DEPRECATION WARNING]: Invoking "yum" only once while using a loop via squash_actions is deprecated. Instead of using a loop to supply multiple items and specifying `name: "{{ item }}"`, please use `name: ['zlib-devel', 'pcre-devel']` and remove the loop. This feature will be removed in version 2.11. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg. ok: [jin-11] => (item=[u'zlib-devel', u'pcre-devel']) TASK [install : Copy nginx software] ************************************************* changed: [jin-11] TASK [install : Uncompression nginx software] **************************************** [WARNING]: Consider using the unarchive module rather than running 'tar'. If you need to use command because unarchive is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [jin-11] TASK [install : Copy nginx start script] ********************************************* ok: [jin-11] TASK [install : Copy nginx config] *************************************************** ok: [jin-11] TASK [install : Create nginx user] *************************************************** changed: [jin-11] TASK [install : Start nginx service] ************************************************* changed: [jin-11] TASK [install : Add boot start nginx service] **************************************** changed: [jin-11] TASK [install : Delete nginx compression files] ************************************** [WARNING]: Consider using the file module with state=absent rather than running 'rm'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. changed: [jin-11] PLAY RECAP *************************************************************************** jin-11 : ok=10 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在jin-11主机上查看是否有nginx的进程: [root@jin-11 ~]# ps aux|grep nginx root 4040 0.0 0.0 20540 628 ? Ss 08:32 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf nobody 4042 0.0 0.3 22984 3192 ? S 08:32 0:00 nginx: worker process nobody 4043 0.0 0.3 22984 3192 ? S 08:32 0:00 nginx: worker process root 4192 0.0 0.1 112724 996 pts/0 S+ 09:45 0:00 grep --color=auto nginx
4.5 playbook管理配置文件
安装软件一般是在初始化环境的时候,而在生产环境中,我们大多数是要管理配置文件。
下面我们来写一个管理nginx配置文件的playbook。
首先先创建所需要的目录: [root@jin-10 ~]# mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}
最终目录如下: [root@jin-10 ~]# tree /etc/ansible/nginx_config/ /etc/ansible/nginx_config/ └── roles ├── new │   ├── files │   ├── handlers │   ├── tasks │   └── vars └── old ├── files ├── handlers ├── tasks └── vars
其中,new目录更新时用到,old回滚时用到,files下面为nginx.conf,handlers为重启nginx服务的命令。
关于回滚,需要在执行playbook之前先备份旧的配置,所以对于旧的配置文件的管理一定要谨慎,千万不要随便去修改线上机器的配置,而且要保证new/files下面的配置和线上的配置保持一致。
拷贝nginx.conf文件到/etc/ansible/nginx_config/roles/new/files/目录下: [root@jin-10 /usr/local/nginx/conf]# cp -r nginx.conf /etc/ansible/nginx_config/roles/new/files/
编辑一个定义变量的文件vim /etc/ansible/nginx_config/roles/new/vars/main.yml,内容如下: nginx_basedir: /usr/local/nginx
再编写一个重新加载nginx服务的文件vim /etc/ansible/nginx_config/roles/new/handlers/main.yml,内容如下: - name: restart nginx shell: /etc/init.d/nginx reload
再编写一个核心任务的文件vim /etc/ansible/nginx_config/roles/new/tasks/main.yml ,内容如下: - name: copy conf file copy: src={{ item.src }} dest={{ nginx_basedir }}/{{ item.dest }} backup=yes owner=r oot group=root mode=0644 with_items: - { src: nginx.conf, dest: conf/nginx.conf } notify: restart nginx
最后,我们定义一个总入口配置文件vim /etc/ansible/nginx_config/update.yml,内容如下: --- - hosts: testhost user: root roles: - new
执行update.yml [root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml PLAY [testhost] ********************************************************************** TASK [Gathering Facts] *************************************************************** ok: [jin-11] ok: [127.0.0.1] TASK [new : copy conf file] ********************************************************** ok: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) ok: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) PLAY RECAP *************************************************************************** 127.0.0.1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 jin-11 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可以看到,nginx服务已经重新加载了: [root@jin-11 ~]# ps aux|grep nginx root 4040 0.0 0.0 20540 628 ? Ss 08:32 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf nobody 4042 0.0 0.3 22984 3192 ? S 08:32 0:00 nginx: worker process nobody 4043 0.0 0.3 22984 3192 ? S 08:32 0:00 nginx: worker process root 4570 0.0 0.1 112724 996 pts/0 S+ 10:43 0:00 grep --color=auto nginx [root@jin-11 ~]# date 2019年 09月 09日 星期一 10:44:12 CST
我们编辑nginx.conf,加上一行注释内容:# test for the rollback,然后再执行update.yml脚本: [root@jin-10 ~]# cat /etc/ansible/nginx_config/roles/new/files/nginx.conf|grep test # test for the rollback [root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml PLAY [testhost] ********************************************************************** TASK [Gathering Facts] *************************************************************** ok: [jin-11] ok: [127.0.0.1] TASK [new : copy conf file] ********************************************************** ok: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) ok: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) PLAY RECAP *************************************************************************** 127.0.0.1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 jin-11 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在jin-11上查看nginx.conf是否备份成功: [root@jin-11 ~]# cat /usr/local/nginx/conf/nginx.conf|grep test # test for the rollback
以上的操作是针对于更新、修改配置文件的,下面来介绍一下回滚操作:
回滚操作就是把旧的配置覆盖,然后重新加载nginx服务, 每次改动nginx配置文件之前先备份到old里,对应目录为/etc/ansible/nginx_config/roles/old/files。
拷贝new目录里的文件到old目录里,相当于把当前nginx配置文件备份到old里,如需回滚就将备份还原。 [root@jin-10 ~]# rsync -av /etc/ansible/nginx_config/roles/new/ /etc/ansible/nginx_config/roles/old/ sending incremental file list files/ files/nginx.conf handlers/ handlers/main.yml tasks/ tasks/main.yml vars/ vars/main.yml sent 2,535 bytes received 108 bytes 5,286.00 bytes/sec total size is 2,080 speedup is 0.79
编写一个总入口配置文件vim /etc/ansible/nginx_config/rollback.yml,内容如下: --- - hosts: jin-11 user: root roles: - old
下面我们来进行一个简单的回滚操作:
1、先将配置文件同步到old目录下: [root@jin-10 ~]# rsync -av /etc/ansible/nginx_config/roles/new/files/nginx.conf /etc/ansible/nginx_config/roles/old/files/nginx.conf sending incremental file list sent 49 bytes received 12 bytes 122.00 bytes/sec total size is 1,772 speedup is 29.05
2、修改配置文件/etc/ansible/nginx_config/roles/new/files/nginx.conf,文件末尾增加一行注释内容: #test the ansible playbook rollback
3、执行update.yml文件向客户端更新文件: [root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml PLAY [testhost] ********************************************************************** TASK [Gathering Facts] *************************************************************** ok: [jin-11] ok: [127.0.0.1] TASK [new : copy conf file] ********************************************************** changed: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) changed: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) RUNNING HANDLER [new : restart nginx] ************************************************ changed: [jin-11] changed: [127.0.0.1] PLAY RECAP *************************************************************************** 127.0.0.1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 jin-11 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4、在jin-11上查看,文件是否同步: [root@jin-11 ~]# tail -n1 /usr/local/nginx/conf/nginx.conf #test the ansible playbook rollback
5、可以看到,同步成功,然后我们执行rollback.yml文件进行回滚操作: [root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/rollback.yml PLAY [jin-11] ************************************************************************ TASK [Gathering Facts] *************************************************************** ok: [jin-11] TASK [old : copy conf file] ********************************************************** changed: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'}) RUNNING HANDLER [old : restart nginx] ************************************************ changed: [jin-11] PLAY RECAP *************************************************************************** jin-11 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
6、在jin-11上查看是否已恢复: [root@jin-11 ~]# tail -n1 /usr/local/nginx/conf/nginx.conf } [root@jin-11 ~]#
可以看到,之前文件末尾增加的那一行没有了。
所以,所谓的回滚就是在操作改动前,先把文件备份一份,如果出现误操作,就将之前备份的文件还原回去,这样就起到了一个回滚的效果。
热门排行