当篇文章需要读者细嚼慢咽,在结合实操即可明白。
一、playbook模块初步介绍
以一个简单的playbook为例,说明yaml
的基本语法
- yaml⽂件以
- - - 开头
,以表明这是⼀个yaml语言⽂件,就像常用的shell脚本⽂件在开头使⽤#!/bin/bash
宣称它是shell脚本文件⼀样。但即使没有使⽤ - - - 开头,也不会有什么影响。 - yaml中使⽤"#“作为注释符,可以注释整⾏,也可以注释⾏内从”#"开始的内容。
- yaml中的字符串通常不⽤加任何引号,即使它包含了某些特殊字符。但有些情况下,必须加引号
" "
,最常见的是在引⽤变量
的时候。
需要单独调用单个变量时候,必须加引用
4. 关于布尔值的书写格式
(我们一般使用的是yes或NO)也可以用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
5、playbook的内容
-
每个play操作时都应该包含⼀个
hosts(必须存在
)和⼀个tasks值
(当角色数值有时可以不存在),(除非定义第二play个否则)。 -
hosts定义规则的是
inventory(主机清单)
中待控制的主机,tasks下定义的是⼀系列task任务列表,⽐如调⽤各个模块。这些task按顺序⼀次执⾏⼀个,直到所有被筛选出来的主机都执⾏了这个task之后才会移动到下⼀个task上进⾏同样的操作。 -
需要注意的是,虽然只有被筛选出来的主机(默认会读取清单中的)会执⾏对应的task,但是所有主机(此处的所有主机表⽰的是,hosts选项所指定的那些主机)都会收到相同的task指令,所有主机收到指令后,
ansible主控端会筛选某些主机并将命令打包为.py的脚本,并通过ssh在远程执⾏任务。
6、判断结果规则
可以通过每次执行命令时可以依据判断
changed=2 受控节点发生改变
unreachable=0 受控制=节点不可达(出现数字)。
YAML字典(常用)
YAML中使用的key/value对也称为字典、散列或关联数组 在key/value对中,键与值通过由冒号和空格组成的分隔符隔开
如:
name:
svcrole
svcservice: http
svcport: 80
字典也可以使用内嵌块格式表示,其中多个key/value对用花括号括起,并由逗号和空格隔开
- {name: svcrole, svcservice: http, svcport: 80}
7、YAML列表
- 在YAML中,列表类似于其他编程语言中的数组 为表示一组列表项,使用一个短划线加一个空格作为每个列表项的前缀,以一排一排的方法
hosts: - server1 - server2 列表也可使用内嵌块表示。
其中多个列表项用方括号括起来并由逗号和空格隔开 hosts: [server1, server2]
8、playbook的预执行使用
ansible-playbook用于运行剧本,-C 测试运行结果,并不是真的执行任务,只是模拟。
[student@server ansible]$ ansible-playbook aa.yml -C
YAML语法和playbook写法
Playbook是通过积累一条一条的模块来运行的
ansible的playbook采用了yaml语法,它简单地实现了json格式的事件描述。在学习ansible playbook之前,很有必要把yaml的语法格式、引用方式做个梳理。
基本编写的与ansible-doc
帮助文档里面的模板类似
yaml 列表:
需要以yml后缀名为结尾
以yaml字典编写(一般用的最多是这种)
二、playbook操作实例
1、搭建仓库示范
[student@server ansible]$ vim aa.yml
---
- name: test //某个横杠和冒号都需要接空格
Hosts : node1 //定义自己的主机名
tasks: //任务清单
- name: mount cdrom //自定义子目录中的名字
mount:
src: /dev/cdrom
dath: /mnt
fstype: iso9660
state: mounted
- name: set repo1 //每个子模块下面需要缩进2字符
yum_repository:
file: server
name: aa
description: aa1
baseurl: file:///mnt/BaseOS
enabled: yes
gpgcheck: no
- name: set repo2
yum_repository:
file: server
name: bb
description: bb1
baseurl: file:///mnt/AppStream
enabled: yes
gpgcheck: no
- 直接输入自动对齐
每一次: 后面都需要空格在换行输入
//运行命令
需注意的是当中间某个节点出现错误后面的程序则都不会运行
[student@server ansible]$ ansible-playbook aa.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
TASK [mount cdrom] *************************************************************
ok: [node1]
TASK [set repo1] ***************************************************************
changed: [node1]
TASK [set repo2] ***************************************************************
changed: [node1]
PLAY RECAP *********************************************************************
node1 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2、安装httpd实例
示例1:
1、 安装httpd
//server本机安装
[root@server html]# systemctl restart httpd
[root@server html]# systemctl enable --now httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
[root@server html]# ss -antl | grep httpd
[root@server html]# ss -antl | grep 80
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
//防火墙处于关闭中
[root@server html]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor>
Active: inactive (dead)
[root@node1 www]# cat /var/www/html/index.html
my name is liutianyang
后映射软连接就有了
[root@node1 www]# pwd
/www
[root@node1 www]# cat index.html
my name is liutianyang
2、 开机自启
3、 给/var/www/html目录创建软链接/www
[student@server ansible]$ cat aa.yml
---
- name: test
hosts: node1
tasks:
- name: mount cdrom
mount:
src: /dev/cdrom
path: /mnt
fstype: iso9660
state: mounted
- name: set repo1 //定义好第一个yum源
yum_repository:
file: server
name: aa
description: aa1
baseurl: file:///mnt/BaseOS
enabled: yes
gpgcheck: no
- name: set repo2 //定义第二个
yum_repository:
file: server
name: bb
description: bb1
baseurl: file:///mnt/AppStream
enabled: yes
gpgcheck: no
- name: install httpd //为node1安装httpd
yum:
name: httpd
statr: present
- name: create link //将本机的httpd网页存放目录映射为受控机的/www
file:
src: /var/www/html
dest: /www
state: link
name: get file //定义拉取
get_url:
url: http://servera.example.com/index.html
dest: /www
- name: set selinux context //这里由于是映射,需要修改数值
sefcontext:
target: /www/index.html //受控机绝对路径
setype: httpd_sys_content_t //设置的值
- name: apply context //在次刷新数值
shell:
cmd: restorecon -Rv /www/index.html
- name: modify apache config //将其受控主机默认网页访问目录改为自己映射的/www
replace:
path: /etc/httpd/conf/httpd.conf
regexp: DocumentRoot "/var/www/html"
replace: DocumentRoot "/www" //替换
- name: modify apache config2
replace:
path: /etc/httpd/conf/httpd.conf
regexp: <Directory "/var/www">
replace: <Directory "/www">
- name: restart httpd //将apache设为开机自启动
service:
name: httpd
state: restarted
enabled: yes
- name: set firewalld for http //添加http放行防火墙规则
firewalld:
service: httpd
state: enabled
permanent: yes
当运行剧本的时候可能由于我们大意打错了会导致报错
//这时所使用的子目录 -name 就派上用场了(一眼就知道那里错了)
//原来是配置文件中防火墙规则打成httpd了
//成功
这里已经替换掉的默认战点,类似于代理模块
[root@node1 html]# vim /etc/httpd/conf/httpd.conf
DocumentRoot “/www”
<Directory “/www”>
4、 从http://server.example.com/index.html下载至/www
5、 能够访问该web站点,documentroot是/www
[student@server ansible]$ curl http://node1
my name is liutianyang
2、条件判断用法
示例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: //当只有创建第二个user2时notify才会触发handlers程序去执行对应的任务
- file3
handlers: //这里需与第一集目录相对应
- name: file3 //指定file3如果user2创建则触发则执行命令,如果u2不触发则不会运行
file:
path: /tmp/cy1
state: touch
mode: 0644
示例3:
1、 写一个剧本runtime.yml,只对node1操作
2、 创建用户aa,该用户不能用于登录,家目录/www
3、 在/www创建一个文件html
4、 每次执行该剧本时,将系统的当前时间输入到html文件中。
5、 如果html中的时间发生变化,那么创建/tmp/kk的文件
[student@ansible ~/ansible]$cat alone.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
[student@ansible ~/ansible]$ansible-playbook alone.yml
PLAY [time]
********************************************************************************************************
****
TASK [Gathering Facts]
*************************************************************************************************
ok: [node1]
TASK [create user]
*****************************************************************************************************
ok: [node1]
TASK [create file]
*****************************************************************************************************
changed: [node1]
TASK [date]
********************************************************************************************************
****
changed: [node1]
RUNNING HANDLER [kk]
***************************************************************************************************
changed: [node1]
PLAY RECAP
********************************************************************************************************
*****
node1 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0
ignored=
[root@node1 ~]# ls /tmp/
aa
ansible_setup_payload_d9nvajm5
b
d
ggg
hhh
kk
3、tags标签示例
示例:4:
tags用法:给任务打标签,一个任务可以有多个标签,
参数-t
来指定需要指定的任务标签。
tags
l2
l3
一般放在模板命令的最后,运行时可直接调用
注意:
其实ansible还预置了5个特殊的tag,这样可以执行一些命令的时候单独执行
1、always:如果添加此标签,不管是否命令行指定该任务,都执行
tag:
- always
2、never:不执行标签
tag:
- never
3、tagged:在执行时使用 -t tagged 只执行带有标签(tags)的任务
[student@server ansible]$ ansible-playbook aa.yml -t tagged
4、 untagged:在执行时使用 -t untagged 只执行不带标签的任务,包含always标签也执行
[student@server ansible]$ ansible-playbook aa.yml -t untagged
5、all:所有任务都执行,默认标签。
6、自定义字典标签:
可以同时使用多个标签,需要用”,”隔开
–tags package,service playbook.yml
查看tag的标签类型
ansible-playbook –list-tags playbook.yml
//示范
[student@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
只执行l2标签的
[student@server ansible]$ 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
4、template模块
补充:template模块
1、template模块的使用方法和copy模块基本一致,但是copy模块从本地ansible节点复制文件到受控节点时,源文件的内容是什么就是什么,不能发生改变;而使用template模块复制文件时,源文件的内容可以随着受控主机的不同而发生变化。
2、使用template模块在server端写入文件变量时,该文件的扩展名必须为“.j2”。
例题1:创建模板文件html.j2,该文件的内容为
The 【受控主机的hostname】 address is 【IP地址】(需要随着受控主机的不同,文件的内容而发生变化)
每一台主机都会有自己的事实变量
1、编辑文件html.j2
[student@server ansible]$ cat html.j2
the {{ansible_fqdn}} address is {{ansible_ens160.ipv4.address}}
2、撰写playbook,将模板文件复制到受控主机的/tmp/目录下,并重命名为html
[student@server ansible]$ vim a.yml
---
- name: test
hosts: node1,node2
tasks:
- name: cp html.j2
template:
src: /etc/ansible/html.j2
dest: /tmp/html
3、执行该playbook
Ansible-playbook a.yml
4、分别去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 ~]#
6、Copy模块
例题五:
Copy模块:
创建一个名为/home/student/ansible/b.yml的playbook
该playbook在所有的清单主机中运行
该playbook的内容为:
如果将受控主机的/tmp/chenyu文件的内容替换成如下:
在net主机组中的主机上,这行文本显示:chenyu
在hr主机组中的主机上,这行文本显示:cy123
[student@server ansible]$cat hosts
[net]
node1
[hr] //主机组
node2
1、撰写剧本
[student@server ansible]$ vim b.yml
---
- name: test
hosts: all
tasks:
- name: cp file
copy:
content: | //判断当主机显示是那列hosts,则执行命令
{% if "net" in group_names %} //group…内置变量,if 则用来找清单中的主机组
Chenyu //判断成功后则显示文本内容
{% elif "hr" in group_names %}
cy123
{% endif %} //结束
dest: /tmp/chenyu //对受控主机的次目录进行执行
2、执行该剧本
Ansible-playbook b.yml
3、验证:
Node1:
[root@node1 ~]# cat /tmp/chenyu
chenyu
[root@node1 ~]#
Node2:
[root@node2 ~]# cat /tmp/chenyu
cy123
[root@node2 ~]#