02-Ansible-Playbook 剧本编写
1. Playbook 的结构
Ansible 的 Playbook 是一个包含多个 Play 的 YAML 文件,每个 Play 负责对指定的 主机组 执行一系列的任务。Playbook 通常由以下几部分组成:
-
Tasks:任务列表,按顺序执行;
-
Variables:用来存储可变数据的机制,目的是让 Playbook 更灵活、可重用、易维护。也就是 :变量 = 把"硬编码"的值抽出来,变成可以动态替换的占位符;
-
Templates:允许在配置文件中嵌入变量和逻辑,通俗点就是一种动态生成配置文件的机制,它使用 Jinja2 模板引擎,让你可以根据变量、主机信息(facts)、环境差异等,自动生成适合目标主机的配置文件;
-
Handlers:特殊的tasks,仅在被notify触发时执行(看任务执行后的变更),其中notify就相当于改完配置文件后的自动更新;
-
Roles:将相关资源打包成独立的角色,以便下次复用(一个playbook内容包含很多,这时roles就相当于为playbook加了目录,方便快速找到要部署的内容)。
2. Ansible Playbook 示例
下面的示例展示了一个简单的 Playbook,演示了基本的任务执行流程和 Ansible 模块使用。
yaml
vim test1.yaml
--- #yaml文件以---开头,以表明这是一个yaml文件,可省略
- name: first play1 #定义一个play的名称,可省略
gather_facts: false #设置不进行facts信息收集,这可以加快执行速度,可省略
hosts: webservers #指定要执行任务的被管理主机组,如多个主机组用冒号分隔
remote_user: root #指定被管理主机上执行任务的用户
tasks: #定义任务列表,任务列表中的各任务按次序逐个在hosts中指定的主机上执行
- name: test connection #自定义任务名称
ping: #使用 module: [options] 格式来定义一个任务
- name: disable selinux
command: '/sbin/setenforce 0' #command模块和shell模块无需使用key=value格式
ignore_errors: True (如果不加此条出现错误就停止) #如执行命令的返回值不为0,就会报错,tasks停止,可使用ignore_errors忽略失败的任务
- name: disable firewalld
service: name=firewalld state=stopped #使用 module: options 格式来定义任务,option使用key=value格式
- name: install httpd
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf #这里需要一个事先准备好的/opt/httpd.conf文件
notify: "restart httpd" #如以上操作(改配置文件)后为changed(正常)的状态时,会通过notify指定的名称触发对应名称的handlers操作
- name: start httpd service
service: enabled=true name=httpd state=started
handlers: #handlers中定义的就是任务,此处handlers中的任务使用的是service模块
- name: restart httpd #notify和handlers中任务的名称必须一致
service: name=httpd state=restarted
##Ansible在执行完某个任务之后并不会立即去执行对应的handler,而是在当前play中所有普通任务都执行完后再去执行handler,这样的好处是可以多次触发notify,但最后只执行一次对应的handler,从而避免多次重启。

3. 命令行运行 Playbook
在运行 Playbook 时,可以使用一些常用参数来调整执行行为:
bash
ansible-playbook test1.yaml # 运行 playbook
ansible-playbook test1.yaml --syntax-check # 检查语法
ansible-playbook test1.yaml --list-task # 查看任务列表
ansible-playbook test1.yaml --list-hosts # 查看影响的主机
ansible-playbook test1.yaml --start-at-task='install httpd' # 从指定任务开始执行
如果要使用 SSH 密码 或 sudo 密码,可以使用以下选项:
bash
ansible-playbook test1.yaml -k # 提示输入 SSH 密码
ansible-playbook test1.yaml -K # 提示输入 sudo 密码
4. 变量和引用
变量在 Playbook 中非常有用,它们可以通过 vars 或命令行进行定义。
yaml
- name: second play
hosts: dbservers
remote_user: root
vars:
groupname: mysql
username: nginx
tasks:
- name: create group
group: name={{ groupname }} system=yes gid=306
- name: create user
user: name={{ username }} uid=306 group={{ groupname }}
- name:ipv4 copy file
copy: content="{{ ansible_default_ipv4 }}" dest=/opt/ceshi.txt #如果目标路径不存在 在copy模块可以自动创建
在命令行中,变量也可以通过 -e 参数传递:
bash
ansible-playbook test1.yaml -e "username=nginx"
#在目标主机上创建名为 nginx 的用户。
-e 允许你在运行 ansible-playbook 命令时,从命令行直接传入变量,这些变量可以在 Playbook 中使用。
5. 条件判断 when
在Ansible中,提供的唯一一个通用的条件判断是when指令,当when指令的值为true时,则该任务执行,否则不执行该任务。
when 用于根据条件执行任务。它的常见用法包括:
-
根据主机的 IP 地址来执行任务:
yaml//when一个比较常见的应用场景是实现跳过某个主机不执行任务或者只有满足条件的主机执行任务 --- - name: ding shi ren wu hosts: all remote_user: root tasks: - name: shutdown host command: /sbin/shutdown -r now #执行这个任务后,远程主机会立即开始重启流程。 #也可以shutdown -r 20 二十分钟后重启 when: #当任务为真 才能被执行ansible_default_ipv4.address == "192.168.10.14" #仅当远程主机的默认 IPv4 地址是 "192.168.10.14" 时,才执行当前任务。 #when指令中的变量名不需要手动加上 {{}} -
或根据主机名来执行:
yamlwhen: inventory_hostname == "<主机名>"
6. **迭代:使用with_items或loop **
Ansible 支持使用 with_items或 loop 进行迭代。两者作用相同,loop 是较新的推荐用法。
yaml
//Ansible提供了很多种循环结构,一般都命名为with_items,作用等同于 loop 循环。
---
- name: play1
hosts: dbservers
gather_facts: false #关闭 Facts 收集(不自动获取远程主机信息,加快执行速度)
tasks:
- name: create directories
file:
path: "{{item}}"
state: directory
with_items: #等同于 loop:
- /tmp/test1
- /tmp/test2
#在远程主机上创建 /tmp/test1 和 /tmp/test2 两个目录
- name: add users
user: name={{item.name}} state=present groups={{item.groups}}
#分别引用每个用户的名称和所属组
with_items:#也可以使用loop
- name: test1
groups: wheel
- name: test2
groups: root
# 创建 test1 用户,加入 wheel 组
#创建 test2 用户,加入 root 组
dir文件夹
#创建文件,循环列表
vim demo06.yaml
---
- name: test play
hosts: webservers
gather_facts: false 禁用 facts 收集(因为这个任务不需要远程主机的系统信息)
tasks:
- name: create files #创建文件
file:
path: "{{item}}" #直接使用路径字符串
state: touch
with_items:
- /tmp/ryf.txt #具体文件路径
- /tmp/ryc.txt
#创建用户
---
- name: test play
hosts: webservers
gather_facts: false
tasks:
- name: create users
user: #创建用户
name: "{{item.name}}" #指定要创建的用户名,这里通过循环变量 item.name 获取(值为 ryf)
groups: "{{item.groups}}" 指定用户所属的组,通过 item.groups 获取(值为 wheel)
state: present 确保用户存在(如果不存在就创建,存在则不做操作)
with_items: 定义循环列表
- name: ryf
groups: wheel
- name: ryc
groups: root
循环列表中的用户信息,包含用户名 ryf 和所属组 wheel 以及 用户名ryc和所属组 root
7. Templates 模块
Jinja是基于Python的模板引擎。Template类是Jinja的一个重要组件,可以看作是一个编译过的模板文件,用来产生目标文本,传递Python的变量给模板去替换模板中的标记。
Jinja2 模板引擎在 Ansible 中用来动态生成文件。例如,在配置 Apache 时,可以使用模板文件来替换动态值。
- 创建 Jinja 模板文件 (
.j2):
bash
#先准备一个以 .j2 为后缀的 template 模板文件,设置引用的变量
cp /etc/httpd/conf/httpd.conf /opt/httpd.conf.j2
vim /opt/httpd.conf.j2
Listen {{http_port}} #42行,修改
ServerName {{server_name}} #95行,修改
DocumentRoot "{{root_dir}}" #119行,修改
1.定义变量并在主机清单中指定:
ini
#修改主机清单文件,使用主机变量定义一个变量名相同,而值不同的变量
vim /etc/ansible/hosts
(两台机器改两个)
[webservers]
192.168.10.141 http_port=192.168.10.141:80 server_name=www.accp.com root_dir=/var/www/html
-
Playbook 示例:
yamlvim demo07.yaml --- - hosts: webservers remote_user: root vars: package: httpd service: httpd tasks: - name: install httpd package yum: name={{ package }} state=latest - name: install configure file template: src=/opt/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf notify: - restart httpd #重启配置notify - name: create root dir file: path=/var/www/html state=directory #看一下这个httpd路径是不是 要创建的目录路径 - name: start httpd server service: name={{ service }} enabled=true state=started handlers: - name: restart httpd service: name={{service }} state=restarted
ansible-playbook dome07.yaml --syntax-check
8. Tags 模块
Tags 允许你指定只执行某些特定任务。通过命令行传入 --tags 参数来执行带有特定标签的任务。
yaml
\\可以在一个playbook中为某个或某些任务定义"标签",在执行此playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。
playbook还提供了一个特殊的tags为always。作用就是当使用always当tags的task时,无论执行哪一个tags时,定义有always的tags都会执行。
---
- hosts: # 指定目标主机组(在Ansible inventory中定义)
remote_user: # 以root用户身份执行任务
tasks # 任务列表(按顺序执行)
- name: Copy hosts file
copy: src=/etc/hosts dest=/etc/hosts
tags# 标签:仅当指定该标签时才执行此任务
- only
- name: touch file
file: path=/opt/testhost state=touch # 使用file模块,在被控节点的/opt目录下创建testhost空文件
tags:
- always # 始终执行
# 标签:无论是否指定标签,始终执行此任务
执行时指定 --tags 参数:
bash
ansible-playbook webhosts.yaml --tags="only"
9. Roles 模块
9.1 Roles 概念
Roles 数据中心有各种不同类型的主机。如web服务器、数据库服务器,基于开发环境的服务器。随着时间的推移,具有处理所有这些情况的任务和人员的Ansible playbook将变得庞大而复杂。
1)角色允许将复杂的剧本组织成独立的、更小的剧本和文件
2)角色提供了一种从外部文件加载任务、处理程序和变量的方法
3)角色也可关联和引用静态的文件和模板
4)角色可以编写成满足普通用途需求,并且能被重复利用
Ansible为了层次化、结构化地组织Playbook,使用了角色(roles),roles可以根据层次型结构自动装载变量文件、task以及handlers等。简单来讲,roles就是通过分别将变量、文件、任务、模块及处理器放置于单独的目录中,并可以便捷地include它们。roles一般用于基于主机构建服务的场景中,但也可以用于构建守护进程等场景中。
9.2 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 文件,用于定义此角色的特殊设定及其依赖关系。
Roles 是将 Playbook 组织成模块化的结构,使其易于管理和重用。每个 Role 都有一套预定义的目录结构:
roles/
├── web/
│ ├── files/
│ ├── templates/
│ ├── tasks/
│ ├── handlers/
│ ├── vars/
│ ├── defaults/
│ └── meta/
└── db/
├── files/
├── templates/
├── tasks/
├── handlers/
├── vars/
├── defaults/
└── meta/
9.3 在一个 playbook 中使用 roles 的步骤:
-
创建以 roles 命名的目录:
bashmkdir /etc/ansible/roles/ -p #yum装完默认就有 -
创建全局变量目录(可选):
yamlmkdir /etc/ansible/group_vars/ -p touch /etc/ansible/group_vars/all #文件名自己定义,引用的时候注意 -
在 roles 目录中分别创建以各角色名称命令的目录,如 httpd、mysql:
yamlmkdir /etc/ansible/roles/httpd mkdir /etc/ansible/roles/mysql -
在每个角色命令的目录中分别创建files、handlers、tasks、templates、meta、defaults和vars目录,用不到的目录可以创建为空目录,也可以不创建:
mkdir /etc/ansible/roles/httpd/{files,templates,tasks,handlers,vars,defaults,meta} mkdir /etc/ansible/roles/mysql/{files,templates,tasks,handlers,vars,defaults,meta} -
在每个角色的 handlers、tasks、meta、defaults、vars 目录下创建 main.yml 文件,千万不能自定义文件名:
touch /etc/ansible/roles/httpd/{defaults,vars,tasks,meta,handlers}/main.yml touch /etc/ansible/roles/mysql/{defaults,vars,tasks,meta,handlers}/main.yml -
修改 site.yml 文件,针对不同主机去调用不同的角色:
vim /etc/ansible/site.yml --- - hosts: webservers remote_user: root roles: - httpd - hosts: dbservers remote_user: root roles: - mysql -
运行 ansible-playbook:
cd /etc/ansible ansible-playbook site.yml
9.4 案列
9.4.1 创建项目目录
mkdir /etc/ansible/roles/httpd/{files,templates,tasks,handlers,vars,defaults,meta} -p
mkdir /etc/ansible/roles/mysql/{files,templates,tasks,handlers,vars,defaults,meta} -p
mkdir /etc/ansible/roles/php/{files,templates,tasks,handlers,vars,defaults,meta} -p
touch /etc/ansible/roles/httpd/{defaults,vars,tasks,meta,handlers}/main.yml
touch /etc/ansible/roles/mysql/{defaults,vars,tasks,meta,handlers}/main.yml
touch /etc/ansible/roles/php/{defaults,vars,tasks,meta,handlers}/main.yml
tree roles/
9.4.2 编写httpd模块
vim /etc/ansible/roles/httpd/tasks/main.yml
- name: install apache
yum: name={{pkg}} state=latest
# 确保安装最新版本(若已安装则更新到最新
- name: start apache
service: enabled=true name={{svc}} state=started # 设置开机自启 # 确保服务处于启动状态(若已停止则启动)
//定义变量:可以定义在全局变量中,也可以定义在roles角色变量中,一般定义在角色变量中
vim /etc/ansible/roles/httpd/vars/main.yml
pkg: httpd
svc: httpd
9.4.3 编写mysql模块
vim /etc/ansible/roles/mysql/tasks/main.yml
- name: install mysql
yum: name={{pkg}} state=latest
- name: start mysql
service: enabled=true name={{svc}} state=started
vim /etc/ansible/roles/mysql/vars/main.yml
pkg:
- mariadb
- mariadb-server
svc: mariadb
9.4.4 编写php模块
vim /etc/ansible/roles/php/tasks/main.yml
- name: install php
yum: name={{pkg}} state=latest
- name: start php-fpm
service: enabled=true name={{svc}} state=started
vim /etc/ansible/roles/php/vars/main.yml
pkg:
- php
- php-fpm
svc: php-fpm
9.4.5 编写roles
vim /etc/ansible/site.yml
#site.yml 自定义 #放主机名、用户、模块
---
- hosts: webservers
remote_user: root
roles:
- httpd
- mysql
- php
cd /etc/ansible
ansible-playbook site.yml
roles 把剧本分解成多个较小的模块 每个角色各司其职 用什么功能就去相对应的模块
创建七个文件夹(files\tasks\vars\templates\handlers\defaults\depencies) 他们的功能就是ansible下边模块的功能(command\shell\cron\user\group\copy\file\hostname\ping\yum\service/systomd\scriipt\setup)
roles #site.yml 自定义 #放主机名、用户、模块