2026-04-09 01:28:15 +08:00

40 KiB
Raw Blame History

Ansible 实战指南

目录

  1. 运维自动化发展历程及技术应用
  2. Ansible 架构和相关命令使用
  3. Ansible 常用模块详解
  4. Ansible Playbook 基础
  5. Playbook 变量、Tags、Handlers 使用
  6. Playbook 模板 Templates
  7. Playbook 条件判断 When
  8. Playbook 字典 with_items
  9. Ansible Roles

1. 运维自动化发展历程及技术应用

1.1 运维自动化发展历程

┌─────────────────────────────────────────────────────┐
│               运维自动化发展历程                       │
├─────────────────────────────────────────────────────┤
│                                                     │
│  1. 手动时代                                          │
│     ├── 人工登录服务器                                │
│     ├── 逐台执行命令                                  │
│     └── 效率低下,易出错                             │
│                                                     │
│  2. 脚本时代                                         │
│     ├── Shell/Python 脚本                           │
│     ├── 批量执行脚本                                 │
│     └── 脚本难以维护,无标准化                        │
│                                                     │
│  3. 工具时代                                         │
│     ├── Puppet、SaltStack、Chef                     │
│     ├── 配置管理工具                                 │
│     └── 解决一致性,但复杂                           │
│                                                     │
│  4. 自动化时代                                       │
│     ├── Ansible、Terraform                          │
│     ├── 简单易用Agentless                         │
│     └── 编排 + 自动化                                │
│                                                     │
│  5. DevOps 时代                                      │
│     ├── CI/CD + 自动化运维                          │
│     ├── Kubernetes + 容器                           │
│     └── GitOps 理念                                  │
│                                                     │
└─────────────────────────────────────────────────────┘

1.2 常见运维自动化工具对比

工具 类型 架构 优点 缺点
Ansible 配置管理/编排 Agentless 简单易学、YAML 语法、无 Agent 执行速度稍慢
Puppet 配置管理 C/S (Agent) 功能强大、成熟 学习曲线陡峭
SaltStack 配置管理/执行 C/S (Agent) 高性能、可远程执行 语法复杂
Chef 配置管理 C/S (Agent) Ruby 语法、社区活跃 需要编写 Ruby 代码
Terraform 基础设施代码 Agentless 基础设施即代码、云原生 专注于基础设施

1.3 Ansible 应用场景

场景 说明
配置管理 统一配置服务器、操作系统、应用软件
应用部署 自动化部署应用程序、容器
批量操作 批量执行命令、批量修改配置
** orchestration** 多节点编排、任务编排
持续交付 CI/CD 流水线集成
基础设施 云资源管理、容器编排

1.4 Ansible 在企业中的应用

┌─────────────────────────────────────────────────────┐
│               Ansible 企业应用架构                   │
├─────────────────────────────────────────────────────┤
│                                                     │
│  ┌─────────────────────────────────────────────┐   │
│  │              Ansible Control Node            │   │
│  │              (Ansible Server)               │   │
│  └────────────────────┬────────────────────────┘   │
│                       │                              │
│         ┌─────────────┼─────────────┐              │
│         │             │             │              │
│         ▼             ▼             ▼              │
│   ┌──────────┐  ┌──────────┐  ┌──────────┐        │
│   │ Web      │  │ App      │  │ Database │        │
│   │ Servers  │  │ Servers  │  │ Servers  │        │
│   └──────────┘  └──────────┘  └──────────┘        │
│                                                     │
│  场景:                                            │
│  - 批量部署/配置服务器                              │
│  - 应用发布和回滚                                   │
│  - 监控和日志收集                                   │
│  - 安全合规检查                                     │
│                                                     │
└─────────────────────────────────────────────────────┘

2. Ansible 架构和相关命令使用

2.1 Ansible 架构

┌─────────────────────────────────────────────────────┐
│                 Ansible 架构                         │
├─────────────────────────────────────────────────────┤
│                                                     │
│  ┌─────────────────────────────────────────────┐   │
│  │              Ansible Engine                 │   │
│  │                                             │   │
│  │  Inventory    ──→  Playbooks               │   │
│  │     │              │                       │   │
│  │     ▼              ▼                       │   │
│  │  Plugins    ──→  Modules                  │   │
│  │     │              │                       │   │
│  │     │              │                       │   │
│  │     └──────────────┘                       │   │
│  │           │                                │   │
│  └───────────┼────────────────────────────────┘   │
│              │                                     │
│              ▼                                     │
│  ┌─────────────────────────────────────────────┐   │
│  │            Managed Nodes                     │   │
│  │            (无 Agent)                        │   │
│  │                                             │   │
│  │  SSH Connection ──→ Execute Modules         │   │
│  │                                             │   │
│  └─────────────────────────────────────────────┘   │
│                                                     │
└─────────────────────────────────────────────────────┘

2.2 Ansible 核心组件

组件 说明
Inventory 主机清单,定义管理的主机
Playbook 任务剧本YAML 格式的任务定义
Module 模块Ansible 执行的具体任务单元
Plugin 插件,扩展 Ansible 功能
API 编程接口,供二次开发使用

2.3 Ansible 安装

# 使用 pip 安装
pip install ansible

# Ubuntu/Debian
apt install ansible

# CentOS/RHEL
yum install epel-release
yum install ansible

# macOS
brew install ansible

# 验证安装
ansible --version

2.4 Inventory 主机清单

2.4.1 静态 Inventory

# /etc/ansible/hosts 或 -i 指定文件

# 单主机
192.168.1.10

# 主机组
[web]
192.168.1.10
192.168.1.11
192.168.1.12

[db]
192.168.1.20
192.168.1.21

# 嵌套组
[production:children]
web
db

# 主机变量
[web]
192.168.1.10 ansible_user=admin ansible_ssh_pass=pass123
192.168.1.11 ansible_user=admin ansible_ssh_pass=pass123

# 组变量
[web:vars]
ansible_user=admin
ansible_ssh_pass=pass123
http_port=80

2.4.2 动态 Inventory

# 使用脚本获取主机列表
ansible-playbook -i inventory.py playbook.yml

# AWS EC2 动态 Inventory
ansible-playbook -i ec2.py playbook.yml

2.5 Ansible 配置文件

# ansible.cfg

[defaults]
inventory = /etc/ansible/hosts
host_key_checking = False
retry_files_enabled = False
gathering = explicit
# 加速配置
pipelining = True
# 并行数
forks = 50

[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True

2.6 常用命令

# 帮助
ansible-doc -h
ansible-doc <module_name>
ansible-doc -l  # 列出所有模块

# 测试连通性
ansible all -m ping

# 执行临时命令
ansible all -m command -a "uptime"
ansible all -m shell -a "df -h"
ansible all -m setup  # 获取主机信息

# 文件传输
ansible all -m copy -a "src=/tmp/file dest=/tmp/"

# 用户管理
ansible all -m user -a "name=test state=present"

# 包管理
ansible all -m yum -a "name=httpd state=present"

# 服务管理
ansible all -m service -a "name=httpd state=started"

# 查看配置
ansible-config dump

# 查看清单
ansible-inventory --list

2.7 Playbook 命令

# 执行 playbook
ansible-playbook playbook.yml

# 检查模式(不执行)
ansible-playbook --check playbook.yml

# 差异化执行(检查变更)
ansible-playbook --diff playbook.yml

# 指定主机
ansible-playbook -i inventory.ini playbook.yml

# 指定标签
ansible-playbook --tags "web" playbook.yml

# 跳过标签
ansible-playbook --skip-tags "debug" playbook.yml

# 启动步骤
ansible-playbook --start-at-task "Install Apache" playbook.yml

# 步骤执行
ansible-playbook --step playbook.yml

# 详细输出
ansible-playbook -v playbook.yml
ansible-playbook -vv playbook.yml
ansible-playbook -vvv playbook.yml  # 详细调试

# 清缓存
ansible-playbook --flush-cache playbook.yml

3. Ansible 常用模块详解

3.1 模块分类

分类 说明 常见模块
命令执行 执行远程命令 command, shell, script, raw
文件操作 文件管理 copy, file, template, synchronize
包管理 软件包管理 yum, apt, package
服务管理 服务管理 service, systemd
用户管理 用户管理 user, group
数据库 数据库操作 mysql_db, postgresql_db
云资源 云资源管理 ec2, azure_rm, gce
容器 容器管理 docker, k8s
通知 通知模块 email, slack

3.2 命令执行模块

3.2.1 command 模块

- name: Execute command
  command: uptime

- name: Execute with args
  command: systemctl start nginx

- name: Check file exists
  command: test -f /etc/nginx/nginx.conf
  register: result

- name: Create directory
  command: mkdir -p /tmp/test
  creates: /tmp/test  # 存在则跳过

3.2.2 shell 模块

- name: Execute shell
  shell: echo $PATH

- name: Execute with pipe
  shell: cat /etc/passwd | grep root

- name: Execute script
  shell: |
    #!/bin/bash
    echo "Hello"

3.2.3 script 模块

- name: Run local script
  script: /tmp/script.sh

- name: Run with args
  script: /tmp/script.sh --arg1 value1

- name: Run on remote
  script: /tmp/script.sh
  args:
    creates: /tmp/result

3.3 文件操作模块

3.3.1 copy 模块

- name: Copy file
  copy:
    src: /tmp/source.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'

- name: Copy with backup
  copy:
    src: /tmp/source.conf
    dest: /etc/nginx/nginx.conf
    backup: yes

- name: Copy content
  copy:
    dest: /tmp/test.txt
    content: "Hello World"

3.3.2 file 模块

- name: Create directory
  file:
    path: /tmp/dir
    state: directory
    mode: '0755'

- name: Create file
  file:
    path: /tmp/file
    state: touch

- name: Create symlink
  file:
    src: /tmp/source
    dest: /tmp/link
    state: link

- name: Delete file
  file:
    path: /tmp/file
    state: absent

3.3.3 template 模块

- name: Template file
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    validate: 'nginx -t -c %s'

3.3.4 synchronize 模块

- name: Sync directory
  synchronize:
    src: /tmp/local/
    dest: /tmp/remote/
    delete: yes
    rsync_opts:
      - "--exclude=.git"

3.4 包管理模块

3.4.1 yum 模块

- name: Install package
  yum:
    name: nginx
    state: present

- name: Install latest
  yum:
    name: '*'
    state: latest

- name: Install multiple
  yum:
    name:
      - nginx
      - php-fpm
    state: present

- name: Remove package
  yum:
    name: nginx
    state: absent

- name: Install from repo
  yum:
    name: epel-release
    enablerepo: epel

3.4.2 apt 模块

- name: Install package
  apt:
    name: nginx
    state: present
    update_cache: yes

- name: Install without update
  apt:
    name: nginx
    state: present
    update_cache: no

- name: Install from deb
  apt:
    deb: /tmp/package.deb
    state: present

3.5 服务管理模块

3.5.1 service 模块

- name: Start service
  service:
    name: nginx
    state: started
    enabled: yes

- name: Stop service
  service:
    name: nginx
    state: stopped

- name: Restart service
  service:
    name: nginx
    state: restarted

- name: Reload service
  service:
    name: nginx
    state: reloaded

3.5.2 systemd 模块

- name: Enable and start service
  systemd:
    name: nginx
    state: started
    enabled: yes
    daemon_reload: yes

3.6 用户管理模块

3.6.1 user 模块

- name: Create user
  user:
    name: appuser
    comment: "Application User"
    shell: /bin/bash
    home: /home/appuser
    create_home: yes

- name: Create with password
  user:
    name: admin
    password: "{{ 'password' | password_hash('sha512') }}"

- name: Add to group
  user:
    name: appuser
    groups:
      - wheel
      - docker
    append: yes

- name: Remove user
  user:
    name: appuser
    state: absent
    remove: yes

3.6.2 group 模块

- name: Create group
  group:
    name: mygroup
    state: present
    gid: 1000

3.7 其他常用模块

3.7.1 get_url 模块

- name: Download file
  get_url:
    url: http://example.com/file.tar.gz
    dest: /tmp/file.tar.gz
    mode: '0644'

3.7.2 unarchive 模块

- name: Unarchive file
  unarchive:
    src: /tmp/file.tar.gz
    dest: /tmp/
    remote_src: no

3.7.3 lineinfile 模块

- name: Add line
  lineinfile:
    path: /etc/selinux/config
    regexp: '^SELINUX='
    line: SELINUX=enforcing

- name: Remove line
  lineinfile:
    path: /etc/selinux/config
    regexp: '^SELINUX='
    state: absent

3.7.4 find 模块

- name: Find files
  find:
    paths: /var/log
    patterns: "*.log"
    age: 7d
  register: log_files

4. Ansible Playbook 基础

4.1 Playbook 概述

Playbook 是 Ansible 的任务配置文件,使用 YAML 格式编写,定义了一组有序的任务。

┌─────────────────────────────────────────────────────┐
│                Playbook 结构                         │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Playbook (剧本)                                    │
│  ├── Play 1                                         │
│  │   ├── Hosts (主机)                               │
│  │   ├── Vars (变量)                                │
│  │   └── Tasks (任务)                              │
│  │       ├── Task 1 (Module)                       │
│  │       └── Task 2 (Module)                       │
│  │                                              │
│  └── Play 2                                         │
│      ├── Hosts                                      │
│      ├── Vars                                       │
│      └── Tasks                                     │
│                                                     │
└─────────────────────────────────────────────────────┘

4.2 基础 Playbook 示例

# playbook.yml
---
- name: Configure Web Server
  hosts: web
  become: yes
  
  vars:
    http_port: 80
    
  tasks:
    - name: Install Apache
      yum:
        name: httpd
        state: present
        
    - name: Ensure Apache is running
      service:
        name: httpd
        state: started
        enabled: yes
        
    - name: Copy configuration
      copy:
        src: files/httpd.conf
        dest: /etc/httpd/conf/httpd.conf
      notify: Restart Apache
      
    - name: Copy index page
      template:
        src: templates/index.html.j2
        dest: /var/www/html/index.html
        
  handlers:
    - name: Restart Apache
      service:
        name: httpd
        state: restarted

4.3 多个 Play

---
- name: Configure Web Servers
  hosts: web
  become: yes
  
  tasks:
    - name: Install Apache
      yum:
        name: httpd
        state: present
        
    - name: Start Apache
      service:
        name: httpd
        state: started

- name: Configure Database Servers
  hosts: db
  become: yes
  
  tasks:
    - name: Install MySQL
      yum:
        name: mysql-server
        state: present
        
    - name: Start MySQL
      service:
        name: mysqld
        state: started

4.4 Play 常用参数

参数 说明
name Play 名称
hosts 目标主机
become 是否提权
become_method 提权方式sudo/su
become_user 提权用户
gather_facts 是否收集主机信息
vars 变量
tasks 任务列表
handlers 处理器
roles 角色

4.5 Task 常用参数

参数 说明
name 任务名称
module 使用的模块
args 模块参数
when 条件判断
register 注册变量
changed_when 改变判断条件
failed_when 失败判断条件
loop 循环
until 循环直到
retries 重试次数
delay 重试延迟

4.6 任务控制

# 顺序执行
- name: Task 1
  yum:
    name: httpd
    state: present
    
- name: Task 2
  service:
    name: httpd
    state: started

# 忽略错误
- name: Ignore error
  command: /some/command
  ignore_errors: yes

# 强制失败
- name: Force fail
  command: /some/command
  failed_when: "'FAILED' in result.stderr"

# 标签
- name: Install packages
  yum:
    name: "{{ item }}"
  tags:
    - packages
    - web

5. Playbook 变量、Tags、Handlers 使用

5.1 变量

5.1.1 变量定义

# 方式 1Play 变量
- hosts: web
  vars:
    http_port: 80
    server_name: example.com
    
  tasks:
    - name: Use variable
      debug:
        msg: "Port is {{ http_port }}"

# 方式 2Task 变量
- name: Task variable
  debug:
    msg: "{{ task_var }}"
  vars:
    task_var: "Hello"

5.1.2 主机变量

# inventory
[web]
192.168.1.10 http_port=8080
192.168.1.11 http_port=8090

5.1.3 组变量

# group_vars/all.yml
---
ansible_user: admin
ansible_ssh_pass: password

# group_vars/web.yml
---
http_port: 80

5.1.4 变量引用

- name: Reference variables
  debug:
    msg: "{{ variable_name }}"
    
- name: Complex reference
  debug:
    msg: "{{ hostvars[groups['web'][0]]['ansible_host'] }}"

5.1.5 Facts 变量

# 获取 facts
- name: Get facts
  setup:
    filter: ansible_*

- name: Show facts
  debug:
    msg: "{{ ansible_hostname }}"
    
# 常用 facts
# ansible_hostname - 主机名
# ansible_default_ipv4.address - IP 地址
# ansible_distribution - 发行版
# ansible_distribution_version - 版本
# ansible_memory_mb.real.total - 内存
# ansible_processor_vcpus - CPU 核心数

5.2 Tags

5.2.1 Tag 定义

- name: Install Apache
  yum:
    name: httpd
    state: present
  tags:
    - web
    - httpd
    
- name: Configure Apache
  template:
    src: httpd.conf.j2
    dest: /etc/httpd/conf/httpd.conf
  tags:
    - config
    - httpd

5.2.2 Tag 使用

# 只执行带 tag 的任务
ansible-playbook --tags "web" playbook.yml

# 跳过 tag
ansible-playbook --skip-tags "debug" playbook.yml

# 多个 tag
ansible-playbook --tags "web,mysql" playbook.yml

5.3 Handlers

5.3.1 Handler 定义

- name: Configure Apache
  template:
    src: httpd.conf.j2
    dest: /etc/httpd/conf/httpd.conf
  notify:
    - Restart Apache
    
handlers:
  - name: Restart Apache
    service:
      name: httpd
      state: restarted

5.3.2 多个 Handlers

- name: Configure Apache
  template:
    src: httpd.conf.j2
    dest: /etc/httpd/conf/httpd.conf
  notify:
    - Restart Apache
    - Reload Nginx
    
handlers:
  - name: Restart Apache
    service:
      name: httpd
      state: restarted
      
  - name: Reload Nginx
    service:
      name: nginx
      state: reloaded

5.3.3 Handler 监听

- name: Config changed
  template:
    src: app.conf.j2
    dest: /etc/app.conf
  notify:
    - Notify handler
    
handlers:
  - name: Notify handler
    service:
      name: app
      state: restarted
    listen: "config changed"

6. Playbook 模板 Templates

6.1 Jinja2 模板概述

Ansible 使用 Jinja2 作为模板引擎,支持变量、过滤器、循环等特性。

6.2 基础模板

{# config.conf.j2 #}
# Server configuration
ServerName {{ server_name }}
Listen {{ http_port }}
DocumentRoot "{{ document_root }}"

{% if enable_ssl %}
SSLEngine on
SSLCertificateFile {{ ssl_cert }}
SSLCertificateKeyFile {{ ssl_key }}
{% endif %}

6.3 变量和过滤器

{# 使用变量 #}
{{ variable }}

{# 默认值 #}
{{ variable | default('default_value') }}

{# 过滤器 #}
{{ name | upper }}
{{ list | join(',') }}
{{ number | int }}

{# 条件判断 #}
{% if var == 'value' %}
...
{% endif %}

{# 循环 #}
{% for item in items %}
{{ item }}
{% endfor %}

6.4 完整示例

# playbook.yml
---
- name: Configure Nginx
  hosts: web
  become: yes
  
  vars:
    server_name: example.com
    http_port: 80
    document_root: /var/www/html
    enable_ssl: true
    ssl_cert: /etc/nginx/ssl/server.crt
    ssl_key: /etc/nginx/ssl/server.key
    
  tasks:
    - name: Ensure Nginx installed
      yum:
        name: nginx
        state: present
        
    - name: Configure Nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        validate: 'nginx -t -c %s'
      notify: Restart Nginx
      
  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted
{# nginx.conf.j2 #}
user nginx;
worker_processes {{ worker_processes | default('auto') }};
error_log /var/log/nginx/error.log;

events {
    worker_connections {{ worker_connections | default(1024) }};
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log main;
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout {{ keepalive_timeout | default(65) }};
    
    upstream backend {
        {% for server in upstream_servers %}
        server {{ server.host }}:{{ server.port }}{% if server.weight %} weight={{ server.weight }}{% endif %};
        {% endfor %}
    }
    
    server {
        listen {{ http_port }};
        server_name {{ server_name }};
        
        root {{ document_root }};
        
        {% if enable_ssl %}
        listen 443 ssl http2;
        ssl_certificate {{ ssl_cert }};
        ssl_certificate_key {{ ssl_key }};
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
        {% endif %}
        
        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

6.5 模板变量文件

# group_vars/web.yml
---
server_name: example.com
http_port: 80
document_root: /var/www/html
enable_ssl: true
ssl_cert: /etc/nginx/ssl/server.crt
ssl_key: /etc/nginx/ssl/server.key

upstream_servers:
  - host: 192.168.1.10
    port: 8080
    weight: 5
  - host: 192.168.1.11
    port: 8080
    weight: 3

worker_processes: 4
worker_connections: 2048
keepalive_timeout: 60

7. Playbook 条件判断 When

7.1 when 基础

- name: Install Apache on CentOS
  yum:
    name: httpd
    state: present
  when: ansible_os_family == "RedHat"

- name: Install Apache on Debian
  apt:
    name: apache2
    state: present
  when: ansible_os_family == "Debian"

7.2 多个条件

# AND 条件
- name: Install on specific OS
  yum:
    name: httpd
    state: present
  when:
    - ansible_os_family == "RedHat"
    - ansible_distribution_version | int >= 7

# OR 条件
- name: Install web server
  yum:
    name: nginx
    state: present
  when: ansible_os_family == "RedHat" or ansible_os_family == "Debian"

7.3 变量判断

- name: Register variable
  command: /usr/bin/test -f /etc/httpd/conf/httpd.conf
  register: httpd_conf
  
- name: Check result
  debug:
    msg: "Config file exists"
  when: httpd_conf.rc == 0

- name: Check changed
  command: /usr/bin/some-command
  register: result
  changed_when: result.rc != 0

- name: Conditional execution
  debug:
    msg: "Command changed"
  when: result is changed

7.4 内置条件测试

- name: Test defined
  debug:
    msg: "Variable defined"
  when: my_var is defined

- name: Test undefined
  debug:
    msg: "Variable not defined"
  when: my_var is not defined

- name: Test true
  debug:
    msg: "Value is true"
  when: my_var | bool

- name: Test false
  debug:
    msg: "Value is false"
  when: not my_var | bool

- name: Test string
  debug:
    msg: "String test"
  when: my_string == "value"

- name: Test number
  debug:
    msg: "Number test"
  when: my_number > 100

- name: Test in
  debug:
    msg: "In list"
  when: ansible_hostname in groups['web']

7.5 循环 + 条件

- name: Install packages based on OS
  yum:
    name: "{{ item }}"
    state: present
  loop:
    - httpd
    - nginx
  when: ansible_os_family == "RedHat"

- name: Install specific packages
  apt:
    name: "{{ item.name }}"
    state: present
  loop:
    - { name: 'apache2', os: 'Debian' }
    - { name: 'httpd', os: 'RedHat' }
  when: ansible_os_family == item.os

7.6 完整示例

---
- name: Configure servers based on OS
  hosts: all
  gather_facts: yes
  
  vars:
    install_web: true
    install_db: false
    
  tasks:
    - name: Install Apache
      yum:
        name: httpd
        state: present
      when:
        - install_web | bool
        - ansible_os_family == "RedHat"
        
    - name: Install Apache on Debian
      apt:
        name: apache2
        state: present
      when:
        - install_web | bool
        - ansible_os_family == "Debian"
        
    - name: Install MySQL
      yum:
        name: mysql-server
        state: present
      when:
        - install_db | bool
        - ansible_distribution == "CentOS"
        
    - name: Configure firewall for CentOS 7+
      firewalld:
        service: http
        permanent: yes
        state: enabled
      when:
        - ansible_os_family == "RedHat"
        - ansible_distribution_version | int >= 7
        
    - name: Only on web servers
      debug:
        msg: "This is a web server"
      when: "'web' in group_names"

8. Playbook 字典 with_items

8.1 with_items 基础

- name: Install multiple packages
  yum:
    name: "{{ item }}"
    state: present
  loop:
    - httpd
    - nginx
    - php-fpm
    
- name: Create users
  user:
    name: "{{ item }}"
    state: present
  loop:
    - alice
    - bob
    - charlie

8.2 字典列表

- name: Create multiple users with attributes
  user:
    name: "{{ item.name }}"
    comment: "{{ item.comment }}"
    shell: "{{ item.shell }}"
    create_home: yes
  loop:
    - { name: 'alice', comment: 'Alice User', shell: '/bin/bash' }
    - { name: 'bob', comment: 'Bob User', shell: '/bin/sh' }

8.3 嵌套循环

- name: Create directories
  file:
    path: "{{ item.0 }}/{{ item.1 }}"
    state: directory
  loop:
    - ['/tmp', 'dir1']
    - ['/tmp', 'dir2']
    - ['/var', 'log']

8.4 with_dict

- name: Define dictionary
  set_fact:
    users:
      alice:
        shell: /bin/bash
        home: /home/alice
      bob:
        shell: /bin/sh
        home: /home/bob
        
- name: Create users from dict
  user:
    name: "{{ item.key }}"
    shell: "{{ item.value.shell }}"
    home: "{{ item.value.home }}"
  loop: "{{ dict(users) | dict2items }}"

8.5 with_fileglob

- name: Copy all files
  copy:
    src: "{{ item }}"
    dest: /tmp/
    mode: '0644'
  loop:
    - "{{ playbook_dir }}/files/*"

8.6 with_sequence

- name: Create sequence files
  file:
    path: "/tmp/file{{ item }}"
    state: touch
  loop: "{{ range(1, 11) | list }}"

8.7 with_together

- name: Combine lists
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  loop: "{{ list1 | zip(list2) | list }}"

8.8 with_nested

- name: Nested loop
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  loop: "{{ ['a', 'b', 'c'] | product(['1', '2', '3']) | list }}"

8.9 注册变量 + 循环

- name: Get file contents
  command: cat {{ item }}
  register: file_contents
  loop:
    - /tmp/file1.txt
    - /tmp/file2.txt
    
- name: Show contents
  debug:
    msg: "{{ item.stdout }}"
  loop: "{{ file_contents.results }}"

8.10 完整示例

---
- name: Configure multi-tier application
  hosts: app
  
  vars:
    app_users:
      - { name: 'appuser', uid: 1000, group: 'app', shell: '/bin/bash' }
      - { name: 'deploy', uid: 1001, group: 'app', shell: '/bin/sh' }
      
    app_dirs:
      - { path: '/opt/app', owner: 'appuser', mode: '0755' }
      - { path: '/var/log/app', owner: 'appuser', mode: '0755' }
      - { path: '/tmp/app', owner: 'appuser', mode: '1777' }
      
    packages:
      - java-11-openjdk
      - maven
      - git
      
  tasks:
    - name: Create groups
      group:
        name: "{{ item }}"
        state: present
      loop:
        - app
        - deploy
        
    - name: Create users
      user:
        name: "{{ item.name }}"
        uid: "{{ item.uid }}"
        group: "{{ item.group }}"
        shell: "{{ item.shell }}"
        create_home: yes
      loop: "{{ app_users }}"
      
    - name: Create directories
      file:
        path: "{{ item.path }}"
        owner: "{{ item.owner }}"
        mode: "{{ item.mode }}"
        state: directory
      loop: "{{ app_dirs }}"
      
    - name: Install packages
      yum:
        name: "{{ item }}"
        state: present
      loop: "{{ packages }}"
      when: ansible_os_family == "RedHat"
      
    - name: Install packages (Debian)
      apt:
        name: "{{ item }}"
        state: present
        update_cache: yes
      loop: "{{ packages }}"
      when: ansible_os_family == "Debian"

9. Ansible Roles

9.1 Roles 概述

Roles 是 Ansible 的组织结构化机制,将 Playbook 分解为可重用的组件。

┌─────────────────────────────────────────────────────┐
│                 Roles 目录结构                        │
├─────────────────────────────────────────────────────┤
│                                                     │
│  roles/                                            │
│  └── role_name/                                    │
│      ├── defaults/          # 默认变量(最低优先级)│
│      │   └── main.yml                             │
│      ├── vars/             # 变量(最高优先级)   │
│      │   └── main.yml                             │
│      ├── tasks/            # 任务                 │
│      │   └── main.yml                             │
│      ├── handlers/         # 处理器               │
│      │   └── main.yml                             │
│      ├── templates/        # 模板                 │
│      │   └── *.j2                                 │
│      ├── files/           # 静态文件             │
│      │   └── *                                    │
│      ├── meta/            # 依赖关系             │
│      │   └── main.yml                             │
│      └── README.md        # 文档                 │
│                                                     │
└─────────────────────────────────────────────────────┘

9.2 创建 Role

# 使用 ansible-galaxy 创建
ansible-galaxy init role_name

# 手动创建目录结构
mkdir -p roles/nginx/{defaults,vars,tasks,handlers,templates,files,meta}

9.3 Role 示例Nginx

9.3.1 defaults/main.yml

---
# defaults/main.yml
nginx_version: "1.24"
nginx_port: 80
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_server_name: localhost
nginx_document_root: /var/www/html

9.3.2 vars/main.yml

---
# vars/main.yml
nginx_user: nginx
nginx_group: nginx
nginx_conf_dir: /etc/nginx
nginx_log_dir: /var/log/nginx

9.3.3 tasks/main.yml

---
# tasks/main.yml
- name: Ensure nginx is installed
  yum:
    name: nginx
    state: present
  when: ansible_os_family == "RedHat"

- name: Ensure nginx is installed
  apt:
    name: nginx
    state: present
    update_cache: yes
  when: ansible_os_family == "Debian"

- name: Copy nginx configuration
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: Restart nginx

- name: Ensure nginx is running
  service:
    name: nginx
    state: started
    enabled: yes

9.3.4 handlers/main.yml

---
# handlers/main.yml
- name: Restart nginx
  service:
    name: nginx
    state: restarted
    
- name: Reload nginx
  service:
    name: nginx
    state: reloaded

9.3.5 templates/nginx.conf.j2

# nginx.conf.j2
user {{ nginx_user }};
worker_processes {{ nginx_worker_processes }};
error_log {{ nginx_log_dir }}/error.log;

events {
    worker_connections {{ nginx_worker_connections }};
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    access_log {{ nginx_log_dir }}/access.log main;
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    
    server {
        listen {{ nginx_port }};
        server_name {{ nginx_server_name }};
        
        root {{ nginx_document_root }};
        
        location / {
            index index.html index.htm;
        }
    }
}

9.4 使用 Role

# site.yml
---
- name: Configure web servers
  hosts: web
  
  roles:
    - role: nginx
      nginx_port: 8080
      nginx_server_name: example.com
      
- name: Configure database servers
  hosts: db
  
  roles:
    - role: mysql
      mysql_port: 3306

9.5 Role 依赖

# roles/common/meta/main.yml
---
dependencies:
  - role: common
    vars:
      common_version: 1.0
  - role: monitoring

9.6 完整 Playbook 示例

# site.yml - 完整项目配置
---
- name: Infrastructure setup
  hosts: all
  gather_facts: yes
  
  roles:
    - common
    - ntp

- name: Web servers setup
  hosts: web
  become: yes
  
  roles:
    - nginx
    - php-fpm
    - firewall
    
- name: Database servers setup
  hosts: db
  become: yes
  
  roles:
    - mysql
    - backup
    
- name: Application deployment
  hosts: app
  become: yes
  
  roles:
    - app_deploy
    - monitoring_agent

9.7 导入 Role

# 静态导入
- name: Import role
  import_role:
    name: nginx
  vars:
    nginx_port: 8080

- name: Import handlers
  import_tasks: handlers.yml

9.8 动态 Role

# 动态导入
- name: Include role
  include_role:
    name: nginx
  vars:
    nginx_port: 80

9.9 Galaxy 角色

# 搜索角色
ansible-galaxy search nginx

# 安装角色
ansible-galaxy install geerlingguy.nginx

# 查看已安装角色
ansible-galaxy list

# 删除角色
ansible-galaxy remove geerlingguy.nginx

附录

常用命令速查

命令 说明
ansible all -m ping 测试连通性
ansible-playbook site.yml 执行 Playbook
ansible-playbook --check site.yml 模拟执行
ansible-playbook --tags "web" site.yml 指定标签
ansible-doc -l 列出模块
ansible-doc user 查看模块文档
ansible-galaxy init role 创建角色
ansible-config dump 查看配置

配置参数速查

参数 说明
inventory 主机清单
forks 并行数
become 提权
host_key_checking 主机指纹检查
retry_files_enabled 重试文件

变量优先级

优先级(低到高)
role defaults
inventory file/script group vars
inventory group vars
playbook group vars
host facts
register vars
set_facts
role/vars
include vars
include params
extra vars

文档创建时间2024年