Playbook简介
Playbooks与Ad-Hoc相比,是一种完全不同的运用Ansible的方式,而且是非常之强大的;也是系统ansible命令的集合,其利用yaml语法编写,运行过程,ansbile-playbook命令根据自上而下的顺序
依次执行任务。playbook 由一个或多个 ‘plays’ 组成.它的内容是一个以 ‘plays’为元素的列表,在 play 之中,一组机器被映射为定义好的角色.在 ansible 中,play 的内容,被称为 tasks,即任务.在基本层次的应用中,一个任务是一个对 ansible模块的调用。当第一个任务依次在所有主机上执行完毕后,开始执行第二个任务。如果某个主机执行时发生错误,则所有操作将会回滚。
Playbook基础组件
hosts
:运行执行任务(task)的目标主机remote_user
:在远程主机上执行任务的用户tasks
:任务列表handlers
:任务,与tasks不同的是只有在接受到通知时才会被触发templates
:使用模板语言的文本文件,使用jinja2语法。variables
:变量,变量替换{{ variable_name }}tag
:标签,为某tasks指定标签,运行该标签可以即运行特定的tasks,定义为always的tag总会执行when
: 条件判断,当条件成立则执行tasks,不成立不执行表达式 判断表达式如:not
or
and
!=
=
with_items
:循环迭代需要重复执行的任务列表,用{item}}
引用列表值
例如一个简单的playbook文件:
---
- hosts: test # 指定运行任务的主机组
remote_user: root # 指定远程执行任务的用户
vars: # 指定变量
- bsh: b.sh
- httprpm: httpd
task: # 任务的开始
- name: install httpd # 一个安装httpd的任务
yum: name={{ httprpm }} state=present # ansible的yum模块
tags: install_httpd # 为该任务打一个install_httpd的标签
- name: copy b.sh # 又一个复制b.sh脚本的任务
copy: src=/root/{{ bsh }} dest=/root/ owner=ala group=ala mode=0644
notify: # 如果copy的文件内容发生改变就会触发
- reload httpd # 指定通知的哪个handlers
when: ansible_distribution == "CentOS" # 通过变量判断系统为CentOS时才执行该copy任务
- name: copy b.sh
copy: src=/root/{{ bsh }} dest=/opt/ owner=ala group=ala mode=0644
notify:
- reload httpd
when: ansible_distribution == "Ubuntu" # 通过变量判断系统为Ubuntu时才执行该copy任务
- name: start httpd # 又一个启动httpd服务的任务
service: name=httpd state=started enabled=yes
handlers: # 满足触发条件则执行的任务
- name: reload httpd # 满足触发条件的任务名
service: name=httpd state=reloaded # 该任务为重新加载一下httpd服务
其中的
ansible_distribution
是ansible收集的facts变量。
playbook定义变量
ansible 常见定义变量有以下 6 种
- /etc/ansible/hosts文件主机中定义
- /etc/ansible/hosts/文件主机组中定义
- playbook的yaml文件中通过vars定义
- 获取系统变量,也称facts变量
- 分文件定义主机和主机组的变量
- playbook 的role中定义
# /etc/ansible/hosts文件主机中定义 主机变量
192.168.200.136 http_port=808 maxRequestsPerChild=808
192.168.200.137 http_port=8080 maxRequestsPerChild=909
# /etc/ansible/hosts文件主机中定义 主机组变量
[websers]
192.168.200.136
192.168.200.137
[websers:vars]
ntp_server=ntp.exampl.com
proxy=proxy.exampl.com # ntp_server和proxy变量可为websers组中主机使用
# playbook的yaml文件中通过vars定义
---
- hosts: test
remote_user: root
vars: # 定义bsh和httprpm的两个变量
- bsh: b.sh
- httprpm: httpd
# 获取系统facts变量
ansible 192.168.200.136 -m setup # 可以获取主机所有的facts变量,通过{{variable_name}}引用
# 分文件定义主机和主机组的变量
/etc/ansible/group_vars/websers # 定义主机组名为websers的变量文件
/etc/ansible/host_vars/hostpc # 定义主机名为hostpc的变量文件
$ cat /etc/ansible/host_vars/hostpc # 变量文件内容格式如下
---
ntp_server: acme.example.org
database_server: storage.example.org
# role中定义 (目录结构下文讲述)
$ cat /etc/ansible/roles/nginx/vars/main.yml
---
nginx_port: 80
nginx_domain: www.abc.com
nginx_user: nginx
playbook roles目录结构
Roles简介
Ansible为了层次化、结构化地组织Playbook,使用了角色(roles)。Roles能够根据层次型结构自动装载变量文件、task及handlers等。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include它们,roles一般用于基于主机构建服务的场景中,但也可以用于构建守护进程等场景中。
创建Roles
创建roles时一般需要以下步骤:首先创建以roles命名的目录。然后在roles目标下分别创建以这个角色名称命令的目录,如websevers等,然后在每个角色命令的目录中分别创建files、handlers、tasks、templates、meta、defaults和vars目录,用不到的目录可以创建为空目录。最后在Playbook文件中调用各角色进行使用。
可以使用命令快捷创建
$ ansible-galaxy init websevers
roles内各目录含义解释
files
:用来存放由copy模块或script模块调用的文件。templates
:用来存放jinjia2模板,template模块会自动在此目录中寻找jinjia2模板文件。tasks
:此目录应当包含一个main.yml文件,用于定义此角色的任务列表,此文件可以使用include包含其它的位于此目录的task文件。handlers
:此目录应当包含一个main.yml文件,用于定义此角色中触发条件时执行的动作。vars
:此目录应当包含一个main.yml文件,用于定义此角色用到的变量。defaults
:此目录应当包含一个main.yml文件,用于为当前角色设定默认变量。meta
:此目录应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系。
如下定义了一个nginx服务的playbook目录结构树。
[root@k8s-master1 roles]# tree /etc/ansible/roles/nginx
/etc/ansible/roles/nginx
├── defaults
│ └── main.yml
├── files
│ └── nginx.tar.gz
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
│ └── nginx.conf.j2
│ └── default.conf.j2
└── vars
└── main.yml
创建和使用角色
需求
- 1、创建名为 apache 的角色
- 2、httpd软件包已安装,设为在系统启动时启用
- 3、防火墙已启用并正在运行,并使用允许访问 Web 服务器的规则
- 4、模板文件 index.html.j2 已存在,用于创建具有以下输出的文件 /var/www/html/index.html:
- Welcome to HOSTNAME on IPADDRESS
- 其中,HOSTNAME 是受管节点的完全限定域名,IPADDRESS 则是受管节点的 IP 地址。
- 5、按照下方所述,创建一个使用此角色的 playbook /home/ansible/ansible/newrole.yml
- 该 playbook 在 webservers 主机组中的主机上运行
实例环境
主机名 | IP | 系统 | 角色 |
---|---|---|---|
ansible | 192.168.20.210 | rhel8.6 | ansible控制器 |
servera | 192.168.20.211 | rhel8.6 | web服务器1 |
serverb | 192.168.20.212 | rhel8.6 | web服务器2 |
环境准备
每台web服务器创建用户,并设置sudo提权
$ useradd devops
$ echo redhat | passwd --stdin devops
$ echo 'devops ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/devops
控制器创建普通用户并设置免密登录
$ useradd ansible
$ echo redhat | passwd --stdin ansible
$ ssh-keygen
$ ssh-copy-id devops@servera
$ ssh-copy-id devops@serverb
配置ansible环境
$ su - ansible
$ mkdir -p ansible/role
$ cd ansible
# 定义主机清单
$ vim inventory
[webserver]
servera
serverb
$ cp /etc/ansible/ansible.cfg .
$ vim ansible.cfg
# 修改如下内容
[defaults]
inventory = /home/ansible/ansible/inventory # 定义主机清单文件
remote_user = devops # 定义远程用户
roles_path = /home/ansible/ansible/roles # 定义roles路径
[privilege_escalation] # 这是一个标签,表示以下配置属于权限提升设置。
become=True # 表示允许在执行任务时进行权限提升。
become_method=sudo # 表示使用sudo命令进行权限提升。
become_user=root # 表示在进行权限提升后,用户身份将切换为root。
become_ask_pass=False # 表示在执行权限提升操作时,不需要输入root用户的密码。
创建角色
$ ansible-galaxy init apache
定义tasks任务
$ vim apache/tasks/main.yml
---
# tasks file for apache
- name: install http # 第一个任务名称
yum: # 模块名称
name: httpd # 要安装的软件名称
state: present # 模块选项
- name: config system service # 第二个任务名称
service: # 模块名称
name: "{{ item }}" # 要开机自启的软件名称
state: started # 模块选项,表示启动
enabled: yes # 模块选项,表示启用开机自启
loop: # 表示一个循环。它用于遍历一个序列
- httpd
- firewalld
- name: firewalld service # 第三个任务名称
firewalld: # 模块名称
zone: public # 开放区域
service: http # 开放service
permanent: yes # 是否永久生效
immediate: yes # 是否立即生效
state: enabled # 启动并运行
- name: use templates # 第四个任务名称
template: # 模块名称
src: index.html.j2 # 源文件
dest: /var/www/html/index.html # 目标文件
定义模版文件
$ vim apache/templates/index.html.j2
# ansible_fqdn和ansible_default_ipv4.address都来源于ansible内置变量,可以通过setup模块获取
Welcome to {{ ansible_fqdn }} on {{ ansible_default_ipv4.address }}
# setup示例
$ ansible node01 -m setup -a "filter=ansible_default_ipv4"
node01 | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "10.0.1.204",
"alias": "ens192",
"broadcast": "10.255.255.255",
"gateway": "10.0.1.1",
"interface": "ens192",
"macaddress": "00:50:56:84:f7:a4",
"mtu": 1500,
"netmask": "255.0.0.0",
"network": "10.0.0.0",
"prefix": "8",
"type": "ether"
},
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
定义role入口文件
$ vim newrole.yml
- name: use apache role
hosts: webservers
roles:
- apache
playbook语法检测
$ ansible-playbook --syntax-check newrole.yaml
playbook: newrole.yml
运行playbook
$ ansible-playbook newrole.yaml
验证安装结果
$ curl serverc
Welcome to servera.lab.example.com on 192.168.20.211
$ curl serverd
Welcome to serverb.lab.example.com on 192.168.20.212
playbook条件判断
在 Ansible Playbook 中,条件判断的基本语法是使用 when
关键字来控制任务的执行。例如:
- name: install software
yum:
name: software
state: present
when: ansible_os_type == 'redhat'
在这个例子中,when
关键字后面的表达式 ansible_os_type == 'redhat'
表示只有当受管节点的操作系统类型为 Red Hat 时,才会执行 install software
任务。
在 Ansible Playbook 中,可以使用变量来控制条件判断。例如:
- name: install software
yum:
name: software
state: present
when: ansible_os_type == 'redhat'
vars:
software_version: '7.0'
在这个例子中,software_version
变量被定义在 vars
关键字后面,表示安装的软件版本为 7.0。在 when
关键字后面的表达式中,可以使用 software_version
变量来控制任务的执行。
同样也可以使用ansible内置变量来控制条件判断。比如:
- name: create lv 600m
lvol:
vg: research
lv: data
size: 600m
when: "'research' in ansible_lvm.vgs"
在这个例子中,当research
vg存在时,则执行创建lv步骤。
playbook任务控制
在 Ansible Playbook 中,block
、rescue
和 always
是三个常用的关键字,用于控制任务的执行流程。
block
关键字用于定义一个任务块,包含多个任务。在任务块中,可以使用 rescue
关键字来定义一个救援块,用于处理任务执行过程中可能出现的错误。always
关键字用于定义一个总是在任务块中执行的任务。
例如,下面是一个使用 block
、rescue
和 always
的 Playbook 示例:
---
- hosts: all
vars:
software_version: '7.0'
tasks:
- name: install software
yum:
name: software
state: present
when: ansible_os_type == 'redhat' and software_version == '7.0'
block:
- name: install additional software
yum:
name: additional_software
state: present
when: ansible_os_type == 'redhat' and software_version == '7.0'
rescue:
- AnsibleError
msg: "Error installing software"
always:
- name: restart services
service:
name: httpd
state: restarted
在这个例子中,install software
任务只有在受管节点的操作系统类型为 Red Hat,并且软件版本为 7.0 时才会执行。在任务块中,install additional software
任务只有在 install software
任务成功执行后才会执行。如果 install additional software
任务执行过程中出现错误,可以使用 rescue
关键字来定义一个救援块,处理错误。always
关键字用于定义一个总是在任务块中执行的任务,例如在这个例子中,restart services
任务总是在任务块中执行,无论前面的任务是否成功执行。
block
、rescue
和 always
是 Ansible Playbook 中常用的关键字,用于控制任务的执行流程,提高 Playbook 的可读性和可维护性。
本文介绍了 Ansible Playbook 的基本概念、组件、目录结构和创建使用方法。通过使用 Playbook,可以更方便地管理和维护多个服务器。同时,Playbook 也提供了更高级的特性,如条件判断、循环迭代等,能够满足更复杂的需求。