linux-ansible-04 ansible-playbook

linux-ansible-04 ansible-playbook

概念解析

playbook

  Playbooks俗称”剧本“,是一种高效运用Ansible的方式,也是系统ansible命令的集合。playbook利用yaml语言编写,其命令根据自上而下的顺序依次执行。
  简单来说,Playbooks 是一种简单的配置管理系统与多机器部署系统的基础。与现有的其他系统有不同之处,且非常适合于复杂应用的部署。

  同时,Playbooks开创了很多特性,它可以允许你传输某个命令的状态到后面的指令,如你可以从一台机器的文件中抓取内容并附为变量,然后在另一台机器中使用,这使得你可以实现一些复杂的部署机制,这是ansible命令无法实现的。

  Playbooks可用于声明配置,更强大的地方在于,在Playbooks中可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤。并且可以同步或异步的发起任务。

  我们完成一个任务,例如安装部署一个httpd服务,我们需要多个模块(一个模块也可以称之为task)提供功能来完成。而playbook就是组织多个task的容器,他的实质就是一个文件,有着特定的组织格式,它采用的语法格式是YAML(Yet Another Markup Language)。YAML语法能够简单的表示散列表,字典等数据结构,详情可参考:YAML详细语法

YAML

  YAML是“YAML不是一种标记语言”的外语缩写,又被称为“另外一种标记语言”,但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用返璞词重新命名。它是一种直观的能够被电脑识别的数据序列化格式,是一个可读性高并且容易被人类阅读,容易和脚本语言交互,用来表达资料序列的编程语言。

playbook基础组件

Hosts:运行执行任务(task)的目标主机
remote_user:在远程主机上执行任务的用户
tasks:任务列表,由模块定义的操作列表
handlers:任务,和nogity结合使用,为条件触发操作,满足条件方才执行,否则不执行;与tasks不同的是只有在接受到通知时才会被触发。
templates:使用模板语言的文本文件,使用jinja2语法。
variables:变量,变量替换{{ variable_name }},内置变量或自定义变量在playbook中调用
roles: 角色

  整个playbook是以task为中心,表明要执行的任务;hosts和remote_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
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template: #作用:将变量在远程主机上变成指定的值,应用变量传参
src: /srv/httpd.j2 #源文件必须以j2结尾
dest: /etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service:
name: httpd
state: started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
1
2
3
4
5
6
7
运行:
-t Tag 指定运行特定的任务
--skip-tags=SKIP_TAGS 跳过指定的标签
--start-at-task=START_AT 从哪个任务后执行

使用 -e选项传入参数,例如:
ansible-playbook 192.168.200.136 -e "httpd_port=808" httpd04.yml

实例解析

webservers是官方对其管理机所管理服务器的统称,我们这里用的是node。

vars: #在playbook中定义变量
http_port: 80
max_clients: 200

变量的引用:

变量

变量的来源:

  • ansible setup facts远程主机的所有变量都可以用
  • 自定义变量

优先级:

  • 通过命令行指定变量,优先级最高
  • 在/etc/ansible/hosts 定义变量,在主机组中的主机单独定义
  • 在/etc/ansible/hosts 定义变量,针对主机组中的所有主机集中定义变量
  • 在Playbook中定义变量(建议使用这种方法)

模版

  • 使用模板语言的文本文件内部嵌套有模板语言脚本(使用模板语言编写)
  • Jinja2 是由python编写的。在我们打算使用基于文本的模板语言时,jinja2是很好的解决方案。yaml是写playbook,jinja2是写配置文件模板的。
  • 功能:将模板的文件的变量值转换成对应的本地主机的确定值。例如:ansible端写一个内建变量,当这个文件被复制到对应主机时会自动生成对应主机 cpu的颗数的结果替换之。
    • templates文件必须存放在templates目录下
    • yaml文件需要和templates目录平级
  • template只能在palybook中使用。
  • Jinja2语法
1
2
3
4
5
6
7
8
9
10
11
12
字面量:
字符串:使用单引号或双引号;
数字:整数、浮点数;
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:
+, -, *, /, //, %, **
比较操作:
==, !=, >, <, >=, <=
逻辑运算:and, or, not

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@node1 templates]# cat nginxconf.j2.bak 
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost }}
# listen {{ vhost.listen }}
}
{% endfor %}
worker_processes {{ ansible_processor_vcpus }};
[root@node1 tmp]# cat nginxtemp.yam
- hosts: mageduweb
remote_user: root
vars:
nginx_vhosts:
- web1
- web2
- web3
# nginx_vhosts:
# - listen: 8080
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

条件判断

一般通过when或者迭代循环

1
2
3
- name: restart Nginx
service: name=nginx state=restarted
when: ansible_distribution_major_version == "6"

循环迭代

迭代列表或者键值对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#基于字符串列表
tasks:
- name: create rsyncd file
copy: src={{ item }} dest=/tmp/{{ item }}
with_items:
- a
- b
- c
- d
*with_itmes 嵌套子变量*
#基于字典列表
- hosts: eagleslab
remote_user: root
tasks:
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1' , groups: 'wheel'}
- { name: 'testuser2' , groups: 'root' }

角色roles

1
2
3
4
5
6
7
8
9
10
[root@node1 ~]# tree /etc/ansible/roles/
/etc/ansible/roles/
└── http
├── defaults
├── files
├── headlers
├── meta
├── tasks
├── template
└── varsfiles/:存储由copy或script等模块调用的文件;
  • tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行“包含”调用;
  • handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;其它的文件需要由main.yml进行“包含”调用;
  • vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable;其它的文件需要由main.yml进行“包含”调用;
  • templates/:存储由template模块调用的模板文本;
  • meta/:此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行“包含”调用;
  • default/:此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;
  • files目录:存放由copy或script等模块调用的文件;

调用roles

1
2
3
4
5
[root@node1 ~]# cat /etc/ansible/roles/site.yml
- hosts: abc
remote_user: root
roles:
- 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
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
[root@node1 ansible]# tree roles/
roles/
├── http
│ ├── defaults
│ │ └── main.yaml
│ ├── files
│ │ └── index.html
│ ├── headlers
│ │ └── main.yaml
│ ├── meta
│ │ └── main.yaml
│ ├── tasks
│ │ └── main.yaml
│ ├── templates
│ │ └── httpd.conf.j2
│ └── vars
│ └── main.yaml
└── site.yaml
[root@node1 roles]# cat site.yaml
- hosts: node2
remote_user: root
# vars:
# httpd_ports: 8080
roles:
- http
[root@node1 http]# cat files/index.html
hello eagleslab!
[root@node1 http]# cat tasks/main.yaml
- name: installed httpd service
yum: name=httpd state=latest
when: ansible_os_family == "RedHat"
- name: start httpd server
service: name=httpd state=restarted
- name: write httpd config
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: config httpd index
copy: src=index.html dest=/var/www/html/index.html
[root@node1 http]# cat templates/httpd.conf.j2 | grep -Ev "^[[:space:]]|^#"
ServerRoot "/etc/httpd"
Listen {{ httpd_ports }}
Include conf.modules.d/*.conf
User apache
Group apache
ServerAdmin root@localhost
<Directory />
</Directory>
DocumentRoot "/var/www/html"
<Directory "/var/www">
</Directory>
<Directory "/var/www/html">
</Directory>
<IfModule dir_module>
</IfModule>
<Files ".ht*">
</Files>
ErrorLog "logs/error_log"
LogLevel warn
<IfModule log_config_module>
</IfModule>
<IfModule alias_module>
</IfModule>
<Directory "/var/www/cgi-bin">
</Directory>
<IfModule mime_module>
</IfModule>
AddDefaultCharset UTF-8
<IfModule mime_magic_module>
</IfModule>
EnableSendfile on
IncludeOptional conf.d/*.conf
[root@node1 http]# cat headlers/main.yaml
- name: restart httpd
service: name=httpd state=restarted
[root@node1 http]# cat vars/main.yaml
httpd_ports: 8000

任务tasks

执行的模块命令

1
2
3
4
5
6
7
8
9
10
11
12
13
格式:
action:模块参数(此种方式只在较新的版本中出现)
module:参数(已键值对的形式出现)

每一个task都有一个名称,用于标记此任务。任务示例:
name: install httpd
yum: name=httpd state=present

注意:shell和command没有参数,可在后面直接跟命令
shell: ss -tnl | grep :80

(1)某任务的运行状态为changed后,可通过相应的notify通知相应的handlers
(2)任务可以通过tags打标签,然后通过palybook命令-t选项调用.

playbook调用方式

1
2
3
4
5
6
7
8
9
10
11
用法:
ansible-playbook <filename.yml> ... [options]

<filename.yml>:yaml格式的playbook文件路径,必须指明
[options]: 选项
-C, --check:并不在远程主机上执行,只是测试。
-i PATH, --inventory=PATH:资产的文件路径
--flush-cache:清楚fact缓存
--list-hosts:列出匹配的远程主机,并不执行任何动作
-t, TAGS, --tags=TAGS:运行指定的标签任务
--skip-tags:跳过指定的notify,后面详细介绍。

palybook实验

实验准备

下述实验环境和之前的一样,无需改动即可。

在服务端安装ansible

1
2
[root@localhost ~]# yum install epel-release -y
[root@localhost ~]# yum install ansible -y

服务端修改主机清单配置文件host

1
2
3
4
5
6
7
[root@localhost ~]# vim /etc/ansible/hosts

#在文档末尾加上一下这几行

[node]
node2
node3

服务端修改host文件

1
2
3
4
5
6
[root@localhost ~]# vim /etc/hosts

#在文档中加入下列两行

192.168.141.53 node2
192.168.141.69 node3

通过playbook添加用户示例

(1)给远程主机node3添加用户test

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@test ~]# vim user.yml
[root@test ~]# cat user.yml
- hosts: node3
remote_user: root
gather_facts: False
vars:
- user: test
tasks:
- name: create user
user: name={{ user }}
[root@test ~]# ansible-playbook user.yml

PLAY [node3] *********************************************************************************************************

TASK [create user] ***************************************************************************************************
changed: [node3]

PLAY RECAP ***********************************************************************************************************
node3 : ok=1 changed=1 unreachable=0 failed=0

[root@test ~]# ansible node3 -a "id test"
node3 | CHANGED | rc=0 >>
uid=1000(test) gid=1000(test) groups=1000(test)

[root@test ~]#

上面的playbook 实现的功能是新增一个用户:

1
2
3
4
5
6
name:对该playbook实现的功能做一个概述,后面执行过程中,会打印name变量的值
hosts:指定了对哪些主机进行参作
remote_user:指定了使用什么用户登录远程主机操作
gather_facts:指定了在以下任务部分执行前,是否先执行setup模块获取主机相关信息,这在后面的task会使用到setup获取的信息时用到
vars:指定了变量,这里指定了一个user变量,其值为test,需要注意的是,变量值一定要用引号引起来
tasks:指定了一个任务,其下面的name参数同样是对任务的描述,在执行过程中会打印出来。user提定了调用user模块,name是user模块里的一个参数,而增加的用户名字调用了上面user变量的值

(2)删除远程主机test的账号
只需改一行:

user: name=”“ state=absent remove=yes

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
[root@test ~]# vim user.yml
[root@test ~]# cat user.yml
- hosts: node3
remote_user: root
gather_facts: False
vars:
- user: test
tasks:
- name: create user
user: name={{ user }} state=absent remove=yes
[root@test ~]# ansible node3 -a "id test"
node3 | CHANGED | rc=0 >>
uid=1000(test) gid=1000(test) groups=1000(test)

[root@test ~]# ansible-playbook user.yml

PLAY [node3] *********************************************************************************************************

TASK [create user] ***************************************************************************************************
changed: [node3]

PLAY RECAP ***********************************************************************************************************
node3 : ok=1 changed=1 unreachable=0 failed=0

[root@test ~]# ansible node3 -a "id test"
node3 | FAILED | rc=1 >>
id: test: no such usernon-zero return code

[root@test ~]#
欢迎打赏,谢谢
------ 本文结束------
0%