23-Ansible
Ansible 是开源的配置管理和批量运维自动化工具。与 Terraform 管理云资源不同,Ansible 专注于操作系统层面的配置——装软件、改配置、启服务。本章覆盖 Ansible 的核心概念、Playbook/Role 工程化、动态 Inventory、Vault 加密,以及与 Terraform 的定位区别。
核心优势#
- 无 Agent:不需要在目标机器上安装客户端,只要 SSH 通就能管。接手已有机器时不用先装 Agent。
- SSH 推送:控制机推送任务到目标机执行,权限边界清晰。相比 Puppet/Chef 的 pull 模式,push 模式在紧急场景响应更快。
- 幂等性:大多数模块设计为幂等,执行一次和执行十次效果相同。
package模块检查软件包是否已安装,file模块检查文件是否已存在。 - YAML 描述:声明式描述目标状态,直观且易 Code Review。
Inventory 管理#
Inventory 定义了 Ansible 要管理的主机列表及分组。
静态 Inventory#
# inventory/hosts
[web]
web-01.example.com
web-02.example.com ansible_port=2222
[db]
db-01.example.com ansible_user=ubuntu ansible_become=true
[production:children]
web
db
[web:vars]
nginx_worker_processes=4
app_env=production动态 Inventory(AWS EC2)#
机器在云上动态扩缩,不可能手动维护 Inventory。Ansible 提供 aws_ec2 插件:
# inventory/aws_ec2.yml
plugin: aws_ec2
regions:
- us-west-2
filters:
instance-state-name: running
tag:Environment: production
keyed_groups:
- key: tags.Role # 按 Tag:Role 自动分组
prefix: role
- key: instance_type # 按实例类型分组
prefix: type
hostnames:
- private-ip-address # 内网 IP 作为主机名ansible-inventory -i inventory/aws_ec2.yml --list
ansible-inventory -i inventory/aws_ec2.yml --graph变量组织#
inventory/
├── hosts.yml
├── group_vars/
│ ├── all.yml # 所有主机共用
│ ├── web.yml # web 组变量
│ └── production.yml
└── host_vars/
└── db-01.example.com.yml # 单台主机变量变量优先级:host_vars > group_vars/<specific-group> > group_vars/all。
常用模块速查#
# copy:上传文件
- name: Upload config file
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
mode: '0644'
backup: yes
# template:渲染 Jinja2 模板后上传
- name: Render and upload template
template:
src: templates/app.conf.j2
dest: /etc/app/app.conf
# file:创建目录/设置权限
- name: Create log directory
file:
path: /var/log/myapp
state: directory
owner: www-data
mode: '0755'
# yum/apt:包管理
- name: Install packages
apt:
name: "{{ packages }}"
state: present
update_cache: yes
vars:
packages: [curl, jq, net-tools]
# service:服务管理
- name: Ensure nginx is running and enabled
service:
name: nginx
state: started
enabled: yes
# command/shell:执行命令
- name: Check disk usage
command: df -h /data
register: disk_info
changed_when: false # 查询操作不算 changedPlaybook 结构#
一个完整的 Playbook 示例——部署 Node Exporter:
- name: Deploy Prometheus Node Exporter
hosts: all
become: true
vars:
node_exporter_version: "1.7.0"
install_dir: "/opt/node_exporter"
pre_tasks:
- name: Check if node_exporter is already installed
stat:
path: "{{ install_dir }}/node_exporter"
register: binary_stat
tasks:
- name: Create node_exporter user
user:
name: node_exporter
system: yes
shell: /usr/sbin/nologin
- name: Download node_exporter
get_url:
url: "https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz"
dest: "/tmp/node_exporter.tar.gz"
when: not binary_stat.stat.exists
- name: Create systemd service
template:
src: templates/node_exporter.service.j2
dest: /etc/systemd/system/node_exporter.service
notify:
- Reload systemd
- Restart node_exporter
- name: Ensure node_exporter is running
service:
name: node_exporter
state: started
enabled: yes
handlers:
- name: Reload systemd
systemd:
daemon_reload: yes
- name: Restart node_exporter
service:
name: node_exporter
state: restarted执行:
# 语法检查
ansible-playbook playbooks/deploy-node-exporter.yml --syntax-check
# dry run(不实际执行,只显示会做什么)
ansible-playbook playbooks/deploy-node-exporter.yml --check --diff
# 只在特定主机组执行
ansible-playbook playbooks/deploy-node-exporter.yml -l web
# 只执行特定 tags
ansible-playbook playbooks/deploy-node-exporter.yml --tags "install,config"Role 工程化#
当多个 Playbook 有重复逻辑时,抽成 Role。Role 是标准化的目录结构,可跨 Playbook 复用:
roles/
└── node_exporter/
├── defaults/
│ └── main.yml # 默认变量(优先级最低,可被覆盖)
├── vars/
│ └── main.yml # 内部变量(优先级较高,不对外暴露)
├── tasks/
│ ├── main.yml # 任务入口
│ ├── install.yml
│ └── configure.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── node_exporter.service.j2
└── meta/
└── main.yml # 依赖声明# 在 Playbook 中使用 Role
- name: Setup monitoring
hosts: all
become: true
roles:
- role: node_exporter
vars:
node_exporter_version: "1.8.0"
- role: filebeat
when: ansible_os_family == "Debian"经验法则:可配置的参数放 defaults/,不对外的内部常量才放 vars/。vars/ 优先级比 group_vars 还高,放错了会导致外部传入的覆盖不生效。
Jinja2 模板#
# templates/node_exporter.service.j2
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
User={{ node_exporter_user }}
Type=simple
ExecStart={{ install_dir }}/node_exporter \
--web.listen-address=:{{ listen_port }}
Restart=on-failure
[Install]
WantedBy=multi-user.targetAnsible Vault:加密敏感变量#
数据库密码、API Token 不应该明文存在代码仓库:
# 创建加密的变量文件
ansible-vault create group_vars/production/vault.yml
# 编辑加密文件
ansible-vault edit group_vars/production/vault.yml
# 加密已有明文文件
ansible-vault encrypt group_vars/production/secrets.yml
# 执行时提供密码
ansible-playbook site.yml --ask-vault-pass
# 从文件读取密码(CI/CD 场景)
ansible-playbook site.yml --vault-password-file ~/.vault_pass幂等性陷阱#
command 和 shell 模块本身不知道命令是否改变了什么,默认每次报 changed。需要显式告诉 Ansible 什么情况算 changed:
# 查询操作,永远不算 changed
- name: Get current timezone
command: timedatectl show --property=Timezone
register: tz_result
changed_when: false
# 配合 creates 参数实现幂等(文件存在时跳过)
- name: Initialize once
command: /opt/scripts/one_time_setup.sh
args:
creates: /opt/.setup_donevs Terraform#
| 维度 | Ansible | Terraform |
|---|---|---|
| 管理对象 | 操作系统配置(装软件、改配置) | 云基础设施(VPC、ECS、RDS) |
| 状态管理 | 无 state(每次执行检查当前状态) | 有 state(记录资源 ID 和依赖) |
| 幂等机制 | 模块内置检查 | 声明式 + state diff |
| 执行模式 | SSH push | API 调用 |
| 适用场景 | 机器初始化、配置同步、批量运维 | 云资源创建/变更/销毁 |
协作模式:Terraform 创建云资源(ECS 实例、安全组),Ansible 配置机器(装 Docker、部署应用、改内核参数)。两者互补不冲突。
性能优化#
大批量执行时默认并发数只有 5,200 台机器要跑 40 批。优化 ansible.cfg:
[defaults]
forks = 50 # 并发数调大
host_key_checking = False
[ssh_connection]
pipelining = True # 减少 SSH 连接次数,显著提速
control_path_dir = /tmp/ansible-ssh
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ConnectTimeout=10pipelining = True 能提升 2-3 倍性能,但需要目标机器 sudoers 没有 requiretty。
小结#
Ansible 的无 Agent + SSH push + 幂等模块模型让它成为机器级配置管理的首选。Inventory 管理是基础——静态 Inventory 适合固定机器,动态 Inventory(aws_ec2 插件)适合云上动态扩缩。Playbook 是任务编排,Role 是复用单元——可配置参数放 defaults/,内部常量放 vars/。Vault 加密敏感变量,命令模块要显式设 changed_when 保证幂等。与 Terraform 互补——Terraform 管云资源,Ansible 管机器配置。