ansible(二)—— playbook
playbooks是 一个不同于使用Ansible命令行执行方式的模式,其功能更强大灵活。简单来说,playbook是一个非常简单的配置管理和多主机部署系统,不同于任何已经存在的模式,可作为一个适合部署复杂应用程序的基础。Playbook可以定制配置,可以按照指定的操作步骤有序执行,支持同步和异步方式。值得注意的是playbook是通过YAML格式来进行描述定义的。
一、playbook核心
Tasks:任务,由模板定义的操作列表
Variables:变量
Templates:模板,即使用模板语法的文件
Handlers:处理器 ,当某条件满足时,触发执行的操作
Roles:角色
---
- name: My playbook # playbook 名
hosts: all #指定主机
remote_user: root #指定在被管理的主机上执行任务的用户
tasks: #任务列表↓
- name: Leaving a mark #任务名
command: "touch /tmp/ansible_was_here" #调用command模块 执行命令
notify:
- restart httpd
- name: start httpd #任务名
service: name=httpd state=started #调用service模块 开启httpd 服务
handlers:
- name: restart httpd
service: name=httpd state=retarted
ansible-playbook a.yml --syntax-check # 检查yaml文件的语法是否正确
ansible-playbook a.yml # 执行playbook
二、tasks
-
task列表中的各任务按次序逐个在hosts中指定的主机上执行,即在每一个主机上完成第一个任务后再开始第二个任务。
在运行playbook时(从上到下执行),如果一个host执行task失败,整个tasks都会回滚,请修正playbook 中的错误,然后重新执行即可。 -
每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个task的。如果没有定义name,
action
的值将会用作输出信息中标记特定的task。 -
大部分 module 都是使用 key=value 来定义参数,但是有 2 个特别的 module: command和 shell,它们不使用 Key=value 格式
三、Variables
任何变量都将覆盖任何playbook关键字,任何命令行选项以及任何配置设置。定义变量可在task中引用,引用变量用{{}}
1、在yaml中定义变量
- hosts: vpc
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd package
yum: name={{package}} state=latest
- name: install cfg file
copy: src=/opt/httpd.cfg dest=/etc/httpd/httpd.cfg
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{service}} state=started
handlers:
- name: restart httpd
service: name={{service}} state=restarted
2、引用主机变量
变量可以在/etc/ansible/hosts
中定义,
# vim /etc/ansible/hosts
[vpc]
192.168.136.180 testvar=httpd
- hosts: vpc
remote_user: root
tasks:
- name: install httpd package
yum: name={{testvar}} state=latest
四、templates
Jinja是基于Python的模板引擎。template类是Jinja的另一个重要组件,可以看作一个编译过的模块文件,用来生产目标文本,传递Python的变量给模板去替换模板中的标记
-
templates文件必须存放于templates目录下,且命名为".j2"结尾,yaml/yml文件需要和templates目录平级,这样我们在yml文件中调用模板的时候,就不需要写模板文件的路径,否则需要描述模板文件的路径,因为template模块会自动去找templates目录下的模板文件
-
template模板去动态生成的配置文件,不是拷贝,拷贝是将文件原封不动的拷贝过去
-
定义模板
# vim templates/httpd.conf.j2 Listen {{http_port}} ServerName {{server_name}} MaxClients {{access_num}}
-
在
/etc/ansible/hosts
中添加变量[vpc] 192.168.136.180 http_port=80 server_name="localhost" access_num=100
-
利用templates同步
- hosts: vpc remote_user: root tasks: - name: install httpd yum: name=httpd - name: template config to remote hosts template: src=httpd.conf.j2 dest=/etc/httpd/httpd.conf
五、Handlers
Handlers 也是一些 task 的列表,通过名字来引用,它们和一般的 task 并没有什么区别。
Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行。不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次。
最佳的应用场景是用来重启服务,或者触发系统重启操作。除此以外很少用到了。
- notify后面使用的是handlers的name
六、roles
官方文档: https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需在playbook中使用include指定即可。
roles就是通过分别将变量、文件、任务、模板以及处理器放置于单独目录中,并可以便捷的使用include指令将他们组织在一块的一种机制。角色一般用于基于主机构建服务的场景中,但也可以用于构建守护进程等场景中。复杂场景建议使用roles,代码复用度高。
---
- hosts: websers
remote_user: root
roles:
- roles_name
1、目录结构
- roles是依赖目录的命名和摆放,默认
tasks/main.yml
是所有任务的入口,所以使用roles的过程可以理解为目录规范化命名的过程。每个目录下均由main.yml定义该功能的任务集,tasks/main.yml
默认执行所有指定的任务。
site.yml
webservers.yml
fooservers.yml
roles/
common/
tasks/
handlers/
library/
files/
templates/
vars/
defaults/
meta/
webservers/
tasks/
defaults/
meta/
files/
目录主要存放copy或scripts模块等调用的文件;templates/
目录主要存放template模块查找所需要的模板文件;tasks/
定义task,role的基本元素,至少应该包含一个名为main.yml
的文件(tasks目录的入口文件),其他的文件需要在此文件中通过include进行包含handlers/
目录主要存放触发器任务的yml文件,同样它里面至少需要有一个main.yml的入口文件,其文件内容通过include指令引用其下文件;vars/
目录主要存放定义的变量文件,同样也需要有main.yml文件;meta/
目录定义当前角色的特殊设定以及依赖关系,同样这个目录也需要有一个main.yml的入口文件;default/
设定默认变量时使用此目录中的main.yml文件;
2、roles目录配置
roles目录可以摆放在/etc/ansible/ansible.cfg
中roles_path
定义路径,也可以和入口playbook文件存放在同级目录,ansible没有强制的要求,但还是建议将代码存放在代码集预先规划的目录,以便管理
3、创建角色
- 创建以
roles
命名的目录 - 在
roles
目录中分别创建以各自角色名称命名的目录,如nginx等 - 在每个角色命名的目录中分别创建
files
、handlers
、meta
、tasks
、templates
、和vars
目录;若角色用不到的目录可以是空目录,也可以不创建 - 在playbook文件中,调用各角色
4、示例
1)普通版
$ tree
.
├── install_nginx.yml
# cat install_nginx.yml
---
- hosts: vpc
remote_user: root
tasks:
- name: install nginx
shell: rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
- name: install nginx
shell: yum install -y nginx
notify: restart nginx
handlers:
- name: restart nginx
service: name=nginx state=started
2)roles版
$ tree
.
├── install_nginx.yml
└── roles
└── nginx
├── handlers
│ ├── main.yaml
│ └── start_nginx.yml
└── tasks
├── add_rpm.yaml
├── install_nginx.yaml
└── main.yaml
$ cat tasks/add_rpm.yaml
- name: add rpm
shell: rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
#############################################################
$ cat tasks/install_nginx.yaml
- name: install nginx
shell: yum install -y nginx
notify: start nginx
#############################################################
$ cat tasks/main.yaml
- include: add_rpm.yaml
- include: install_nginx.yaml
#############################################################
$ cat handlers/start_nginx.yml
- name: start nginx
service: name=nginx state=started
#############################################################
$ cat handlers/main.yaml
- include: start_nginx.yml
#############################################################
$ cat install_nginx.yml
---
- hosts: vpc
remote_user: root
roles:
- nginx
七、其它
1、条件判断
- when的值是一个条件表达式,如果条件判断成立,这个task就执行,如果判断不成立,则task不执行
- 如果需要根据变量、facts(setup)或此前任务的执行结果来作为某task执行与否的前提时要用到条件测试,在Playbook中条件测试使用when子句。
- 在task后添加when子句即可使用条件,when子句支持jinjia2表达式或语法
# 满足系统为CentOS 7 或 Ubuntu 18时,执行关机命令
- hosts: vpc
remote_user: root
tasks:
- name: "shutdown"
command: shutdown -h now
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
(ansible_distribution == "Ubuntu" and ansible_distribution_major_version == "18")