3.1 核心概念概述
Ansible 的核心概念构成了整个自动化框架的基础。理解这些概念对于有效使用 Ansible 至关重要。
3.1.1 概念关系图
┌─────────────────────────────────────────────────────────────┐
│ Ansible 核心架构 │
├─────────────────────────────────────────────────────────────┤
│ Control Node (控制节点) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Playbooks │ │ Inventory │ │ Modules │ │
│ │ │ │ │ │ │ │
│ │ ┌───────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ Tasks │ │ │ │ Groups │ │ │ │ Actions │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ ┌───┐ │ │ │ │ ┌─────┐ │ │ │ │ ┌─────┐ │ │ │
│ │ │ │Var│ │ │ │ │ │Host │ │ │ │ │ │Args │ │ │ │
│ │ │ └───┘ │ │ │ │ └─────┘ │ │ │ │ └─────┘ │ │ │
│ │ └───────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ SSH/WinRM 连接 ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Managed Nodes (被管理节点) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Server1 │ │ Server2 │ │ Server3 │ │
│ │ │ │ │ │ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ Python │ │ │ │ Python │ │ │ │ Python │ │ │
│ │ │ SSH │ │ │ │ SSH │ │ │ │ SSH │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
3.2 Inventory(主机清单)
3.2.1 Inventory 基本概念
Inventory 是 Ansible 中定义和组织被管理主机的文件,它告诉 Ansible 要管理哪些主机以及如何连接这些主机。
主要功能: - 定义主机列表 - 组织主机分组 - 设置连接参数 - 定义变量
3.2.2 静态 Inventory
INI 格式示例
# inventory/hosts
# 单独的主机
web1.example.com
web2.example.com ansible_host=192.168.1.11 ansible_port=2222
# 主机组
[webservers]
web1.example.com
web2.example.com
web3.example.com
[databases]
db1.example.com
db2.example.com
[cache]
redis1.example.com
redis2.example.com
# 主机组的组(父子关系)
[production:children]
webservers
databases
cache
[staging:children]
webservers
# 组变量
[webservers:vars]
http_port=80
max_clients=200
ansible_user=deploy
[databases:vars]
db_port=3306
ansible_user=dbadmin
# 主机范围
[test]
test[01:10].example.com
test[a:f].example.com
# 连接参数
[windows]
win1.example.com ansible_host=192.168.1.50 ansible_connection=winrm ansible_user=administrator
YAML 格式示例
# inventory/hosts.yml
all:
children:
production:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
ansible_host: 192.168.1.11
ansible_port: 2222
web3.example.com:
vars:
http_port: 80
max_clients: 200
ansible_user: deploy
databases:
hosts:
db1.example.com:
db2.example.com:
vars:
db_port: 3306
ansible_user: dbadmin
cache:
hosts:
redis1.example.com:
redis2.example.com:
staging:
children:
webservers:
hosts:
staging-web1.example.com:
staging-web2.example.com:
windows:
hosts:
win1.example.com:
ansible_host: 192.168.1.50
ansible_connection: winrm
ansible_user: administrator
3.2.3 动态 Inventory
云平台动态 Inventory
#!/usr/bin/env python3
# inventory/aws_inventory.py
import boto3
import json
import sys
def get_aws_inventory():
ec2 = boto3.client('ec2')
response = ec2.describe_instances()
inventory = {
'all': {
'hosts': [],
'vars': {}
},
'_meta': {
'hostvars': {}
}
}
for reservation in response['Reservations']:
for instance in reservation['Instances']:
if instance['State']['Name'] == 'running':
instance_name = instance.get('PublicDnsName', instance['InstanceId'])
inventory['all']['hosts'].append(instance_name)
# 主机变量
inventory['_meta']['hostvars'][instance_name] = {
'ansible_host': instance.get('PublicIpAddress'),
'instance_id': instance['InstanceId'],
'instance_type': instance['InstanceType'],
'availability_zone': instance['Placement']['AvailabilityZone']
}
# 根据标签创建组
for tag in instance.get('Tags', []):
if tag['Key'] == 'Environment':
env = tag['Value']
if env not in inventory:
inventory[env] = {'hosts': []}
inventory[env]['hosts'].append(instance_name)
if tag['Key'] == 'Role':
role = tag['Value']
if role not in inventory:
inventory[role] = {'hosts': []}
inventory[role]['hosts'].append(instance_name)
return inventory
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--list':
print(json.dumps(get_aws_inventory(), indent=2))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
print(json.dumps({}, indent=2))
else:
print("Usage: %s --list or %s --host <hostname>" % (sys.argv[0], sys.argv[0]))
数据库动态 Inventory
#!/usr/bin/env python3
# inventory/db_inventory.py
import mysql.connector
import json
import sys
from configparser import ConfigParser
def get_db_inventory():
# 读取数据库配置
config = ConfigParser()
config.read('db_config.ini')
# 连接数据库
conn = mysql.connector.connect(
host=config.get('database', 'host'),
user=config.get('database', 'user'),
password=config.get('database', 'password'),
database=config.get('database', 'name')
)
cursor = conn.cursor(dictionary=True)
# 查询主机信息
cursor.execute("""
SELECT
hostname,
ip_address,
environment,
role,
ssh_user,
ssh_port
FROM servers
WHERE status = 'active'
""")
servers = cursor.fetchall()
inventory = {
'all': {
'hosts': [],
'vars': {}
},
'_meta': {
'hostvars': {}
}
}
for server in servers:
hostname = server['hostname']
inventory['all']['hosts'].append(hostname)
# 主机变量
inventory['_meta']['hostvars'][hostname] = {
'ansible_host': server['ip_address'],
'ansible_user': server['ssh_user'],
'ansible_port': server['ssh_port']
}
# 环境分组
env = server['environment']
if env not in inventory:
inventory[env] = {'hosts': []}
inventory[env]['hosts'].append(hostname)
# 角色分组
role = server['role']
if role not in inventory:
inventory[role] = {'hosts': []}
inventory[role]['hosts'].append(hostname)
cursor.close()
conn.close()
return inventory
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--list':
print(json.dumps(get_db_inventory(), indent=2))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
print(json.dumps({}, indent=2))
else:
print("Usage: %s --list or %s --host <hostname>" % (sys.argv[0], sys.argv[0]))
3.2.4 Inventory 插件
使用内置插件
# inventory/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
- us-west-2
keyed_groups:
- key: tags
prefix: tag
- key: instance_type
prefix: instance_type
- key: placement.region
prefix: aws_region
compose:
ansible_host: public_ip_address
# inventory/gcp_compute.yml
plugin: google.cloud.gcp_compute
projects:
- my-project-id
auth_kind: serviceaccount
service_account_file: /path/to/service-account.json
keyed_groups:
- key: labels
prefix: label
- key: machineType
prefix: machine_type
- key: zone
prefix: zone
3.3 Modules(模块)
3.3.1 模块基本概念
模块是 Ansible 的工作单元,每个模块负责执行特定的任务。Ansible 提供了数百个内置模块,涵盖了系统管理的各个方面。
模块特点: - 幂等性:多次执行相同结果 - 返回 JSON 格式结果 - 可以在任何支持 Python 的系统上运行 - 支持 check 模式(干运行)
3.3.2 常用系统模块
文件操作模块
# file 模块 - 文件和目录操作
- name: 创建目录
file:
path: /opt/myapp
state: directory
mode: '0755'
owner: app
group: app
- name: 创建文件
file:
path: /opt/myapp/config.txt
state: touch
mode: '0644'
- name: 创建符号链接
file:
src: /opt/myapp/current
dest: /opt/myapp/releases/v1.2.3
state: link
# copy 模块 - 复制文件
- name: 复制配置文件
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
backup: yes
owner: root
group: root
mode: '0644'
notify: restart nginx
# template 模块 - 模板文件
- name: 生成配置文件
template:
src: templates/app.conf.j2
dest: /opt/myapp/app.conf
owner: app
group: app
mode: '0600'
vars:
db_host: "{{ database_host }}"
db_port: "{{ database_port }}"
# fetch 模块 - 从远程主机获取文件
- name: 获取日志文件
fetch:
src: /var/log/myapp.log
dest: logs/
flat: yes
包管理模块
# package 模块 - 通用包管理
- name: 安装软件包
package:
name: "{{ item }}"
state: present
loop:
- nginx
- mysql-server
- redis-server
# apt 模块 - Debian/Ubuntu 包管理
- name: 更新包缓存
apt:
update_cache: yes
cache_valid_time: 3600
- name: 安装特定版本的包
apt:
name: nginx=1.18.0-1ubuntu1
state: present
- name: 安装 .deb 包
apt:
deb: /tmp/myapp.deb
# yum 模块 - RedHat/CentOS 包管理
- name: 安装开发工具组
yum:
name: "@Development tools"
state: present
- name: 从特定仓库安装
yum:
name: docker-ce
state: present
enablerepo: docker-ce-stable
# pip 模块 - Python 包管理
- name: 安装 Python 包
pip:
name:
- django==3.2.0
- requests
- celery[redis]
virtualenv: /opt/myapp/venv
virtualenv_python: python3.8
服务管理模块
# service 模块 - 通用服务管理
- name: 启动并启用服务
service:
name: nginx
state: started
enabled: yes
# systemd 模块 - systemd 服务管理
- name: 重新加载 systemd 配置
systemd:
daemon_reload: yes
- name: 管理用户服务
systemd:
name: myapp
state: started
scope: user
user: app
# cron 模块 - 定时任务管理
- name: 添加备份任务
cron:
name: "database backup"
minute: "0"
hour: "2"
job: "/usr/local/bin/backup.sh"
user: backup
- name: 删除定时任务
cron:
name: "old backup task"
state: absent
3.3.3 网络和云模块
网络配置模块
# uri 模块 - HTTP 请求
- name: 检查 API 健康状态
uri:
url: "http://{{ inventory_hostname }}:8080/health"
method: GET
status_code: 200
register: health_check
- name: 发送 POST 请求
uri:
url: "https://api.example.com/webhook"
method: POST
body_format: json
body:
message: "Deployment completed"
server: "{{ inventory_hostname }}"
headers:
Authorization: "Bearer {{ api_token }}"
# get_url 模块 - 下载文件
- name: 下载应用程序
get_url:
url: "https://releases.example.com/myapp-{{ app_version }}.tar.gz"
dest: "/tmp/myapp-{{ app_version }}.tar.gz"
checksum: "sha256:{{ app_checksum }}"
timeout: 30
# wait_for 模块 - 等待条件
- name: 等待端口开放
wait_for:
host: "{{ inventory_hostname }}"
port: 8080
delay: 10
timeout: 300
state: started
- name: 等待文件存在
wait_for:
path: /opt/myapp/ready
state: present
timeout: 600
云平台模块
# AWS EC2 模块
- name: 启动 EC2 实例
amazon.aws.ec2_instance:
name: "web-server-{{ ansible_date_time.epoch }}"
image_id: ami-0abcdef1234567890
instance_type: t3.micro
key_name: my-key
security_groups:
- web-servers
tags:
Environment: production
Role: webserver
wait: yes
wait_timeout: 600
register: ec2_result
# AWS S3 模块
- name: 上传文件到 S3
amazon.aws.s3_object:
bucket: my-app-backups
object: "backups/{{ ansible_date_time.date }}/database.sql"
src: /tmp/database.sql
mode: put
encrypt: yes
# Azure 虚拟机模块
- name: 创建 Azure VM
azure.azcollection.azure_rm_virtualmachine:
resource_group: myResourceGroup
name: myVM
vm_size: Standard_B1s
admin_username: azureuser
ssh_password_enabled: false
ssh_public_keys:
- path: /home/azureuser/.ssh/authorized_keys
key_data: "{{ ssh_public_key }}"
image:
offer: UbuntuServer
publisher: Canonical
sku: 18.04-LTS
version: latest
3.3.4 自定义模块
Python 自定义模块
#!/usr/bin/python
# library/custom_service_check.py
from ansible.module_utils.basic import AnsibleModule
import requests
import time
def check_service_health(url, timeout, retries):
"""检查服务健康状态"""
for attempt in range(retries):
try:
response = requests.get(url, timeout=timeout)
if response.status_code == 200:
return True, f"Service is healthy (attempt {attempt + 1})"
else:
time.sleep(2)
except requests.RequestException as e:
if attempt == retries - 1:
return False, f"Service check failed: {str(e)}"
time.sleep(2)
return False, "Service check failed after all retries"
def main():
module = AnsibleModule(
argument_spec=dict(
url=dict(type='str', required=True),
timeout=dict(type='int', default=10),
retries=dict(type='int', default=3),
expected_status=dict(type='int', default=200)
),
supports_check_mode=True
)
url = module.params['url']
timeout = module.params['timeout']
retries = module.params['retries']
if module.check_mode:
module.exit_json(changed=False, msg="Check mode - would check service health")
success, message = check_service_health(url, timeout, retries)
if success:
module.exit_json(changed=False, msg=message, url=url)
else:
module.fail_json(msg=message, url=url)
if __name__ == '__main__':
main()
使用自定义模块
# 使用自定义模块
- name: 检查应用程序健康状态
custom_service_check:
url: "http://{{ inventory_hostname }}:8080/health"
timeout: 15
retries: 5
register: health_result
- name: 显示健康检查结果
debug:
msg: "{{ health_result.msg }}"
3.4 Playbooks(剧本)
3.4.1 Playbook 基本结构
Playbook 是 Ansible 的配置、部署和编排语言。它们可以描述你希望远程系统执行的策略,或者一般 IT 流程中的一系列步骤。
# basic-playbook.yml
---
# Playbook 头部信息
- name: 基础 Web 服务器配置
hosts: webservers
become: yes
gather_facts: yes
vars:
http_port: 80
max_clients: 200
# 前置任务
pre_tasks:
- name: 更新包缓存
apt:
update_cache: yes
cache_valid_time: 3600
# 主要任务
tasks:
- name: 安装 Nginx
package:
name: nginx
state: present
- name: 启动并启用 Nginx
service:
name: nginx
state: started
enabled: yes
- name: 配置防火墙
ufw:
rule: allow
port: "{{ http_port }}"
proto: tcp
# 处理器
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
# 后置任务
post_tasks:
- name: 验证 Nginx 运行状态
uri:
url: "http://{{ inventory_hostname }}"
status_code: 200
3.4.2 多 Play Playbook
# multi-play-playbook.yml
---
# 第一个 Play - 配置数据库服务器
- name: 配置数据库服务器
hosts: databases
become: yes
vars:
mysql_root_password: "{{ vault_mysql_root_password }}"
tasks:
- name: 安装 MySQL
package:
name: mysql-server
state: present
- name: 配置 MySQL
template:
src: my.cnf.j2
dest: /etc/mysql/my.cnf
notify: restart mysql
- name: 启动 MySQL
service:
name: mysql
state: started
enabled: yes
handlers:
- name: restart mysql
service:
name: mysql
state: restarted
# 第二个 Play - 配置 Web 服务器
- name: 配置 Web 服务器
hosts: webservers
become: yes
vars:
app_version: "1.2.3"
tasks:
- name: 安装应用程序依赖
package:
name:
- python3
- python3-pip
- nginx
state: present
- name: 部署应用程序
unarchive:
src: "https://releases.example.com/myapp-{{ app_version }}.tar.gz"
dest: /opt/
remote_src: yes
creates: "/opt/myapp-{{ app_version }}"
- name: 创建符号链接
file:
src: "/opt/myapp-{{ app_version }}"
dest: /opt/myapp/current
state: link
# 第三个 Play - 配置负载均衡器
- name: 配置负载均衡器
hosts: loadbalancers
become: yes
tasks:
- name: 安装 HAProxy
package:
name: haproxy
state: present
- name: 配置 HAProxy
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: restart haproxy
handlers:
- name: restart haproxy
service:
name: haproxy
state: restarted
3.4.3 条件执行和循环
# conditional-loops.yml
---
- name: 条件执行和循环示例
hosts: all
become: yes
tasks:
# 条件执行
- name: 仅在 Ubuntu 上安装 apt 包
apt:
name: "{{ item }}"
state: present
loop:
- curl
- wget
- vim
when: ansible_distribution == "Ubuntu"
- name: 仅在 CentOS 上安装 yum 包
yum:
name: "{{ item }}"
state: present
loop:
- curl
- wget
- vim
when: ansible_distribution == "CentOS"
# 复杂条件
- name: 在生产环境的 Web 服务器上配置 SSL
template:
src: ssl.conf.j2
dest: /etc/nginx/conf.d/ssl.conf
when:
- environment == "production"
- "'webservers' in group_names"
- ssl_enabled | default(false)
# 字典循环
- name: 创建多个用户
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
shell: "{{ item.shell | default('/bin/bash') }}"
state: present
loop:
- { name: "alice", groups: "developers", shell: "/bin/zsh" }
- { name: "bob", groups: "operators" }
- { name: "charlie", groups: "developers,operators" }
# 条件循环
- name: 安装开发工具(仅在开发环境)
package:
name: "{{ item }}"
state: present
loop:
- git
- nodejs
- docker
when: environment == "development"
# 注册变量和条件
- name: 检查服务状态
command: systemctl is-active nginx
register: nginx_status
failed_when: false
changed_when: false
- name: 启动 Nginx(如果未运行)
service:
name: nginx
state: started
when: nginx_status.stdout != "active"
# 文件存在性检查
- name: 检查配置文件是否存在
stat:
path: /etc/myapp/config.yml
register: config_file
- name: 创建默认配置(如果不存在)
template:
src: default-config.yml.j2
dest: /etc/myapp/config.yml
when: not config_file.stat.exists
3.4.4 错误处理
# error-handling.yml
---
- name: 错误处理示例
hosts: all
tasks:
# 忽略错误
- name: 尝试停止可能不存在的服务
service:
name: optional-service
state: stopped
ignore_errors: yes
# 自定义失败条件
- name: 检查磁盘空间
shell: df -h / | tail -1 | awk '{print $5}' | sed 's/%//'
register: disk_usage
failed_when: disk_usage.stdout | int > 90
# 重试机制
- name: 下载文件(带重试)
get_url:
url: "https://example.com/large-file.zip"
dest: /tmp/large-file.zip
register: download_result
until: download_result is succeeded
retries: 3
delay: 10
# 块和救援
- name: 尝试配置应用程序
block:
- name: 停止应用程序
service:
name: myapp
state: stopped
- name: 更新配置
template:
src: app.conf.j2
dest: /etc/myapp/app.conf
- name: 启动应用程序
service:
name: myapp
state: started
rescue:
- name: 恢复备份配置
copy:
src: /etc/myapp/app.conf.backup
dest: /etc/myapp/app.conf
remote_src: yes
- name: 重启应用程序
service:
name: myapp
state: restarted
- name: 发送告警
mail:
to: admin@example.com
subject: "应用程序配置失败"
body: "在 {{ inventory_hostname }} 上配置应用程序失败,已恢复备份配置"
always:
- name: 清理临时文件
file:
path: /tmp/config-update.lock
state: absent
3.5 Variables(变量)
3.5.1 变量类型和优先级
Ansible 变量有明确的优先级顺序(从低到高):
- 命令行变量(-e)
- 任务变量
- 块变量
- 角色和包含变量
- play 变量
- 主机事实
- 注册变量
- set_facts
- 角色默认变量
- inventory 文件或脚本组变量
- inventory 组_vars/all
- playbook 组_vars/all
- inventory 组_vars/*
- playbook 组_vars/*
- inventory 文件或脚本主机变量
- inventory host_vars/*
- playbook host_vars/*
- 主机事实 / 缓存的 set_facts
- play vars
- play vars_prompt
- play vars_files
- 角色变量(在角色/vars/main.yml 中定义)
- 块变量(仅适用于块中的任务)
- 任务变量(仅适用于任务)
- include_vars
- set_facts / 注册变量
- 角色(和 include_role)参数
- include 参数
- 额外变量(在命令行中使用 -e 传递)
3.5.2 变量定义方式
Inventory 变量
# inventory/hosts
[webservers]
web1.example.com http_port=8080 ssl_enabled=true
web2.example.com http_port=8081 ssl_enabled=false
[webservers:vars]
app_version=1.2.3
environment=production
max_connections=1000
# group_vars/webservers.yml
---
app_version: "1.2.3"
environment: production
max_connections: 1000
# 复杂数据结构
database:
host: db.example.com
port: 3306
name: myapp
user: app_user
# 列表变量
required_packages:
- nginx
- python3
- redis-server
# 字典变量
ssl_config:
enabled: true
cert_path: /etc/ssl/certs/myapp.crt
key_path: /etc/ssl/private/myapp.key
protocols:
- TLSv1.2
- TLSv1.3
# host_vars/web1.example.com.yml
---
server_id: 1
special_config: true
local_storage_path: /opt/data
# 覆盖组变量
max_connections: 2000
Playbook 变量
# playbook-vars.yml
---
- name: 变量定义示例
hosts: webservers
vars:
# 简单变量
app_name: myapp
app_version: "1.2.3"
# 字典变量
database:
host: "{{ db_host | default('localhost') }}"
port: 3306
name: "{{ app_name }}"
# 列表变量
required_services:
- nginx
- mysql
- redis
vars_files:
- vars/common.yml
- "vars/{{ environment }}.yml"
vars_prompt:
- name: db_password
prompt: "请输入数据库密码"
private: yes
encrypt: sha512_crypt
confirm: yes
tasks:
- name: 显示变量
debug:
msg: |
应用名称: {{ app_name }}
版本: {{ app_version }}
数据库: {{ database.host }}:{{ database.port }}/{{ database.name }}
服务列表: {{ required_services | join(', ') }}
任务变量
# task-vars.yml
---
- name: 任务级变量示例
hosts: all
tasks:
- name: 设置任务变量
debug:
msg: "当前用户: {{ current_user }}"
vars:
current_user: "{{ ansible_user | default('unknown') }}"
- name: 循环中使用变量
package:
name: "{{ item.name }}"
state: "{{ item.state | default('present') }}"
vars:
package_list:
- { name: "nginx", state: "present" }
- { name: "apache2", state: "absent" }
- { name: "mysql-server" }
loop: "{{ package_list }}"
- name: 注册变量
command: whoami
register: current_user_result
changed_when: false
- name: 使用注册变量
debug:
msg: "命令输出: {{ current_user_result.stdout }}"
- name: 设置事实
set_fact:
deployment_time: "{{ ansible_date_time.iso8601 }}"
server_role: |
{% if 'webservers' in group_names %}
web
{% elif 'databases' in group_names %}
db
{% else %}
unknown
{% endif %}
- name: 使用设置的事实
debug:
msg: "服务器角色: {{ server_role }}, 部署时间: {{ deployment_time }}"
3.5.3 变量作用域和继承
# variable-scope.yml
---
- name: 全局变量
hosts: all
vars:
global_var: "我是全局变量"
common_config:
timeout: 30
retries: 3
tasks:
- name: 显示全局变量
debug:
var: global_var
- name: 块级变量
block:
- name: 在块内使用变量
debug:
msg: "块变量: {{ block_var }}, 全局变量: {{ global_var }}"
- name: 修改全局变量(仅在块内有效)
set_fact:
global_var: "块内修改的值"
- name: 显示修改后的变量
debug:
var: global_var
vars:
block_var: "我是块变量"
global_var: "块内覆盖的全局变量"
- name: 块外检查变量
debug:
msg: "块外的全局变量: {{ global_var }}"
- name: 包含任务文件
include_tasks: tasks/subtasks.yml
vars:
include_var: "传递给包含文件的变量"
common_config:
timeout: 60 # 覆盖全局配置
max_size: 100 # 新增配置
# tasks/subtasks.yml
---
- name: 在包含的任务中使用变量
debug:
msg: |
包含变量: {{ include_var | default('未定义') }}
全局变量: {{ global_var | default('未定义') }}
合并配置: {{ common_config }}
- name: 设置包含文件中的变量
set_fact:
subtask_result: "子任务完成"
- name: 返回结果
debug:
var: subtask_result
3.5.4 变量过滤器和测试
# filters-tests.yml
---
- name: 变量过滤器和测试示例
hosts: localhost
vars:
sample_string: " Hello World "
sample_list: [1, 2, 3, 4, 5]
sample_dict:
name: "John Doe"
age: 30
email: "john@example.com"
sample_number: 42
empty_var: ""
undefined_var: null
tasks:
# 字符串过滤器
- name: 字符串操作
debug:
msg: |
原始: '{{ sample_string }}'
去空格: '{{ sample_string | trim }}'
大写: '{{ sample_string | upper }}'
小写: '{{ sample_string | lower }}'
替换: '{{ sample_string | replace("World", "Ansible") }}'
长度: {{ sample_string | length }}
# 列表过滤器
- name: 列表操作
debug:
msg: |
原始列表: {{ sample_list }}
第一个: {{ sample_list | first }}
最后一个: {{ sample_list | last }}
随机: {{ sample_list | random }}
排序: {{ sample_list | sort }}
反转: {{ sample_list | reverse }}
唯一: {{ (sample_list + [1, 2]) | unique }}
连接: {{ sample_list | join('-') }}
过滤: {{ sample_list | select('>', 3) | list }}
# 字典过滤器
- name: 字典操作
debug:
msg: |
键列表: {{ sample_dict | list }}
值列表: {{ sample_dict | dict2items | map(attribute='value') | list }}
键值对: {{ sample_dict | dict2items }}
# 数学过滤器
- name: 数学运算
debug:
msg: |
绝对值: {{ -42 | abs }}
四舍五入: {{ 3.14159 | round(2) }}
最大值: {{ [1, 5, 3, 9, 2] | max }}
最小值: {{ [1, 5, 3, 9, 2] | min }}
求和: {{ [1, 2, 3, 4, 5] | sum }}
# 默认值和条件
- name: 默认值处理
debug:
msg: |
默认值: {{ undefined_var | default('默认值') }}
非空默认: {{ empty_var | default('非空默认', true) }}
三元运算: {{ (sample_number > 40) | ternary('大于40', '小于等于40') }}
# 变量测试
- name: 变量测试
debug:
msg: |
是否定义: {{ sample_string is defined }}
是否未定义: {{ undefined_var is undefined }}
是否为空: {{ empty_var is empty }}
是否为数字: {{ sample_number is number }}
是否为字符串: {{ sample_string is string }}
是否为列表: {{ sample_list is iterable }}
是否为字典: {{ sample_dict is mapping }}
# 条件判断
- name: 条件示例
debug:
msg: "变量已定义且不为空"
when:
- sample_string is defined
- sample_string is not empty
- sample_string | trim | length > 0
# JSON 和 YAML 处理
- name: 数据格式转换
debug:
msg: |
JSON格式: {{ sample_dict | to_json }}
YAML格式: {{ sample_dict | to_yaml }}
美化JSON: {{ sample_dict | to_nice_json }}
美化YAML: {{ sample_dict | to_nice_yaml }}
# 日期时间过滤器
- name: 日期时间处理
debug:
msg: |
当前时间: {{ ansible_date_time.iso8601 }}
格式化时间: {{ ansible_date_time.epoch | strftime('%Y-%m-%d %H:%M:%S') }}
时间戳: {{ ansible_date_time.epoch }}
# 文件路径过滤器
- name: 路径操作
vars:
file_path: "/opt/myapp/config/app.conf"
debug:
msg: |
目录名: {{ file_path | dirname }}
文件名: {{ file_path | basename }}
扩展名: {{ file_path | splitext | last }}
无扩展名: {{ file_path | splitext | first }}
3.6 本章总结
本章深入介绍了 Ansible 的核心概念,主要内容包括:
- Inventory(主机清单):静态和动态 Inventory 的创建和管理
- Modules(模块):系统、网络、云平台模块的使用和自定义模块开发
- Playbooks(剧本):Playbook 结构、多 Play 设计、条件执行和错误处理
- Variables(变量):变量类型、作用域、优先级和高级用法
这些概念是 Ansible 自动化的基础,掌握它们对于编写高效、可维护的自动化脚本至关重要。
3.7 练习题
基础练习
Inventory 管理
- 创建包含 Web、数据库、缓存三个组的 Inventory
- 将 Inventory 转换为 YAML 格式
- 编写简单的动态 Inventory 脚本
模块使用
- 使用 file 模块创建目录结构
- 使用 template 模块生成配置文件
- 使用 service 模块管理系统服务
进阶练习
Playbook 编写
- 编写多 Play Playbook 部署 LAMP 栈
- 实现条件执行和循环
- 添加错误处理和重试机制
变量管理
- 设计多环境变量结构
- 使用变量过滤器处理数据
- 实现变量继承和覆盖
实战练习
自定义模块
- 开发检查服务状态的自定义模块
- 实现支持 check 模式的模块
- 添加模块文档和测试
复杂场景
- 设计支持滚动更新的 Playbook
- 实现基于条件的服务发现
- 创建可重用的任务模板
下一章:第4章:Ad-hoc 命令详解
返回目录:Ansible 自动化运维教程