Ansible 自动化:配置管理与应用部署

FreeGuideOnline 最新 2026-06-12

Ansible 自动化运维入门到精通

从零掌握 Ansible,用声明式自动化实现配置管理与应用部署,让重复劳动成为历史。


一、为什么选择 Ansible

Ansible 是一款极简主义的 IT 自动化引擎,它通过 SSH 协议(无需安装客户端)将指令推送到远程服务器执行,彻底消除“手动一台台机器操作”的痛苦。它的核心竞争力在于:

  • 零客户端架构:被管理节点只需 Python 与 SSH,无需额外代理。
  • 声明式配置:用人类可读的 YAML 描述期望状态,而非编写复杂脚本。
  • 幂等性:多次执行同一个 Playbook,结果总是一致的,避免副作用。
  • 模块化:内置 3000+ 模块,覆盖系统管理、云服务、网络设备等几乎所有领域。
  • 编排能力:支持角色(Roles)、条件判断、循环与动态清单,轻松管理成千上万台服务器。

无论你管理的是 5 台还是 500 台机器,Ansible 都能帮助你实现快速部署、一致配置和标准化运维。


二、环境安装与快速验证

2.1 控制节点安装

Ansible 只需安装在控制节点(你的工作电脑或跳板机)上。首选 Python 包管理器 pip:

# 建议在虚拟环境中安装
python3 -m venv ansible-env
source ansible-env/bin/activate
pip install ansible

验证版本:

ansible --version

提示:控制节点可以使用 Linux、macOS,Windows 需通过 WSL 使用。被管理节点需要 Python 2.7 或 3.5+。

2.2 被管理节点准备

确认目标服务器 IP 可连通,并且控制节点能通过 SSH 免密登录(推荐使用 SSH 密钥):

ssh-copy-id user@192.168.1.101

也可以使用用户名密码,但不安全且不推荐。


三、基础概念与第一个命令

3.1 清单文件(Inventory)

清单文件定义被管理节点的集合。最简单的静态清单 inventory.ini

[webservers]
web01 ansible_host=192.168.1.101 ansible_user=admin
web02 ansible_host=192.168.1.102 ansible_user=admin

[dbservers]
db01 ansible_host=10.0.0.51 ansible_user=root

组名 [webservers] 用于批量操作,之后还可嵌套成组。

3.2 第一道 Ad-Hoc 命令

Ad-Hoc 命令用于临时执行一次任务,无需编写剧本。使用 ansible 命令测试连通性:

ansible all -i inventory.ini -m ping

输出示例:

web01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

-m ping 调用 ping 模块,all 代表清单中所有主机,-i 指定清单文件。


四、剧本(Playbook)与 YAML 语法精要

Playbook 是 Ansible 的核心工作流,使用 YAML 撰写,一个剧本可包含多个 Play,每个 Play 定义在一组主机上执行的一系列任务。

4.1 YAML 快速入门

  • 使用缩进表示层级(空格,不能使用 Tab)
  • 键值对:key: value
  • 列表项:- item1
  • 字符串可加引号,但通常不需要(除非包含特殊符号)
  • 布尔值:yes/notrue/false

示例:

---
- name: 第一个Play
  hosts: webservers
  become: yes
  tasks:
    - name: 确保Nginx已安装
      apt:
        name: nginx
        state: present

4.2 执行 Playbook

将上述内容保存为 deploy.yml,运行:

ansible-playbook -i inventory.ini deploy.yml

become: yes 表示任务需要提权(sudo),等同于 -b 参数。


五、配置管理实战

5.1 管理软件包

在不同发行版间,Ansible 使用对应模块(apt/yum/dnf/pkgng):

- name: 在Debian系上安装软件
  apt:
    name: "{{ packages }}"
    state: present
  vars:
    packages:
      - curl
      - git
      - nginx

或使用通用 package 模块(Ansible 2.0+)自动适配:

- name: 跨平台安装
  package:
    name: "{{ item }}"
    state: latest
  loop:
    - htop
    - vim

5.2 管理服务

确保服务运行并开机自启:

- name: 启动并启用Nginx
  service:
    name: nginx
    state: started
    enabled: yes

state 可选:started, stopped, restarted, reloaded

5.3 管理文件与模板

拷贝文件或渲染配置文件模板(Jinja2):

- name: 放置静态配置文件
  copy:
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: 0644
  notify: restart nginx

模板示例 templates/app.conf.j2

server {
    listen 80;
    server_name {{ server_name }};
    root {{ document_root }};
}

使用模板模块:

- name: 渲染配置文件
  template:
    src: app.conf.j2
    dest: /etc/nginx/conf.d/app.conf
  notify: reload nginx

notify 会在任务触发变更时调用 handler。

5.4 Handlers

Handlers 只在被通知时执行,且在所有任务之后集中运行:

handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted

  - name: reload nginx
    service:
      name: nginx
      state: reloaded

六、应用部署实战:从代码到上线

考虑一个典型的 Python Web 应用(FastAPI)部署流程,包含依赖安装、代码拉取、配置文件渲染、systemd 服务管理。

6.1 目录结构与变量

项目布局:

deploy/
├── inventory.ini
├── deploy_app.yml
├── files/
│   └── myapp.service
└── templates/
    └── config.env.j2

Playbook deploy_app.yml

---
- name: 部署MyApp
  hosts: appservers
  become: yes
  vars:
    repo_url: "https://github.com/example/myapp.git"
    dest_path: "/opt/myapp"
    app_user: "myapp"
    app_port: 8080
    database_url: "postgresql://db.example.com/myapp"
  tasks:
    - name: 创建应用用户
      user:
        name: "{{ app_user }}"
        system: yes
        create_home: no

    - name: 安装系统依赖
      package:
        name:
          - python3
          - python3-pip
          - git
        state: present

    - name: 克隆代码仓库
      git:
        repo: "{{ repo_url }}"
        dest: "{{ dest_path }}"
        version: main
        force: yes
      become_user: "{{ app_user }}"

    - name: 安装Python依赖
      pip:
        requirements: "{{ dest_path }}/requirements.txt"
        virtualenv: "{{ dest_path }}/venv"
        virtualenv_command: python3 -m venv
      become_user: "{{ app_user }}"

    - name: 渲染环境变量文件
      template:
        src: config.env.j2
        dest: "{{ dest_path }}/.env"
        owner: "{{ app_user }}"
        mode: 0600
      notify: restart myapp

    - name: 安装systemd服务文件
      copy:
        src: files/myapp.service
        dest: /etc/systemd/system/myapp.service
      notify: restart myapp

    - name: 启动并启用应用服务
      systemd:
        name: myapp
        state: started
        enabled: yes
        daemon_reload: yes

  handlers:
    - name: restart myapp
      systemd:
        name: myapp
        state: restarted

模板 templates/config.env.j2

DATABASE_URL={{ database_url }}
PORT={{ app_port }}

Systemd 单元文件 files/myapp.service

[Unit]
Description=MyApp Web Service
After=network.target

[Service]
User=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/opt/myapp/.env
ExecStart=/opt/myapp/venv/bin/uvicorn main:app --host 0.0.0.0 --port ${PORT}
Restart=always

[Install]
WantedBy=multi-user.target

执行:

ansible-playbook -i inventory.ini deploy_app.yml

结果:应用按照统一流程完成部署,每次运行均可保证配置一致、服务运行。


七、变量、事实与流程控制

7.1 变量来源

变量可以定义在多种位置,优先级由低到高:

  • 命令行 -e "key=value"(最高)
  • Playbook 的 varsvars_files
  • 角色默认值
  • 主机/组变量(host_vars/, group_vars/
  • Ansible Facts

7.2 Ansible Facts

默认会收集被管理节点的系统信息(IP、OS、内存等),这些数据以变量形式可用:

- name: 打印操作系统
  debug:
    msg: "系统是 {{ ansible_distribution }} {{ ansible_distribution_version }}"

禁用事实采集可提高速度:gather_facts: no

7.3 条件判断

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

- name: 仅在CentOS上安装epel
  yum:
    name: epel-release
    state: present
  when: ansible_distribution == "CentOS"

7.4 循环

通过 loopwith_* 关键字遍历列表:

- name: 创建多个用户
  user:
    name: "{{ item.name }}"
    groups: "{{ item.groups | default('') }}"
  loop:
    - { name: 'alice', groups: 'dev' }
    - { name: 'bob' }

对于哈希遍历,可使用 dict2items 过滤器。


八、角色(Roles):可复用的自动化单元

当 Playbook 变得庞大,必须拆分为角色。角色将变量、任务、模板、文件等组织在一个标准目录结构中:

roles/
└── nginx/
    ├── tasks/
    │   └── main.yml
    ├── handlers/
    │   └── main.yml
    ├── templates/
    │   └── nginx.conf.j2
    ├── files/
    ├── vars/
    │   └── main.yml
    ├── defaults/
    │   └── main.yml
    └── meta/
        └── main.yml

使用角色只需在 Playbook 中引用:

---
- hosts: webservers
  roles:
    - nginx
    - { role: app_deploy, app_port: 9090 }

角色可以通过 ansible-galaxy 命令从 Ansible Galaxy 社区下载复用:

ansible-galaxy install geerlingguy.nginx

九、最佳实践与进阶技巧

9.1 目录结构标准化

推荐的企业级项目布局:

production/
├── inventories/
│   └── production/
│       ├── hosts         # 主机列表
│       └── group_vars/   # 组变量
├── roles/
├── playbooks/
│   └── site.yml
└── ansible.cfg

将清单和变量分离,通过 ansible-playbook -i inventories/production playbooks/site.yml 执行。

9.2 敏感信息加密:Ansible Vault

ansible-vault 可加密任何含有机密变量的文件:

ansible-vault encrypt group_vars/all/passwords.yml

运行时提供密码:

ansible-playbook --ask-vault-pass site.yml

或使用密码文件,更适合 CI/CD。

9.3 动态清单

云环境下主机动态变化,可编写脚本或使用插件(如 AWS EC2 Plugin)自动生成清单:

ansible-playbook -i aws_ec2.yml site.yml

9.4 执行策略与错误处理

  • strategy: free 可并行执行任务,不等待全部主机完成。
  • 使用 ignore_errors: yes 让某一任务失败不中断 Playbook。
  • any_errors_fatal: true 则相反,任何主机失败立即中止。
  • serial 控制滚动更新批次,避免服务全部下线。

9.5 调试与检查模式

  • --check:干运行模式,不实际修改系统(但部分模块会产生副作用)。
  • --diff:显示文件变化对比。
  • -vvv:获得极详细的执行过程,用 debug 模块打印变量。
- name: 显示计算后的变量
  debug:
    var: database_url

十、总结与学习路径

本文从 Ansible 的核心理念出发,逐步覆盖了安装配置、Ad-Hoc 命令、Playbook 编写、配置管理、应用部署、变量与控制流、角色封装以及企业级最佳实践。掌握这些内容足以应对 90% 的日常自动化场景。

进一步深入学习建议

  1. 深入研究 Ansible Galaxy 上常用角色源码。
  2. 阅读官方文档中的模块索引和高级执行策略。
  3. 使用 Molecule 测试自己的角色。
  4. 将 Ansible 融入 CI/CD 流程,实现 Git + Ansible 的 GitOps。

自动化不是一蹴而就,而是从第一个能够“一键部署”的 Playbook 开始。现在就写一个 Playbook,将你手头最烦人的重复操作交出去吧。