ansible playbook基础
ansible playbook基础
相关文档:
https://docs.ansible.com/ansible/latest/(更新更详细)
playbook简介和运行
ad-hoc(点对点模式)每次只能执行一个任务,又不能持久化使用,只适合执行一些临时的简单任务。
使用ansible做自动化的是它的灵魂,playbook,就如同saltstack的.sls状态文件一样。
ansible的playbook也叫剧本
- playbook是一个文本文件,其中包含由一个或多个按特定顺序运行的play组成的列表。
- 剧本中包含多个任务
- YAML格式书写,随时调用
- 根据编写的方式记录任务所需步骤,适合执行复杂任务
运行playbook
absible-playbook命令可用于运行playbook。该命令在控制节点上执行,要运行的playbook的名称则作为参数传递。
ansible-playbook site.yml
在运行playbook时,将生成输出来显示所执行的play和任务。输出中也会报告执行的每一项任务的结果。
#输出示例
[root@ansible ~]# ansible-playbook test.yaml
PLAY [webserver] ************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************
ok: [nginx]
ok: [apache]
ok: [tomcat]
TASK [this is my first playbook] ********************************************************************************
ok: [apache]
ok: [nginx]
ok: [tomcat]
PLAY RECAP ******************************************************************************************************
apache : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
nginx : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
tomcat : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
请注意,在playbook运行时,屏幕中会显示每个play和任务的name键的值。(Gathering Facts任务是一项特别的任务,setup模块通常在play启动时自动运行这项任务。)对于含有多个play和任务的playbook,设置name属性后可以更加轻松地监控playbook执行的进展。
通常而言,Ansible Playbook中的任务是幂等的,而且能够安全地多次运行playbook。如果目标受管主机已处于正确的状态,则不应进行任何更改。如果再次运行这个playbook,所有任务都会以状态OK传递,且不报告任何更改。
输出的详细程度
ansible-playbook命令提供的默认输出不提供详细的任务执行信息。ansible-playbook -v命令提供了额外的信息,总共有四个级别。
配置Playbook执行的输出详细程序
选项 | 描述 |
---|---|
-v | 显示任务结果 |
-vv | 任务结果和任务配置都会显示 |
-vvv | 包含关于与受管主机连接的信息 |
-vvvv | 增加了连接插件相关的额外详细程序选项,包括受管主机上用于执行脚本的用户以及所执行的脚本 |
语法检查
在执行playbook之前,最好要进行验证,确保其内容的语法正确无误。ansible-playbook命令提供了一个--syntax-check选项,可用于验证playbook的语法。
语法检查正确时:
[root@ansible ~]# ansible-playbook --syntax-check test.yaml
playbook: test.yaml
语法检查到错误时:
[root@ansible ~]# ansible-playbook --syntax-check test.yaml
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: No JSON object could be decoded
Syntax Error while loading YAML.
mapping values are not allowed in this context
The error appears to be in '/root/test.yaml': line 3, column 8, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- hosts:webserver
tasks:
^ here
#yaml语法错误,hosts:后少一个空格
空跑
尝试运行,不会在受控机器上做任何更改
可以使用-C选项对playbook执行空运行。这会使Ansible报告在执行该playbook时将会发生什么更改,但不会对受管主机进行任何实际的更改。
下例演示了一个playbook的空运行,它包含单项任务,可确保在受管主机上安装了最新版本的httpd软件包。注意该空运行报告此任务会对受管主机产生的更改。
ansible-playbook -C webserver.yml
playbook的元素
- Hosts 执行的远程主机列表
- Tasks 任务集
- Varniables 内置变量或自定义变量在playbook中调用
- Templates 模板,即使用模板语法的文件,比如配置文件等
- Handlers 和notity结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
- tags 标签,指定某条任务执行,用于选择运行playbook中的部分代码。
还有用户元素,很少使用,
指定用户
---
- hosts: 192.168.1.31
remote_user: root
除了上面的定义外,还可以在某一个tasks
中定义要执行该任务的远程用户
tasks:
- name: run df -h
remote_user: test
shell: name=df -h
还可以定义使用sudo
授权用户执行该任务
tasks:
- name: run df -h
sudo_user: test
sudo: yes
shell: name=df -h
playbook的语法
语法格式:
-
使用yaml编写
-
playbook文件有一个和多个play组成
-
每个play中可以包含:
hosts(主机)、tasks(任务)
variables(变量)、roles(角色)、handlers等元素组成
hosts由一个或多个组或者主机组成,逗号分隔
tasks由一个或多个任务组成,多个任务按顺序执行
-f 自定义并发量,默认5
[root@ansible ~]# cat test.yaml
---
- hosts: all
tasks:
- name: this is my first playbook
ping:
- name: touch a file
shell:
cmd: touch a.txt
#执行
[root@ansible ~]# ansible-playbook test.yaml
PLAY [all] ******************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************
ok: [tomcat]
ok: [nginx]
ok: [apache]
TASK [this is my first playbook] ********************************************************************************
ok: [nginx]
ok: [tomcat]
ok: [apache]
TASK [touch a file] *********************************************************************************************
changed: [apache]
changed: [nginx]
changed: [tomcat]
PLAY RECAP ******************************************************************************************************
apache : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
nginx : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
tomcat : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
指定执行play的目标主机
1.直接使用主机名或组名,多个用逗号隔开(或者冒号)
hosts: webserver
hosts: nginx,apache
hosts: all
2.使用组的索引来精确到组中某个主机
hosts: webserver[0] #索引从0开始,-1是最后一个
3.范围表示
hosts: webserver[1:2] #webserver组的第2和第3个主机
#也可以字母
hosts: webserver[A:F] #webserverA-webserverF的主机
4.使用通配符
#匹配web开头的主机或主机组
hosts: web*
5.使用正则表达式,~
放在开头用来表示使用正则
hosts: ~(web|db)server
6.&
和 !
pattern前面加一个&符号表示取交集
pattern1:&pattern2
#要求同时存在于pattern1和pattern2中的主机
pattern前面加一个!符号表示排除
pattern1:!pattern2
#要求出现在pattern1中但未出现在pattern2中
tasks 任务列表和 gather_facts
http://ansible.com.cn/docs/playbooks_intro.html#tasks
tasks指令用来指定这个play中包含的任务,可以是一个或多个任务,任务也需要放在play的数组中,所以tasks指令内使用- xxx:
的方式来表示每一个任务
gather_facts
是一个play级别的指令设置,它是一个负责收集目标主机信息的任务,由setup模块提供。默认情况下,每个play都会先执行这个特殊的任务,收集完信息之后才开始执行其它任务。但是,收集目标主机信息的效率很低,如果能够确保playbook中不会使用到所收集的信息,可以显式指定gather_facts: no
来禁止这个默认执行的收集任务,这对效率的提升是非常可观的。
此外每个play和每个task都可以使用name指令来命名,也建议尽量为每个play和每个task都命名,且名称具有唯一性。
例如:
---
- hosts: nginx
gather_facts: false
tasks:
- copy: src=/etc/passwd dest=/tmp
加上name
---
- name: first play
hosts: nginx
gather_facts: false
tasks:
- name: copy /etc/passwd to /tmp
copy: src=/etc/passwd dest=/tmp
每一个task
必须有一个名称name
,这样在运行playbook
时,能从输出信息中明确辨别是属于哪一个task
的,如果没有定义 name
,action
的值将会用作输出信息中标记特定的task
。
tasks:
- name: create new file
file: path=/tmp/test01.txt state=touch
- name: create new user
user: name=tom state=present
每一个playbook
中可以包含一个或者多个tasks
任务列表,每一个tasks
中多个动作组合完成具体的一件事,,在hosts
中定义的主机或者主机组都将会执行这个被定义的tasks
。
示例:
---
- name: play to setup web server
hosts: webservers
tasks:
- name: latest httpd version installed
yum:
name: httpd
state: latest
- name: service is enabled
service:
name: httpd
enabled: true
Handlers与Notify
http://ansible.com.cn/docs/playbooks_intro.html#handlers
官方文档资料更全:https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html
handler,用来执行某些条件下的任务,比如当配置文件发生变化的时候,通过notify触发处理程序去重启服务。
注意:
- handlers和tasks是同级别的
- notify在tasks的下级
- notify可以指定handlers的name或者listen(一般用name)
- meta: flush_handlers 想立即执行所有的 handler 命令
示例:
当apache配置文件发生改变时,notify语句显示调用处理程序restart apache
---
- hosts: localhost
tasks:
- name: copy configuratioon
template:
src: /root/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart apache
handlers:
- name: restart apache
service:
name: httpd
state: restarted
上面的例子中,restart apache处理程序只有在template任务通知已发生更改时才会触发。一个任务可以在其notify部分中调用多个处理程序。Ansible将notify语句视为数组,并且迭代处理程序名称:
---
- hosts: localhost
tasks:
- name: copy configuratioon
template:
src: /root/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart apache
- restart redis
handlers:
- name: restart apache
service:
name: httpd
state: restarted
- name: restart redis
service:
name: redis
state: restarted
多个paly
Playbook是一个YAML文件,含有由一个或多个play组成的列表。记住一个play按顺序列出了要对清单中的选定主机执行的任务。因此,如果一个playbook中有多个play,每个play可以将其任务应用到单独的一组主机。
在编排可能涉及对不同主机执行不同任务的复杂部署时,这会大有帮助。我们可以这样进行编写:对一组主机运行一个play,完成后再对另一组主机运行另一个play。
缩写包含多个play的playbook非常简单。Playbook中的各个play编写为playbook中的顶级列表项。各个play是含有常用play关键字的列表项。
以下示例显示了含有两个play的简单playbook。第一个play针对10.11.114.65运行,第二个play则针对10.11.114.66运行。
---
# This is a simple playbook with two plays
- name: first play
hosts: 10.11.114.65
tasks:
- name: first task
yum:
name: httpd
status: present
- name: second task
service:
name: httpd
enabled: true
- name: second play
hosts: 10.11.114.66
tasks:
- name: first task
service:
name: mariadb
enabled: true
playbook中模块的参数传递
用 copy模块做示例:
tasks:
- name: copy /etc/passwd to /tmp
copy: src=/etc/passwd dest=/tmp
键值对形式和使用arg传递
---
- name: first play
hosts: nginx
gather_facts: false
tasks:
- name: copy1
copy:
src: /etc/passwd
dest: /tmp
- name: copy2
copy:
args:
src: /etc/passwd
dest: /tmp
怎样书写都可以,但要追求简洁、易读、美观
关于变量的简单使用
一些简单的变量使用,不包含jinja和条件控制等
定义变量
子母数字下划线组成,子母开头。
可以在Ansible项目中的多个位置定义变量。不过,这些变量大致可简化为三个范围级别:
- 全局范围:从命令行或Ansible配置设置的变量
- Play范围:在play和相关结构中设置的变量
- 主机范围:由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量
更细的也可以在任务中取细分,但都遵循范围越小,优先级越高。
如果在多个相同名称的变量,则采用优先级别最高的变量。窄范围优先于更广泛的范围:由清单定义的变量将被playbook定义的变量覆盖,后者将被命令行中定义的变量覆盖。
如从inventory、role、play、task、block、facts的信息变量等等
命令行传入指定变量
执行playbook时-e传入变量,属于全局的变量,在整个playbook都可以使用。
清单变量可被playbook中设置的变量覆盖,这两种变量又可通过在命令行中传递参数到ansible或ansible-playbook命令来覆盖。在命令行上设置的变量称为额外变量。
当需要覆盖一次性运行的playbook的变量的已定义值时,额外变量非常有用。
# 定义单个变量
[root@ansible ~]# ansible-playbook -e 'var1="value1"' xxx.yml
# 定义多个变量
[root@ansible ~]# ansible-playbook -e 'var1="value1" var2="value2"' xxx.yml
# 引入单个变量文件
[root@ansible ~]# ansible-playbook -e '@varfile1.yml' xxx.yml
# 引入多个变量文件
[root@ansible ~]# ansible-playbook -e '@varfile1.yml' -e '@varfile2.yml' xxx.yml
小示例:
[root@ansible ~]# cat var.yaml
---
- hosts: all
tasks:
- name: install pkg
yum: name={{ pkg }}
[root@ansible ~]# ansible-playbook -e "pkg=wget" var.yaml
hosts中主机和主机组变量(inventory变量)
也就是在清单文件中定义变量
直接应用于主机的清单变量分为两在类:
- 主机变量,应用于特定主机
- 组管理,应用于一个主机组或一组主机组中的所有主机
主机变量优先于组变量,但playbook中定义的变量的优先级比这两者更高。
若要定义主机变量和组变量:
一种方法是直接在清单文件中定义
还有一种是和前面清单文件一样,用目录的形势
清单文件中定义
由于默认配置在/etc/ansible/hosts
文件中,
示例:
# 编辑hosts文件定义变量
[root@ansible ~]# vim /etc/ansible/hosts
[apache]
10.11.114.65 webdir=/opt/test #定义单个主机的变量
10.11.114.66
[apache:vars] #定义整个组的统一变量
webdir=/web/test
[nginx]
10.100.21.1[1:5]
[nginx:vars]
webdir=/opt/web
# 编辑playbook文件
[root@ansible ~]# cat variables.yml
---
- hosts: all
tasks:
- name: create webdir
file: name={{ webdir }} state=directory #引用变量
# 执行playbook
[root@ansible ~]# ansible-playbook variables.yml
分文件定义 Host 和 Group 变量
http://ansible.com.cn/docs/intro_inventory.html#host-group
例子:
[root@ansible project]# pwd
/root/project
[root@ansible project]# tree
.
├── group_vars
│ └── webserver
├── host_vars
│ └── nginx
├── inventory
└── playbook.yaml
[root@ansible project]# cat ~/project/group_vars/webserver
dir_name: /tmp/webserver_test
[root@ansible project]# cat ~/project/host_vars/nginx
dir_name: /tmp/nginx_test
[root@ansible project]# cat ~/project/inventory
[webserver]
nginx ansible_ssh_host=10.11.114.65
apache ansible_ssh_host=10.11.114.66
tomcat ansible_ssh_host=10.11.114.67
[webserver:vars]
ansible_ssh_port=22
ansible_ssh_user=root
ansible_ssh_pass=123456
#playbook中,变量位于开头元素时一定要加引号,除非是下面这种等号方式
[root@ansible project]# cat ~/project/playbook.yaml
---
- hosts: all
gather_facts: false
tasks:
- name: create dir
file:
# file: name={{ dir_name }} state=directory
path: "{{ dir_name }}"
state: directory
#nginx主机中将会创建/tmp/nginx_test,其他则创建/tmp/webserver_test
[root@ansible project]# ansible-playbook -i inventory playbook.yaml
playbook中使用变量
编写playbook时,可以定义自己的变量,然后在任务中调用这些值。例如,名为web_package的变量可以使用值httpd来定义。然后,任务可以使用yum模块调用该变量来安装httpd软件包。
Playbook变量可以通过多种方式定义。一种常见的方式是将变量放在playbook开头的vars块中:
- hosts: all
vars:
user: joe
home: /home/joe
也可以在外部文件中定义playbook变量。此时不使用playbook中的vars块,可以改为使用vars_files指令,后面跟上相对于playbook位置的外部变量文件名称列表:
- hosts: all
vars_files:
- vars/users.yml
而后,可以使用YAML格式在这一/这些文件中定义playbook变量:
user: joe
home: /home/joe
示例:
引用变量就是将变量名放在双大括号内。在任务执行时,Ansible会将变量替换为其值。
---
- hosts: all
gather_facts: false
vars:
user: tom
tasks:
- name: create a user
user:
name: "{{ user }}"
注意:当变量用作开始一个值的第一元素时,必须使用引号。这可以防止Ansible将变量引用视为YAML字典的开头。
使用来自gather_facts的变量
http://ansible.com.cn/docs/playbooks_variables.html?highlight=facts#facts
https://www.cnblogs.com/shipment/p/15555335.html#setup模块
也就是使用setup模块的变量
示例:
---
- hosts: all
tasks:
- name: create a file
file: name={{ ansible_hostname }}.txt state=touch
playbook中标签的使用
playbook中可以对每个任务集打标签(tags)
执行的时候可以通过-t
选择指定标签执行
还可以通过--skip-tags
选择除了某个标签外全部执行等。
示例:
---
- hosts: localhost
tasks:
- name: task1
file: name=t1.txt state=touch
tags: t1
- name: task2
file: name=t2.txt state=touch
tags: t2
#只运行t1标签的tasks
[root@ansible ~]# ansible-playbook -t t1 var.yaml
运行方式和执行策略
-f并发连接数
在配置文件中有一项配置forks,默认值是5
[root@ansible ~]# grep 'fork' /etc/ansible/ansible.cfg
#forks = 5
forks的值也代表了最多有几个节点同时执行任务,每个节点默认对应一个ansible-playbook进程和ssh进程,
默认的forks是5,运行一个playbook对10台主机操作,查看一下进程
[root@ansible ~]# pstree -c | grep ansible
| |-sshd-+-bash---ansible-playboo-+-ansible-playboo---sshpass---ssh
| | | |-ansible-playboo---sshpass---ssh
| | | |-ansible-playboo---sshpass---ssh
| | | |-ansible-playboo---sshpass---ssh
| | | |-ansible-playboo---sshpass---ssh
| | | `-{ansible-playboo}
#有6个进程,其中父进程是ansible的主控进程,负责监控fork出的子进程
#如果由于连接失败或者执行某个任务失败,则该节点不会执行当前paly的后续任务,但是仍会执行后续play
也就是说:
forks=5是指同时有5个节点执行任务,可能有的节点执行的快,有的执行的慢。比如上例的10个节点,第一批同时执行5个,当某个执行的快,已经完成返回退出时。ansible的主控进程会在开一个进程,让第6个主机执行,也不是去等待其它节点执行完毕。始终保持有5个进程在工作。