【自动化部署】Ansible Playbook 基础应用
文章目录
- Ansible Playbook
- 基础示例
- Playbook 结构
- 运行 Playbook
- 定义和引用变量
- 指定远程主机sudo切换用户
- when条件判断
- Ansible Playbook 迭代功能
- `with_items` 循环结构
- 创建文件(Play 1)
- 创建目录(Play 2)
- 添加用户(Play 3)
- 执行 Playbook
- Tags 与 Templates 模块
- Tags 模块
- Templates 模块
- Ansible Roles 模块
- Roles 简介
- Roles 的目录结构
- 在 Playbook 中使用 Roles
- 示例
- 编写httpd、mysql、php模块的 roles
- 1. 创建 httpd 模块
- 2. 创建 mysql 模块
- 3. 创建 php 模块
- 4. 编写 site.yml 以使用这些 roles
- 注意
Ansible Playbook
Ansible Playbook 是 Ansible 的核心功能之一,它允许你以声明性的方式定义一系列的任务(tasks),这些任务将被应用到一组主机(hosts)上。Playbook 提供了强大的灵活性,可以组织复杂的自动化任务,包括配置管理、应用部署、服务编排等。
基础示例
vim test1.yaml
--- #yaml文件以---开头,以表明这是一个yaml文件,可省略
- name: first play #定义一个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,从而避免多次重启。
Playbook 结构
-
Playbook 文件头
---
:YAML 文件的标准开头,表明这是一个 YAML 格式的文件。
-
Play 定义
- name: first play
:定义这个 play 的名称,便于日志记录和调试。gather_facts: false
:指定不收集目标主机的系统信息(facts),这可以加快执行速度。hosts: webservers
:指定这个 play 将要应用到的主机组。remote_user: root
:指定在目标主机上执行命令的用户。
-
Tasks(任务)
- 每个任务都包含一个
name
和一个或多个模块调用。 ping:
:使用ping
模块检查主机的可达性。command: '/sbin/setenforce 0'
:使用command
模块执行命令,这里用于禁用 SELinux。ignore_errors: True
:忽略命令执行失败的情况,继续执行后续任务。service: name=firewalld state=stopped
:使用service
模块停止firewalld
服务。yum: name=httpd state=latest
:使用yum
模块安装或更新httpd
到最新版本。copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
:使用copy
模块复制配置文件到目标主机。notify: "restart httpd"
:如果任务导致状态改变(changed),则触发名为restart httpd
的 handler。service: enabled=true name=httpd state=started
:确保httpd
服务启动并设置为开机自启。
- 每个任务都包含一个
-
Handlers(处理器)
- Handlers 类似于任务,但只在被
notify
触发时执行。 restart httpd
:使用service
模块重启httpd
服务。
- Handlers 类似于任务,但只在被
运行 Playbook
直接运行 Playbook
ansible-playbook test1.yaml
-k
或--ask-pass
:提示输入 SSH 密码。-K
或--ask-become-pass
:提示输入 sudo 密码。-u
:指定远程执行的用户。
附加参数和命令
ansible-playbook test1.yaml --syntax-check #检查yaml文件的语法是否正确
ansible-playbook test1.yaml --list-task #检查tasks任务
ansible-playbook test1.yaml --list-hosts #检查生效的主机
ansible-playbook test1.yaml --start-at-task='install httpd' #指定从某个task开始运行
--syntax-check
:检查 Playbook 的语法是否正确。--list-tasks
:列出 Playbook 中的所有任务。--list-hosts
:列出 Playbook 将要应用到的主机。--start-at-task='install httpd'
:从指定的任务开始执行 Playbook。
注意
- 错误处理:使用
ignore_errors
可以忽略任务失败,但应谨慎使用,因为它可能掩盖了重要的问题。 - Handlers 的执行时机:Handlers 在当前 play 的所有任务执行完毕后统一执行,这有助于避免不必要的重复操作(如多次重启服务)。
- 安全性:在生产环境中,应避免使用
root
用户执行 Playbook,而是使用具有必要权限的最小权限用户。
定义和引用变量
在Ansible Playbook中,变量用于存储和管理在执行任务时需要用到的数据。变量的定义和引用如下:
- 定义变量:在
vars
部分,可以定义一系列的变量。每个变量都有一个键(key)和一个值(value)。vars: - groupname: mysql - username: nginx
- 引用变量:在任务(task)中,可以使用
{{key}}
的格式来引用变量的值。tasks: - name: create group group: name={{groupname}} system=yes gid=306 - name: create user user: name={{username}} uid=306 group={{groupname}}
- 命令行定义变量:在执行Playbook时,也可以通过命令行参数
-e
来定义变量。ansible-playbook test1.yaml -e "username=nginx"
指定远程主机sudo切换用户
在Ansible Playbook中,可以使用become
和become_user
参数来指定在远程主机上执行命令时切换的用户。
- become:启用sudo切换用户功能(Ansible 2.6版本以后的参数,之前使用的是
sudo
)。 - become_user:指定要切换到的用户。
示例:
---
- hosts: dbservers
remote_user: zhangsan
become: yes
become_user: root
在执行Playbook时,需要输入远程用户zhangsan
的密码和sudo用户的密码(如果使用-K
参数)。
ansible-playbook test1.yml -k -K
when条件判断
Ansible中的when
指令用于条件判断。当when
指令的值为true
时,该任务将被执行;否则,该任务将被跳过。
- 常见应用场景:跳过某个主机不执行任务,或者只有满足条件的主机执行任务。
示例:
---
- hosts: all
remote_user: root
tasks:
- name: shutdown host
command: /sbin/shutdown -r now
when: ansible_default_ipv4.address == "192.168.80.12"
# 或者
# when: inventory_hostname == "<主机名>"
Ansible Playbook 迭代功能
with_items
循环结构
用于在任务中迭代一组项目。每个项目都可以是字符串、字典或其他数据结构。
创建文件(Play 1)
- name: play1
hosts: dbservers
gather_facts: false
tasks:
- name: create file
file:
path: "{{item}}"
state: touch
with_items:
- /opt/a
- /opt/b
- /opt/c
- /opt/d
with_items
列表包含了四个路径。对于列表中的每个路径,file
模块都会被调用一次,以在该路径上创建一个空文件。
创建目录(Play 2)
- name: play2
hosts: dbservers
gather_facts: false
vars:
test:
- /tmp/test1
- /tmp/test2
- /tmp/test3
- /tmp/test4
tasks:
- name: create directories
file:
path: "{{item}}"
state: directory
with_items: "{{test}}"
定义了一个变量 test
,它是一个包含四个目录路径的列表。然后,使用 with_items: "{{test}}"
来迭代这个列表,并为每个路径创建一个目录。
添加用户(Play 3)
- name: play3
hosts: dbservers
gather_facts: false
tasks:
- name: add users
user: name={{item.name}} state=present groups={{item.groups}}
with_items:
- {name: 'test1', groups: 'wheel'}
- {name: 'test2', groups: 'root'}
with_items
列表包含了两个字典,每个字典都有 name
和 groups
键。对于列表中的每个字典,user
模块都会被调用一次,以添加具有指定名称和组的用户。这里使用 {{item.name}}
和 {{item.groups}}
引用字典中的值。
state=present
参数指定了用户应该存在,如果不存在则创建。groups
参数指定了用户应该属于的组。
注意
- 在 Ansible 2.5 及更高版本中,建议使用
loop
关键字代替with_items
,因为loop
是更现代、更灵活的迭代机制。不过,with_items
仍然被广泛使用,并且在许多情况下都是有效的。 - 在使用
with_items
或loop
时,请确保迭代的项目列表或字典是正确格式的,以避免运行时错误。 - 在定义变量时,可以使用 YAML 的列表和字典语法来组织数据,这使得 Playbook 更加清晰和易于维护。
执行 Playbook
ansible-playbook test3.yaml
这将按顺序执行 play1
、play2
和 play3
,并在 dbservers
组中的每个主机上应用相应的任务。
Tags 与 Templates 模块
Tags 模块
在 Ansible Playbook 中,可以为任务(tasks)定义标签(tags),以便在执行 Playbook 时通过 --tags
选项仅运行指定的任务。
- 定义标签:在任务的
tags
字段下,可以定义一个或多个标签。例如:tasks: - name: Copy hosts file copy: src=/etc/hosts dest=/opt/hosts tags: - only - name: touch file file: path=/opt/testhost state=touch tags: - always
- 执行带标签的任务:使用
ansible-playbook
命令并添加--tags
选项来仅执行带有指定标签的任务。例如:ansible-playbook webhosts.yaml --tags="only"
- 特殊标签
always
:当使用always
作为标签的任务时,无论执行哪一个标签,定义有always
标签的任务都会执行。
Templates 模块
Jinja 是基于 Python 的模板引擎,用于在 Ansible 中生成目标文本。Template 类是 Jinja 的一个重要组件,可以看作是一个编译过的模板文件,用来将 Python 变量传递给模板,并替换模板中的标记。
- 准备模板文件:创建一个以
.j2
为后缀的模板文件,并在其中设置引用的变量。 - 例如:
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行,修改
-
定义主机变量:在 Ansible 的主机清单文件(
/etc/ansible/hosts
)中,为不同的主机定义相同名称但值不同的变量。例如:[webservers] 192.168.80.11 http_port=80 server_name=www.accp.com root_dir=/var/www/html [dbservers] 192.168.80.12 http_port=8080 server_name=www.benet.com root_dir=/var/www/html_backup
-
编写 Playbook:在 Playbook 中使用
template
模块将模板文件应用到远程主机上,并替换模板中的变量。例如:--- - hosts: all 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 - name: create root dir file: path={{root_dir}} state=directory # 注意这里使用了 {{root_dir}},但需要在每个主机的变量中定义 - name: start httpd server service: name={{service}} enabled=true state=started handlers: - name: restart httpd service: name={{service}} state=restarted
注意:在上面的 Playbook 中,
{{root_dir}}
变量应该在每个主机的变量中定义,但上面的示例为了简化而直接放在了file
任务的路径中。在实际应用中,可能需要在 Playbook 的vars
部分或使用host_vars
目录为每个主机定义不同的变量。 -
执行 Playbook:使用
ansible-playbook
命令执行 Playbook。例如:ansible-playbook apache.yaml
这将安装 httpd 包、复制模板配置文件(替换模板中的变量)、创建根目录(如果变量已定义),并启动 httpd 服务。如果配置文件发生变化,将触发 restart httpd
处理器来重启服务。
Ansible Roles 模块
Roles 简介
Roles 是 Ansible 中用于层次性、结构化地组织 Playbook 的一种机制。通过将变量、文件、任务、模板及处理器分别放置在单独的目录中,Roles 使得 Playbook 的编写更加模块化、清晰化,并提高了代码复用度。
Roles 的目录结构
在 Ansible 的配置目录中(默认为 /etc/ansible/
),roles/
目录用于存放所有的角色。每个角色都是一个子目录,其内部包含以下子目录和文件:
files/
:用于存放由copy
模块或script
模块调用的文件。templates/
:用于存放 Jinja2 模板文件,template
模块会自动在此目录中查找模板。tasks/
:应包含一个main.yml
文件,用于定义角色的任务列表。可以包含其他任务文件,并通过include
指令引入。handlers/
:应包含一个main.yml
文件,用于定义触发条件时执行的动作。vars/
:应包含一个main.yml
文件,用于定义角色使用的变量。defaults/
:应包含一个main.yml
文件,用于为角色设定默认变量。这些变量具有最低的优先级,可以被其他变量覆盖。meta/
:应包含一个main.yml
文件,用于定义角色的元数据信息及其依赖关系。
在 Playbook 中使用 Roles
- 创建 Roles 目录:确保
/etc/ansible/roles/
目录存在。 - 创建角色目录:为每个角色创建一个子目录,如
httpd
、mysql
等。 - 创建必要的子目录和文件:在每个角色目录中创建
files
、templates
、tasks
、handlers
、vars
、defaults
和meta
子目录,并创建相应的main.yml
文件。 - 编写 Playbook:在 Playbook 中使用
roles
关键字来引用角色。例如:--- - hosts: webservers remote_user: root roles: - httpd - hosts: dbservers remote_user: root roles: - mysql - hosts: lampserver remote_user: root roles: - httpd - mysql - php
- 运行 Playbook:使用
ansible-playbook
命令运行 Playbook,如ansible-playbook /etc/ansible/site.yml
。
示例
# 创建角色目录和文件
mkdir -p /etc/ansible/roles/httpd/{files,templates,tasks,handlers,vars,defaults,meta}
mkdir -p /etc/ansible/roles/mysql/{files,templates,tasks,handlers,vars,defaults,meta}
mkdir -p /etc/ansible/roles/php/{files,templates,tasks,handlers,vars,defaults,meta}
# 创建 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
touch /etc/ansible/roles/php/{defaults,vars,tasks,meta,handlers}/main.yml
# 编写 Playbook(site.yml)
vim /etc/ansible/site.yml
---
- hosts: webservers
remote_user: root
roles:
- httpd
- hosts: dbservers
remote_user: root
roles:
- mysql
- hosts: lampserver
remote_user: root
roles:
- httpd
- mysql
- php
# 运行 Playbook
ansible-playbook /etc/ansible/site.yml
编写httpd、mysql、php模块的 roles
1. 创建 httpd 模块
步骤:
- 创建 tasks 文件:
内容: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
- 定义变量:
内容:vim /etc/ansible/roles/httpd/vars/main.yml
pkg: httpd svc: httpd
2. 创建 mysql 模块
步骤:
- 创建 tasks 文件:
内容: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
3. 创建 php 模块
步骤:
- 创建 tasks 文件:
内容: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
4. 编写 site.yml 以使用这些 roles
步骤:
- 创建 site.yml 文件:
内容:vim /etc/ansible/site.yml
--- - hosts: webservers remote_user: root roles: - httpd - mysql - php
- 运行 ansible-playbook:
cd /etc/ansible ansible-playbook site.yml
注意
- 定义变量:可以定义在全局变量中,也可以定义在roles角色变量中,一般定义在角色变量中。
- 服务管理:在
service
模块中,enabled=true
表示设置服务为开机自启,state=started
表示启动服务。 - Ansible 版本:确保你使用的 Ansible 版本支持以上语法。例如,
yum
模块和service
模块的参数可能会随着 Ansible 版本的更新而变化。 - 权限:确保你有足够的权限在目标机器上安装软件和服务。