自动化运维 Ansible Playbook 编写

FreeGuideOnline 14阅读 2026-07-08

Ansible Playbook 入门:从零掌握自动化部署与配置管理

Ansible 是一款简单强大的自动化运维工具,而 Playbook 是 Ansible 的核心。它使用 YAML 语法,将一组任务编排为可重复执行的“剧本”,实现对多台服务器的配置管理、应用部署和任务编排。本教程将带你从基础概念到实战编写,快速上手 Playbook。


1. 环境准备与基础概念

在开始编写 Playbook 之前,请确保已安装 Ansible(推荐使用 Python 的 pip 安装):

pip install ansible

并通过 ansible --version 确认版本。你需要一个控制节点(你的电脑)和至少一台被管理节点(远程服务器),控制节点可通过 SSH 免密登录到被管理端。

1.1 什么是 Inventory?

Inventory(清单)定义了要管理的主机列表,可以是静态文件或动态脚本。最简单的静态 Inventory 文件 hosts.ini

[web]
192.168.1.10
192.168.1.11

[db]
db.example.com ansible_user=root

方括号内的为组名,组下每一行是一台主机,可附加连接变量。

1.2 什么是 Playbook?

Playbook 是一个以 .yml.yaml 结尾的文本文件,它包含一个或多个 play(剧本),每个 play 针对一组主机执行一系列任务。一个极简的 Playbook 示例 ping.yml

---
- name: 测试连通性
  hosts: web
  tasks:
    - name: Ping 主机
      ansible.builtin.ping:

执行命令:ansible-playbook -i hosts.ini ping.yml


2. Playbook 核心结构详解

一个结构完整的 Playbook 包含 Play 定义、主机与用户、变量、任务列表等部分。

2.1 YAML 语法快速回顾

  • 使用缩进表示层级关系,通常用两个空格。
  • 键值对用冒号分隔,冒号后必须有空格
  • 列表项以短横线开头,同样需要空格。
  • 可使用 true / false 表示布尔值。

错误示范:name:value(缺少空格)。正确写法:name: value

2.2 Playbook 组成要素

---
- name: 部署 Web 应用          # Play 的名称(可选但推荐)
  hosts: web                    # 目标主机组
  become: yes                   # 是否提权(如 sudo)
  vars:                         # 定义变量
    http_port: 80
  tasks:                        # 任务列表
    - name: 安装 Nginx           # 任务的描述
      ansible.builtin.yum:       # 使用的模块
        name: nginx
        state: present
    - name: 启动服务
      ansible.builtin.service:
        name: nginx
        state: started
  • hosts:字符串,支持通配符、逻辑与或(如 web:&staging)。
  • tasks:按顺序执行,一个任务调用一个模块。
  • 模块:Ansible 提供的工具单元,例如 copyfiletemplatecommand。推荐使用完全限定集合名(FQCN),如 ansible.builtin.yum,以确保清晰。

3. 常用模块实践

3.1 文件与目录操作

  • 创建目录并设置权限:
- name: 确保应用目录存在
  ansible.builtin.file:
    path: /opt/myapp
    state: directory
    owner: appuser
    group: appgroup
    mode: '0755'
  • 拷贝文件到远程主机:
- name: 上传配置文件
  ansible.builtin.copy:
    src: files/app.conf
    dest: /etc/myapp/app.conf
    owner: root
    mode: '0644'

3.2 包管理

根据操作系统使用相应模块,例如在 CentOS/RHEL 上用 yum,Ubuntu 上用 apt

- name: 安装多个软件包
  ansible.builtin.yum:
    name:
      - git
      - curl
      - vim
    state: present

3.3 服务管理

- name: 重启并设置开机自启
  ansible.builtin.service:
    name: nginx
    state: restarted
    enabled: yes

3.4 执行命令与脚本

尽量避免使用 commandshell 模块,优先使用专用模块以保证幂等性。但必要时:

- name: 运行自定义脚本
  ansible.builtin.shell: /opt/scripts/setup.sh >> /var/log/setup.log
  args:
    creates: /opt/scripts/setup.done   # 幂等性标记

4. 变量与 Facts

4.1 定义和使用变量

变量可在多处定义:Playbook vars 块、外部文件、Inventory、命令行等。

- hosts: web
  vars:
    app_version: 2.4.0
    download_url: "https://example.com/release/{{ app_version }}/app.tar.gz"
  tasks:
    - name: 下载应用包
      ansible.builtin.get_url:
        url: "{{ download_url }}"
        dest: /tmp/app.tar.gz

使用 {{ }} 引用变量。可在单独 YAML 文件中定义变量并通过 vars_files 导入:

vars_files:
  - vars/global.yml

4.2 注册变量与 Facts

使用 register 保存任务输出结果;ansible_facts 包含目标主机的信息(IP、系统版本等)。

- name: 获取磁盘使用情况
  ansible.builtin.shell: df -h /
  register: disk_usage

- name: 打印结果
  ansible.builtin.debug:
    msg: "根分区磁盘使用状况 {{ disk_usage.stdout }}"

自定义 Facts 可放在 /etc/ansible/facts.d/ 下,动态生成主机信息。


5. 条件判断与循环

5.1 when 条件

根据变量或事实决定任务是否执行:

- name: 仅在 CentOS 上安装 yum 插件
  ansible.builtin.yum:
    name: yum-plugin-fastestmirror
    state: present
  when: ansible_os_family == "RedHat"

支持标准比较运算符,逻辑组合 and / or / not

5.2 循环

早期使用 with_items,现在推荐 loop

- name: 创建多个用户
  ansible.builtin.user:
    name: "{{ item }}"
    state: present
  loop:
    - alice
    - bob
    - charlie

结合字典列表:

- name: 安装指定版本的包
  ansible.builtin.apt:
    name: "{{ item.name }}"
    state: "{{ item.state }}"
  loop:
    - { name: nginx, state: latest }
    - { name: git, state: present }

6. 模板与 Jinja2

使用 template 模块可将本地模板文件渲染后传送到远程主机,模板使用 Jinja2 语法。

模板文件 nginx.conf.j2

server {
    listen {{ nginx_port }};
    server_name {{ server_name }};
    ...
}

任务定义:

- name: 渲染 nginx 配置
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    mode: '0644'
  notify: restart nginx

notify 用于触发 handler,后文会讲到。

6.1 Jinja2 常用功能

  • 过滤器{{ some_var | default('N/A') }}{{ list | join(',') }}
  • 条件表达式:可在模板内使用 {% if %}...{% endif %}
  • 循环{% for item in items %}...{% endfor %}

7. Handlers 与错误处理

7.1 Handlers

Handlers 类似于被触发的“回调任务”,仅在发生变化时执行,常用于重启服务。

tasks:
  - name: 更新配置文件
    ansible.builtin.template:
      src: app.conf.j2
      dest: /etc/myapp/app.conf
    notify: restart myapp

handlers:
  - name: restart myapp
    ansible.builtin.service:
      name: myapp
      state: restarted

多个任务可通知同一个 handler,handler 会在任务执行结束后统一运行(仅运行一次)。

7.2 错误控制

  • ignore_errors:任务失败时继续执行。
  • failed_when:自定义失败条件。
  • block/rescue/always:类似 try/except/finally 结构。
- block:
    - name: 尝试执行可能失败的操作
      ansible.builtin.command: /bin/false
  rescue:
    - name: 出错时清理
      ansible.builtin.debug:
        msg: "操作失败,执行回滚"
  always:
    - name: 始终执行的任务
      ansible.builtin.debug:
        msg: "完成"

8. 角色 (Roles) 与组织最佳实践

当 Playbook 变得复杂时,应使用角色对任务、变量、模板、文件等进行模块化组织。一个角色目录结构如下:

roles/
  common/
    tasks/
      main.yml
    handlers/
      main.yml
    templates/
    files/
    vars/
      main.yml
    defaults/
      main.yml

定义角色后,在 Playbook 中使用:

---
- hosts: web
  roles:
    - common
    - nginx

角色内部 tasks/main.yml 会自动加载,变量优先级:vars > defaults,并可通过 vars 文件夹覆盖默认值。Ansible Galaxy 可以分享和安装社区角色。


9. 实战示例:部署一个静态网站

将所有知识串联起来:

  1. Inventory hosts.ini:
[web]
webserver ansible_host=192.168.1.100 ansible_user=deploy
  1. Playbook deploy.yml:
---
- name: 部署静态网站
  hosts: web
  become: yes
  vars:
    site_domain: example.com
    site_root: /var/www/example
  tasks:
    - name: 确保站点目录存在
      ansible.builtin.file:
        path: "{{ site_root }}"
        state: directory
        owner: www-data
        group: www-data

    - name: 上传站点文件
      ansible.builtin.copy:
        src: site/
        dest: "{{ site_root }}"

    - name: 配置 Nginx 虚拟主机
      ansible.builtin.template:
        src: nginx-vhost.conf.j2
        dest: /etc/nginx/sites-available/{{ site_domain }}
      notify: reload nginx

    - name: 启用站点
      ansible.builtin.file:
        src: /etc/nginx/sites-available/{{ site_domain }}
        dest: /etc/nginx/sites-enabled/{{ site_domain }}
        state: link
      notify: reload nginx

  handlers:
    - name: reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
  1. 模板 nginx-vhost.conf.j2:
server {
    listen 80;
    server_name {{ site_domain }};
    root {{ site_root }};
    index index.html;
}

运行:ansible-playbook -i hosts.ini deploy.yml 即可完成部署。


10. 检查、调试与优化

  • 语法检查ansible-playbook deploy.yml --syntax-check
  • 试运行--check 模式模拟执行,--diff 显示文件变更。
  • 详细输出:增加 -v-vvv 查看调试信息。
  • 标签 (tags):给任务打标签,选择性执行部分任务:
    - name: 更新代码
      tags: deploy
      ...
    
    执行时使用 -t deploy--skip-tags
  • 并行与策略:通过 forks 控制并发数,--limit 限定主机。

不断练习并参考官方文档,你就能编写出健壮、可维护的 Ansible Playbook,轻松管理成千上万台服务器。