Ansible 实战指南
目录
- 运维自动化发展历程及技术应用
- Ansible 架构和相关命令使用
- Ansible 常用模块详解
- Ansible Playbook 基础
- Playbook 变量、Tags、Handlers 使用
- Playbook 模板 Templates
- Playbook 条件判断 When
- Playbook 字典 with_items
- 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 变量定义
# 方式 1:Play 变量
- hosts: web
vars:
http_port: 80
server_name: example.com
tasks:
- name: Use variable
debug:
msg: "Port is {{ http_port }}"
# 方式 2:Task 变量
- 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年