Ansible 最佳实践 #
项目结构 #
推荐的目录结构 #
text
project/
├── ansible.cfg # Ansible 配置文件
├── README.md # 项目文档
├── requirements.yml # 角色依赖
├── inventory/ # 清单目录
│ ├── production/
│ │ ├── hosts
│ │ ├── group_vars/
│ │ │ ├── all.yml
│ │ │ ├── webservers.yml
│ │ │ └── vault/
│ │ │ └── all.yml
│ │ └── host_vars/
│ │ └── web1.yml
│ └── staging/
│ ├── hosts
│ └── group_vars/
│ └── all.yml
├── playbooks/ # Playbook 目录
│ ├── site.yml # 主 Playbook
│ ├── webservers.yml
│ ├── databases.yml
│ └── maintenance/
│ ├── backup.yml
│ └── update.yml
├── roles/ # 角色目录
│ ├── common/
│ ├── nginx/
│ ├── mysql/
│ └── app/
├── files/ # 静态文件
├── templates/ # 模板文件
├── vars/ # 全局变量
│ └── main.yml
├── library/ # 自定义模块
├── module_utils/ # 模块工具
├── filter_plugins/ # 过滤器插件
└── tests/ # 测试文件
├── inventory
└── test.yml
清晰的职责划分 #
text
┌─────────────────────────────────────────────────────────────┐
│ 目录职责划分 │
├─────────────────────────────────────────────────────────────┤
│ │
│ inventory/ 存放主机清单和环境变量 │
│ playbooks/ 存放 Playbook 文件 │
│ roles/ 存放可复用的角色 │
│ files/ 存放静态文件 │
│ templates/ 存放 Jinja2 模板 │
│ vars/ 存放全局变量 │
│ library/ 存放自定义模块 │
│ tests/ 存放测试文件 │
│ │
└─────────────────────────────────────────────────────────────┘
命名规范 #
文件命名 #
text
# Playbook 文件
site.yml # 主 Playbook
webservers.yml # 功能 Playbook
deploy-app.yml # 操作 Playbook
# 变量文件
all.yml # 全局变量
webservers.yml # 组变量
# 模板文件
nginx.conf.j2 # 配置模板
app.env.j2 # 环境变量模板
# 角色目录
roles/nginx/ # 小写,连字符分隔
roles/mysql-server/
变量命名 #
yaml
# 好的命名
app_name: myapp
nginx_port: 80
db_host: localhost
max_connections: 100
# 不好的命名
n: myapp
p: 80
h: localhost
mc: 100
# 布尔变量使用问号结尾或 is_ 前缀
ssl_enabled: true
is_production: false
# 列表变量使用复数
nginx_vhosts: []
allowed_hosts: []
任务命名 #
yaml
# 好的命名 - 描述行为和结果
- name: Install Nginx web server
apt:
name: nginx
state: present
- name: Ensure Nginx service is running
service:
name: nginx
state: started
# 不好的命名 - 太模糊
- name: Install
apt:
name: nginx
- name: Service
service:
name: nginx
代码组织 #
使用 Roles 组织代码 #
yaml
# 不推荐 - 所有任务在一个文件
- hosts: all
tasks:
- name: Install Nginx
...
- name: Configure Nginx
...
- name: Install MySQL
...
- name: Configure MySQL
...
# 推荐 - 使用 Roles
- hosts: webservers
roles:
- nginx
- hosts: databases
roles:
- mysql
模块化任务文件 #
yaml
# roles/nginx/tasks/main.yml
---
- name: Include install tasks
include_tasks: install.yml
tags: install
- name: Include configure tasks
include_tasks: configure.yml
tags: configure
- name: Include service tasks
include_tasks: service.yml
tags: service
使用标签 #
yaml
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
tags:
- install
- nginx
- name: Configure Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- configure
- nginx
# 执行特定标签
# ansible-playbook site.yml --tags "install"
# ansible-playbook site.yml --tags "configure"
变量管理 #
分离敏感数据 #
yaml
# inventory/group_vars/all.yml (非敏感)
---
app_name: myapp
app_port: 8080
db_host: localhost
db_port: 3306
# inventory/group_vars/vault/all.yml (加密)
---
db_password: "{{ vault_db_password }}"
api_key: "{{ vault_api_key }}"
使用默认值 #
yaml
# roles/nginx/defaults/main.yml
---
nginx_port: 80
nginx_user: www-data
nginx_worker_processes: auto
# 使用默认值
- name: Configure Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
vars:
nginx_port: "{{ nginx_port | default(80) }}"
变量优先级 #
text
优先级从低到高:
1. role defaults (roles/x/defaults/main.yml)
2. inventory group_vars (inventory/group_vars/*.yml)
3. inventory host_vars (inventory/host_vars/*.yml)
4. play vars (vars:)
5. play vars_files (vars_files:)
6. role vars (roles/x/vars/main.yml)
7. extra vars (-e)
幂等性 #
确保幂等性 #
yaml
# 不幂等 - 每次都会创建
- name: Add line to file
shell: echo "new line" >> /etc/hosts
# 幂等 - 使用 lineinfile
- name: Add line to file
lineinfile:
path: /etc/hosts
line: "192.168.1.100 webserver"
state: present
# 不幂等 - 每次都重启
- name: Restart service
service:
name: nginx
state: restarted
# 幂等 - 只在配置变更时重启
- name: Configure Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Reload Nginx
使用 changed_when #
yaml
- name: Run migration
command: /app/migrate.sh
register: migration_result
changed_when: "'Migration completed' in migration_result.stdout"
- name: Check if restart needed
command: /app/check_restart.sh
register: check_result
changed_when: false
failed_when: false
错误处理 #
合理的错误处理 #
yaml
tasks:
- name: Stop application
service:
name: app
state: stopped
ignore_errors: yes
- name: Update application
block:
- name: Pull latest code
git:
repo: "{{ app_repo }}"
dest: "{{ app_dir }}"
- name: Run migrations
command: "{{ app_dir }}/migrate.sh"
- name: Start application
service:
name: app
state: started
rescue:
- name: Rollback
command: "{{ app_dir }}/rollback.sh"
- name: Start application
service:
name: app
state: started
- name: Notify team
slack:
token: "{{ slack_token }}"
msg: "Deployment failed on {{ inventory_hostname }}"
always:
- name: Clean up
file:
path: /tmp/deploy_temp
state: absent
失败条件 #
yaml
- name: Run health check
command: /app/health_check.sh
register: health_result
failed_when: "'ERROR' in health_result.stderr or health_result.rc != 0"
changed_when: false
性能优化 #
禁用 Facts 收集 #
yaml
- hosts: all
gather_facts: no
tasks:
- name: Simple task
...
使用 Pipelining #
ini
# ansible.cfg
[ssh_connection]
pipelining = True
控制并发 #
yaml
- hosts: all
serial: 5 # 每次处理 5 台主机
tasks:
...
使用策略 #
yaml
- hosts: all
strategy: free # 自由策略,主机独立执行
tasks:
...
异步任务 #
yaml
- name: Long running task
command: /usr/bin/long_task.sh
async: 3600
poll: 0
register: long_task
- name: Check task status later
async_status:
jid: "{{ long_task.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 60
delay: 60
安全实践 #
不在代码中硬编码密码 #
yaml
# 不安全
- name: Create user
user:
name: deploy
password: "plain_password"
# 安全 - 使用 Vault
- name: Create user
user:
name: deploy
password: "{{ vault_deploy_password }}"
使用最小权限 #
yaml
- name: Start service
service:
name: nginx
state: started
become: yes
become_user: root
验证配置 #
yaml
- name: Deploy Nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
validate: nginx -t -c %s
notify: Reload Nginx
限制敏感信息输出 #
yaml
- name: Run command with password
command: mysql -u root -p{{ mysql_root_password }} -e "SHOW DATABASES"
no_log: true
文档化 #
README 文件 #
markdown
# Project Name
## Description
Brief description of what this project does.
## Requirements
- Ansible 2.9+
- Python 3.6+
## Installation
```bash
ansible-galaxy install -r requirements.yml
Usage #
bash
ansible-playbook -i inventory/production playbooks/site.yml
Variables #
| Variable | Default | Description |
|---|---|---|
| app_name | myapp | Application name |
| app_port | 8080 | Application port |
Author #
DevOps Team
text
### 角色文档
```yaml
# roles/nginx/README.md
# Ansible Role: Nginx
## Description
Installs and configures Nginx web server.
## Requirements
- Ubuntu 20.04/22.04
- Ansible 2.9+
## Role Variables
Available variables are listed below:
| Variable | Default | Description |
|----------|---------|-------------|
| nginx_port | 80 | Listen port |
| nginx_user | www-data | Nginx user |
## Dependencies
None
## Example Playbook
```yaml
- hosts: webservers
roles:
- role: nginx
nginx_port: 8080
License #
MIT
text
### 内联注释
```yaml
tasks:
- name: Configure Nginx worker processes
lineinfile:
path: /etc/nginx/nginx.conf
regexp: '^worker_processes'
line: "worker_processes {{ ansible_facts.processor_vcpus }};"
# Auto-configure based on CPU cores for optimal performance
# Reference: https://nginx.org/en/docs/ngx_core_module.html#worker_processes
测试 #
语法检查 #
bash
# 检查 Playbook 语法
ansible-playbook --syntax-check site.yml
# 检查 YAML 语法
yamllint site.yml
检查模式 #
bash
# 模拟执行
ansible-playbook --check site.yml
# 显示差异
ansible-playbook --check --diff site.yml
使用 Molecule 测试角色 #
bash
# 安装 Molecule
pip install molecule
# 初始化测试
molecule init scenario
# 运行测试
molecule test
CI/CD 集成 #
GitLab CI #
yaml
# .gitlab-ci.yml
stages:
- lint
- test
- deploy
lint:
stage: lint
script:
- ansible-lint playbooks/
- yamllint playbooks/ roles/
test:
stage: test
script:
- ansible-playbook --syntax-check playbooks/site.yml
- ansible-playbook --check playbooks/site.yml -i inventory/staging
deploy_staging:
stage: deploy
script:
- ansible-playbook playbooks/site.yml -i inventory/staging
environment: staging
only:
- develop
deploy_production:
stage: deploy
script:
- ansible-playbook playbooks/site.yml -i inventory/production
environment: production
only:
- main
when: manual
GitHub Actions #
yaml
# .github/workflows/ansible.yml
name: Ansible CI/CD
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run ansible-lint
uses: ansible/ansible-lint-action@main
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Syntax check
run: ansible-playbook --syntax-check playbooks/site.yml
deploy:
runs-on: ubuntu-latest
needs: [lint, test]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Deploy to production
run: ansible-playbook playbooks/site.yml -i inventory/production
env:
VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
总结 #
遵循这些最佳实践可以帮助你:
- 编写可维护、可读性强的代码
- 提高代码复用性
- 确保代码安全
- 提升执行效率
- 便于团队协作
下一步 #
现在你已经掌握了最佳实践,接下来学习 高级特性 了解 Ansible 的更多高级功能!
最后更新:2026-03-29