playbook概念
playbook是由一个或多个“play” 组成的列表
play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。 Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
Playbook采用YAML语言编写
YAML介绍
YAML是一个可读性高的用来表达资料序列的格式。 YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。 Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者.
YAML Ain’t Markup Language,即YAML不是XML。不过,在开发的这种语言时,YAML的意思其实是:”Yet Another Markup Language”(仍是一种标记语言)
特性
YAML的可读性好
YAML和脚本语言的交互性好
- YAML使用实现语言的数据类型
- YAML有一个一致的信息模型
- YAML易于实现
- YAML可以基于流来处理
- YAML表达能力强,扩展性好
YAML语法简介
在单一档案中,可用连续三个连字号(—)区分多个档案。另外,还有选择性的连续三个点号( … )用来表示档案结尾
次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
- 使用#号注释代码
- 缩进必须是统一的,不能空格和tab混用
- 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
- YAML文件内容是区别大小写的,k/v的值均需大小写敏感
- k/v的值可同行写也可换行写。同行使用:分隔
- v可是个字符串,也可是另一个列表
- 一个完整的代码块功能需最少元素需包括 name: task
- 一个name只能包括一个task
- YAML文件扩展名通常为yml或yaml
List:列表,其所有元素均使用“-” 打头
示例:
1 | # A list of tasty fruits |
Dictionary:字典,通常由多个key与value构成
示例:
1 | --- |
也可以将key:value放置于{}中进行表示,用,分隔多个key:value
示例:
1 | --- |
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用”-“来代表,Map里的键值对用”:”分隔
示例1
2
3
4
5
6
7
8
9
10
11
12
13
14name: John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age: 37
gender: Female
children:
- name: Jimmy Smith
age: 17
gender: Male
- name: Jenny Smith
age 13
gender: Female
Playbook核心元素
- Hosts 执行的远程主机列表
- Tasks 任务集
- Varniables 内置变量或自定义变量在playbook中调用
- Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers 和notity结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
- tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。 ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
1
ansible-playbook –t tagsname useradd.yml
playbook基础组件
Hosts
playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。 hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
可以是如下形式:1
2
3
4one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
Websrvs:dbsrvs 或者,两个组的并集
Websrvs:&dbsrvs 与,两个组的交集
webservers:!phoenix 在websrvs组,但不在dbsrvs组
示例: - hosts: websrvs:dbsrvs
remote_user
用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户1
2
3
4
5
6
7
8- hosts: websrvs
remote_user: root
tasks:
- name: test connection
ping:
remote_user: magedu
sudo: yes 默认sudo为root
sudo_user:wang sudo为wang
task列表和action
play的主体部分是task list。 task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后,再开始第二个任务
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出
tasks:任务列表
两种格式:
- action: module arguments
- module: arguments 建议使用
注意:shell和command模块后面跟命令,而非key=value
任务可以通过”tags“打标签,可在ansible-playbook命令上使用-t指定进行调用
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16tasks:
- name: disable selinux
command: /sbin/setenforce 0
如果命令或脚本的退出码不为零,可以使用如下方式替代
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
或者使用ignore_errors来忽略错误信息
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
运行playbook的方式
ansible-playbook <filename.yml> … [options]
常见选项:
–check -C 只检测可能会发生的改变,但不真正执行操作
–list-hosts 列出运行任务的主机1
2
3
4
5
6
7
8
9[root@centos7 playbook]#ansible-playbook test.yml --list-hosts
playbook: test.yml
play #1 (appsrvs): appsrvs TAGS: []
pattern: [u'appsrvs']
hosts (2):
192.168.183.132
192.168.183.129
–list-tags 列出tag1
2
3
4
5
6[root@centos7 playbook]#ansible-playbook test.yml --list-tags
playbook: test.yml
play #1 (appsrvs): appsrvs TAGS: []
TASK TAGS: []
–list-tasks 列出task1
2
3
4
5
6
7[root@centos7 playbook]#ansible-playbook test.yml --list-tasks
playbook: test.yml
play #1 (appsrvs): appsrvs TAGS: []
tasks:
first task TAGS: []
second task TAGS: []
–limit 主机列表 只针对主机列表中的主机执行1
[root@centos7 playbook]#ansible-playbook test.yml --limit 192.168.183.129
-v -vv -vvv 显示过程
Playbook示例
安装httpd,并且开机启动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[root@cetos7 ~]#vim /etc/ansible/hosts
##[dbservers]
##db01.intranet.mydomain.net
##db02.intranet.mydomain.net
##10.25.1.56
##10.25.1.57
# Here's another example of host ranges, this time there are no
# leading 0s:
## db-[99:101]-node.example.com
[appsrvs] #添加分组
192.168.183.132
192.168.183.129
~
"/etc/ansible/hosts" 50L, 1100C 47,0-1 Bot
[root@centos7 playbook]#vim httpd.yml
---
- hosts: appsrvs
remote_user: root
tasks:
- name: creat group
group: name=apache system=yes gid=80
- name: creat user
user: name=apache group=apache uid=80 shell=/sbin/nologin home=/usr/share/httpd system=yes password='$1$MrKn.0gj$CvMvkger.03UzBwQIrya.0'
- name: install package
yum: name=httpd
- name: config file
copy: src=/root/playbook/httpd.conf dest=/etc/httpd/conf/ backup=yes
- name: service
service: name=httpd state=started enabled=yes
~
[root@centos7 playbook]#ansible-playbook httod.yml
handlers和notify结合使用触发条件
Handlers
是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作
Notify
此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操 作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称handler,也即notify中调用handler中定义的操作
如果httpd.conf文件内容修改了再运行一遍httpd.yml,只有config file发生改变,其他任务不会继续做了,所以把上述的playbook改写一下,加上notify和handlers:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22[root@centos7 playbook]#vim httpd.yml
---
- hosts: appsrvs
remote_user: root
tasks:
- name: creat group
group: name=apache system=yes gid=80
- name: creat user
user: name=apache group=apache uid=80 shell=/sbin/nologin home=/usr/share/httpd system=yes password='$1$MrKn.0gj$CvMvkger.03UzBwQIrya.0'
- name: install package
yum: name=httpd
- name: config file
copy: src=/root/playbook/httpd.conf dest=/etc/httpd
notify: restart service
/conf/ backup=yes
- name: service
service: name=httpd state=started enabled=yes
handlers:
- name: restart service
service: name=httpd state=restart
[root@centos7 playbook]#ansible-playbook httod.yml
如果我们httpd端口80 改成8080,再运行一遍`ansible-playbook`时,这时就只会触发重启httpd服务
Playbook中tags使用
1 | [root@centos7 playbook]#vim httpd.yml |
给playbook打上tags我们就可以单独的执行tags的那部分tasks
[root@centos7 playbook]#ansible-playbook -t install httpd.yml
仅仅执行了安装httpd
Playbook中变量使用
变量来源:
- ansible setup facts 远程主机的所有变量都可直接调用
在/etc/ansible/hosts中定义
普通变量:主机组中主机单独定义,优先级高于公共变量
公共(组)变量:针对主机组中所有主机定义统一变量通过命令行指定变量,优先级最高
ansible-playbook –e varname=value
在playbook中定义
1
2
3vars:
- var1: value1
- var2: value2在独立的变量YAML文件中定义
- 在role中定义
变量命名
变量名仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:key=value
示例:http_port=80
变量调用方式
通过 调用变量,且变量名前后必须有空格,有时用“”才生效
ansible-playbook –e 选项指定
1 ansible-playbook test.yml -e “hosts=www user=magedu”
示例
使用setup变量
示例:var.yml1
2
3
4
5
6
7- hosts: websrvs
remote_user: root
tasks:
- name: create log file
file: name=/var/log/ {{ ansible_fqdn }} state=touch
ansible-playbook var.yml
变量
示例:var.yml1
2
3
4
5
6
7
8
9
10
11
12
13- hosts: websrvs
remote_user: root
vars:
- username: user1
- groupname: group1
tasks:
- name: create group
group: name={{ groupname }} state=present
- name: create user
user: name={{ username }} state=present
ansible-playbook var.yml
ansible-playbook -e "username=user2 groupname=group2” var2.yml
- 主机变量
可以在inventory中定义主机时为其添加主机变量以便于在playbook中使用
示例:1
2
3[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909
- 组变量
组变量是指赋予给指定组内所有主机上的在playbook中可用的变量
示例:1
2
3
4
5
6[websrvs]
www1.magedu.com
www2.magedu.com
[websrvs:vars]
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com
普通变量
1
2
3[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2公共(组)变量
1
2
3
4
5
6
7[websvrs:vars]
http_port=808
mark=“_”
[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2
ansible websvrs –m hostname –a 'name={{ hname }}{{ mark }}{{ http_port }}'命令行指定变量:
1
ansible websvrs –e http_port=8000 –m hostname –a 'name={{ hname }}{{ mark }}{{ http_port }}'
模板templates
- 文本文件,嵌套有脚本(使用模板编程语言编写)
Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, …]
元组:(item1, item2, …)
字典:{key1:value1, key2:value2, …}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and, or, not
流表达式:For If Whentemplates功能:根据模块文件动态生成对应的配置文件
- templates文件必须存放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下:
1
2
3
4./
├── temnginx.yml
└── templates
└── nginx.conf.j2Playbook中template变更替换
- Playbook中template算术运算
Templates示例
利用templates 同步nginx配置文件,并修改配置文件nginx.conf1
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89[root@centos7 playbook]#mkdir templates
[root@centos7 playbook]#mv nginx.conf templates/nginx.conf.j2
[root@centos7 playbook]#tree
.
├── test_templ.yml
├── templates
└── nginx.conf.j2
[root@centos7 playbook]#vim test_templ.yml
---
- hosts: appsrvs
remote_user: root
tasks:
- name: install
yum: name=nginx
- name: template
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart
- name: service
service: name=nginx state=started enabled=yes
handlers:
- name: restart
service: name=nginx state=restarted
[root@centos7 playbook]#ansible-playbook test_templ.yml
.........省略结果
[root@centos7 playbook]#ansible appsrvs -a 'ss -ntlp' #查看80端口是否开启
[root@centos7 playbook]#ansible appsrvs -m shell -a 'ps axu | grep nginx'
192.168.183.137 | CHANGED | rc=0 >>
root 16688 0.0 0.1 120812 2228 ? Ss 21:15 0:00 nginx: master process /usr/sbin/nginx
nginx 16689 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
nginx 16690 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
root 16755 0.0 0.0 113172 1196 pts/1 S+ 21:15 0:00 /bin/sh -c ps axu | grep nginx
root 16757 0.0 0.0 112704 940 pts/1 S+ 21:15 0:00 grep nginx
192.168.183.136 | CHANGED | rc=0 >>
root 18759 0.0 0.1 122924 2100 ? Ss 20:46 0:00 nginx: master process /usr/sbin/nginx
nginx 18760 0.0 0.1 125472 3540 ? S 20:46 0:00 nginx: worker process
root 36053 0.0 0.0 113128 1196 pts/1 S+ 21:15 0:00 /bin/sh -c ps axu | grep nginx
root 36055 0.0 0.0 112664 948 pts/1 S+ 21:15 0:00 grep nginx
[root@centos7 playbook]#ansible appsrvs -m shell -a 'ps axu | grep nginx'
192.168.183.137 | CHANGED | rc=0 >>
root 16688 0.0 0.1 120812 2228 ? Ss 21:15 0:00 nginx: master process /usr/sbin/nginx
nginx 16689 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
nginx 16690 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
root 16755 0.0 0.0 113172 1196 pts/1 S+ 21:15 0:00 /bin/sh -c ps axu | grep nginx
root 16757 0.0 0.0 112704 940 pts/1 S+ 21:15 0:00 grep nginx
192.168.183.136 | CHANGED | rc=0 >>
root 18759 0.0 0.1 122924 2100 ? Ss 20:46 0:00 nginx: master process /usr/sbin/nginx
nginx 18760 0.0 0.1 125472 3540 ? S 20:46 0:00 nginx: worker process
root 36053 0.0 0.0 113128 1196 pts/1 S+ 21:15 0:00 /bin/sh -c ps axu | grep nginx
root 36055 0.0 0.0 112664 948 pts/1 S+ 21:15 0:00 grep nginx
[root@centos7 playbook]#ansible appsrvs -m setup -a 'filter=ansible_processor_count'
192.168.183.136 | SUCCESS => {
"ansible_facts": {
"ansible_processor_count": 1
},
"changed": false
}
192.168.183.137 | SUCCESS => {
"ansible_facts": {
"ansible_processor_count": 2
},
"changed": false
}
worker process 与 CPU数量一致
[root@centos7 playbook]#vim templates/nginx.conf.j2
.....省略.....
worker_processes {{ ansible_processor_count*2 }}; #Playbook中template算术运算
.....省略.....
[root@centos7 playbook]#ansible appsrvs -m shell -a 'ps axu | grep nginx'
192.168.183.136 | CHANGED | rc=0 >>
root 18759 0.0 0.1 122924 2100 ? Ss 20:46 0:00 nginx: master process /usr/sbin/nginx
nginx 18760 0.0 0.1 125472 3540 ? S 20:46 0:00 nginx: worker process
nginx 18761 0.0 0.1 125472 3540 ? S 20:46 0:00 nginx: worker process
root 36485 0.0 0.0 113128 1196 pts/1 S+ 21:36 0:00 /bin/sh -c ps axu | grep nginx
root 36487 0.0 0.0 112664 944 pts/1 S+ 21:36 0:00 grep nginx
192.168.183.137 | CHANGED | rc=0 >>
root 16688 0.0 0.1 120812 2228 ? Ss 21:15 0:00 nginx: master process /usr/sbin/nginx
nginx 16689 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
nginx 16690 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
nginx 16691 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
nginx 16692 0.0 0.1 123360 3524 ? S 21:15 0:00 nginx: worker process
root 17220 0.0 0.0 113172 1200 pts/1 S+ 21:36 0:00 /bin/sh -c ps axu | grep nginx
root 17222 0.0 0.0 112704 940 pts/1 S+ 21:36 0:00 grep nginx
when
条件测试:如果需要根据变量、 facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法
格式
when语句
在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法
示例: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[root@centos7 playbook]#tree templates/
templates/
├── httpd6.conf.j2
└── httpd7.conf.j2
[root@centos7 playbook]#vim httpd.yml
---
- hosts: appsrvs
remote_user: root
tasks:
- name: install
yum: name=httpd
- name: template1
template: src=httpd6.conf.j2 dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version=="6"
notify: restart
- name: template2
template: src=httpd7.conf.j2 dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version=="7"
notify: restart
- name: service
service: name=httpd state=started enabled=yes
handlers:
- name: restart
service: name=httpd state=restart
迭代:with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”item”
要在task中使用with_items给定要迭代的元素列表
列表格式:字符串
字典
示例:1
2
3
4
5- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
迭代嵌套子变量
例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15- hosts:websrvs
remote_user: root
tasks:
- name: add groups
group: name={{ item }}
with_items:
- group1
- group2
- group3
- name: add users
user: name={{ item.name }} group={{ item.group }}
with_items:
- { name: 'user1', group: 'group1' }
- { name: 'user2', group: 'group2' }
- { name: 'user3', group: 'group3' }
roles
ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。
复杂场景:建议使用roles,代码复用度高
变更指定主机或主机组
如命名不规范维护和传承成本大
某些功能需多个Playbook,通过includes即可实现
角色(roles):角色集合
roles/
mysql/
httpd/
nginx/
memcached/
roles目录结构
每个角色,以特定的层级目录结构进行组织
roles目录结构:
playbook.yml
roles/
project/
tasks/
files/
vars/
templates/
handlers/
default/ 不常用
meta/ 不常用
Roles各目录作用
/roles/project/ :项目名称,有以下子目录
files/ :存放由copy或script模块等调用的文件
templates/:template模块查找所需要模板文件的目录
tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
vars/:定义变量,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
default/:设定默认变量时使用此目录中的main.yml文件
创建role
创建role的步骤
- 创建以roles命名的目录
- 在roles目录中分别创建以各角色名称命名的目录,如webservers等
- 在每个角色命名的目录中分别创建files、 handlers、 meta、 tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建
- 在playbook文件中,调用各角色
针对大型项目使用Roles进行编排
1 | [root@centos7 playbook]#mkdir roles |