Ansible Playbook 基础 #
什么是 Playbook? #
Playbook 是 Ansible 的核心组件,使用 YAML 格式编写,定义了一系列自动化任务。它描述了在哪些主机上执行什么任务,是 Ansible 自动化的脚本文件。
text
┌─────────────────────────────────────────────────────────────┐
│ Playbook 结构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Playbook │
│ ├── Play 1 │
│ │ ├── hosts: 目标主机 │
│ │ ├── vars: 变量 │
│ │ └── tasks: 任务列表 │
│ │ ├── Task 1 │
│ │ ├── Task 2 │
│ │ └── ... │
│ │ │
│ └── Play 2 │
│ ├── hosts: 目标主机 │
│ └── tasks: 任务列表 │
│ │
└─────────────────────────────────────────────────────────────┘
YAML 语法基础 #
基本规则 #
yaml
# YAML 基本规则
# 1. 使用缩进表示层级关系(空格,不用 Tab)
# 2. 缩进必须一致
# 3. 大小写敏感
# 4. 文件以 --- 开始(可选)
# 5. 注释使用 #
---
# 键值对
key: value
# 列表
- item1
- item2
- item3
# 字典
person:
name: John
age: 30
city: Beijing
# 列表中的字典
users:
- name: Alice
age: 25
- name: Bob
age: 30
# 字典中的列表
server:
name: web1
ports:
- 80
- 443
YAML 在 Ansible 中的应用 #
yaml
---
# Playbook 示例
- name: Configure web servers
hosts: webservers
become: yes
vars:
nginx_port: 80
document_root: /var/www/html
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Start Nginx
service:
name: nginx
state: started
enabled: yes
Playbook 结构 #
基本结构 #
yaml
---
- name: Play 名称
hosts: 目标主机
vars: # 变量定义(可选)
var1: value1
vars_files: # 变量文件(可选)
- vars.yml
become: yes # 是否提权(可选)
gather_facts: yes # 是否收集 Facts(可选)
tasks: # 任务列表
- name: Task 1
module_name:
parameter: value
- name: Task 2
module_name:
parameter: value
handlers: # 处理器(可选)
- name: Handler 1
module_name:
parameter: value
多个 Play #
yaml
---
# Play 1: 配置 Web 服务器
- name: Configure web servers
hosts: webservers
become: yes
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
# Play 2: 配置数据库服务器
- name: Configure database servers
hosts: databases
become: yes
tasks:
- name: Install MySQL
apt:
name: mysql-server
state: present
# Play 3: 配置缓存服务器
- name: Configure cache servers
hosts: cache
become: yes
tasks:
- name: Install Redis
apt:
name: redis-server
state: present
第一个 Playbook #
创建 Playbook #
yaml
# site.yml
---
- name: My first playbook
hosts: all
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install Nginx
apt:
name: nginx
state: present
- name: Start Nginx
service:
name: nginx
state: started
enabled: yes
- name: Create index page
copy:
content: "Hello Ansible!"
dest: /var/www/html/index.html
执行 Playbook #
bash
# 基本执行
ansible-playbook site.yml
# 指定清单文件
ansible-playbook -i inventory/hosts site.yml
# 检查语法
ansible-playbook --syntax-check site.yml
# 模拟执行(不实际更改)
ansible-playbook --check site.yml
# 详细输出
ansible-playbook -v site.yml
ansible-playbook -vv site.yml
ansible-playbook -vvv site.yml
# 指定标签
ansible-playbook --tags "install" site.yml
# 从特定任务开始
ansible-playbook --start-at-task "Start Nginx" site.yml
任务编写 #
任务基本格式 #
yaml
tasks:
- name: 任务描述
module_name:
parameter1: value1
parameter2: value2
常用任务示例 #
yaml
tasks:
# 安装软件包
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: yes
# 复制文件
- name: Copy configuration file
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: Restart Nginx
# 使用模板
- name: Deploy application config
template:
src: templates/app.conf.j2
dest: /etc/app/app.conf
backup: yes
# 管理服务
- name: Ensure Nginx is running
service:
name: nginx
state: started
enabled: yes
# 创建用户
- name: Create application user
user:
name: appuser
shell: /bin/bash
groups: sudo
append: yes
# 创建目录
- name: Create application directory
file:
path: /var/www/app
state: directory
owner: appuser
group: appuser
mode: '0755'
# 执行命令
- name: Check application status
command: /usr/bin/app status
register: app_status
changed_when: false
# 执行 Shell 命令
- name: Get system information
shell: uname -a
register: system_info
# 调试输出
- name: Display system information
debug:
msg: "System: {{ system_info.stdout }}"
任务属性 #
yaml
tasks:
- name: Task with all attributes
copy:
src: file.txt
dest: /tmp/file.txt
# 条件执行
when: ansible_facts['os_family'] == "Debian"
# 循环
loop:
- item1
- item2
# 提权
become: yes
become_user: root
# 忽略错误
ignore_errors: yes
# 注册结果
register: result
# 更改条件
changed_when: "'success' in result.stdout"
# 失败条件
failed_when: "'error' in result.stdout"
# 通知处理器
notify: Restart Service
# 标签
tags:
- install
- config
# 重试
retries: 3
delay: 10
until: result is success
变量使用 #
定义变量 #
yaml
---
- name: Use variables
hosts: webservers
become: yes
# 在 Play 中定义变量
vars:
app_name: myapp
app_port: 8080
app_user: appuser
# 使用变量文件
vars_files:
- vars/app.yml
- vars/secrets.yml
tasks:
- name: Create application user
user:
name: "{{ app_user }}"
shell: /bin/bash
- name: Create application directory
file:
path: "/var/www/{{ app_name }}"
state: directory
owner: "{{ app_user }}"
- name: Configure application port
lineinfile:
path: /etc/app/config.yml
line: "port: {{ app_port }}"
create: yes
变量文件 #
yaml
# vars/app.yml
---
app_name: myapp
app_version: 1.0.0
app_port: 8080
app_user: appuser
app_dir: /var/www/myapp
database:
host: localhost
port: 3306
name: app_production
user: appuser
password: "{{ vault_db_password }}"
使用 Facts #
yaml
---
- name: Use facts
hosts: all
tasks:
- name: Show system information
debug:
msg: |
Hostname: {{ ansible_facts['hostname'] }}
OS: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}
IP: {{ ansible_facts['default_ipv4']['address'] }}
Memory: {{ ansible_facts['memtotal_mb'] }} MB
- name: Install package based on OS
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == "Debian"
- name: Install package on RedHat
yum:
name: nginx
state: present
when: ansible_facts['os_family'] == "RedHat"
Handlers #
定义 Handlers #
yaml
---
- name: Use handlers
hosts: webservers
become: yes
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
notify: Restart Nginx
- name: Copy Nginx config
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
notify:
- Restart Nginx
- Reload Firewall
- name: Copy site config
template:
src: templates/site.conf.j2
dest: /etc/nginx/sites-available/default
notify: Restart Nginx
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
- name: Reload Nginx
service:
name: nginx
state: reloaded
- name: Reload Firewall
command: ufw reload
Handler 特点 #
yaml
# Handler 只在任务产生变更时触发
# Handler 在所有任务执行完后执行
# Handler 只执行一次(即使被多次通知)
# Handler 按定义顺序执行
tasks:
- name: Task 1
copy:
src: file1
dest: /tmp/file1
notify: Handler 1 # 如果变更,触发 Handler 1
- name: Task 2
copy:
src: file2
dest: /tmp/file2
notify: Handler 1 # 如果变更,再次触发 Handler 1
handlers:
- name: Handler 1
debug:
msg: "Handler 1 executed"
# 即使被通知两次,也只执行一次
执行控制 #
条件判断 #
yaml
---
- name: Conditional execution
hosts: all
become: yes
tasks:
# 基本条件
- name: Install on Debian
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == "Debian"
# 多条件(AND)
- name: Install on Ubuntu 20.04
apt:
name: nginx
state: present
when:
- ansible_facts['distribution'] == "Ubuntu"
- ansible_facts['distribution_version'] == "20.04"
# 多条件(OR)
- name: Install on Debian or Ubuntu
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == "Debian" or ansible_facts['os_family'] == "Ubuntu"
# 条件组合
- name: Complex condition
apt:
name: nginx
state: present
when: >
(ansible_facts['distribution'] == "Ubuntu" and ansible_facts['distribution_version'] == "20.04") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "10")
# 变量条件
- name: Deploy to production
debug:
msg: "Deploying to production"
when: environment == "production"
# 布尔值条件
- name: Run if enabled
debug:
msg: "Feature is enabled"
when: feature_enabled | bool
# 检查变量是否定义
- name: Run if variable is defined
debug:
msg: "Variable is {{ my_var }}"
when: my_var is defined
# 检查变量是否未定义
- name: Run if variable is undefined
debug:
msg: "Variable is not defined"
when: my_var is undefined
循环 #
yaml
---
- name: Use loops
hosts: all
become: yes
tasks:
# 基本循环
- name: Install multiple packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- git
- curl
- vim
# 循环字典列表
- name: Create multiple users
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
shell: "{{ item.shell }}"
loop:
- { name: 'user1', groups: 'sudo', shell: '/bin/bash' }
- { name: 'user2', groups: 'docker', shell: '/bin/bash' }
- { name: 'user3', groups: 'www-data', shell: '/bin/sh' }
# 循环范围
- name: Create numbered directories
file:
path: "/tmp/dir{{ item }}"
state: directory
loop: "{{ range(1, 6) | list }}"
# 循环字典
- name: Create files from dictionary
copy:
content: "{{ item.value }}"
dest: "/tmp/{{ item.key }}.txt"
loop: "{{ files_dict | dict2items }}"
vars:
files_dict:
file1: "Content of file 1"
file2: "Content of file 2"
file3: "Content of file 3"
# 嵌套循环
- name: Nested loops
debug:
msg: "{{ item[0] }} - {{ item[1] }}"
loop: "{{ ['a', 'b'] | product(['1', '2']) | list }}"
# 注册循环结果
- name: Loop with register
command: "echo {{ item }}"
loop:
- one
- two
- three
register: echo_results
- name: Show loop results
debug:
msg: "{{ item.stdout }}"
loop: "{{ echo_results.results }}"
标签 #
定义标签 #
yaml
---
- name: Use tags
hosts: webservers
become: yes
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
tags:
- install
- nginx
- name: Configure Nginx
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
tags:
- config
- nginx
- name: Start Nginx
service:
name: nginx
state: started
enabled: yes
tags:
- service
- nginx
- name: Deploy application
copy:
src: files/app/
dest: /var/www/app/
tags:
- deploy
- app
使用标签 #
bash
# 只执行特定标签的任务
ansible-playbook site.yml --tags "install"
# 执行多个标签的任务
ansible-playbook site.yml --tags "install,config"
# 跳过特定标签的任务
ansible-playbook site.yml --skip-tags "deploy"
# 列出所有标签
ansible-playbook site.yml --list-tags
包含和导入 #
包含任务 #
yaml
# tasks/install.yml
---
- name: Install Nginx
apt:
name: nginx
state: present
- name: Install Git
apt:
name: git
state: present
# site.yml
---
- name: Include tasks
hosts: webservers
become: yes
tasks:
- name: Include install tasks
include_tasks: tasks/install.yml
- name: Configure application
include_tasks: tasks/config.yml
vars:
app_name: myapp
导入任务 #
yaml
# site.yml
---
- name: Import tasks
hosts: webservers
become: yes
tasks:
- name: Import install tasks
import_tasks: tasks/install.yml
- name: Import config tasks
import_tasks: tasks/config.yml
包含 vs 导入 #
text
┌─────────────────────────────────────────────────────────────┐
│ include_tasks vs import_tasks │
├─────────────────────────────────────────────────────────────┤
│ │
│ include_tasks import_tasks │
│ ────────────── ────────────── │
│ 运行时处理 解析时处理 │
│ 可使用变量 不能使用变量 │
│ 可循环 不能循环 │
│ 可条件包含 不能条件导入 │
│ 任务列表中 可在任意位置 │
│ │
└─────────────────────────────────────────────────────────────┘
调试技巧 #
debug 模块 #
yaml
tasks:
# 输出消息
- name: Debug message
debug:
msg: "Current host is {{ inventory_hostname }}"
# 输出变量
- name: Debug variable
debug:
var: ansible_facts
# 输出表达式结果
- name: Debug expression
debug:
msg: "Result is {{ 1 + 2 }}"
# 条件调试
- name: Conditional debug
debug:
msg: "This is production"
when: environment == "production"
注册结果 #
yaml
tasks:
- name: Run command
command: ls -la /tmp
register: ls_result
- name: Show command output
debug:
msg: "{{ ls_result.stdout }}"
- name: Show all result data
debug:
var: ls_result
详细输出 #
bash
# 一级详细
ansible-playbook site.yml -v
# 二级详细
ansible-playbook site.yml -vv
# 三级详细
ansible-playbook site.yml -vvv
# 连接调试
ansible-playbook site.yml -vvvv
完整示例 #
yaml
# site.yml
---
- name: Deploy Web Application
hosts: webservers
become: yes
gather_facts: yes
vars:
app_name: myapp
app_version: 1.0.0
app_user: appuser
app_dir: /var/www/myapp
nginx_port: 80
vars_files:
- vars/secrets.yml
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
tags: always
- name: Install required packages
apt:
name:
- nginx
- git
- curl
state: present
tags: install
- name: Create application user
user:
name: "{{ app_user }}"
shell: /bin/bash
system: yes
create_home: yes
tags: setup
- name: Create application directory
file:
path: "{{ app_dir }}"
state: directory
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: '0755'
tags: setup
- name: Copy Nginx configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
notify: Restart Nginx
tags: config
- name: Copy application files
copy:
src: files/app/
dest: "{{ app_dir }}/"
owner: "{{ app_user }}"
group: "{{ app_user }}"
notify: Restart Nginx
tags: deploy
- name: Ensure Nginx is running
service:
name: nginx
state: started
enabled: yes
tags: service
- name: Check application status
uri:
url: "http://localhost:{{ nginx_port }}"
method: GET
status_code: 200
register: health_check
retries: 3
delay: 5
until: health_check.status == 200
tags: verify
- name: Display deployment info
debug:
msg: |
Application {{ app_name }} v{{ app_version }} deployed successfully!
URL: http://{{ ansible_facts['default_ipv4']['address'] }}:{{ nginx_port }}
tags: verify
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
下一步 #
现在你已经掌握了 Playbook 的基础知识,接下来学习 Playbook 进阶 了解更高级的任务编排技巧!
最后更新:2026-03-29