Ansible实践指南
概述
Ansible是一个开源的配置管理、应用部署和任务自动化工具。它采用无代理架构,通过SSH或WinRM协议远程执行任务,具有简单易用、幂等性、模块化设计等特点。本指南详细介绍Ansible的核心概念、安装配置、使用方法和最佳实践,帮助您快速掌握Ansible并在实际项目中应用。
Ansible基础概念
什么是Ansible
Ansible是一个由Red Hat赞助的开源自动化工具,用于配置管理、应用部署、任务自动化和编排。它使用Python编写,采用声明式语言(YAML)描述系统配置,通过SSH协议(或Windows上的WinRM)远程执行任务,无需在被管理节点上安装额外的代理软件。
Ansible的特点
- 无代理架构:不需要在被管理节点上安装代理软件
- 简单易用:使用YAML语法编写Playbooks,易于学习和理解
- 幂等性:确保多次执行相同的任务产生相同的结果
- 模块化设计:提供丰富的内置模块,支持各种任务
- 广泛集成:与主流云平台和工具(如AWS、Azure、Docker、Kubernetes等)集成
- 自动化编排:支持复杂的工作流编排
- 开源社区:拥有活跃的开源社区和丰富的文档
Ansible的核心组件
- 控制节点:运行Ansible命令和Playbooks的机器
- 被管理节点:由Ansible管理的机器
- Inventory:定义被管理节点的主机清单
- 模块(Modules):执行特定任务的代码单元
- Playbooks:定义自动化任务的YAML文件
- Tasks:在Playbooks中定义的单个操作
- Plays:将一组任务应用到特定主机的配置
- Roles:组织和重用Playbooks的方式
- Variables:存储和传递值的变量
- Templates:使用Jinja2模板语言生成配置文件
- Handlers:由其他任务触发的任务(如重启服务)
Ansible的工作原理
Ansible的工作流程如下:
- 读取Inventory:Ansible从Inventory文件中获取被管理节点的信息
- 解析Playbooks:解析Playbooks中的任务和配置
- 执行任务:通过SSH(或WinRM)连接到被管理节点并执行任务
- 收集结果:收集任务执行的结果并返回给控制节点
- 生成报告:生成任务执行报告
+----------------+ +----------------+ +----------------+
| | | | | |
| 控制节点 +--->+ 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,默认情况下位于以下位置(按优先级排序):
- 当前目录下的
./ansible.cfg - 用户主目录下的
~/.ansible.cfg - 系统级配置
/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
-
合理使用变量类型
- 使用字典存储相关配置项
- 使用数组存储列表数据
- 使用
set_fact动态计算变量
-
变量命名规范
- 使用有意义的变量名(例如
webserver_port而不是p) - 使用统一的命名约定(如 snake_case)
- 为变量添加前缀以表明其用途或所属组件
- 使用有意义的变量名(例如
-
避免硬编码值
# 不好的做法
- 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设计最佳实践
-
保持任务的幂等性
- 确保多次执行相同任务产生相同结果
- 优先使用Ansible内置模块而非命令行
# 幂等性任务示例
- name: Ensure nginx is installed
apt:
name: nginx
state: present
# 非幂等性任务示例(应避免)
- name: Install nginx
command: apt-get install nginx -y -
使用条件语句和循环
- 使用
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] - 使用
-
模块化和重用
- 将相关任务分组到独立的Playbook中
- 使用
include_tasks和import_tasks重用任务代码 - 使用
include_role和import_role重用角色
# 使用include_role动态包含角色
- name: Include webserver role with custom variables
include_role:
name: webserver
vars:
webserver_port: 8080
webserver_ssl: true -
任务标记和文档
- 使用
tags标记任务,便于选择性执行 - 为复杂任务添加描述性注释
- 使用
name属性提供清晰的任务描述
- name: Configure firewall rules for web server
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop: [80, 443]
tags: [firewall, web, security] - 使用
-
错误处理和调试
- 使用
block/rescue/always处理可能的错误 - 使用
debug模块输出变量和中间结果 - 使用
failed_when和changed_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" - 使用
角色设计最佳实践
-
单一职责原则
- 每个角色应有明确的单一职责
- 避免创建过于复杂或功能过多的角色
- 例如:一个角色负责安装配置Nginx,另一个负责安装配置数据库
-
合理使用角色目录结构
- 使用
defaults存储可覆盖的默认值 - 使用
vars存储角色内部使用的常量 - 使用
meta定义角色依赖关系
# roles/common/meta/main.yml
dependencies:
- role: firewall
vars:
firewall_allow_ssh: true - 使用
-
参数化角色
- 使用变量使角色灵活可配置
- 为所有重要设置提供默认值
- 避免在角色内部硬编码值
# roles/webserver/defaults/main.yml
webserver_port: 80
webserver_ssl: false
webserver_document_root: /var/www/html
webserver_max_clients: 100 -
角色间通信
- 使用
set_fact设置可被其他角色使用的变量 - 使用
delegate_to和run_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'] - 使用
-
测试和文档
- 为角色编写示例Playbook和测试用例
- 提供详细的README.md说明角色用途和参数
- 使用
ansible-lint检查角色代码质量
# roles/webserver/tests/test.yml
---
- hosts: localhost
become: true
roles:
- role: webserver
webserver_port: 8080
安全性最佳实践
-
使用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 -
限制权限提升
- 只在需要时使用
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 - 只在需要时使用
-
安全的连接配置
- 禁用SSH主机密钥检查(仅在可信环境中)
- 使用SSH密钥而非密码进行认证
- 配置合理的SSH超时和重试策略
# ansible.cfg
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o PreferredAuthentications=publickey
host_key_checking = False -
避免在日志中暴露敏感信息
- 使用
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 # 防止密码出现在日志中 - 使用
-
定期审计和更新
- 使用
ansible-playbook --check定期验证系统配置 - 定期更新Ansible和使用的模块
- 实施代码审查流程确保Playbook安全
# 使用ansible-lint检查Playbook
ansible-lint playbooks/*.yml
# 使用check模式验证配置
ansible-playbook site.yml --check - 使用
性能优化最佳实践
-
调整并行连接数
- 根据控制节点资源和网络状况调整
forks参数 - 对于大规模环境,增加
forks值提高并行度 - 监控系统资源使用情况以找到最佳值
# ansible.cfg
[defaults]
forks = 20 - 根据控制节点资源和网络状况调整
-
使用异步任务和轮询
- 对长时间运行的任务使用
async和poll参数 - 避免因单个任务阻塞整个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 - 对长时间运行的任务使用
-
优化事实收集
- 使用
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小时 - 使用
-
减少模块调用
- 合并多个简单任务为单个复合任务
- 使用
with_items而非多个单独任务 - 优先使用原生模块而非
shell或command
# 合并多个文件操作任务
- 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' } -
使用本地执行和委托
- 对本地操作使用
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集成
-
自动化测试和部署
- 在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 -
使用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 -
不可变基础设施
- 使用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"]
}
]
} -
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 != ""
常见问题与解决方案
连接问题
-
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 -
权限被拒绝(publickey)
# 问题:SSH密钥认证失败
# 解决方案:检查SSH密钥权限和所有权
chmod 600 ~/.ssh/id_rsa # 确保私钥权限正确
ansible webservers -m ping -u username -e ansible_ssh_private_key_file=~/.ssh/custom_key -
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
执行问题
-
任务执行失败
# 问题:任务执行失败,需要调试
# 解决方案:使用详细输出、检查模式和调试模块
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 -
变量未定义错误
# 问题:出现"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 # 不推荐,最好修复未定义的变量 -
模块找不到或不支持
# 问题:找不到模块或模块不支持当前系统
# 解决方案:安装缺失的模块或使用兼容的模块
ansible-galaxy collection install community.general # 安装社区模块
ansible-doc -l | grep module_name # 检查模块是否可用
ansible webservers -m setup -a 'filter=ansible_os_family' # 检查系统信息
性能问题
-
执行速度慢
# 问题: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管道 -
内存使用过高
# 问题:Ansible控制节点内存使用过高
# 解决方案:减少并行连接数,拆分大型Playbook,优化变量使用
ansible-playbook playbook.yml -f 10 # 减少并行连接数
split -l 1000 inventory inventory.part. # 拆分大型inventory文件 -
大量主机执行超时
# 问题:在大量主机上执行任务时超时
# 解决方案:使用异步任务,增加超时时间,分批执行
- 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未来趋势
自动化趋势
-
AI驱动的自动化
- Ansible与人工智能和机器学习技术的集成
- 预测性分析和智能建议
- 自动化任务优化和自修复系统
-
GitOps和DevOps演进
- GitOps工作流的广泛采用
- 基础设施即代码的成熟与标准化
- DevSecOps的深度融合
-
多云和混合云管理
- 跨云平台的统一管理解决方案
- 混合云环境的自动化编排
- 云原生应用的部署和管理
-
边缘计算自动化
- 边缘设备的配置和管理
- 分布式系统的自动化协调
- 低带宽环境下的高效自动化
Ansible未来发展方向
-
Ansible Automation Platform
- 企业级自动化平台的增强
- 更多集成和扩展能力
- 增强的用户界面和协作功能
-
Ansible Lightspeed
- AI辅助Playbook开发
- 自动化代码生成和优化
- 智能错误检测和修复
-
增强的云原生支持
- 更好的Kubernetes集成
- 容器原生自动化功能
- 云服务的深度集成
-
安全性和合规自动化
- 内置安全合规检查
- 自动化安全响应
- 增强的审计和合规报告
总结
Ansible是一个强大而灵活的自动化工具,适用于配置管理、应用部署、任务编排和基础设施自动化等多种场景。通过本指南,我们详细介绍了Ansible的核心概念、安装配置、模块使用、Playbook编写、角色设计、高级功能和最佳实践。
在实际应用中,Ansible可以帮助组织实现基础设施即代码、自动化配置管理、持续集成和持续部署,提高系统的一致性、可靠性和安全性,同时减少手动操作和人为错误。
随着自动化需求的不断增长和技术的不断发展,Ansible将继续演进和增强,为IT自动化提供更强大、更智能的解决方案。通过不断学习和实践,您可以充分利用Ansible的强大功能,构建高效、可靠的自动化系统,为组织的数字化转型提供有力支持。
祝您在自动化之旅中取得成功!