第五章:Playbook 基础
深入学习 Ansible Playbook 的结构、语法和编写方法。
最后更新: 2024-01-19
页面目录
Playbook 基础
Playbook 是 Ansible 的核心组件,用于定义复杂的自动化任务和配置。
Playbook 概述
┌─────────────────────────────────────────────────────────────────┐
│ Playbook 结构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Playbook │
│ └── Play (一个或多个) │
│ ├── name: Play 名称 │
│ ├── hosts: 目标主机 │
│ ├── become: 是否提权 │
│ ├── vars: Play 变量 │
│ ├── vars_files: 变量文件 │
│ ├── tasks: 任务列表 │
│ ├── handlers: 处理器列表 │
│ ├── pre_tasks: 前置任务 │
│ └── post_tasks: 后置任务 │
│ │
└─────────────────────────────────────────────────────────────────┘
YAML 基础
YAML 语法规则
# 键值对
name: value
port: 80
# 嵌套结构
server:
host: localhost
port: 8080
# 列表
packages:
- nginx
- vim
- git
# 复杂结构
servers:
- name: web1
ip: 192.168.1.10
- name: web2
ip: 192.168.1.11
YAML 注意事项
# 字符串引号(一般不需要)
message: "Hello World"
message: 'Hello World'
# 多行字符串
description: |
This is a multi-line
string that will be
preserved as-is.
# 折叠字符串
description: >
This will be folded
into a single line.
# 布尔值
enabled: true
disabled: false
Playbook 基本结构
单 Play 结构
# simple-playbook.yml
---
- name: Install and configure Nginx
hosts: webservers
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install Nginx
apt:
name: nginx
state: present
- name: Start Nginx service
service:
name: nginx
state: started
enabled: yes
多 Play 结构
# multi-playbook.yml
---
# Play 1: Web 服务器
- name: Configure Web Servers
hosts: webservers
become: yes
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
- name: Copy Nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Reload Nginx
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
# Play 2: Database 服务器
- name: Configure Database Servers
hosts: dbservers
become: yes
tasks:
- name: Install MySQL
apt:
name: mysql-server
state: present
- name: Start MySQL
service:
name: mysql
state: started
enabled: yes
Play 属性详解
hosts
# 单个主机
- name: Configure web1
hosts: web1
# 主机组
- name: Configure webservers
hosts: webservers
# 多个组(使用冒号)
- name: Configure web and db
hosts: webservers:dbservers
# 排除组(使用感叹号)
- name: All except dbservers
hosts: all:!dbservers
# 组交集(使用冒号)
- name: Common servers
hosts: webservers:&production
# 模式匹配
- name: All web servers
hosts: 'web*'
# 使用变量
- name: Configure dynamic hosts
hosts: "{{ target_hosts }}"
become
# 整个 Play 启用提权
- name: Admin tasks
hosts: all
become: yes
become_method: sudo
become_user: root
# 任务级别覆盖
tasks:
- name: Install packages
apt:
name: nginx
become: yes
- name: Run as normal user
command: whoami
remote_user
- name: Deploy application
hosts: webservers
remote_user: deploy
become: yes
become_user: www-data
gather_facts
# 禁用 Facts 收集(提高性能)
- name: Fast playbook
hosts: all
gather_facts: no
# 收集部分 Facts
- name: Selective facts
hosts: all
gather_facts:
- ansible_distribution
- ansible_memory_mb
Task 详解
Task 基本结构
tasks:
- name: Task description
module_name:
module_argument: value
register: result
when: condition
loop: ["item1", "item2"]
tags: [tag1, tag2]
Task 执行顺序
tasks:
# 1. 先执行 pre_tasks
pre_tasks:
- name: Pre-task
debug:
msg: "Running before main tasks"
# 2. 执行 tasks
tasks:
- name: Main task
apt:
name: nginx
state: present
# 3. 执行 post_tasks
post_tasks:
- name: Post-task
debug:
msg: "Running after main tasks"
常用模块作为 Task
tasks:
# apt 模块
- name: Install packages
apt:
name:
- nginx
- vim
- git
state: present
update_cache: yes
# yum 模块
- name: Install packages (RHEL)
yum:
name: httpd
state: present
# service 模块
- name: Start service
service:
name: nginx
state: started
enabled: yes
# copy 模块
- name: Copy file
copy:
src: ./files/app.conf
dest: /etc/myapp/app.conf
owner: app
group: app
mode: '0644'
backup: yes
# template 模块
- name: Generate config from template
template:
src: app.conf.j2
dest: /etc/myapp/app.conf
notify: Restart app
# command 模块
- name: Run command
command: /usr/local/bin/setup.sh
args:
creates: /etc/myapp/.setup_complete
# shell 模块
- name: Run shell script
shell: |
cd /opt/app
./build.sh
register: build_result
# file 模块
- name: Create directory
file:
path: /var/log/myapp
state: directory
owner: root
group: root
mode: '0755'
Playbook 执行控制
条件执行 (when)
tasks:
# 简单条件
- name: Install on CentOS
yum:
name: httpd
state: present
when: ansible_os_family == "RedHat"
# 复合条件
- name: Install on Debian
apt:
name: apache2
state: present
when:
- ansible_os_family == "Debian"
- ansible_distribution_version | int >= 20
# 注册变量条件
- name: Check if file exists
command: test -f /etc/myapp/config.yml
register: config_check
ignore_errors: yes
- name: Create config if not exists
copy:
src: default.yml
dest: /etc/myapp/config.yml
when: config_check.rc != 0
# 变量存在性条件
- name: Use variable if defined
debug:
msg: "Value is {{ custom_var }}"
when: custom_var is defined
循环 (loop)
tasks:
# 简单循环
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- vim
- git
- curl
# 字典列表循环
- name: Create users
user:
name: "{{ item.name }}"
shell: "{{ item.shell }}"
comment: "{{ item.comment }}"
loop:
- { name: 'alice', shell: '/bin/bash', comment: 'Alice User' }
- { name: 'bob', shell: '/bin/sh', comment: 'Bob User' }
- { name: 'charlie', shell: '/bin/bash', comment: 'Charlie User' }
# 使用 loop_control
- name: Create databases
mysql_db:
name: "{{ item.db_name }}"
state: present
loop:
- { db_name: 'app_production', owner: 'app' }
- { db_name: 'app_staging', owner: 'app' }
loop_control:
label: "{{ item.db_name }}"
# with_items 简写
- name: Create directories
file:
path: "{{ item }}"
state: directory
with_items:
- /tmp/dir1
- /tmp/dir2
- /tmp/dir3
# 嵌套循环
- name: Create app directories
file:
path: "/opt/{{ item.app }}/{{ item.env }}"
state: directory
with_nested:
- ['app1', 'app2', 'app3']
- ['production', 'staging']
其他迭代器
tasks:
# with_dict 字典迭代
- name: Configure sites
template:
src: "{{ item.value.template }}"
dest: "/etc/nginx/sites-available/{{ item.key }}"
with_dict: "{{ nginx_sites }}"
# with_fileglob 文件迭代
- name: Copy all config files
copy:
src: "{{ item }}"
dest: "/etc/myapp/"
mode: '0644'
with_fileglob:
- "files/*.conf"
# with_url URL 迭代
- name: Download files
get_url:
url: "{{ item }}"
dest: "/tmp/downloads/"
with_url:
- https://example.com/file1.zip
- https://example.com/file2.zip
# with_sequence 序列迭代
- name: Create servers
command: "create_server.sh {{ item }}"
with_sequence: start=1 end=5 format=web%02d
块 (block)
tasks:
# 块定义
- name: Block example
block:
- name: Install packages
apt:
name:
- nginx
- vim
state: present
- name: Configure application
template:
src: app.conf.j2
dest: /etc/myapp/app.conf
when: ansible_os_family == "Debian"
become: yes
# 块错误处理
- name: Block with rescue
block:
- name: Try to deploy
command: /usr/local/bin/deploy.sh
rescue:
- name: Rollback on failure
command: /usr/local/bin/rollback.sh
always:
- name: Always run
debug:
msg: "This always runs"
Playbook 命令
基本命令
# 运行 Playbook
ansible-playbook site.yml
# 指定 Inventory
ansible-playbook -i inventory/production site.yml
# 指定运行标签
ansible-playbook site.yml --tags "install,config"
# 跳过标签
ansible-playbook site.yml --skip-tags "testing"
# 检查模式
ansible-playbook site.yml --check
# 列出任务
ansible-playbook site.yml --list-tasks
# 列出主机
ansible-playbook site.yml --list-hosts
# 列出标签
ansible-playbook site.yml --list-tags
# 详细输出
ansible-playbook site.yml -v # 详细
ansible-playbook site.yml -vv # 更详细
ansible-playbook site.yml -vvv # 连接调试
ansible-playbook site.yml -vvvv # 详细信息
ansible-playbook site.yml -vvvvv # 全部信息
# 传递额外变量
ansible-playbook site.yml -e "var1=value1 var2=value2"
ansible-playbook site.yml -e @vars.yml
# 从特定步骤开始
ansible-playbook site.yml --start-at-task="Install packages"
# 逐步执行
ansible-playbook site.yml --step
Playbook 输出解读
PLAY [Configure Web Servers] *************************************************
TASK [Gathering Facts] ********************************************************
ok: [web1]
ok: [web2]
TASK [Update apt cache] ******************************************************
ok: [web1]
ok: [web2]
TASK [Install Nginx] **********************************************************
changed: [web1]
changed: [web2]
TASK [Copy Nginx configuration] **********************************************
changed: [web1]
changed: [web2]
RUNNING HANDLER [Reload Nginx] ***********************************************
changed: [web1]
changed: [web2]
PLAY RECAP ********************************************************************
web1 : ok=5 changed=2 unreachable=0 failed=0 skipped=0
web2 : ok=5 changed=2 unreachable=0 failed=0 skipped=0
输出状态说明
| 状态 | 说明 |
|---|---|
ok |
任务执行成功,状态未改变 |
changed |
任务执行成功,状态已改变 |
failed |
任务执行失败 |
skipped |
任务被跳过 |
unreachable |
主机不可达 |
下一步
现在你已经掌握了 Playbook 的基础知识。接下来让我们学习 Playbook 的进阶特性。