YAML语法和playbook写法
ansible的playbook采用了yaml语法,它简单地实现了json格式的事件描述。在学习ansible playbook之前,很有必要把yaml的语法格式、引用方式做个梳理。
一、初步说明
以一个简单的playbook为例,说明yaml的基本语法
1. yaml⽂件以 --- 开头,以表明这是⼀个yaml⽂件,就像xml⽂件在开头使⽤ <?xml version="1.0" encoding="utf-8"?> 宣称它是xml⽂件⼀样。但即使没有使⽤ --- 开头,也不会有什么影响。
2. yaml中使⽤"#"作为注释符,可以注释整⾏,也可以注释⾏内从"#"开始的内容。
3. yaml中的字符串通常不⽤加任何引号,即使它包含了某些特殊字符。但有些情况下,必须加引号,最常见的是在引⽤变量的时候。
4. 关于布尔值的书写格式,即true/false的表达⽅式。其实playbook中的布尔值类型⾮常灵活,可分为两种情况:
模块的参数: 这时布尔值作为字符串被ansible解析。接受yes/on/1/true/no/of f /0/false,这时被ansible解析。例如上⾯⽰例中的 update_cache=yes 。
⾮模块的参数: 这时布尔值被yaml解释器解析,完全遵循yaml语法。接受不区分⼤⼩写的 true/yes/on/y/f alse/no/off /n。例如上⾯的 gpgcheck=no 和 enabled=True 。建议遵循ansible的官⽅规范,模块的布尔参数采⽤yes/no,⾮模块的布尔参数采⽤True/False
playbook的内容
每个play都包含⼀个hosts和⼀个tasks,hosts定义的是inventory中待控制的主机,tasks下定义的是⼀系列task任务列表,⽐如调⽤各个模块。这些task按顺序⼀次执⾏⼀个,直到所有被筛选出来的主机都执⾏了这个task之后才会移动到下⼀个task上进⾏同样的操作。
需要注意的是,虽然只有被筛选出来的主机会执⾏对应的task,但是所有主机(此处的所有主机表⽰的是,hosts选项所指定的那些主机)都会收到相同的task指令,所有主机收到指令后,ansible主控端会筛选某些主机,并通过ssh在远程执⾏任务。
YAML字典
YAML中使用的key/value对也称为字典、散列或关联数组在key/value对中,键与值通过由冒号和空格组成的分隔符隔开name: svcrolesvcservice: httpsvcport: 80字典也可以使用内嵌块格式表示,其中多个key/value对用花括号括起,并由逗号和空格隔开- {name: svcrole, svcservice: http, svcport: 80}YAML列表
在YAML中,列表类似于其他编程语言中的数组为表示一组列表项,使用一个短划线加一个空格作为每个列表项的前缀hosts: - server1 - server2列表也可使用内嵌块表示,其中多个列表项用方括号括起来并由逗号和空格隔开hosts: [server1, server2]
playbook的使用
ansible-playbook用于运行剧本,-C 测试运行结果,并不是真的执行任务。
示例1:
- 安装httpd
- 开机自启
- 给/var/www/html目录创建软链接/www
- 从http://server.example.com/index.html下载至/www
- 能够访问该web站点
[root@server ansible]# cat cy.yml
---
- name: web station
hosts: node1
tasks:
- name: yum_repo
yum_repository:
file: server
name: BaseOS
description: rhel8
baseurl: file:///mnt/BaseOS
enabled: yes
gpgcheck: no
- name: yum_repo2
yum_repository:
file: server
name: AppStream
description: RHEL8
baseurl: file:///mnt/AppStream
enabled: yes
gpgcheck: no
- name: install httpd
yum:
name: httpd
state: latest
- name: create /www
file:
src: /var/www/html
dest: /www
state: link
mode: 0755
- name: get html
get_url:
url: http://172.16.30.10/index.html
dest: /www
mode: 0644
- name: firewalld http
firewalld:
rich_rule: rule family=ipv4 source address=172.16.30.0/24 service name=http accept
permanent: yes
immediate: yes
state: enabled
- name: context
sefcontext:
target: /www/index.html
setype: httpd_sys_content_t
state: present
- name: restorecon
command: restorecon -Rv /www/index.html
- name: httpd.conf
replace:
path: /etc/httpd/conf/httpd.conf
regexp: 'DocumentRoot "/var/www/html"'
replace: 'DocumentRoot "/www"'
- name: httpd1.conf
replace:
path: /etc/httpd/conf/httpd.conf
regexp: <Directory "/var/www">
replace: <Directory "/">
- name: start httpd
service:
name: httpd
state: restarted
enabled: yes
示例2:
notify handlers用法(当完成….任务时,则进行….任务)
[root@server ansible]# cat test.yml
---
- name: this is a test playbook
hosts: node1
tasks:
- name: create user1
user:
name: user1
state: present
- name: create user2
user:
name: user2
state: present
notify:
- file3
handlers:
- name: file3
file:
path: /tmp/cy1
state: touch
mode: 0644
示例3:
- 写一个剧本galaxy.yml,只对node1操作
- 创建用户aa,该用户不能用于登录,家目录/www
- 在/www创建一个文件html
- 每次执行该剧本时,将系统的当前时间输入到html文件中。
- 如果html中的时间发生变化,那么创建/tmp/kk的文件
[root@server ansible]# cat galaxy.yml
---
- name: time
hosts: node1
tasks:
- name: create user
user:
name: aa
shell: /sbin/nologin
home: /www
- name: create file
file:
path: /www/html
state: touch
- name: date
shell: date > /www/html
notify:
- kk
handlers:
- name: kk
file:
path: /tmp/kk
state: touch
示例:4:
tags用法:给任务打标签,一个任务可以有多个标签,ansible-playbook -t 来指定需要指定的任务标签。
注意:
其实ansible还预置了5个特殊的tag
always:如果添加此标签,不管是否指定该任务,都执行
never:不执行标签
tagged:在执行时使用ansible-playbook playbook.yml -t tagged 只执行带有标签的任务
untagged:在执行时使用ansible-playbook playbook.yml -t untagged 只执行不带标签的任务,包含always标签也执行
all:所有任务都执行,默认标签。
可以同时使用多个标签,需要用”,”隔开
ansible-playbook –tags package,service playbook.yml
查看tag的标签类型
ansible-playbook –list-tags playbook.yml
[root@server ansible]# cat test2.yml
---
- name: test playbook
hosts: node1
tasks:
- name: create user3
user:
name: user3
state: present
tags:
- l1
- l2
- name: create user4
user:
name: user4
state: present
tags:
- l2
- l3
- name: create user5
user:
name: user5
state: present
tags:
- l3
- l4
ansible-playbook test2.yml -t l2
ansible-playbook --skip-tags l1 test2.yml ---跳过l1,其他执行,除了never外
ansible-playbook --tags always test2.yml --只执行always标签
ansible-playbook --tags tagged test2.yml --执行带标签任务,除了never标签外
ansible-playbook --tags untagged test2.yml --执行不带标签的任务,但是always仍执行
ansible-playbook --tags never test2.yml --执行never标签任务,但是always仍执行
写法:
Tags:
- always
补充:template模块
- template模块的使用方法和copy模块基本一致,但是copy模块从本地ansible节点复制文件到受控节点时,源文件的内容是什么就是什么,不能发生改变;而使用template模块复制文件时,源文件的内容可以随着受控主机的不同而发生变化。
- 使用template模块复制文件时,该文件的扩展名必须为“.j2”。
例题1:创建模板文件html.j2,该文件的内容为
The 【受控主机的hostname】 address is 【IP地址】(需要随着受控主机的不同,文件的内容而发生变化)
1、编辑文件html.j2
[root@server ansible]# cat html.j2
the {{ansible_fqdn}} address is {{ansible_ens160.ipv4.address}}
2、撰写playbook,将模板文件复制到受控主机的/tmp/目录下,并重命名为html
[root@server ansible]# vim a.yml
---
- name: test
hosts: node1,node2
tasks:
- name: cp html.j2
template:
src: /etc/ansible/html.j2
dest: /tmp/html
- 执行该playbook
Ansible-playbook a.yml
- 分别去node1和node2两台受控主机中去验证
Node1:
[root@node1 ~]# cat /tmp/html
the node1.example.com address is 172.16.30.10
[root@node1 ~]#
Node2:
[root@node2 ~]# cat /tmp/html
the node2.example.com address is 172.16.30.20
[root@node2 ~]#
例题2:
Copy模块:
创建一个名为/etc/ansible/b.yml的playbook
该playbook在所有的清单主机中运行
该playbook的内容为:
如果将受控主机的/tmp/chenyu文件的内容替换成如下:
在net主机组中的主机上,这行文本显示:chenyu
在hr主机组中的主机上,这行文本显示:cy123
[root@server ansible]# cat hosts
[net]
node1
[hr]
node2
1、撰写剧本
[root@server ansible]# vim b.yml
---
- name: test
hosts: all
tasks:
- name: cp file
copy:
content: |
{% if "net" in group_names %}
chenyu
{% elif "hr" in group_names %}
cy123
{% endif %}
dest: /tmp/chenyu
2、执行该剧本
Ansible-playbook b.yml
- 验证:
Node1:
[root@node1 ~]# cat /tmp/chenyu
chenyu
[root@node1 ~]#
Node2:
[root@node2 ~]# cat /tmp/chenyu
cy123
[root@node2 ~]#