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

1840 lines
40 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Ansible 实战指南
## 目录
1. [运维自动化发展历程及技术应用](#1-运维自动化发展历程及技术应用)
2. [Ansible 架构和相关命令使用](#2-ansible-架构和相关命令使用)
3. [Ansible 常用模块详解](#3-ansible-常用模块详解)
4. [Ansible Playbook 基础](#4-ansible-playbook-基础)
5. [Playbook 变量、Tags、Handlers 使用](#5-playbook-变量tagshandlers使用)
6. [Playbook 模板 Templates](#6-playbook-模板-templates)
7. [Playbook 条件判断 When](#7-playbook-条件判断-when)
8. [Playbook 字典 with_items](#8-playbook-字典-with_items)
9. [Ansible Roles](#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 安装
```bash
# 使用 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
```ini
# /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
```bash
# 使用脚本获取主机列表
ansible-playbook -i inventory.py playbook.yml
# AWS EC2 动态 Inventory
ansible-playbook -i ec2.py playbook.yml
```
### 2.5 Ansible 配置文件
```ini
# 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 常用命令
```bash
# 帮助
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 命令
```bash
# 执行 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 模块
```yaml
- 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 模块
```yaml
- 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 模块
```yaml
- 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 模块
```yaml
- 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 模块
```yaml
- 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 模块
```yaml
- 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 模块
```yaml
- name: Sync directory
synchronize:
src: /tmp/local/
dest: /tmp/remote/
delete: yes
rsync_opts:
- "--exclude=.git"
```
### 3.4 包管理模块
#### 3.4.1 yum 模块
```yaml
- 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 模块
```yaml
- 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 模块
```yaml
- 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 模块
```yaml
- name: Enable and start service
systemd:
name: nginx
state: started
enabled: yes
daemon_reload: yes
```
### 3.6 用户管理模块
#### 3.6.1 user 模块
```yaml
- 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 模块
```yaml
- name: Create group
group:
name: mygroup
state: present
gid: 1000
```
### 3.7 其他常用模块
#### 3.7.1 get_url 模块
```yaml
- name: Download file
get_url:
url: http://example.com/file.tar.gz
dest: /tmp/file.tar.gz
mode: '0644'
```
#### 3.7.2 unarchive 模块
```yaml
- name: Unarchive file
unarchive:
src: /tmp/file.tar.gz
dest: /tmp/
remote_src: no
```
#### 3.7.3 lineinfile 模块
```yaml
- 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 模块
```yaml
- 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 示例
```yaml
# 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
```yaml
---
- 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 任务控制
```yaml
# 顺序执行
- 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 变量定义
```yaml
# 方式 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 主机变量
```ini
# inventory
[web]
192.168.1.10 http_port=8080
192.168.1.11 http_port=8090
```
#### 5.1.3 组变量
```yaml
# group_vars/all.yml
---
ansible_user: admin
ansible_ssh_pass: password
# group_vars/web.yml
---
http_port: 80
```
#### 5.1.4 变量引用
```yaml
- name: Reference variables
debug:
msg: "{{ variable_name }}"
- name: Complex reference
debug:
msg: "{{ hostvars[groups['web'][0]]['ansible_host'] }}"
```
#### 5.1.5 Facts 变量
```yaml
# 获取 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 定义
```yaml
- 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 使用
```bash
# 只执行带 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 定义
```yaml
- 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
```yaml
- 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 监听
```yaml
- 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 基础模板
```jinja
{# 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 变量和过滤器
```jinja
{# 使用变量 #}
{{ variable }}
{# 默认值 #}
{{ variable | default('default_value') }}
{# 过滤器 #}
{{ name | upper }}
{{ list | join(',') }}
{{ number | int }}
{# 条件判断 #}
{% if var == 'value' %}
...
{% endif %}
{# 循环 #}
{% for item in items %}
{{ item }}
{% endfor %}
```
### 6.4 完整示例
```yaml
# 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
```
```jinja
{# 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 模板变量文件
```yaml
# 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 基础
```yaml
- 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 多个条件
```yaml
# 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 变量判断
```yaml
- 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 内置条件测试
```yaml
- 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 循环 + 条件
```yaml
- 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 完整示例
```yaml
---
- 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 基础
```yaml
- 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 字典列表
```yaml
- 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 嵌套循环
```yaml
- name: Create directories
file:
path: "{{ item.0 }}/{{ item.1 }}"
state: directory
loop:
- ['/tmp', 'dir1']
- ['/tmp', 'dir2']
- ['/var', 'log']
```
### 8.4 with_dict
```yaml
- 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
```yaml
- name: Copy all files
copy:
src: "{{ item }}"
dest: /tmp/
mode: '0644'
loop:
- "{{ playbook_dir }}/files/*"
```
### 8.6 with_sequence
```yaml
- name: Create sequence files
file:
path: "/tmp/file{{ item }}"
state: touch
loop: "{{ range(1, 11) | list }}"
```
### 8.7 with_together
```yaml
- name: Combine lists
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ list1 | zip(list2) | list }}"
```
### 8.8 with_nested
```yaml
- name: Nested loop
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ ['a', 'b', 'c'] | product(['1', '2', '3']) | list }}"
```
### 8.9 注册变量 + 循环
```yaml
- 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 完整示例
```yaml
---
- 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
```bash
# 使用 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
```yaml
---
# 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
```yaml
---
# 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
```yaml
---
# 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
```yaml
---
# 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
```jinja
# 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
```yaml
# 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 依赖
```yaml
# roles/common/meta/main.yml
---
dependencies:
- role: common
vars:
common_version: 1.0
- role: monitoring
```
### 9.6 完整 Playbook 示例
```yaml
# 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
```yaml
# 静态导入
- name: Import role
import_role:
name: nginx
vars:
nginx_port: 8080
- name: Import handlers
import_tasks: handlers.yml
```
### 9.8 动态 Role
```yaml
# 动态导入
- name: Include role
include_role:
name: nginx
vars:
nginx_port: 80
```
### 9.9 Galaxy 角色
```bash
# 搜索角色
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年*