[TOC]
0x00 快速入门 基础概念 什么是ansible? 答:它是一个Linux系统上的”自动化运维工具”,类似一个”配置管理工具”;
ansible能做什么? 正如其他配置管理工具一样,ansible可以帮助我们完成一些批量任务,或者完成一些需要经常重复的工作。
比如:同时在100台服务器上安装nginx服务,并在安装后启动它们。
比如:将某个文件一次性拷贝到100台服务器上。
比如:每当有新服务器加入工作环境时,你都要为新服务器部署redis服务,也就是说你需要经常重复的完成相同的工作。
ansible优秀的特性 :
“幂等性”:可以保证我们重复的执行同一项操作时得到的结果是一样的。
举个例子:你想把一个文件拷贝到目标主机的某个目录上,但是你不确定此目录中是否已经存在此文件,当你使用ansible完成这项任务时,就非常简单了,因为如果目标主机的对应目录中已经存在此文件,那么ansible则不会进行任何操作,如果目标主机的对应目录中并不存在此文件,ansible就会将文件拷贝到对应目录中;
ansible是”以结果为导向的”,我们指定了一个”目标状态”,ansible会自动判断,”当前状态”是否与”目标状态”一致,如果一致,则不进行任何操作,如果不一致那么就将”当前状态”变成”目标状态”
剧本
模板
角色
其他的一些运维配置管理工具还有puppet或者saltstack而ansible相比较于他们的优点:
使用puppet管理100台主机,就要在这100台主机上安装puppet对应的agent(客户端代理程序),比较繁琐;
不同之处在于ansible只需要依赖ssh即可正常工作,不用在受管主机上安装agent,也就是说只要你能通过ssh连接到对应主机,你就可以通过ansible管理对应的主机。
为了好分辨后面将Ansible主机就是管理主机,受管理的主机叫做受控主机;
参考文档帮助:https://docs.ansible.com/ansible/latest/index.html
1.环境安装与设置 环境设置:采用VMWARE-player模拟环境实现;
[TOC]
0x00 快速入门 基础概念 什么是ansible? 答:它是一个Linux系统上的”自动化运维工具”,类似一个”配置管理工具”;
ansible能做什么? 正如其他配置管理工具一样,ansible可以帮助我们完成一些批量任务,或者完成一些需要经常重复的工作。
比如:同时在100台服务器上安装nginx服务,并在安装后启动它们。
比如:将某个文件一次性拷贝到100台服务器上。
比如:每当有新服务器加入工作环境时,你都要为新服务器部署redis服务,也就是说你需要经常重复的完成相同的工作。
ansible优秀的特性 :
“幂等性”:可以保证我们重复的执行同一项操作时得到的结果是一样的。
举个例子:你想把一个文件拷贝到目标主机的某个目录上,但是你不确定此目录中是否已经存在此文件,当你使用ansible完成这项任务时,就非常简单了,因为如果目标主机的对应目录中已经存在此文件,那么ansible则不会进行任何操作,如果目标主机的对应目录中并不存在此文件,ansible就会将文件拷贝到对应目录中;
ansible是”以结果为导向的”,我们指定了一个”目标状态”,ansible会自动判断,”当前状态”是否与”目标状态”一致,如果一致,则不进行任何操作,如果不一致那么就将”当前状态”变成”目标状态”
剧本
模板
角色
其他的一些运维配置管理工具还有puppet或者saltstack而ansible相比较于他们的优点:
使用puppet管理100台主机,就要在这100台主机上安装puppet对应的agent(客户端代理程序),比较繁琐;
不同之处在于ansible只需要依赖ssh即可正常工作,不用在受管主机上安装agent,也就是说只要你能通过ssh连接到对应主机,你就可以通过ansible管理对应的主机。
为了好分辨后面将Ansible主机就是管理主机,受管理的主机叫做受控主机;
参考文档帮助:https://docs.ansible.com/ansible/latest/index.html
1.环境安装与设置 环境设置:采用VMWARE-player模拟环境实现;1 2 3 10.10.107.222 Master-Ansible管理端 10.10.107.234 Slave-Ansible 受控端(Ubuntu) 10.20.172.235 Slave-Ansible 受控端(Centos)
(1) CentOS下Ansible安装: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 $ pwd /etc/yum.repos.d [aliBase] name=aliBase baseurl=https://mirrors.aliyun.com/centos/$releasever /os/$basearch / enabled=1 gpgcheck=1 gpgkey=https://mirrors.aliyun.com/centos/$releasever /os/$basearch /RPM-GPG-KEY-CentOS-$releasever [aliEpel] name=aliEpel baseurl=https://mirrors.aliyun.com/epel/$releasever \Server/$basearch / enabled=1 gpgcheck=0 yum install ansible $ansible 127.0.0.1 -m ping 127.0.0.1 | SUCCESS => { "changed" : false , "ping" : "pong" }
安装成功后如果想要通过ansible管理某主机,使用ansible管理必须同时满足两个最基本的条件如下
条件一、ansible所在的主机可以通过ssh连接到受管主机。
条件二、受管主机的IP地址等信息已经添加到ansible的”管理清单”中,如果清单中没有的主机无法通过ansible进行配置管理;
ansible提供一个默认的”清单”文件 /etc/ansible/hosts并且采用ini风格里面有默认的配置示例使用提示;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 echo "10.10.107.234 ansible_port=22 ansible_user=root ansible_ssh_pass=ubuntu" >> /etc/ansible/hosts echo "test ansible_host=10.20.172.104 ansible_port=22 ansible_user=root ansible_ssh_pass=2019" >> /etc/ansible/hosts ansible_port ansible_user ansible_host $ansible 10.10.107.234 -m ping10.10.107.234 | SUCCESS => { "ansible_facts" : { "discovered_interpreter_python" : "/usr/bin/python" }, "changed" : false , "ping" : "pong" } ansible test -m ping test | SUCCESS => { "ansible_facts" : { "discovered_interpreter_python" : "/usr/bin/python" }, "changed" : false , "ping" : "pong" }
ansible主控端如何采用密匙来登录受控端? 1 2 3 4 5 ssh-keygen ssh-copy-id -i /root/.ssh/id_rsa.pub root@10.10.107.234
因为配置了密钥认证,所以可以实现免密码创建ssh连接,既然已经能够免密码创建ssh连接,那么在配置”主机清单”时,就没有必要再提供对应主机的用户名与密码了,所以在完成了密钥认证的相关配置后,我们可以将清单中的配置精简为如下格式。1 2 10.10.107.234 ansible_port=22 test ansible_host=10.10.107.234 ansible_port=22
安装总结:
在上面我们使用的是ssh账号密码登录,但是在生产环境中为了提高安全性,我们通常会基于密钥进行ssh认证甚至会禁用密码认证;
在接入之前需要将受控端的公匙写入ansible的kown_hosts中;
(2) Ubuntu下Ansible安装:
安装方式:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ sudo apt update $ sudo apt install software-properties-common $ sudo apt-add-repository --yes --update ppa:ansible/ansible $ sudo apt install ansible sudo apt update sudo apt install ansible ansible --version ansible 2.9.6 config file = /etc/ansible/ansible.cfg configured module search path = ['/home/weiyigeek/.ansible/plugins/modules' , '/usr/share/ansible/plugins/modules' ] ansible python module location = /usr/lib/python3/dist-packages/ansible executable location = /usr/bin/ansible python version = 3.8.5 (default, Jul 28 2020, 12:59:40) [GCC 9.3.0]
至此现在,您的Ansible控制节点具有管理主机所需的所有软件;
2.清单配置详解 描述:该清单文件包含有关你会Ansible管理的主机信息
清单文件中包括从一到数百台服务器的任何位置,并且可以将主机组织为组和子组。
清单文件通常还用于设置仅对特定主机或组有效的变量,以便在剧本和模板中使用。
我们可以在ansible提供的清单配置文件中进行配置我们以该文件进行讲解1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 $vim /etc/ansible/hosts[A] 10.10.107.234 10.10.107.235 [B] 10.10.107.221 [A] 10.10.107.[234:235] [B] 10.10.107.221 [A] db01.weiyigeek.net db02.weiyigeek.net [B] db0[1:2].weiyigeek.net [testA] 10.10.107.1 [testB] 10.10.107.2 [Master:children] test [A:B][manager] admin ansible_host=10.10.107.202 ansible_port=20211 ansible_user=WeiyiGeeker ansible_sudo_pass='123456' [master] k8s-master-1 ansible_host=10.10.107.210 k8s-master-2 ansible_host=10.10.107.211 k8s-master-3 ansible_host=10.10.107.212 [node] k8s-node-1 ansible_host=10.10.107.213 k8s-node-2 ansible_host=10.20.172.220 k8s-node-3 ansible_host=10.20.172.221 [k8s:children] master node [k8s:vars] ansible_port=20211 ansible_user=WeiyiGeeker ansible_become=true ansible_become_method=sudo ansible_become_pass='123456' [all:vars] ansible_python_interpreter=/usr/bin/python3
验证配置结果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 ansible A -m ping ansible B -m ping ansible all -m ping ansible Master -m ping $ansible -inventory --list -yall: children: k8s: children: master: hosts: k8s-master-1: ansible_become: 'true' ansible_become_method: sudo ansible_become_pass: 123456 ansible_host: 10.10.107.210 ansible_port: 20211 ansible_python_interpreter: /usr/bin/python3 ansible_user: WeiyiGeeker k8s-master-2: ansible_become: 'true' ansible_become_method: sudo ansible_become_pass: 123456 ansible_host: 10.10.107.211 ansible_port: 20211 ansible_python_interpreter: /usr/bin/python3 ansible_user: WeiyiGeeker k8s-master-3: ansible_become: 'true' ansible_become_method: sudo ansible_become_pass: 123456 ansible_host: 10.10.107.212 ansible_port: 20211 ansible_python_interpreter: /usr/bin/python3 ansible_user: WeiyiGeeker node: hosts: k8s-node-1: ansible_become: 'true' ansible_become_method: sudo ansible_become_pass: 123456 ansible_host: 10.10.107.213 ansible_port: 20211 ansible_python_interpreter: /usr/bin/python3 ansible_user: WeiyiGeeker k8s-node-2: ansible_become: 'true' ansible_become_method: sudo ansible_become_pass: 123456 ansible_host: 10.20.172.220 ansible_port: 20211 ansible_python_interpreter: /usr/bin/python3 ansible_user: WeiyiGeeker k8s-node-3: ansible_become: 'true' ansible_become_method: sudo ansible_become_pass: 123456 ansible_host: 10.20.172.221 ansible_port: 20211 ansible_python_interpreter: /usr/bin/python3 ansible_user: WeiyiGeeker manager: hosts: admin: ansible_host: 10.10.107.202 ansible_port: 20211 ansible_python_interpreter: /usr/bin/python3 ansible_sudo_pass: 123456 ansible_user: WeiyiGeeker ungrouped: {}
weiyigeek.top-验证1
其实Ansible的清单文件/etc/ansible/hosts不仅能够识别INI的配置语法还能够识别”YAML”的配置语法。 注意,为了使缩进显得更加明显,此处每次缩进使用两个空格1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 $vim /etc/ansible/hostsall: hosts: 10.10.107.1 10.10.107.2 10.1.1.60 10.1.1.61 10.1.1.61 [test1] 10.1.1.60 [test2] 10.1.1.70 all: hosts: 10.1.1.61: children: test1: hosts: 10.1.1.60: test2: hosts: 10.1.1.70:
组中嵌套时候:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [proA] 10.1.1.60 [proB] 10.1.1.70 [pro:children] proA proB all: children: pro: children: proA: hosts: 10.1.1.60 proB: hosts: 10.1.1.70
当我们使用YAML语法配置清单时,无非是使用hosts、children
等关键字与我们的自定义名称进行排列组合罢了。
认证管理yaml配置:1 2 3 4 5 6 7 8 9 10 11 12 13 14 10.1.1.6 test7 ansible_host=10.1.1.7 ansible_port=22 localhost ansible_connection=local all: hosts: 10.1.1.6 test7: ansible_host: 10.1.1.7 ansible_port: 22 localhost: ansible_connection: local
综合示例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - name: create jenkins container docker_container: docker_host: myserver.net:4243 name: my_jenkins image: jenkins - name: add container to inventory add_host: name: my_jenkins ansible_connection: docker ansible_docker_extra_args: "--tlsverify --tlscacert=/path/to/ca.pem --tlscert=/path/to/client-cert.pem --tlskey=/path/to/client-key.pem -H=tcp://myserver.net:4243" ansible_user: jenkins changed_when: false - name: create directory for ssh keys delegate_to: my_jenkins file: path: "/var/jenkins_home/.ssh/jupiter" state: directory
参考absible的yaml语法:https://docs.ansible.com/ansible/2.4/intro_inventory.html#id7
0x01 命令详解 描述:主要是描述ansible命令与ansible-doc命令参数
语法参数:1 2 3 4 5 ansible [主机] [选项] [主机连与认证] -a -m -e
补充命令1:1 2 3 4 5 ansible-doc -l,--list 模块简介与全部模块 -s 模块详情
补充命令2:1 2 3 4 5 6 7 8 9 ansible-playbook --syntax-check --check --list-tags --tags [tagname] --skip-tags [tagname] -e,--extra-vars
命令示例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ansible-playbook --syntax-check test.yml ansible-playbook --check test.yml ansible-playbook --tags task1 test.yml ansible-playbook --skip-tags task1 test.yml ansible-playbook cmdvar.yml --extra-vars "pass_var=cmdline pass var" ansible-playbook cmdvar.yml -e 'pass_var="test" pass_var1="test1"' ansible-playbook cmdvar.yml -e '{"testvar":"test","testvar1":"test1"}' ansible-playbook cmdvar.yml -e '{"countlist":["one","two","three","four"]}'
0x02 Ansible模块基础使用 当我们使用ansible完成实际任务时,需要依靠ansible的各个模块,比如前的ping模块1 2 3 4 5 6 $ansible all -m pingansible-doc -l ansible-doc -s ping ansible-doc -s fetch
比如:查看fetch模块的使用帮助1 2 3 4 5 6 7 8 - name: Fetch files from remote nodes fetch: dest: src: validate_checksum: fail_on_missing: flat:
基础示例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 all: hosts: local : ansible_host: 10.10.107.222 ansible_user: root ansible_ssh_pass: root@2019 children: ops: children: testA: hosts: 10.10.107.221 testB: hosts: 10.20.172.179 ansible ops -m fetch -a "src=/etc/fstab dest=/tmp/ansible/" 10.10.107.221 | CHANGED => { "changed" : true , "checksum" : "2b8323413e9c5a3067f61c27ca5ea21378bae582" , "dest" : "/tmp/ansible/10.10.107.221/etc/fstab" , "md5sum" : "edf31ba4fd10068f6310f4343855af89" , "remote_checksum" : "2b8323413e9c5a3067f61c27ca5ea21378bae582" , "remote_md5sum" : null }
weiyigeek.top-fetch
返回提示颜色来看幂等性
当返回信息为绿色时,”changed”为false,表示ansible没有进行任何操作,没有”改变什么”。
当返回信息为黄色时,”changed”为true,表示ansible执行了操作,”当前状态”已经被ansible改变成了”目标状态”。
比如:这时候我把10.10.107.221的fstab进行更改1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 echo " " >> /etc/fstab10.10.107.221 | CHANGED => { "changed" : true , "checksum" : "e0719b31dd9445c5da3dd5e04f13ed44855aacd0" , "dest" : "/tmp/ansible/10.10.107.221/etc/fstab" , "md5sum" : "631e37410fac691ead3c90e6938494ef" , "remote_checksum" : "e0719b31dd9445c5da3dd5e04f13ed44855aacd0" , "remote_md5sum" : null } 10.20.172.179 | SUCCESS => { "changed" : false , "checksum" : "39ffc633a100c2b2d06a3d9d0e625dff1ca7043c" , "dest" : "/tmp/ansible/10.20.172.179/etc/fstab" , "file" : "/etc/fstab" , "md5sum" : "c63b434a7a09baea8b7b59fce8cb807b" }
weiyigeek.top-幂等性差别
_总结_:
注释中包含 “required” 字样则表示使用模块中的参数必须要设置;
注意幂等性的区别点,以及yaml配置受管主机清单
0x03 PlayBook(剧本) 描述:将我们前面所学到的模块的知识点应用到工作场景,进一步理解与使用ansible
剧本yml语法 假设,我们想要在test70主机上安装nginx并启动,我们可以在ansible主机中执行如下3条命令1 2 3 4 ansible test70 -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/' ansible test70 -m yum -a 'name=nginx disable_gpg_check=yes enablerepo=aliEpel' ansible test70 -m service -a "name=nginx state=started"
但是在实际的工作环境中我们可能需要经常在新主机上安装nginx,难道每次有新的服务器加入工作环境,我们都要修改上述3条命令中的主机名并且重新将每一条命令执行一遍吗?
这样似乎有些麻烦,肯定有更好的办法,没错我们可以将上述命令写成脚本,每次修改一些变量然后执行脚本就行了,而ansible天生就提供了这种类似"脚本"的功能
,在ansible中类似”脚本”的文件被称作”剧本”,’剧本’的英文名称为’playbook’,我们只需要将要做的事情编写成playbook,把不同的模块按照顺序编排在剧本中,ansible就会按照剧本一步一步的执行,最终达到我们的目的,虽然playbook的功能与脚本类似,但是剧本并不是简单的将ad-hoc命令按照顺序堆砌在一个可执行文件中,编写剧本需要遵循YAML语法
;
一个’playbook’是由一个或多个’play’组成的,这样说可能不太容易理解,那么我们打个比方,一个'剧本'是由一个或多个'桥段'组成的,每个桥段都有不同的场景、人物、故事
,所有的桥段组合在一起,组成一个完整的剧本,剧本就是playbook桥段就是play;当然’桥段’只是我自己为了方便理解给’play’起的中文名,官方名称只叫\”play\”。
剧本初识-单个play 首先,我们需要创建一个YAML格式的playbook文件,playbook文件以”.yaml”或者”.yml”作为文件名后缀,此处我们创建一个名为”test.yml”的剧本文件。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ansible local -m ping ansible local -m file -a "path=/testdir/test state=directory" --- - hosts: local ,testA remote_user: root tasks: - name: ping The host ping: - name: make directory test file: path: /tmp/ansible-playbook state: directory
yml配置文件解析:
第一行:---
表示yml文档的开始
第二行:-
作为开头表示一个块序列的节点;host关键字指定要操作的主机或者组,多台主机或者组采用,
分割
第三行:remote_user关键字与hosts关键字对齐表示它们是平级的,使用remote_user关键字可以指定在进行远程操作时使用哪个用户进行操作
第四行:使用tasks关键字指明要进行操作的任务列表之后的行都属于tasks键值对中的值;整个任务列表一共有两个任务组成,每个任务都以\”- \”开头,每个任务都有自己的名字,任务名使用name关键字进行指定
第一个任务使用ping模块,使用ping模块时没有指定任何参数。
第二个任务使用file模块,使用file模块时,指定了path参数与state参数的值。
采用'ansible-playbook'命令
测试运行剧本(脚本): playbook执行后返回了一些信息,这些信息是这次剧本运行的概况:
weiyigeek.top-playbook
‘make directory ansible-playbook’任务返回的信息是绿色的,如果对应的目录并不存在
‘make directory ansible-playbook’任务返回的信息应该是黄色的
,这是因为幂等性的缘故,比如这次local主机
我们在playbook中明明只写了两个任务,为什么最后执行时却有三个任务呢? 答:因为每个play在执行时都会先执行一个默认任务,’Gathering Facts’任务会收集当前play对应的目标主机的相关信息,收集完这些基础信息后才会执行我们指定的任务,
补充说明 :
脚本语法验证
脚本模拟执行 : 我们并不能完全以’模拟’的反馈结果作为playbook是否能够正常运行的判断依据,只能通过’模拟’大概的’预估’一下而已1 2 3 4 5 $ansible -playbook --syntax-check test.yml $ansible -playbook --syntax-check demo.yml playbook: demo.yml $ansible -playbook --check test.yml
weiyigeek.top-playbook--check
剧本初识-多个play 比如我们把上面的主机或者组分别分成两个不同的场景:对于Local主机模块是不变化的,对于主机组B采用file模块以及user模块来创建文件和建立用户1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 demo.yml --- - hosts: local remote_user: root tasks: - name: ping The host ping: - name: make directory test file: path: /tmp/ansible-playbook state: directory - hosts: testB remote_user: root tasks: - name: touch file file: path: /tmp/file.txt state: touch - name: create user demo user: name: demo password: "$6$ygRbo7Fj.mMU2KY0$OEqihCCn5UfOsvMyzPNPBgx3bzAtwrOFyFvacgUmA374XOAEtUCrdjbW5Ip.Zqo491o3kD5I.HaC9nLhh6x741" uid: 1024 mode: 0700
脚本(剧本执行):ansible-playbook demo.yml
,执行后的结果验证:
weiyigeek.top-playbookdemo.yml
其他yml配置文件形式说明:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 tasks: - name: make testfile file: path=/testdir/testfile state=touch mode=0700 - name: make testfile file: path=/testdir/testfile state=touch mode=0700 --- - hosts: local remote_user: root tasks: - name: make file action: file path=/tmp/test.yml state=touch mode=0700
weiyigeek.top-2.8.1向下兼容
在前面示例中我们对每个任务都指定了对应的名称,即每个task都有对应的name,当我们省略name时,默认以当前任务调用的模块的名称作为任务的名称,不过建议不要省略name
,因为当任务存在name时可读性比较高。1 2 3 4 5 6 7 8 9 10 11 12 13 tasks: - name: make testfile file: path=/testdir/testfile state=touch mode=0700 tasks: - file: path=/testdir/testfile state=touch mode=0700 name: make testfile
各属性顺序虽然没有要求,但是仍然需要严格按照缩进进行对齐。
handlers 用法 描述:先来描述一个工作场景当我们修改了某些程序的配置文件以后,有可能需要重启应用程序,以便能够使新的配置生效,那么如果使用playbook来实现这个简单的功能该怎样编写playbook呢?
假设我们想要将nginx中的某个server的端口从8080改成8088,并且在修改配置以后重启nginx,那么我们可以编写如下剧本。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --- - hosts: test70 remote_user: root tasks: - name: Modify the configuration lineinfile: path=/etc/nginx/conf.d/test.conf regexp="listen(.*) 8080 (.*)" line="listen\1 8088 \2" backrefs=yes backup=yes - name: restart nginx service: name=nginx state=restarted
weiyigeek.top-restarnginx
那么问题来了 ?
第一次执行修改后重新是没有什么问题,但是在第二/n次运行时候会进行行替换匹配而不发生改变(由于幂等性),而是有一次执行了restart来重启了nginx服务;简单的说就是配置未发生任何变化却进行了服务重启;
解决问题的方法:采用 handlers 方法
handlers的概念:你可以把handlers理解成另一种tasks(平级),handlers是另一种’任务列表’,handlers中的任务会被tasks中的任务进行\”调用\”,但是被\”调用\”并不意味着一定会执行,只有当tasks中的任务"真正执行"以后(真正的进行实际操作,造成了实际的改变)
,handlers中被调用的任务才会执行,如果tasks中的任务并没有做出任何实际的操作,那么handlers中的任务即使被’调用’,也并不会执行。
handlers示例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 --- - hosts: test70 remote_user: root tasks: - name: Modify the configuration lineinfile: path=/etc/nginx/conf.d/test.conf regexp="listen(.*) 8080 (.*)" line="listen\1 8088 \2" backrefs=yes backup=yes notify: restart nginx handlers: - name: restart nginx service: name=nginx state=restarted
所以综上所述上例中的play表示,如果"Modify the configuration"
真正的修改了配置文件(实际的操作),那么则执行"restart nginx"任务
,如果"Modify the configuration"
并没有进行任何实际的改动,则不执行"restart nginx"
通常来说,任务执行后如果做出了实际的操作,任务执行后的状态为changed则会执行对应的handlers,
handlers是另一种任务列表并且可以有多个任务,被tasks中不同的任务notify,
默认情况下所有task执行完毕后才会执行各个handler,并不是执行完某个task后,立即执行对应的handler
如果你想要在执行完某些task以后立即执行对应的handler,则需要使用meta模块
示例如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 --- - hosts: local remote_user: root tasks: - name: make testfile1 file: path=/tmp/testfile1 state=directory notify: ht2 - name: make testfile2 file: path=/tmp/testfile2 state=directory notify: ht1 - meta: flush_handlers - name: task3 file: path=/tmp/testfile3 state=directory notify: ht3 handlers: - name: ht1 file: path=/tmp/testfile1/ht1 state=touch - name: ht2 file: path=/tmp/testfile2/ht2 state=touch - name: ht3 file: path=/tmp/testfile3/ht3 state=touch PLAY [local] TASK [Gathering Facts] TASK [make testfile1] TASK [make testfile2] RUNNING HANDLER [ht1] RUNNING HANDLER [ht2] TASK [task3] RUNNING HANDLER [ht3] PLAY RECAP
weiyigeek.top-meta模块与handler
在一个task中一次性notify多个handler,当多个handler的name相同时只有一个handler会被执行
,所以我们并不能通过这种方式notify多个handler,
如果想要一次notify多个handler就需要设置组名来进行handlers多任务的调用,则需要借助另一个关键字它就是'listen'理解成"组名",我们可以把多个handler分成"组"
,当我们需要一次性notify多个handler时,只要将多个handler分为”一组”,使用相同的”组名”即可,当notify对应的值"组名"时,"组"内的所有handler都会被notify
一个notify调用多个handler中的任务:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 --- - hosts: test70 remote_user: root tasks: - name: task1 file: path=/tmp/test state=directory notify: handler group1 handlers: - name: handler1 listen: handler group1 file: path=/tmp/test/ht1 state=touch - name: handler2 listen: handler group1 file: path=/tmp/test/ht2 state=touch
监测与执行:1 2 3 4 $ansible -playbook --syntax-check notify.ymlplaybook: notify.yml ansible-playbook notify.yml
weiyigeek.top-notify-nutil-handlers
handler总结 :
handler执行的顺序与handler在playbook中定义的顺序是相同的,与”handler被notify”的顺序无关。
可以使用meta模块来执行完某些task以后立即执行对应的handler;如果想要每个task在实际操作后都立马执行对应handlers,则可以在每个任务之后都添加一个meta任务并将其值设置为flush_handlers
采用tasks默认都notify只能调用一个handlers任务,如果想调用多个handlers任务就采用listen关键字来设置监听组
描述: 在实际使用这个剧本时你可能只是想要执行其中的一部分任务而已,或者你只想要执行其中一类任务而已,而并非想要执行整个剧本中的全部任务
这个时候我们该怎么办呢? 答:可以借助tags实现这个需求,见名知义tags可以帮助我们对任务进行'打标签'的操作
,当任务存在标签以后,我们就可以在执行playbook时,借助标签指定执行哪些任务,或者指定不执行哪些任务了
;
示例:play中有3个task每个task都有对应的tags,我只是简单的把tags的值写成了t1、t2、t3当然您也可以定义成为其他;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 --- - hosts: local remote_user: root tasks: - name: task1 file: path: /tmp/t1 state: touch tags: t1 - name: task2 file: path=/tmp/t2 state=touch tags: t2 - name: task3 file: path=/tmp/t3 state=touch tags: t3
下面利用ansible-playbook中--tags选项
以及--skip-tags选项
来执行指定的task任务以及跳过任务执行:1 2 3 4 5 6 7 8 9 ansible-playbook --list-tags testhttpd.yml ansible-playbook --tags=t2 testtag.yml ansible-playbook --skip-tags='t2' testtag.yml
除了使用上例中的语法指定标签,我们可以为每个任务添加多个标签三种语法添加多个标签的示例:1 2 3 4 5 6 7 8 9 10 tags: - testtag - t1 tags: tag1,tag2 tags: ['tagtest' ,'t2' ]
将上面所学知识的进行综合演示,实现标签的常规用法,当拥有共同的标签时候将主tags标签提取出来与tasks同级,还可以在tasks里面建立子标签:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 --- - hosts: local remote_user: root tags: command tasks: - name: show ip address tags: ['ip'] shell: ifconfig > /tmp/ipaddr.txt #值得注意(shell模块在play中的使用) - name: mkdir directory tags: - createdir file: path: /tmp/createdir state: directory - hosts: testA remote_user: root tags: nginx tasks: - name: install nginx package tags: ['package'] yum: name=httpd state=latest - name: start up nginx server tags: - startservices service: name: nginx state: started
当tags写在play中而非task中时,play中的所有task会继承当前play中的tags,而上例中两个任务都会继承httpd标签,同时还有拥有自己的标签
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ansible-playbook --list-tags tag.yml playbook: tag.yml play TASK TAGS: [command , createdir, ip] play TASK TAGS: [nginx, package, startservices] ansible-playbook --tags package,startservices testhttpd.yml ansible-playbook --tags command ,nginx tag.yml
weiyigeek.top-tags-demo
ansible特殊预置5个tag:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 tags: t3,always,nginx * always : 把任务的tags的值指定为always时任务就总是会被执行,除非你使用'--skip-tags' 选项明确指定不执行对应的任务 ansible-playbook --skip-tags always testtag.yml ansible-playbook --skip-tags t3 testtag.yml * never(2.5版本中新加入的特殊tag): 从字面上理解never的作用应该与always正好相反 ansible-playbook --tags never testtag.yml * tagged ansible-playbook --tags tagged testtag.yml ansible-playbook --skip-tags tagged testtag.yml * untagged ansible-playbook --tags untagged testtag.yml ansible-playbook --skip-tags untagged testtag.yml * all: 表示所有任务会被执行,不用指定,默认情况下就是使用这个标签。