Linux · 5 分钟阅读
Playbook
Playbook = 用 YAML 描述"远端该做什么"。比 ad-hoc 命令更适合长期维护、版本控制、复用。本篇把 Playbook 的写法 + 流程控制 + 变量体系一次讲清。
1. 核心元素
| 元素 | 作用 |
|---|---|
hosts |
目标主机 / 组 |
tasks |
任务列表 |
vars |
变量 |
templates |
Jinja2 模板 |
handlers |
变更通知触发器 |
tags |
任务标签 |
2. YAML 速记
- 缩进 2 空格,不允许 Tab
- 文件以
---起头 - 字符串里含特殊字符用引号
3. 完整示例
---
- name: 部署 Apache
hosts: web
remote_user: root
vars:
http_port: 8088
tasks:
- name: 创建测试文件
ansible.builtin.file:
path: /tmp/playtest.txt
state: touch
- name: 创建系统用户
ansible.builtin.user:
name: test02
system: true
shell: /sbin/nologin
- name: 安装 httpd
ansible.builtin.yum:
name: httpd
state: present
- name: 推送 httpd 配置
ansible.builtin.template:
src: ./httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- restart apache
- name: 复制测试页
ansible.builtin.copy:
src: /var/www/html/index.html
dest: /var/www/html/index.html
- name: 启动 httpd
ansible.builtin.service:
name: httpd
state: started
handlers:
- name: restart apache
ansible.builtin.service:
name: httpd
state: restarted
httpd.conf 模板(httpd.conf.j2)里直接用 {{ http_port }} 引用变量:
Listen {{ http_port }}
执行:
ansible-playbook playbook01.yml
验证:
ansible 192.168.1.31 -m shell -a 'ls /tmp/playtest.txt && id test02'
curl 192.168.1.31:8088
4. 运行选项
| 选项 | 作用 |
|---|---|
--syntax-check |
只检查语法 |
--check / -C |
Dry-run |
--list-hosts |
列出受影响主机 |
--list-tags |
列出所有 tag |
--list-tasks |
列出所有 task |
--limit web1 |
限制主机 |
-f 10 |
并发数(默认 5) |
-t deploy |
只跑某 tag |
-vvv |
调试输出 |
ansible-playbook site.yml -C
ansible-playbook site.yml --limit web
ansible-playbook site.yml -t deploy
ansible-playbook site.yml -vvv
5. 元素属性
5.1 主机与用户
- hosts: webservers:dbservers
remote_user: deploy
tasks:
- name: df -h
remote_user: test
ansible.builtin.shell: df -h
- name: install package
become: true
become_user: admin
ansible.builtin.yum:
name: httpd
state: present
sudo: yes在 2.8 起改名become: true,老写法已废弃。
5.2 任务列表
tasks:
- name: create file
ansible.builtin.file:
path: /tmp/test01.txt
state: touch
- name: create user
ansible.builtin.user:
name: test001
state: present
5.3 Handlers
tasks:
- name: 推送配置
ansible.builtin.template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: restart apache
handlers:
- name: restart apache
ansible.builtin.service:
name: httpd
state: restarted
Handler 只在被
notify时触发,且一个 Play 内只跑一次(即使被多次通知)。
6. 变量
6.1 命令行
ansible-playbook test.yml -e "version=1.0.0"
ansible-playbook test.yml -e "@vars.yml"
6.2 Playbook 内
- hosts: web
vars:
http_port: 80
max_clients: 200
6.3 变量文件
# group_vars/webservers.yml
---
db_name: myapp
db_user: admin
6.4 规则
- 名字只能字母、数字、下划线,字母开头
- 模板里用
{{ var }} - 命令行
-e优先级最高 group_vars/比host_vars/优先级低
6.5 特殊变量
ansible_hostname # 主机名
ansible_distribution # OS
ansible_os_family # OS 家族
ansible_architecture # 架构
注册变量:
- name: 检查服务
ansible.builtin.command: systemctl status httpd
register: svc
changed_when: false
- name: 打印结果
ansible.builtin.debug:
var: svc.stdout
6.6 作用域
| 级别 | 文件 | 作用 |
|---|---|---|
| 全局 | group_vars/all.yml |
全部主机 |
| 组 | group_vars/<group>.yml |
该组 |
| 主机 | host_vars/<host>.yml |
单台 |
| 任务 | task 内 vars |
仅本任务 |
别在
hosts文件里写变量,迁移到 YAML 格式的host_vars/,可读性更好。
7. 条件判断:when
when/loop/block是 Playbook 三大控制结构。2026 年新写法已经统一成loop,with_items/with_dict等老循环基本弃用。
7.1 单一条件
- name: 安装 Apache
ansible.builtin.yum:
name: httpd
state: present
when: ansible_os_family == "RedHat"
7.2 组合条件
- name: CentOS 7 专属配置
ansible.builtin.template:
src: service.conf.j2
dest: /etc/service.conf
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"
- name: 安装 RHEL 系包
ansible.builtin.yum:
name: httpd
state: present
when: >
ansible_distribution == "CentOS" or
ansible_distribution == "RedHat"
7.3 注册变量 + 条件
- name: 检查服务
ansible.builtin.command: systemctl status httpd
register: svc
changed_when: false
- name: 重启
ansible.builtin.service:
name: httpd
state: restarted
when: svc.rc != 0
7.4 变量存在性
- name: 配置数据库
ansible.builtin.template:
src: db.conf.j2
dest: /etc/db.conf
when: db_password is defined
8. 循环:loop(推荐)
8.1 基本列表
- name: 安装多个包
ansible.builtin.yum:
name: "{{ item }}"
state: present
loop:
- httpd
- php
- mariadb-server
8.2 字典循环
- name: 创建用户
ansible.builtin.user:
name: "{{ item.key }}"
groups: "{{ item.value.groups }}"
shell: "{{ item.value.shell }}"
loop: "{{ users | dict2items }}"
vars:
users:
admin: {groups: wheel, shell: /bin/bash}
dev: {groups: developers, shell: /bin/zsh}
8.3 文件匹配
- name: 复制配置
ansible.builtin.copy:
src: "{{ item }}"
dest: /etc/app/
loop: "{{ lookup('fileglob', 'files/*.conf', wantlist=True) }}"
老语法
with_fileglob、with_dict仍能用,但 2.5+ 起官方推荐loop。
8.4 数字序列
- name: 建目录
ansible.builtin.file:
path: "/data/dir{{ item }}"
state: directory
loop: "{{ range(1, 6) | list }}"
9. 错误处理
9.1 忽略失败
- name: 尝试命令
ansible.builtin.command: /bin/false
ignore_errors: true
9.2 自定义失败条件
- name: 检查服务
ansible.builtin.command: systemctl status httpd
register: result
failed_when: "'active' not in result.stdout"
changed_when: false
9.3 block / rescue / always
- name: 部署
block:
- ansible.builtin.yum: {name: app, state: present}
- ansible.builtin.service: {name: app, state: started}
rescue:
- ansible.builtin.yum: {name: app, state: absent}
always:
- ansible.builtin.mail:
to: admin@example.com
subject: 部署结果
10. 任务控制
10.1 Tags
tasks:
- name: 安装
ansible.builtin.yum: {name: httpd, state: present}
tags: install
- name: 配置
ansible.builtin.template:
src: httpd.conf.j2
dest: /etc/httpd.conf
tags: [config, httpd]
10.2 委派
- name: 加入负载均衡
ansible.builtin.shell: /usr/local/bin/add_to_lb.sh {{ inventory_hostname }}
delegate_to: localhost
10.3 异步
- name: 长时间任务
ansible.builtin.command: /usr/bin/long_running
async: 3600 # 1 小时
poll: 0 # 不阻塞,立即返回
11. 几条提醒
when里别写复杂逻辑,能放到set_fact里就提出来- 避免在循环里嵌套
with_*,两层loop比嵌套清晰 - 异步任务记得加
wait_for或在最后一步收尾