跳到主要内容

Ansible实践指南

概述

Ansible是一个开源的配置管理、应用部署和任务自动化工具。它采用无代理架构,通过SSH或WinRM协议远程执行任务,具有简单易用、幂等性、模块化设计等特点。本指南详细介绍Ansible的核心概念、安装配置、使用方法和最佳实践,帮助您快速掌握Ansible并在实际项目中应用。

Ansible基础概念

什么是Ansible

Ansible是一个由Red Hat赞助的开源自动化工具,用于配置管理、应用部署、任务自动化和编排。它使用Python编写,采用声明式语言(YAML)描述系统配置,通过SSH协议(或Windows上的WinRM)远程执行任务,无需在被管理节点上安装额外的代理软件。

Ansible的特点

  1. 无代理架构:不需要在被管理节点上安装代理软件
  2. 简单易用:使用YAML语法编写Playbooks,易于学习和理解
  3. 幂等性:确保多次执行相同的任务产生相同的结果
  4. 模块化设计:提供丰富的内置模块,支持各种任务
  5. 广泛集成:与主流云平台和工具(如AWS、Azure、Docker、Kubernetes等)集成
  6. 自动化编排:支持复杂的工作流编排
  7. 开源社区:拥有活跃的开源社区和丰富的文档

Ansible的核心组件

  1. 控制节点:运行Ansible命令和Playbooks的机器
  2. 被管理节点:由Ansible管理的机器
  3. Inventory:定义被管理节点的主机清单
  4. 模块(Modules):执行特定任务的代码单元
  5. Playbooks:定义自动化任务的YAML文件
  6. Tasks:在Playbooks中定义的单个操作
  7. Plays:将一组任务应用到特定主机的配置
  8. Roles:组织和重用Playbooks的方式
  9. Variables:存储和传递值的变量
  10. Templates:使用Jinja2模板语言生成配置文件
  11. Handlers:由其他任务触发的任务(如重启服务)

Ansible的工作原理

Ansible的工作流程如下:

  1. 读取Inventory:Ansible从Inventory文件中获取被管理节点的信息
  2. 解析Playbooks:解析Playbooks中的任务和配置
  3. 执行任务:通过SSH(或WinRM)连接到被管理节点并执行任务
  4. 收集结果:收集任务执行的结果并返回给控制节点
  5. 生成报告:生成任务执行报告
+----------------+    +----------------+    +----------------+
| | | | | |
| 控制节点 +--->+ Playbooks +--->+ 被管理节点 |
| (Ansible核心) | | (任务定义) | | (执行实际任务) |
+-------^--------+ +----------------+ +-------^--------+
| |
| |
+------------------------------------------+
结果反馈

Ansible安装与配置

安装Ansible

在Linux上安装Ansible

在Ubuntu/Debian上安装:

# 更新包索引
sudo apt update

# 安装Ansible
sudo apt install ansible -y

# 验证安装
ansible --version

在CentOS/RHEL上安装:

# 安装EPEL仓库
sudo yum install epel-release -y

# 安装Ansible
sudo yum install ansible -y

# 验证安装
ansible --version

在Fedora上安装:

# 安装Ansible
sudo dnf install ansible -y

# 验证安装
ansible --version

在macOS上安装Ansible

# 使用Homebrew安装Ansible
brew install ansible

# 验证安装
ansible --version

在Windows上安装Ansible

Windows系统上可以通过Windows Subsystem for Linux (WSL)安装Ansible:

# 在WSL中安装Ansible
sudo apt update
sudo apt install ansible -y

# 验证安装
ansible --version

或者通过Python的pip安装:

# 安装pip
python -m pip install --upgrade pip

# 安装Ansible
pip install ansible

# 验证安装
ansible --version

配置Ansible

Ansible的主配置文件是ansible.cfg,默认情况下位于以下位置(按优先级排序):

  1. 当前目录下的./ansible.cfg
  2. 用户主目录下的~/.ansible.cfg
  3. 系统级配置/etc/ansible/ansible.cfg

以下是一个基本的ansible.cfg配置示例:

[defaults]
# 主机清单文件路径
inventory = inventory

# 远程用户
remote_user = ec2-user

# 私钥文件路径
private_key_file = ~/.ssh/id_rsa

# 关闭主机密钥检查
host_key_checking = False

# 角色路径
roles_path = roles/

# 模块搜索路径
default_modules = command,shell,copy,file,yum,apt,service

# 超时时间
timeout = 30

# 日志级别
log_path = /var/log/ansible.log

# 临时文件目录
tmpdir = /tmp/ansible

# 并行连接数
forks = 5

# 重试次数
retries = 3

# 显示跳过的任务
display_skipped_hosts = True

# 显示差异
diff_always = False

# 错误处理策略
error_on_undefined_vars = True

# 任务哈希行为
task_hash_behaviour = error

[privilege_escalation]
# 是否启用权限提升
become = True

# 权限提升方法
become_method = sudo

# 权限提升用户
become_user = root

# 是否询问密码
become_ask_pass = False

[ssh_connection]
# SSH连接类型
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

# 管道连接
pipelining = True

# 连接插件
connection_plugins = ~/.ansible/plugins/connection:/usr/share/ansible/plugins/connection

# 控制路径
control_path_dir = /tmp/.ansible/cp

# 转移缓冲区大小
transfer_buffer_size = 131072

# 记录SSH输出
ssh_logfile = /var/log/ansible-ssh.log

配置Inventory

Inventory文件用于定义被管理的主机和主机组。以下是一个基本的Inventory文件示例:

# 简单的主机清单
# 单个主机
webserver ansible_host=192.168.1.101 ansible_user=ubuntu

# 主机组
[webservers]
web1 ansible_host=192.168.1.101 ansible_user=ubuntu
web2 ansible_host=192.168.1.102 ansible_user=ubuntu
web3 ansible_host=192.168.1.103 ansible_user=ubuntu

[dbservers]
db1 ansible_host=192.168.1.201 ansible_user=centos

# 子组
[servers:children]
webservers
dbservers

# 组变量
[webservers:vars]
ansible_python_interpreter=/usr/bin/python3
http_port=80
max_clients=200

[dbservers:vars]
ansible_python_interpreter=/usr/bin/python3
db_port=3306

# 所有主机的变量
[all:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=no'

Inventory也可以使用YAML格式:

# YAML格式的主机清单
all:
vars:
ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
hosts:
webserver:
ansible_host: 192.168.1.101
ansible_user: ubuntu
children:
webservers:
hosts:
web1:
ansible_host: 192.168.1.101
ansible_user: ubuntu
web2:
ansible_host: 192.168.1.102
ansible_user: ubuntu
web3:
ansible_host: 192.168.1.103
ansible_user: ubuntu
vars:
ansible_python_interpreter: /usr/bin/python3
http_port: 80
max_clients: 200
dbservers:
hosts:
db1:
ansible_host: 192.168.1.201
ansible_user: centos
vars:
ansible_python_interpreter: /usr/bin/python3
db_port: 3306
servers:
children:
webservers:
dbservers:

动态Inventory用于从外部源(如云提供商的API)获取主机信息:

#!/usr/bin/env python3
# 简单的动态Inventory脚本示例

import json
import sys

if __name__ == '__main__':
# 检查参数
if len(sys.argv) > 1 and sys.argv[1] == '--list':
# 返回所有主机和组信息
inventory = {
'webservers': {
'hosts': ['web1', 'web2', 'web3'],
'vars': {
'http_port': 80,
'max_clients': 200
}
},
'dbservers': {
'hosts': ['db1'],
'vars': {
'db_port': 3306
}
},
'_meta': {
'hostvars': {
'web1': {
'ansible_host': '192.168.1.101',
'ansible_user': 'ubuntu'
},
'web2': {
'ansible_host': '192.168.1.102',
'ansible_user': 'ubuntu'
},
'web3': {
'ansible_host': '192.168.1.103',
'ansible_user': 'ubuntu'
},
'db1': {
'ansible_host': '192.168.1.201',
'ansible_user': 'centos'
}
}
}
}
print(json.dumps(inventory))
elif len(sys.argv) > 1 and sys.argv[1] == '--host':
# 返回特定主机的详细信息
host = sys.argv[2]
hostvars = {
'ansible_host': '192.168.1.100',
'ansible_user': 'ubuntu'
}
print(json.dumps(hostvars))
else:
# 默认返回空
print(json.dumps({}))

测试连接

安装和配置完成后,可以使用ansible命令测试与被管理节点的连接:

# 测试与所有主机的连接
ansible all -m ping

# 测试与特定主机组的连接
ansible webservers -m ping

# 测试与特定主机的连接
ansible web1 -m ping

# 使用特定用户测试连接
ansible webservers -m ping -u ubuntu

# 使用sudo测试连接
ansible webservers -m ping -b

# 使用自定义端口测试连接
ansible webservers -m ping -e ansible_port=2222

Ansible核心模块

命令模块

命令模块用于在被管理节点上执行命令:

command模块

# 执行简单命令
ansible webservers -m command -a "ls -la"

# 查看磁盘使用情况
ansible webservers -m command -a "df -h"

# 查看内存使用情况
ansible webservers -m command -a "free -m"

# 执行带参数的命令
ansible webservers -m command -a "systemctl status nginx"

# 禁用shell处理
ansible webservers -m command -a "echo $HOME" # 不会展开变量

shell模块

# 执行shell命令
ansible webservers -m shell -a "ls -la | grep ansible"

# 使用管道和重定向
ansible webservers -m shell -a "cat /etc/passwd | grep root > /tmp/root_users.txt"

# 展开环境变量
ansible webservers -m shell -a "echo $HOME"

# 执行多行命令
ansible webservers -m shell -a "cd /tmp && mkdir test && touch test/file.txt"

# 执行脚本文件
ansible webservers -m shell -a "/path/to/script.sh"

raw模块

# 执行原始命令,不依赖Python
ansible webservers -m raw -a "apt update && apt install python3 -y"

# 在没有安装Python的系统上执行命令
ansible webservers -m raw -a "echo 'Hello World'"

# 使用raw模块安装Python
ansible webservers -m raw -a "yum install python3 -y"

文件模块

文件模块用于管理文件和目录:

copy模块

# 复制文件到远程主机
ansible webservers -m copy -a "src=/path/to/local/file dest=/path/to/remote/file"

# 复制文件并设置权限
ansible webservers -m copy -a "src=/path/to/local/file dest=/path/to/remote/file owner=root group=root mode=0644"

# 复制目录
ansible webservers -m copy -a "src=/path/to/local/dir dest=/path/to/remote/dir"

# 备份现有文件
ansible webservers -m copy -a "src=/path/to/local/file dest=/path/to/remote/file backup=yes"

# 仅当源文件更新时复制
ansible webservers -m copy -a "src=/path/to/local/file dest=/path/to/remote/file force=no"

file模块

# 创建目录
ansible webservers -m file -a "path=/path/to/dir state=directory mode=0755"

# 创建文件
ansible webservers -m file -a "path=/path/to/file state=touch mode=0644"

# 删除文件或目录
ansible webservers -m file -a "path=/path/to/delete state=absent"

# 设置文件权限
ansible webservers -m file -a "path=/path/to/file owner=root group=root mode=0644"

# 创建符号链接
ansible webservers -m file -a "src=/path/to/source dest=/path/to/link state=link"

# 创建硬链接
ansible webservers -m file -a "src=/path/to/source dest=/path/to/link state=hard"

fetch模块

# 从远程主机获取文件
ansible webservers -m fetch -a "src=/path/to/remote/file dest=/path/to/local/dir"

# 保留目录结构
ansible webservers -m fetch -a "src=/path/to/remote/file dest=/path/to/local/dir flat=no"

# 仅当远程文件更新时获取
ansible webservers -m fetch -a "src=/path/to/remote/file dest=/path/to/local/dir validate_checksum=yes"

template模块

# 使用模板生成配置文件
ansible webservers -m template -a "src=/path/to/template.j2 dest=/path/to/config.conf"

# 设置文件权限
ansible webservers -m template -a "src=/path/to/template.j2 dest=/path/to/config.conf owner=root group=root mode=0644"

# 备份现有文件
ansible webservers -m template -a "src=/path/to/template.j2 dest=/path/to/config.conf backup=yes"

模板文件示例 (nginx.conf.j2):

worker_processes {{ ansible_processor_vcpus }};
events {
worker_connections {{ max_clients }};
}
http {
server {
listen {{ http_port }};
server_name {{ server_name }};
location / {
root /var/www/html;
index index.html;
}
}
}

包管理模块

包管理模块用于安装、更新和删除软件包:

apt模块 (Debian/Ubuntu)

# 安装软件包
ansible webservers -m apt -a "name=nginx state=present" -b

# 安装特定版本的软件包
ansible webservers -m apt -a "name=nginx=1.18.0-0ubuntu1 state=present" -b

# 更新软件包
ansible webservers -m apt -a "name=nginx state=latest" -b

# 删除软件包
ansible webservers -m apt -a "name=nginx state=absent" -b

# 安装多个软件包
ansible webservers -m apt -a "name=nginx,git,curl state=present" -b

# 更新包列表
ansible webservers -m apt -a "update_cache=yes" -b

# 升级所有软件包
ansible webservers -m apt -a "upgrade=dist" -b

yum模块 (CentOS/RHEL)

# 安装软件包
ansible webservers -m yum -a "name=nginx state=present" -b

# 安装特定版本的软件包
ansible webservers -m yum -a "name=nginx-1.18.0 state=present" -b

# 更新软件包
ansible webservers -m yum -a "name=nginx state=latest" -b

# 删除软件包
ansible webservers -m yum -a "name=nginx state=absent" -b

# 安装多个软件包
ansible webservers -m yum -a "name=nginx,git,curl state=present" -b

# 更新包列表
ansible webservers -m yum -a "update_cache=yes" -b

# 升级所有软件包
ansible webservers -m yum -a "name=* state=latest" -b

dnf模块 (Fedora)

# 安装软件包
ansible webservers -m dnf -a "name=nginx state=present" -b

# 安装特定版本的软件包
ansible webservers -m dnf -a "name=nginx-1.18.0 state=present" -b

# 更新软件包
ansible webservers -m dnf -a "name=nginx state=latest" -b

# 删除软件包
ansible webservers -m dnf -a "name=nginx state=absent" -b

pip模块

# 安装Python包
ansible webservers -m pip -a "name=requests state=present"

# 安装特定版本的Python包
ansible webservers -m pip -a "name=requests==2.25.1 state=present"

# 从requirements.txt安装
ansible webservers -m pip -a "requirements=/path/to/requirements.txt"

# 使用特定的pip版本
ansible webservers -m pip -a "name=requests executable=/usr/bin/pip3"

# 从Git仓库安装
ansible webservers -m pip -a "name='git+https://github.com/example/repo.git'"

服务模块

服务模块用于管理系统服务:

service模块

# 启动服务
ansible webservers -m service -a "name=nginx state=started" -b

# 停止服务
ansible webservers -m service -a "name=nginx state=stopped" -b

# 重启服务
ansible webservers -m service -a "name=nginx state=restarted" -b

# 重载服务配置
ansible webservers -m service -a "name=nginx state=reloaded" -b

# 启用服务开机自启
ansible webservers -m service -a "name=nginx enabled=yes" -b

# 禁用服务开机自启
ansible webservers -m service -a "name=nginx enabled=no" -b

# 同时设置状态和自启
ansible webservers -m service -a "name=nginx state=started enabled=yes" -b

systemd模块

# 启动服务
ansible webservers -m systemd -a "name=nginx state=started" -b

# 停止服务
ansible webservers -m systemd -a "name=nginx state=stopped" -b

# 重启服务
ansible webservers -m systemd -a "name=nginx state=restarted" -b

# 重载服务配置
ansible webservers -m systemd -a "name=nginx daemon_reload=yes" -b

# 启用服务开机自启
ansible webservers -m systemd -a "name=nginx enabled=yes" -b

# 设置服务环境变量
ansible webservers -m systemd -a "name=nginx state=started environment='OPTIONS=--debug'" -b

用户和组模块

用户和组模块用于管理系统用户和组:

user模块

# 创建用户
ansible webservers -m user -a "name=john shell=/bin/bash home=/home/john" -b

# 创建用户并添加到组
ansible webservers -m user -a "name=john groups=sudo,developers append=yes" -b

# 设置用户密码(密码需要预先加密)
ansible webservers -m user -a "name=john password='$6$rounds=65536$...'" -b

# 创建系统用户
ansible webservers -m user -a "name=nginx system=yes shell=/sbin/nologin" -b

# 删除用户
ansible webservers -m user -a "name=john state=absent remove=yes" -b

group模块

# 创建组
ansible webservers -m group -a "name=developers" -b

# 创建系统组
ansible webservers -m group -a "name=nginx system=yes" -b

# 删除组
ansible webservers -m group -a "name=developers state=absent" -b

# 设置组ID
ansible webservers -m group -a "name=developers gid=1000" -b

网络模块

网络模块用于管理网络配置:

ping模块

# 测试主机连通性
ansible webservers -m ping

# 自定义ping消息
ansible webservers -m ping -a "data='Hello World'"

uri模块

# 发送HTTP请求
ansible localhost -m uri -a "url=http://example.com return_content=yes"

# 发送POST请求
ansible localhost -m uri -a "url=http://example.com/api method=POST body='{"name":"test"}' headers='Content-Type: application/json'"

# 检查URL状态
ansible localhost -m uri -a "url=http://example.com status_code=200"

# 使用基本认证
ansible localhost -m uri -a "url=http://example.com/auth user=admin password=secret force_basic_auth=yes"

get_url模块

# 下载文件
ansible webservers -m get_url -a "url=http://example.com/file.txt dest=/tmp/file.txt"

# 下载文件并设置权限
ansible webservers -m get_url -a "url=http://example.com/file.txt dest=/tmp/file.txt mode=0644"

# 使用自定义HTTP头
ansible webservers -m get_url -a "url=http://example.com/file.txt dest=/tmp/file.txt headers='Authorization: Bearer token123'"

# 验证SSL证书
ansible webservers -m get_url -a "url=https://example.com/file.txt dest=/tmp/file.txt validate_certs=yes ca_cert=/path/to/ca.crt"

Ansible Playbooks

Playbook基础

Playbook是Ansible的配置、部署和编排语言,使用YAML格式编写。以下是一个基本的Playbook示例:

# 简单的Playbook示例
---
- name: Configure web servers
hosts: webservers
become: true
vars:
http_port: 80
max_clients: 200
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
when: ansible_os_family == "Debian"

- name: Install nginx (CentOS/RHEL)
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"

- name: Create nginx configuration file
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Restart nginx

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

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

执行Playbook:

# 执行Playbook
ansible-playbook site.yml

# 执行特定标签的任务
ansible-playbook site.yml --tags "install,config"

# 跳过特定标签的任务
ansible-playbook site.yml --skip-tags "restart"

# 列出Playbook中的任务
ansible-playbook site.yml --list-tasks

# 列出Playbook中的主机
ansible-playbook site.yml --list-hosts

# 语法检查
ansible-playbook site.yml --syntax-check

# 模拟执行
ansible-playbook site.yml --check

# 显示详细输出
ansible-playbook site.yml -v
ansible-playbook site.yml -vv
ansible-playbook site.yml -vvv

# 限制执行的主机
ansible-playbook site.yml --limit web1

变量和事实

变量用于存储和传递值,事实是Ansible自动收集的关于被管理节点的信息:

# 使用变量的Playbook示例
---
- name: Configure web servers with variables
hosts: webservers
become: true
vars:
# 基本变量
web_package: nginx
web_user: nginx
web_root: /var/www/html
# 数组变量
web_packages: [nginx, git, curl]
# 字典变量
web_config: {
port: 80,
server_name: "example.com",
max_clients: 200
}
# 从文件加载变量
# 可以在vars_files中指定变量文件
vars_files:
- vars/common.yml
- vars/webservers.yml
tasks:
- name: Install web packages
apt:
name: "{{ item }}"
state: present
loop: "{{ web_packages }}"
when: ansible_os_family == "Debian"

- name: Create web root directory
file:
path: "{{ web_root }}"
state: directory
owner: "{{ web_user }}"
group: "{{ web_user }}"
mode: '0755'

- name: Configure web server
template:
src: templates/web.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Restart web server
vars:
# 任务级变量,优先级高于play级变量
http_port: 8080

- name: Display ansible facts
debug:
msg: "Hostname: {{ ansible_hostname }}, IP: {{ ansible_default_ipv4.address }}"

- name: Set custom fact
set_fact:
custom_fact: "This is a custom fact for {{ ansible_hostname }}"

- name: Display custom fact
debug:
var: custom_fact

handlers:
- name: Restart web server
service:
name: "{{ web_package }}"
state: restarted

变量文件示例 (vars/webservers.yml):

# 变量文件示例
web_package: nginx
web_user: nginx
web_root: /var/www/html
web_port: 80
max_clients: 200
server_name: example.com

条件语句

条件语句用于根据条件执行任务:

# 使用条件语句的Playbook示例
---
- name: Configure servers with conditionals
hosts: all
become: true
tasks:
- name: Install Apache on Debian systems
apt:
name: apache2
state: present
when: ansible_os_family == "Debian"

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

- name: Configure firewall for web servers
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop: [80, 443]
when: ansible_hostname in groups['webservers']

- name: Configure firewall for database servers
ufw:
rule: allow
port: 3306
proto: tcp
from_ip: "{{ item }}"
loop: groups['webservers']
when: ansible_hostname in groups['dbservers']

- name: Create development configuration
template:
src: templates/dev.conf.j2
dest: /etc/app/config.conf
when: environment == 'development'

- name: Create production configuration
template:
src: templates/prod.conf.j2
dest: /etc/app/config.conf
when: environment == 'production'

- name: Configure high performance settings
template:
src: templates/high_perf.conf.j2
dest: /etc/app/performance.conf
when: ansible_processor_vcpus > 4 and ansible_memtotal_mb > 8192

- name: Display message based on OS version
debug:
msg: "This is a new version of Ubuntu"
when: ansible_distribution == 'Ubuntu' and ansible_distribution_version is version('20.04', '>=')

- name: Fail if not on a supported OS
fail:
msg: "This playbook only supports Ubuntu and CentOS"
when: ansible_distribution not in ['Ubuntu', 'CentOS']

循环语句

循环语句用于重复执行任务:

# 使用循环语句的Playbook示例
---
- name: Use loops in Ansible
hosts: all
become: true
tasks:
- name: Install multiple packages
apt:
name: "{{ item }}"
state: present
loop: [nginx, git, curl, vim]
when: ansible_os_family == "Debian"

- name: Create multiple directories
file:
path: "{{ item }}"
state: directory
mode: '0755'
loop:
- /var/log/app
- /var/run/app
- /etc/app/conf.d

- name: Configure multiple users
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
state: present
loop:
- { name: 'john', groups: 'sudo,developers' }
- { name: 'jane', groups: 'developers' }
- { name: 'bob', groups: 'users' }

- name: Create files with content
copy:
content: "{{ item.content }}"
dest: "{{ item.path }}"
mode: '0644'
loop:
- { path: '/etc/motd', content: 'Welcome to {{ ansible_hostname }}' }
- { path: '/etc/issue', content: 'Company Internal Server' }

- name: Iterate with loop and index
debug:
msg: "Item {{ ansible_loop.index }}: {{ item }}"
loop: ['a', 'b', 'c', 'd']

- name: Install packages with version
apt:
name: "{{ item.package }}={{ item.version }}"
state: present
loop:
- { package: 'nginx', version: '1.18.0-0ubuntu1' }
- { package: 'postgresql', version: '12+214ubuntu0.1' }
loop_control:
label: "{{ item.package }} (version {{ item.version }})"
when: ansible_os_family == "Debian"

- name: Use with_dict to loop over a dictionary
debug:
msg: "Service {{ item.key }} runs on port {{ item.value }}"
loop: "{{ lookup('dict', services) }}"
vars:
services:
nginx: 80
apache: 8080
mysql: 3306
redis: 6379

模板和Jinja2

Ansible使用Jinja2模板语言生成配置文件:

# 使用模板的Playbook示例
---
- name: Use templates in Ansible
hosts: webservers
become: true
vars:
http_port: 80
max_clients: 200
server_name: "example.com"
web_root: "/var/www/html"
workers: "{{ ansible_processor_vcpus }}"
ssl_enabled: true
ssl_cert_path: "/etc/ssl/certs/example.crt"
ssl_key_path: "/etc/ssl/private/example.key"
# 动态变量
app_env: "{{ 'development' if ansible_hostname starts with 'dev' else 'production' }}"
tasks:
- name: Create nginx configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify:
- Restart nginx

- name: Create index.html
template:
src: templates/index.html.j2
dest: "{{ web_root }}/index.html"
owner: nginx
group: nginx
mode: '0644'

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

Nginx配置模板示例 (templates/nginx.conf.j2):

# Nginx配置模板
user nginx;
worker_processes {{ workers }};

error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
worker_connections {{ max_clients }};
}

http {
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 65;
types_hash_max_size 2048;

include /etc/nginx/mime.types;
default_type application/octet-stream;

# Gzip compression
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

server {
listen {{ http_port }};
{% if ssl_enabled %}
listen 443 ssl;
ssl_certificate {{ ssl_cert_path }};
ssl_certificate_key {{ ssl_key_path }};
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
{% endif %}
server_name {{ server_name }};
root {{ web_root }};
index index.html;

location / {
try_files $uri $uri/ =404;
}

# Error pages
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# Application environment
{% if app_env == 'development' %}
# Development specific settings
error_log /var/log/nginx/error.log debug;
{% else %}
# Production specific settings
error_log /var/log/nginx/error.log warn;
{% endif %}
}
}

HTML模板示例 (templates/index.html.j2):

<!DOCTYPE html>
<html>
<head>
<title>{{ server_name }}</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: {{ 'lightblue' if app_env == 'development' else 'lightgray' }};
}
h1 {
color: #333;
}
.info {
background-color: white;
padding: 15px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<h1>Welcome to {{ server_name }}</h1>
<div class="info">
<p><strong>Environment:</strong> {{ app_env }}</p>
<p><strong>Hostname:</strong> {{ ansible_hostname }}</p>
<p><strong>IP Address:</strong> {{ ansible_default_ipv4.address }}</p>
<p><strong>Server Time:</strong> {{ ansible_date_time.iso8601 }}</p>
<p><strong>Server Specifications:</strong></p>
<ul>
<li>CPU: {{ ansible_processor_vcpus }} cores</li>
<li>Memory: {{ ansible_memtotal_mb }} MB</li>
<li>OS: {{ ansible_distribution }} {{ ansible_distribution_version }}</li>
</ul>
{% if ssl_enabled %}
<p><strong>SSL Status:</strong> Enabled</p>
{% endif %}
</div>
</body>
</html>

处理程序

处理程序是由其他任务触发的任务,通常用于重启服务:

# 使用处理程序的Playbook示例
---
- name: Use handlers in Ansible
hosts: webservers
become: true
tasks:
- name: Install nginx
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"

- name: Create nginx configuration file
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: # 通知处理程序
- Restart nginx
- Reload nginx

- name: Create default site configuration
template:
src: templates/default.conf.j2
dest: /etc/nginx/sites-available/default
notify:
- Reload nginx

- name: Create web root directory
file:
path: /var/www/html
state: directory
owner: nginx
group: nginx
mode: '0755'

- name: Deploy website files
copy:
src: files/website/
dest: /var/www/html/
owner: nginx
group: nginx

- name: Force restart nginx (always notify handler)
command: echo "Force restart nginx"
notify:
- Restart nginx

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

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

- name: Log nginx restart
lineinfile:
path: /var/log/ansible-nginx.log
line: "{{ ansible_date_time.iso8601 }} - nginx restarted on {{ ansible_hostname }}"
create: yes
listen: "Restart nginx" # 监听特定通知

- name: Log nginx reload
lineinfile:
path: /var/log/ansible-nginx.log
line: "{{ ansible_date_time.iso8601 }} - nginx reloaded on {{ ansible_hostname }}"
create: yes
listen: "Reload nginx" # 监听特定通知

块和错误处理

块用于将任务分组,并可以设置错误处理策略:

# 使用块和错误处理的Playbook示例
---
- name: Use blocks and error handling in Ansible
hosts: webservers
become: true
tasks:
- name: Configure web server
block:
- name: Install nginx
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"

- name: Install nginx (CentOS/RHEL)
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"

- name: Create nginx configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf

- name: Create web root directory
file:
path: /var/www/html
state: directory
owner: nginx
group: nginx

- name: Deploy website files
copy:
src: files/website/
dest: /var/www/html/
rescue: # 块中的任务失败时执行
- name: Clean up failed installation
file:
path: /etc/nginx
state: absent
ignore_errors: yes

- name: Log installation failure
lineinfile:
path: /var/log/ansible-failures.log
line: "{{ ansible_date_time.iso8601 }} - Web server installation failed on {{ ansible_hostname }}"
create: yes

- name: Notify admin about failure
mail:
host: mail.example.com
port: 25
to: admin@example.com
subject: "Ansible Failure on {{ ansible_hostname }}"
body: "Web server installation failed on {{ ansible_hostname }}. Please investigate."
delegate_to: localhost
ignore_errors: yes
always: # 无论块是否成功都会执行
- name: Ensure nginx is stopped
service:
name: nginx
state: stopped
ignore_errors: yes

- name: Configure database
block:
- name: Install mysql-server
apt:
name: mysql-server
state: present
when: ansible_os_family == "Debian"

- name: Install mariadb-server
yum:
name: mariadb-server
state: present
when: ansible_os_family == "RedHat"

- name: Start and enable database service
service:
name: "{{ 'mysql' if ansible_os_family == 'Debian' else 'mariadb' }}"
state: started
enabled: yes
when: inventory_hostname in groups['dbservers']

- name: Fail task with custom message
fail:
msg: "This task is designed to fail"
when: fail_test is defined and fail_test
ignore_errors: yes # 忽略错误,继续执行

- name: This task will run even if the previous task failed
debug:
msg: "Continuing execution..."

Ansible Roles

Role基础

Roles是Ansible中组织和重用Playbooks的方式。一个Role通常包含以下目录结构:

role_name/
├── defaults/ # 默认变量
│ └── main.yml
├── files/ # 静态文件
├── handlers/ # 处理程序
│ └── main.yml
├── meta/ # 元数据
│ └── main.yml
├── README.md # 文档
├── tasks/ # 任务定义
│ └── main.yml
├── templates/ # 模板文件
├── tests/ # 测试
│ ├── inventory
│ └── test.yml
└── vars/ # 角色变量
└── main.yml

创建和使用Role

创建一个基本的Role:

# 创建Role骨架
ansible-galaxy init webserver

Role的主要文件内容:

# roles/webserver/tasks/main.yml
---
- name: Include OS-specific variables
include_vars: "{{ ansible_os_family }}.yml"

- name: Install web server package
package:
name: "{{ webserver_package }}"
state: present
update_cache: yes

- name: Create web server configuration directory
file:
path: "{{ webserver_conf_dir }}"
state: directory
owner: root
group: root
mode: '0755'

- name: Create web server configuration
template:
src: webserver.conf.j2
dest: "{{ webserver_conf_file }}"
owner: root
group: root
mode: '0644'
notify:
- Restart web server

- name: Create web root directory
file:
path: "{{ webserver_root_dir }}"
state: directory
owner: "{{ webserver_user }}"
group: "{{ webserver_group }}"
mode: '0755'

- name: Deploy default index page
template:
src: index.html.j2
dest: "{{ webserver_root_dir }}/index.html"
owner: "{{ webserver_user }}"
group: "{{ webserver_group }}"
mode: '0644'

- name: Ensure web server is running and enabled
service:
name: "{{ webserver_service }}"
state: started
enabled: yes
# roles/webserver/defaults/main.yml
---
# Default variables for webserver role
webserver_package: nginx
webserver_service: nginx
webserver_user: nginx
webserver_group: nginx
webserver_root_dir: /var/www/html
webserver_port: 80
webserver_max_clients: 200
webserver_server_name: "{{ ansible_fqdn }}"
# roles/webserver/vars/Debian.yml
---
# Debian/Ubuntu specific variables
webserver_conf_dir: /etc/nginx/conf.d
webserver_conf_file: /etc/nginx/nginx.conf
webserver_default_conf: /etc/nginx/sites-available/default
# roles/webserver/vars/RedHat.yml
---
# RedHat/CentOS specific variables
webserver_conf_dir: /etc/nginx/conf.d
webserver_conf_file: /etc/nginx/nginx.conf
webserver_default_conf: /etc/nginx/conf.d/default.conf
# roles/webserver/handlers/main.yml
---
# Handlers for webserver role
- name: Restart web server
service:
name: "{{ webserver_service }}"
state: restarted

- name: Reload web server
service:
name: "{{ webserver_service }}"
state: reloaded
# roles/webserver/meta/main.yml
---
# Metadata for webserver role
galaxy_info:
author: Your Name
description: Install and configure web server
company: Your Company
license: MIT
min_ansible_version: "2.9"
platforms:
- name: Ubuntu
versions:
- focal
- bionic
- name: Debian
versions:
- bullseye
- buster
- name: EL
versions:
- "7"
- "8"
galaxy_tags:
- web
- nginx
- apache
- server

dependencies:
- role: common
vars:
common_packages: [curl, wget, vim]

在Playbook中使用Role:

# site.yml
---
- name: Configure web servers
hosts: webservers
become: true
roles:
- role: common
- role: webserver
vars:
webserver_port: 8080
webserver_max_clients: 500
- role: firewall
vars:
firewall_rules:
- { port: 8080, protocol: tcp }

- name: Configure database servers
hosts: dbservers
become: true
roles:
- role: common
- role: database
vars:
db_type: mysql
db_name: myapp
db_user: myappuser
db_password: "{{ vault_db_password }}"

共享和重用Role

从Ansible Galaxy下载和使用共享Role:

# 搜索Role
ansible-galaxy search nginx

# 查看Role详情
ansible-galaxy info geerlingguy.nginx

# 安装Role
ansible-galaxy install geerlingguy.nginx

# 安装多个Role
ansible-galaxy install -r requirements.yml

# 列出已安装的Role
ansible-galaxy list

# 删除Role
ansible-galaxy remove geerlingguy.nginx

requirements.yml文件示例:

# requirements.yml
---
# 从Ansible Galaxy安装Role
- src: geerlingguy.nginx
version: 3.1.0
name: nginx

- src: geerlingguy.mysql
version: 3.1.2
name: mysql

# 从Git仓库安装Role
- src: https://github.com/example/ansible-role-common.git
scm: git
version: main
name: common

# 从本地路径安装Role
- src: ./roles/custom-role
name: custom

发布Role到Ansible Galaxy:

# 登录到Ansible Galaxy
ansible-galaxy login

# 发布Role
ansible-galaxy role publish ./roles/my-role

# 查看已发布的Role
ansible-galaxy role list

Ansible高级功能

变量管理与加密

Ansible Vault用于加密敏感数据:

# 创建加密文件
ansible-vault create secrets.yml

# 编辑加密文件
ansible-vault edit secrets.yml

# 查看加密文件
ansible-vault view secrets.yml

# 加密现有文件
ansible-vault encrypt secrets.yml

# 解密文件
ansible-vault decrypt secrets.yml

# 更改加密密码
ansible-vault rekey secrets.yml

# 使用加密文件运行Playbook
ansible-playbook site.yml --ask-vault-pass
ansible-playbook site.yml --vault-id @prompt
ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt

加密文件示例:

# secrets.yml (加密前)
db_password: "secret_password"
api_key: "abc123def456"
admin_password: "admin123"

# 引用加密变量
---
- name: Use encrypted variables
hosts: dbservers
become: true
vars_files:
- secrets.yml
tasks:
- name: Configure database with encrypted password
mysql_user:
name: dbuser
password: "{{ db_password }}"
priv: "dbname.*:ALL"
state: present

动态Inventory和云集成

Ansible支持动态Inventory,特别是与云平台集成:

AWS EC2动态Inventory

# 安装必要的Python包
pip install boto boto3

# 配置AWS凭证
# ~/.aws/credentials
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY

# 使用AWS EC2动态Inventory脚本
wget https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/ec2.py
chmod +x ec2.py
wget https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/ec2.ini

# 测试动态Inventory
./ec2.py --list
./ec2.py --host i-1234567890abcdef0

# 在Playbook中使用动态Inventory
ansible-playbook -i ec2.py site.yml

在Playbook中使用AWS模块:

# 使用AWS模块的Playbook示例
---
- name: Manage AWS resources with Ansible
hosts: localhost
gather_facts: false
vars:
aws_region: us-west-2
tasks:
- name: Create EC2 key pair
amazon.aws.ec2_key:
name: my-key-pair
region: "{{ aws_region }}"
key_material: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present

- name: Create security group
amazon.aws.ec2_security_group:
name: web-sg
description: Security group for web servers
region: "{{ aws_region }}"
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 443
to_port: 443
cidr_ip: 0.0.0.0/0
state: present
register: web_sg

- name: Launch EC2 instance
amazon.aws.ec2_instance:
name: web-server
region: "{{ aws_region }}"
instance_type: t2.micro
image_id: ami-0c55b159cbfafe1f0
key_name: my-key-pair
security_group_ids:
- "{{ web_sg.group_id }}"
vpc_subnet_id: subnet-12345678
user_data: |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<html><body><h1>Hello from EC2</h1></body></html>" > /var/www/html/index.html
state: running
tags:
Name: web-server
Environment: production
register: ec2_instance

- name: Wait for SSH to be available
wait_for:
host: "{{ ec2_instance.instances[0].public_ip_address }}"
port: 22
delay: 10
timeout: 300
state: started

- name: Add new instance to inventory
add_host:
hostname: "{{ ec2_instance.instances[0].public_ip_address }}"
groupname: launched
ansible_user: ec2-user
ansible_ssh_private_key_file: ~/.ssh/id_rsa

- name: Configure launched instance
hosts: launched
become: true
gather_facts: true
tasks:
- name: Install additional packages
yum:
name: git
state: present

- name: Deploy application code
git:
repo: https://github.com/example/myapp.git
dest: /var/www/html/app

异步任务和并行执行

异步任务用于处理长时间运行的操作:

# 使用异步任务的Playbook示例
---
- name: Use asynchronous tasks in Ansible
hosts: all
become: true
tasks:
- name: Long running task with async
command: /path/to/long_running_script.sh
async: 3600 # 超时时间(秒)
poll: 0 # 不轮询结果
register: async_result

- name: Check on async task periodically
async_status:
jid: "{{ async_result.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 30 # 重试次数
delay: 60 # 重试间隔(秒)

- name: Another long running task
shell: sleep 300 && echo "Done"
async: 600
poll: 10 # 每10秒轮询一次结果

- name: Run multiple tasks in parallel
command: "sleep {{ item }}"
loop: [10, 20, 30, 40, 50]
async: 60
poll: 0
register: async_results

- name: Wait for all parallel tasks to complete
async_status:
jid: "{{ item.ansible_job_id }}"
register: job_results
until: job_results.finished
retries: 10
delay: 5
loop: "{{ async_results.results }}"

调整并行连接数:

# ansible.cfg
[defaults]
# 设置并行连接数(默认5)
forks = 20

或者在命令行中指定:

ansible-playbook site.yml -f 20

委托和本地执行

委托(delegation)用于在其他主机上执行任务,本地执行用于在控制节点上执行任务:

# 使用委托和本地执行的Playbook示例
---
- name: Use delegation and local actions in Ansible
hosts: webservers
become: true
tasks:
- name: Update inventory in CMDB
uri:
url: http://cmdb.example.com/api/update
method: POST
body: "{\"host\": \"{{ ansible_hostname }}\", \"ip\": \"{{ ansible_default_ipv4.address }}\"}"
headers:
Content-Type: "application/json"
delegate_to: localhost

- name: Ping a remote host from the current host
command: ping -c 3 {{ item }}
with_items: groups['dbservers']
delegate_to: localhost
register: ping_results

- name: Display ping results
debug:
var: ping_results

- name: Create a local backup before deployment
archive:
path: /path/to/app
dest: "/backups/app_{{ ansible_date_time.date }}.tar.gz"
delegate_to: localhost

- name: Deploy application from control node
copy:
src: /path/to/local/app/
dest: /path/to/remote/app/

- name: Wait for application to be ready
wait_for:
port: 8080
host: "{{ ansible_default_ipv4.address }}"
timeout: 300
delegate_to: localhost

- name: Send notification email
mail:
host: mail.example.com
port: 25
to: admin@example.com
subject: "Deployment completed on {{ ansible_hostname }}"
body: "Application has been successfully deployed to {{ ansible_hostname }} ({{ ansible_default_ipv4.address }})."
delegate_to: localhost
when: deployment_successful is defined and deployment_successful

- name: Run task locally (alternative syntax)
local_action:
module: command
_raw_params: ls -la /tmp
register: local_files

- name: Display local files
debug:
var: local_files.stdout_lines

自定义模块和插件

Ansible允许创建自定义模块和插件:

自定义模块示例

#!/usr/bin/python3
# 简单的自定义模块示例 (my_module.py)

from ansible.module_utils.basic import AnsibleModule

def main():
# 定义模块参数
module_args = {
'name': {
'type': 'str',
'required': True
},
'state': {
'type': 'str',
'default': 'present',
'choices': ['present', 'absent']
},
'message': {
'type': 'str',
'default': 'Hello'
}
}

# 创建模块实例
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)

# 获取参数
name = module.params['name']
state = module.params['state']
message = module.params['message']

# 模拟操作
result = {
'changed': False,
'name': name,
'state': state,
'message': message
}

# 检查模式
if module.check_mode:
module.exit_json(**result)

# 根据state执行操作
if state == 'present':
result['changed'] = True
result['msg'] = f"{message}, {name}!"
else:
result['changed'] = True
result['msg'] = f"Goodbye, {name}!"

# 返回结果
module.exit_json(**result)

if __name__ == '__main__':
main()

使用自定义模块:

# 将自定义模块放在ansible.cfg中指定的library目录或当前目录的library子目录
mkdir -p library
cp my_module.py library/

# 在Playbook中使用自定义模块
cat > test_custom_module.yml << EOF
---
- name: Test custom module
hosts: localhost
gather_facts: false
tasks:
- name: Use custom module
my_module:
name: World
state: present
message: Hello
register: custom_result

- name: Display custom module result
debug:
var: custom_result
EOF

# 运行Playbook
ansible-playbook test_custom_module.yml

自定义插件示例

自定义回调插件示例 (callback_plugins/my_callback.py):

#!/usr/bin/python3
# 简单的自定义回调插件示例

from ansible.plugins.callback import CallbackBase

class CallbackModule(CallbackBase):
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'stdout'
CALLBACK_NAME = 'my_callback'
CALLBACK_NEEDS_WHITELIST = False

def __init__(self):
super(CallbackModule, self).__init__()

def v2_runner_on_start(self, host, task):
self._display.display(f"Starting task '{task.name}' on {host}")

def v2_runner_on_ok(self, result):
host = result._host.get_name()
task = result.task_name
self._display.display(f"✓ Task '{task}' completed successfully on {host}")

def v2_runner_on_failed(self, result, ignore_errors=False):
host = result._host.get_name()
task = result.task_name
self._display.display(f"✗ Task '{task}' failed on {host}: {result._result.get('msg', '')}")

def v2_runner_on_skipped(self, result):
host = result._host.get_name()
task = result.task_name
self._display.display(f"→ Task '{task}' skipped on {host}")

def v2_playbook_on_stats(self, stats):
self._display.display("\n===== Playbook Summary =====")
for host in stats.processed.keys():
summary = stats.summarize(host)
self._display.display(f"{host}: ok={summary['ok']}, changed={summary['changed']}, unreachable={summary['unreachable']}, failed={summary['failures']}")
self._display.display("===========================")

# 配置自定义插件
# ansible.cfg
#[defaults]
#callback_plugins = ./callback_plugins
#library = ./library

# 自定义查找插件示例 (lookup_plugins/my_lookup.py)
##!/usr/bin/python3
## 简单的自定义查找插件示例

#from ansible.plugins.lookup import LookupBase

#class LookupModule(LookupBase):
# def run(self, terms, variables=None, **kwargs):
# results = []
# for term in terms:
# # 简单示例:返回大写的term
# results.append(term.upper())
# return results

# 在Playbook中使用自定义查找插件
##---
##- name: Test custom lookup plugin
## hosts: localhost
## gather_facts: false
## tasks:
## - name: Use custom lookup plugin
## debug:
## msg: "{{ lookup('my_lookup', 'hello world') }}"

# 自定义过滤器插件示例 (filter_plugins/my_filters.py)
##!/usr/bin/python3
## 简单的自定义过滤器插件示例

#def to_uppercase(text):
# """Convert text to uppercase"""
# return text.upper()

#def to_lowercase(text):
# """Convert text to lowercase"""
# return text.lower()

#class FilterModule(object):
# """Custom filter plugin"""
# def filters(self):
# return {
# 'to_uppercase': to_uppercase,
# 'to_lowercase': to_lowercase
# }

# 在Playbook中使用自定义过滤器
##---
##- name: Test custom filter plugins
## hosts: localhost
## gather_facts: false
## vars:
## message: "Hello World"
## tasks:
## - name: Use custom uppercase filter
## debug:
## msg: "{{ message | to_uppercase }}"

## - name: Use custom lowercase filter
## debug:
## msg: "{{ message | to_lowercase }}"

### 配置管理最佳实践

# Ansible配置管理最佳实践

## 项目结构最佳实践

# 推荐的Ansible项目结构

ansible-project/ ├── ansible.cfg # Ansible配置文件 ├── inventory/ # 主机清单目录 │ ├── production/ # 生产环境清单 │ │ ├── hosts # 主机定义 │ │ └── group_vars/ # 组变量 │ └── staging/ # 测试环境清单 │ ├── hosts # 主机定义 │ └── group_vars/ # 组变量 ├── group_vars/ # 全局组变量 │ ├── all/ # 所有主机的变量 │ ├── webservers/ # webservers组变量 │ └── dbservers/ # dbservers组变量 ├── host_vars/ # 主机特定变量 │ ├── web1.example.com/ # 特定主机变量 │ └── db1.example.com/ # 特定主机变量 ├── playbooks/ # Playbooks目录 │ ├── site.yml # 主Playbook │ ├── webservers.yml # Web服务器配置 │ └── dbservers.yml # 数据库服务器配置 ├── roles/ # 角色目录 │ ├── common/ # 通用角色 │ ├── webserver/ # Web服务器角色 │ └── database/ # 数据库角色 ├── files/ # 通用文件 ├── templates/ # 通用模板 ├── scripts/ # 辅助脚本 ├── vars/ # 通用变量 │ ├── common.yml # 通用变量 │ ├── secrets.yml # 加密的敏感变量 │ └── vault.yml # Ansible Vault配置 └── README.md # 项目文档


## 变量管理最佳实践

1. **使用层次化变量结构**
- 使用`group_vars`和`host_vars`组织变量
- 为不同环境(开发、测试、生产)创建单独的变量文件
- 遵循变量优先级规则

2. **使用Ansible Vault保护敏感数据**
```bash
# 创建加密文件存储敏感数据
ansible-vault create group_vars/all/secrets.yml
# 或加密现有文件
ansible-vault encrypt group_vars/production/secrets.yml
  1. 合理使用变量类型

    • 使用字典存储相关配置项
    • 使用数组存储列表数据
    • 使用set_fact动态计算变量
  2. 变量命名规范

    • 使用有意义的变量名(例如webserver_port而不是p
    • 使用统一的命名约定(如 snake_case)
    • 为变量添加前缀以表明其用途或所属组件
  3. 避免硬编码值

    # 不好的做法
    - name: Start nginx
    service:
    name: nginx
    state: started
    enabled: yes

    # 好的做法
    - name: Start web service
    service:
    name: "{{ web_service_name }}"
    state: "{{ web_service_state }}"
    enabled: "{{ web_service_enabled }}"

任务和Playbook设计最佳实践

  1. 保持任务的幂等性

    • 确保多次执行相同任务产生相同结果
    • 优先使用Ansible内置模块而非命令行
    # 幂等性任务示例
    - name: Ensure nginx is installed
    apt:
    name: nginx
    state: present

    # 非幂等性任务示例(应避免)
    - name: Install nginx
    command: apt-get install nginx -y
  2. 使用条件语句和循环

    • 使用when条件避免不必要的任务执行
    • 使用loop替代重复的任务定义
    • 避免嵌套循环,考虑使用扁平化数据结构
    - name: Install packages based on OS
    package:
    name: "{{ item }}"
    state: present
    loop: "{{ packages[ansible_os_family] }}"
    vars:
    packages:
    Debian: [nginx, php-fpm, mysql-server]
    RedHat: [httpd, php, mariadb-server]
  3. 模块化和重用

    • 将相关任务分组到独立的Playbook中
    • 使用include_tasksimport_tasks重用任务代码
    • 使用include_roleimport_role重用角色
    # 使用include_role动态包含角色
    - name: Include webserver role with custom variables
    include_role:
    name: webserver
    vars:
    webserver_port: 8080
    webserver_ssl: true
  4. 任务标记和文档

    • 使用tags标记任务,便于选择性执行
    • 为复杂任务添加描述性注释
    • 使用name属性提供清晰的任务描述
    - name: Configure firewall rules for web server
    ufw:
    rule: allow
    port: "{{ item }}"
    proto: tcp
    loop: [80, 443]
    tags: [firewall, web, security]
  5. 错误处理和调试

    • 使用block/rescue/always处理可能的错误
    • 使用debug模块输出变量和中间结果
    • 使用failed_whenchanged_when自定义任务状态
    - name: Check service status and handle errors
    block:
    - name: Get service status
    command: systemctl status nginx
    register: service_status
    ignore_errors: yes

    - name: Fail if service is not running
    fail:
    msg: "Nginx service is not running"
    when: service_status.rc != 0
    rescue:
    - name: Attempt to restart service
    service:
    name: nginx
    state: restarted
    always:
    - name: Log service check result
    debug:
    msg: "Service check completed for nginx"

角色设计最佳实践

  1. 单一职责原则

    • 每个角色应有明确的单一职责
    • 避免创建过于复杂或功能过多的角色
    • 例如:一个角色负责安装配置Nginx,另一个负责安装配置数据库
  2. 合理使用角色目录结构

    • 使用defaults存储可覆盖的默认值
    • 使用vars存储角色内部使用的常量
    • 使用meta定义角色依赖关系
    # roles/common/meta/main.yml
    dependencies:
    - role: firewall
    vars:
    firewall_allow_ssh: true
  3. 参数化角色

    • 使用变量使角色灵活可配置
    • 为所有重要设置提供默认值
    • 避免在角色内部硬编码值
    # roles/webserver/defaults/main.yml
    webserver_port: 80
    webserver_ssl: false
    webserver_document_root: /var/www/html
    webserver_max_clients: 100
  4. 角色间通信

    • 使用set_fact设置可被其他角色使用的变量
    • 使用delegate_torun_once协调跨主机操作
    • 使用wait_for确保服务已准备就绪
    # 在一个角色中设置事实供其他角色使用
    - name: Set database connection info
    set_fact:
    db_host: "{{ ansible_default_ipv4.address }}"
    db_port: 3306
    when: inventory_hostname in groups['dbservers']
  5. 测试和文档

    • 为角色编写示例Playbook和测试用例
    • 提供详细的README.md说明角色用途和参数
    • 使用ansible-lint检查角色代码质量
    # roles/webserver/tests/test.yml
    ---
    - hosts: localhost
    become: true
    roles:
    - role: webserver
    webserver_port: 8080

安全性最佳实践

  1. 使用Ansible Vault加密敏感数据

    • 加密密码、API密钥和证书等敏感信息
    • 使用单独的Vault文件而非将敏感数据混合在普通文件中
    • 管理Vault密码安全(使用密码文件、环境变量或保险库服务)
    # 使用Vault密码文件
    ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt

    # 使用环境变量
    export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt
    ansible-playbook site.yml
  2. 限制权限提升

    • 只在需要时使用become: true
    • 避免在整个Playbook中全局启用权限提升
    • 使用最小权限原则设计Playbook
    # 仅在特定任务中使用权限提升
    - name: Install system packages
    apt:
    name: nginx
    state: present
    become: true
    become_user: root

    - name: Configure application settings
    template:
    src: app.conf.j2
    dest: /opt/app/app.conf
    become: true
    become_user: appuser # 使用应用用户而非root
  3. 安全的连接配置

    • 禁用SSH主机密钥检查(仅在可信环境中)
    • 使用SSH密钥而非密码进行认证
    • 配置合理的SSH超时和重试策略
    # ansible.cfg
    [ssh_connection]
    ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o PreferredAuthentications=publickey
    host_key_checking = False
  4. 避免在日志中暴露敏感信息

    • 使用no_log: true隐藏敏感任务的输出
    • 避免使用debug模块输出敏感变量
    • 配置适当的日志级别
    - name: Configure database with sensitive credentials
    mysql_db:
    name: "{{ db_name }}"
    state: present
    login_user: root
    login_password: "{{ db_root_password }}"
    no_log: true # 防止密码出现在日志中
  5. 定期审计和更新

    • 使用ansible-playbook --check定期验证系统配置
    • 定期更新Ansible和使用的模块
    • 实施代码审查流程确保Playbook安全
    # 使用ansible-lint检查Playbook
    ansible-lint playbooks/*.yml

    # 使用check模式验证配置
    ansible-playbook site.yml --check

性能优化最佳实践

  1. 调整并行连接数

    • 根据控制节点资源和网络状况调整forks参数
    • 对于大规模环境,增加forks值提高并行度
    • 监控系统资源使用情况以找到最佳值
    # ansible.cfg
    [defaults]
    forks = 20
  2. 使用异步任务和轮询

    • 对长时间运行的任务使用asyncpoll参数
    • 避免因单个任务阻塞整个Playbook执行
    • 使用async_status检查长时间运行任务的状态
    - name: Run database backup (async)
    command: /usr/local/bin/db_backup.sh
    async: 3600
    poll: 0
    register: backup_task

    - name: Check backup status
    async_status:
    jid: "{{ backup_task.ansible_job_id }}"
    register: backup_result
    until: backup_result.finished
    retries: 60
    delay: 60
  3. 优化事实收集

    • 使用gather_facts: false禁用不需要的事实收集
    • 使用setup模块有选择地收集需要的事实
    • 缓存事实以避免重复收集
    # 禁用全局事实收集
    - hosts: all
    gather_facts: false
    tasks:
    # 选择性收集事实
    - name: Gather only network facts
    setup:
    filter: ansible_*_ipv4

    # 启用事实缓存
    # ansible.cfg
    [defaults]
    gathering = smart
    fact_caching = jsonfile
    fact_caching_connection = /tmp/ansible_facts
    fact_caching_timeout = 86400 # 24小时
  4. 减少模块调用

    • 合并多个简单任务为单个复合任务
    • 使用with_items而非多个单独任务
    • 优先使用原生模块而非shellcommand
    # 合并多个文件操作任务
    - name: Configure multiple files
    copy:
    content: "{{ item.content }}"
    dest: "{{ item.path }}"
    mode: "{{ item.mode }}"
    loop:
    - { path: '/etc/motd', content: 'Welcome', mode: '0644' }
    - { path: '/etc/issue', content: 'Internal Server', mode: '0644' }
  5. 使用本地执行和委托

    • 对本地操作使用delegate_to: localhost避免SSH开销
    • 使用run_once: true减少重复执行
    • 考虑使用connection: local对仅在本地运行的Playbook
    - name: Generate configuration files locally
    template:
    src: "{{ item }}.j2"
    dest: "/tmp/{{ item }}"
    loop: [config1.conf, config2.conf]
    delegate_to: localhost
    run_once: true

与CI/CD集成

  1. 自动化测试和部署

    • 在CI/CD流水线中使用Ansible自动化测试和部署
    • 集成Ansible与Jenkins、GitLab CI、GitHub Actions等工具
    • 实施测试驱动的部署流程
    # GitHub Actions工作流示例
    # .github/workflows/ansible.yml
    name: Ansible CI

    on:
    push:
    branches: [ main ]
    pull_request:
    branches: [ main ]

    jobs:
    build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
    uses: actions/checkout@v2

    - name: Set up Python
    uses: actions/setup-python@v2
    with:
    python-version: '3.8'

    - name: Install dependencies
    run: |
    python -m pip install --upgrade pip
    pip install ansible ansible-lint

    - name: Lint Playbooks
    run: ansible-lint playbooks/*.yml

    - name: Test Playbooks (dry-run)
    run: ansible-playbook -i inventory/testing playbooks/site.yml --check --diff

    - name: Deploy to staging
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    run: ansible-playbook -i inventory/staging playbooks/site.yml
    env:
    ANSIBLE_VAULT_PASSWORD_FILE: .vault_pass
  2. 使用Ansible进行持续配置

    • 定期运行Ansible Playbook确保系统配置一致性
    • 实施漂移检测和自动修复
    • 集成配置管理与监控系统
    # 漂移检测Playbook示例
    ---
    - name: Detect and remediate configuration drift
    hosts: all
    gather_facts: true
    tasks:
    - name: Check for configuration drift
    command: ansible-playbook -i inventory/{{ inventory_dir }} playbooks/site.yml --check --diff
    register: drift_check
    delegate_to: localhost
    run_once: true

    - name: Remediate configuration drift
    command: ansible-playbook -i inventory/{{ inventory_dir }} playbooks/site.yml
    when: drift_check.rc != 0
    delegate_to: localhost
    run_once: true
  3. 不可变基础设施

    • 使用Ansible构建不可变基础设施镜像
    • 结合Packer和Ansible创建自定义镜像
    • 实施蓝绿部署或金丝雀发布策略
    // Packer配置文件示例 (ansible.json)
    {
    "builders": [
    {
    "type": "amazon-ebs",
    "region": "us-west-2",
    "source_ami": "ami-0c55b159cbfafe1f0",
    "instance_type": "t2.micro",
    "ssh_username": "ubuntu",
    "ami_name": "my-application-{{timestamp}}"
    }
    ],
    "provisioners": [
    {
    "type": "ansible",
    "playbook_file": "./playbooks/packer-provision.yml",
    "extra_arguments": ["--tags", "packer"]
    }
    ]
    }
  4. GitOps工作流

    • 实施GitOps,将Git作为基础设施和配置的单一真实来源
    • 使用Ansible自动化GitOps工作流
    • 集成版本控制、代码审查和自动部署
    # GitOps工作流示例
    ---
    - name: GitOps deployment
    hosts: localhost
    gather_facts: false
    tasks:
    - name: Clone configuration repository
    git:
    repo: https://github.com/example/infra-config.git
    dest: /tmp/infra-config
    version: main

    - name: Check for configuration changes
    command: git diff --stat HEAD^ HEAD
    args:
    chdir: /tmp/infra-config
    register: config_changes

    - name: Deploy configuration changes
    command: ansible-playbook -i /tmp/infra-config/inventory/production /tmp/infra-config/playbooks/site.yml
    when: config_changes.stdout != ""

常见问题与解决方案

连接问题

  1. SSH连接超时

    # 问题:无法通过SSH连接到远程主机
    # 解决方案:检查网络连接、防火墙设置和SSH服务状态
    ansible webservers -m ping -vvv # 增加详细输出以调试连接问题

    # 配置SSH超时和重试
    # ansible.cfg
    [ssh_connection]
    ssh_args = -o ConnectTimeout=30 -o ControlMaster=auto -o ControlPersist=60s
    timeout = 60
  2. 权限被拒绝(publickey)

    # 问题:SSH密钥认证失败
    # 解决方案:检查SSH密钥权限和所有权
    chmod 600 ~/.ssh/id_rsa # 确保私钥权限正确
    ansible webservers -m ping -u username -e ansible_ssh_private_key_file=~/.ssh/custom_key
  3. sudo权限问题

    # 问题:无法使用sudo提升权限
    # 解决方案:确保用户有sudo权限,并配置正确的sudo密码或NOPASSWD
    # playbook.yml
    - hosts: webservers
    become: true
    become_method: sudo
    become_user: root
    vars:
    ansible_become_pass: "{{ sudo_password }}" # 或在命令行使用--ask-become-pass
    tasks:
    - name: Update package cache
    apt: update_cache=yes

执行问题

  1. 任务执行失败

    # 问题:任务执行失败,需要调试
    # 解决方案:使用详细输出、检查模式和调试模块
    ansible-playbook playbook.yml -vvv # 显示详细的执行信息
    ansible-playbook playbook.yml --check # 模拟执行,不实际修改系统
    ansible-playbook playbook.yml --start-at-task="Task name" # 从特定任务开始执行

    # 在Playbook中添加调试任务
    - name: Debug variables
    debug:
    var: variable_name
  2. 变量未定义错误

    # 问题:出现"VARIABLE IS NOT DEFINED"错误
    # 解决方案:确保变量已定义,使用默认值或条件检查
    - name: Use variable with default
    debug:
    msg: "{{ my_variable | default('Default value') }}"

    - name: Only execute if variable is defined
    debug:
    msg: "Variable is defined"
    when: my_variable is defined

    # 在ansible.cfg中设置错误处理
    # [defaults]
    # error_on_undefined_vars = False # 不推荐,最好修复未定义的变量
  3. 模块找不到或不支持

    # 问题:找不到模块或模块不支持当前系统
    # 解决方案:安装缺失的模块或使用兼容的模块
    ansible-galaxy collection install community.general # 安装社区模块
    ansible-doc -l | grep module_name # 检查模块是否可用
    ansible webservers -m setup -a 'filter=ansible_os_family' # 检查系统信息

性能问题

  1. 执行速度慢

    # 问题:Ansible执行速度慢,特别是在大规模环境中
    # 解决方案:优化并行连接、事实收集和任务执行
    # ansible.cfg
    [defaults]
    forks = 50 # 增加并行连接数
    gathering = smart # 智能事实收集
    fact_caching = jsonfile
    fact_caching_connection = /tmp/ansible_facts
    fact_caching_timeout = 86400

    [ssh_connection]
    pipelining = True # 启用SSH管道
  2. 内存使用过高

    # 问题:Ansible控制节点内存使用过高
    # 解决方案:减少并行连接数,拆分大型Playbook,优化变量使用
    ansible-playbook playbook.yml -f 10 # 减少并行连接数
    split -l 1000 inventory inventory.part. # 拆分大型inventory文件
  3. 大量主机执行超时

    # 问题:在大量主机上执行任务时超时
    # 解决方案:使用异步任务,增加超时时间,分批执行
    - name: Long running task with increased timeout
    command: /path/to/script.sh
    async: 7200 # 2小时超时
    poll: 60 # 每分钟检查一次
    register: task_result

    # 使用子组分批执行
    ansible-playbook -l webservers[0:10] playbook.yml # 只在前10个web服务器上执行

Ansible监控与日志

日志配置

# ansible.cfg
[defaults]
# 配置Ansible日志文件
log_path = /var/log/ansible.log

# 配置日志级别(DEBUG, INFO, WARNING, ERROR, CRITICAL)
verbosity = 1

# 记录主机和任务结果
record_host_keys = True

[ssh_connection]
# 记录SSH连接日志
ssh_logfile = /var/log/ansible-ssh.log

使用外部日志系统

# 将Ansible日志发送到ELK或其他日志系统
---
- name: Configure rsyslog to forward Ansible logs
hosts: localhost
become: true
tasks:
- name: Create rsyslog configuration for Ansible
copy:
content: |
# Forward Ansible logs to log server
if $programname == 'ansible' then @@logserver:514;AnsibleFormat
dest: /etc/rsyslog.d/40-ansible.conf
mode: '0644'
notify:
- Restart rsyslog

handlers:
- name: Restart rsyslog
service:
name: rsyslog
state: restarted

监控Ansible执行

# 监控Ansible执行并发送通知
---
- name: Monitor and report Ansible execution
hosts: all
become: true
tasks:
- block:
- name: Run main tasks
include_tasks: main_tasks.yml
always:
- name: Collect execution stats
set_fact:
execution_stats: |
Host: {{ ansible_hostname }}
Status: {{ 'Success' if ansible_failed is not defined else 'Failed' }}
Changed: {{ ansible_changed_hosts | default(0) }}
Failed: {{ ansible_failed_hosts | default(0) }}
Duration: {{ (ansible_date_time.epoch | int - play_start_time | int) }} seconds
run_once: true
delegate_to: localhost

- name: Send notification
mail:
host: mail.example.com
port: 25
to: admin@example.com
subject: "Ansible Playbook Execution Report"
body: "{{ execution_stats }}"
delegate_to: localhost
run_once: true

审计跟踪

# 创建审计跟踪记录
---
- name: Create audit trail for configuration changes
hosts: all
become: true
vars:
audit_log: /var/log/ansible-audit.log
tasks:
- name: Create audit log directory
file:
path: /var/log/ansible-audit
state: directory
mode: '0750'
owner: root
group: root

- name: Log playbook start
lineinfile:
path: "{{ audit_log }}"
line: "{{ ansible_date_time.iso8601 }} - PLAYBOOK START - {{ playbook_dir | basename }} - User: {{ lookup('env', 'USER') }} - Hosts: {{ ansible_play_hosts | join(', ') }}"
create: yes
mode: '0640'
delegate_to: localhost
run_once: true

- name: Log task execution
lineinfile:
path: "{{ audit_log }}"
line: "{{ ansible_date_time.iso8601 }} - TASK EXECUTE - Host: {{ ansible_hostname }} - Task: {{ task.name }} - Status: {{ task.status }}{% if task.changed %}} - Changed: true{% endif %}}"
delegate_to: localhost
loop: "{{ ansible_run_tags }}" # 这是一个示例,实际使用时需要自定义如何收集任务状态
loop_control:
loop_var: task
run_once: true

- name: Log playbook completion
lineinfile:
path: "{{ audit_log }}"
line: "{{ ansible_date_time.iso8601 }} - PLAYBOOK COMPLETE - {{ playbook_dir | basename }} - Success: {{ ansible_play_hosts | difference(ansible_play_hosts_all) | length }} - Failed: {{ ansible_failed_hosts | default([]) | length }}"
delegate_to: localhost
run_once: true

Ansible与其他工具集成

与Docker集成

# 使用Ansible管理Docker容器
---
- name: Manage Docker containers with Ansible
hosts: docker-hosts
become: true
tasks:
- name: Install Docker
apt:
name: docker.io
state: present
when: ansible_os_family == "Debian"

- name: Install Docker SDK for Python
pip:
name: docker

- name: Start Docker service
service:
name: docker
state: started
enabled: yes

- name: Pull Nginx image
docker_image:
name: nginx:latest
source: pull

- name: Create Nginx container
docker_container:
name: web-server
image: nginx:latest
state: started
restart_policy: always
ports:
- "80:80"
- "443:443"
volumes:
- "/opt/nginx/html:/usr/share/nginx/html:ro"
- "/opt/nginx/conf:/etc/nginx/conf.d:ro"
env:
TZ: "Asia/Shanghai"

- name: Create Docker network
docker_network:
name: app-network
driver: bridge
ipam_config:
- subnet: "172.20.0.0/16"
gateway: "172.20.0.1"

- name: Create Docker Compose file
template:
src: templates/docker-compose.yml.j2
dest: /opt/app/docker-compose.yml
mode: '0644'

- name: Start services with Docker Compose
docker_compose:
project_src: /opt/app
state: present
restarted: yes

与Kubernetes集成

# 使用Ansible管理Kubernetes资源
---
- name: Manage Kubernetes resources with Ansible
hosts: localhost
gather_facts: false
vars:
k8s_namespace: default
tasks:
- name: Install kubernetes Python module
pip:
name: kubernetes

- name: Create Kubernetes namespace
k8s:
name: "{{ k8s_namespace }}"
api_version: v1
kind: Namespace
state: present

- name: Create Kubernetes deployment
k8s:
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: "{{ k8s_namespace }}"
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
resources:
limits:
memory: "128Mi"
cpu: "500m"
state: present

- name: Create Kubernetes service
k8s:
definition:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: "{{ k8s_namespace }}"
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: LoadBalancer
state: present

- name: Apply Kubernetes manifest from file
k8s:
state: present
src: /path/to/kubernetes-manifest.yml

- name: Get Kubernetes pods
k8s_info:
kind: Pod
namespace: "{{ k8s_namespace }}"
label_selectors:
- app=nginx
register: pod_list

- name: Display pod information
debug:
var: pod_list.resources

与云服务集成

AWS集成

# 使用Ansible管理AWS资源
---
- name: Manage AWS resources with Ansible
hosts: localhost
gather_facts: false
vars:
aws_region: us-west-2
ec2_instance_type: t2.micro
ec2_image_id: ami-0c55b159cbfafe1f0
tasks:
- name: Install AWS modules dependencies
pip:
name: boto3

- name: Create EC2 instance
amazon.aws.ec2_instance:
name: ansible-test
key_name: my-key-pair
instance_type: "{{ ec2_instance_type }}"
image_id: "{{ ec2_image_id }}"
region: "{{ aws_region }}"
security_group: default
volumes:
- device_name: /dev/sda1
ebs:
volume_size: 20
delete_on_termination: true
tags:
Name: ansible-test
Environment: test
wait: true
count: 1
register: ec2_result

- name: Create S3 bucket
amazon.aws.s3_bucket:
name: ansible-test-bucket-{{ 1000 | random }}
state: present
region: "{{ aws_region }}" # 使用正确的区域
versioning:
enabled: true
tags:
Name: ansible-test-bucket
Environment: test

- name: Create IAM role
amazon.aws.iam_role:
name: ansible-test-role
state: present
assume_role_policy_document: "{{ lookup('file', 'role-policy.json') }}"
description: Role for Ansible testing

- name: Create Lambda function
community.aws.lambda_function:
name: ansible-test-function
state: present
runtime: python3.8
role: "{{ iam_role.arn }}"
handler: index.handler
zip_file: "{{ lookup('file', 'lambda-function.zip', rstrip=False) }}"
region: "{{ aws_region }}"

Azure集成

# 使用Ansible管理Azure资源
---
- name: Manage Azure resources with Ansible
hosts: localhost
gather_facts: false
vars:
resource_group: ansible-test-rg
location: eastus
tasks:
- name: Install Azure modules dependencies
pip:
name: azure-cli-core, azure-core, ansible[azure]

- name: Create Azure resource group
azure.azcollection.azure_rm_resourcegroup:
name: "{{ resource_group }}"
location: "{{ location }}"
tags:
Environment: Test
Department: IT

- name: Create virtual network
azure.azcollection.azure_rm_virtualnetwork:
resource_group: "{{ resource_group }}"
name: vnet-test
address_prefixes: "10.0.0.0/16"

- name: Add subnet
azure.azcollection.azure_rm_subnet:
resource_group: "{{ resource_group }}"
name: subnet-test
address_prefix: "10.0.1.0/24"
virtual_network: vnet-test

- name: Create storage account
azure.azcollection.azure_rm_storageaccount:
resource_group: "{{ resource_group }}"
name: ansiblestorage{{ 1000 | random }}
account_type: Standard_LRS

- name: Create Linux virtual machine
azure.azcollection.azure_rm_virtualmachine:
resource_group: "{{ resource_group }}"
name: vm-test
vm_size: Standard_B1s
admin_username: azureuser
admin_password: Password1234!
image:
offer: UbuntuServer
publisher: Canonical
sku: '18.04-LTS'
version: latest
virtual_network_name: vnet-test
subnet_name: subnet-test
public_ip_allocation_method: Dynamic
open_ports:
- 22

与监控工具集成

# 使用Ansible集成Prometheus监控
---
- name: Configure Prometheus monitoring
hosts: monitoring
become: true
tasks:
- name: Install Prometheus
apt:
name: prometheus
state: present
when: ansible_os_family == "Debian"

- name: Configure Prometheus targets
template:
src: templates/prometheus.yml.j2
dest: /etc/prometheus/prometheus.yml
mode: '0644'
notify:
- Restart Prometheus

- name: Install Node Exporter on all servers
apt:
name: prometheus-node-exporter
state: present
when: ansible_os_family == "Debian"
delegate_to: "{{ item }}"
loop: "{{ groups['all'] }}"

- name: Start Node Exporter service
service:
name: prometheus-node-exporter
state: started
enabled: yes
delegate_to: "{{ item }}"
loop: "{{ groups['all'] }}"

handlers:
- name: Restart Prometheus
service:
name: prometheus
state: restarted

Ansible未来趋势

自动化趋势

  1. AI驱动的自动化

    • Ansible与人工智能和机器学习技术的集成
    • 预测性分析和智能建议
    • 自动化任务优化和自修复系统
  2. GitOps和DevOps演进

    • GitOps工作流的广泛采用
    • 基础设施即代码的成熟与标准化
    • DevSecOps的深度融合
  3. 多云和混合云管理

    • 跨云平台的统一管理解决方案
    • 混合云环境的自动化编排
    • 云原生应用的部署和管理
  4. 边缘计算自动化

    • 边缘设备的配置和管理
    • 分布式系统的自动化协调
    • 低带宽环境下的高效自动化

Ansible未来发展方向

  1. Ansible Automation Platform

    • 企业级自动化平台的增强
    • 更多集成和扩展能力
    • 增强的用户界面和协作功能
  2. Ansible Lightspeed

    • AI辅助Playbook开发
    • 自动化代码生成和优化
    • 智能错误检测和修复
  3. 增强的云原生支持

    • 更好的Kubernetes集成
    • 容器原生自动化功能
    • 云服务的深度集成
  4. 安全性和合规自动化

    • 内置安全合规检查
    • 自动化安全响应
    • 增强的审计和合规报告

总结

Ansible是一个强大而灵活的自动化工具,适用于配置管理、应用部署、任务编排和基础设施自动化等多种场景。通过本指南,我们详细介绍了Ansible的核心概念、安装配置、模块使用、Playbook编写、角色设计、高级功能和最佳实践。

在实际应用中,Ansible可以帮助组织实现基础设施即代码、自动化配置管理、持续集成和持续部署,提高系统的一致性、可靠性和安全性,同时减少手动操作和人为错误。

随着自动化需求的不断增长和技术的不断发展,Ansible将继续演进和增强,为IT自动化提供更强大、更智能的解决方案。通过不断学习和实践,您可以充分利用Ansible的强大功能,构建高效、可靠的自动化系统,为组织的数字化转型提供有力支持。

祝您在自动化之旅中取得成功!