前言:为什么你需要 Ansible?
假设你有 10 台 VPS,每台都需要安装 Docker、配置 Nginx 反向代理、设置 SSL 证书、定期更新安全补丁。如果手动操作,你可能需要花费数小时甚至数天。
Ansible 让你只需编写一份配置文件,就能在所有 VPS 上执行相同的操作——这就是**基础设施即代码(Infrastructure as Code, IaC)**的核心理念。
手动运维 → 容易出错、耗时、不可复现
Ansible 运维 → 一键部署、版本可控、可审计
什么是 Ansible?
Ansible 是一款由 Red Hat 维护的开源自动化工具,具有以下特点:
- 无代理架构:无需在目标服务器上安装任何 Agent,通过 SSH 连接即可
- 声明式配置:你只需要描述"最终状态是什么",Ansible 会自动处理差异
- YAML 语法:人类可读的配置语言,学习曲线平缓
- 丰富的模块库:超过 3000 个内置模块,覆盖几乎所有运维场景
环境准备
控制节点要求
Ansible 运行在一台控制节点(Control Node)上,可以是你的本地电脑或任意一台 VPS:
| 组件 | 推荐配置 |
|---|---|
| 操作系统 | Ubuntu 22.04+ / Debian 12+ / CentOS Stream 9 |
| Python | Python 3.8+ |
| 内存 | 2GB+ |
| 磁盘 | 10GB+(存放 playbook 和 inventory) |
受控节点要求
被管理的 VPS 只需满足:
- Linux:Python 3 或 Python 2.7 + Jinja2
- Windows:WinRM + PowerShell(可选)
- 网络:控制节点能通过 SSH 访问所有受控节点
第一步:安装 Ansible
# Ubuntu/Debian
sudo apt update
sudo apt install -y python3-pip sshpass
pip3 install --user ansible
# CentOS/RHEL
sudo dnf install -y epel-release
sudo dnf install -y ansible sshpass
# 验证安装
ansible --version
第二步:配置 SSH 免密登录
这是 Ansible 高效运行的关键。在控制节点上生成 SSH 密钥并分发到所有受控节点:
# 1. 生成密钥对(如果没有的话)
ssh-keygen -t ed25519 -C "ansible@control-node" -N ""
# 2. 将公钥分发到所有 VPS
ssh-copy-id -o StrictHostKeyChecking=no user@vps1.example.com
ssh-copy-id -o StrictHostKeyChecking=no user@vps2.example.com
ssh-copy-id -o StrictHostKeyChecking.no user@vps3.example.com
# 3. 测试连接
ansible all -m ping
输出 SUCCESS 表示配置成功!
第三步:创建 Inventory 清单
Inventory 文件定义了哪些主机受 Ansible 管理,以及它们的分组方式:
# inventory.ini
[webservers]
vps1.example.com ansible_host=1.2.3.4
vps2.example.com ansible_host=5.6.7.8
[databases]
db1.example.com ansible_host=9.10.11.12
[monitoring]
mon1.example.com ansible_host=13.14.15.16
[all:vars]
ansible_user=deploy
ansible_python_interpreter=/usr/bin/python3
你可以按业务逻辑分组:
[production]
web-prod-1.example.com
web-prod-2.example.com
db-prod-1.example.com
[staging]
web-stg-1.example.com
db-stg-1.example.com
[production:children]
webservers
databases
第四步:编写第一个 Playbook
Playbook 是 Ansible 的核心——用 YAML 编写的自动化剧本。以下是一个完整的示例:
基础系统加固 Playbook
# playbook.yml
---
- name: 基础系统加固
hosts: all
become: true
vars:
timezone: Asia/Shanghai
ntp_servers:
- 0.cn.pool.ntp.org
- 1.cn.pool.ntp.org
firewall_allowed_ports:
- 22/tcp
- 80/tcp
- 443/tcp
tasks:
- name: 更新系统包
apt:
update_cache: yes
upgrade: dist
when: ansible_os_family == "Debian"
- name: 安装常用工具
apt:
name:
- curl
- wget
- htop
- jq
- vim
- git
- unzip
state: present
- name: 配置时区
timezone:
timezone: "{{ timezone }}"
- name: 配置 NTP 时间同步
systemd:
name: chrony
state: started
enabled: yes
when: ansible_os_family == "RedHat"
- name: 创建管理员用户
user:
name: admin
groups: sudo
shell: /bin/bash
state: present
- name: 配置 SSH 安全加固
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
loop:
- { regexp: "^#?PermitRootLogin", line: "PermitRootLogin no" }
- { regexp: "^#?PasswordAuthentication", line: "PasswordAuthentication no" }
- { regexp: "^#?Port ", line: "Port 22" }
notify: 重启 SSH
- name: 配置防火墙(UFW)
ufw:
rule: allow
port: "{{ item }}"
loop: "{{ firewall_allowed_ports }}"
handlers:
- name: 重启 SSH
service:
name: sshd
state: restarted
运行 Playbook
# 检查语法(dry-run)
ansible-playbook playbook.yml --check --diff
# 实际执行
ansible-playbook playbook.yml -i inventory.ini -v
# 指定特定组
ansible-playbook playbook.yml -i inventory.ini --limit webservers
第五步:Docker 容器化部署
大多数现代 VPS 都运行 Docker 容器。这个 Playbook 帮你自动化整个流程:
# docker-setup.yml
---
- name: 安装和配置 Docker
hosts: all
become: true
tasks:
- name: 安装 Docker 依赖
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
state: present
- name: 添加 Docker GPG 密钥
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: 添加 Docker 源
apt_repository:
repo: >-
deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]
https://download.docker.com/linux/ubuntu
{{ ansible_lsb.codename | lower }} stable
state: present
- name: 安装 Docker Engine
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
state: present
update_cache: yes
- name: 启动 Docker 服务
systemd:
name: docker
state: started
enabled: yes
- name: 配置 Docker 镜像加速
copy:
content: |
{
"registry-mirrors": ["https://mirror.ccs.tencentyun.com"]
}
dest: /etc/docker/daemon.json
notify: 重启 Docker
- name: 允许当前用户管理 Docker
user:
name: "{{ ansible_user }}"
groups: docker
append: yes
handlers:
- name: 重启 Docker
systemd:
name: docker
state: restarted
第六步:Nginx 反向代理模板
使用 Ansible 的模板功能,根据变量动态生成 Nginx 配置:
# templates/nginx-site.conf.j2
server {
listen 80;
server_name {{ domain }};
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://{{ domain }}$request_uri;
}
}
server {
listen 443 ssl http2;
server_name {{ domain }};
ssl_certificate /etc/letsencrypt/live/{{ domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
{% if enable_gzip %}
gzip on;
gzip_types text/plain application/json application/javascript text/css;
{% endif %}
location / {
proxy_pass http://{{ backend_service }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
对应的 Playbook 任务:
- name: 部署 Nginx 站点配置
template:
src: nginx-site.conf.j2
dest: /etc/nginx/sites-available/{{ domain }}
owner: root
group: root
mode: '0644'
notify: 重载 Nginx
- name: 启用站点
file:
src: /etc/nginx/sites-available/{{ domain }}
dest: /etc/nginx/sites-enabled/{{ domain }}
state: link
notify: 重载 Nginx
第七步:SSL 证书自动续期
Let’s Encrypt 证书有效期仅 90 天,Ansible 可以帮你自动化:
# certbot-setup.yml
---
- name: 安装和配置 Certbot
hosts: all
become: true
tasks:
- name: 安装 Certbot
apt:
name: certbot
state: present
- name: 申请 SSL 证书
community.general.certbot:
command: certificate_only
email: admin@{{ domain }}
domains:
- "{{ domain }}"
- "www.{{ domain }}"
challenge_hook: "systemctl reload nginx"
account_sid: my-account
csr: /etc/ssl/certs/{{ domain }}.csr
state: present
- name: 创建证书续期脚本
copy:
content: |
#!/bin/bash
certbot renew --quiet --post-hook "systemctl reload nginx"
logger "Certificate renewal completed"
dest: /usr/local/bin/renew-certs.sh
mode: '0755'
- name: 添加 Cron 定时任务(每天凌晨3点检查)
cron:
name: "自动续期SSL证书"
minute: "0"
hour: "3"
job: "/usr/local/bin/renew-certs.sh >> /var/log/certbot-renew.log 2>&1"
第八步:多环境管理
生产环境和开发环境使用不同的配置,Ansible 通过变量文件轻松管理:
project/
├── inventory/
│ ├── production.ini
│ ├── staging.ini
│ └── development.ini
├── group_vars/
│ ├── all.yml # 全局变量
│ ├── webservers.yml # Web 服务器变量
│ └── databases.yml # 数据库变量
├── host_vars/
│ ├── vps1.example.com.yml
│ └── db1.example.com.yml
├── roles/
│ ├── nginx/
│ ├── docker/
│ ├── certbot/
│ └── monitoring/
└── site.yml # 主 Playbook
变量优先级
# group_vars/all.yml
ntp_servers:
- 0.cn.pool.ntp.org
- 1.cn.pool.ntp.org
# host_vars/vps1.example.com.yml(覆盖全局)
ntp_servers:
- ntp1.mycompany.com
- ntp2.mycompany.com
第九步:监控与告警
在每台 VPS 上部署 Uptime Kuma 或 Prometheus Node Exporter:
# monitoring-setup.yml
---
- name: 部署监控代理
hosts: all
become: true
tasks:
- name: 部署 Node Exporter
docker_container:
name: node-exporter
image: prom/node-exporter:latest
restart_policy: always
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
- name: 部署 Uptime Kuma
docker_container:
name: uptime-kuma
image: louislam/uptime-kuma:1
restart_policy: always
ports:
- "3001:3001"
volumes:
- uptime-kuma-data:/app/data
第十步:CI/CD 集成
将 Ansible 集成到 GitHub Actions,每次代码变更自动部署:
# .github/workflows/deploy.yml
name: Deploy to VPS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 安装 Ansible
run: pip3 install ansible
- name: 配置 SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts
- name: 运行 Playbook
run: |
ansible-playbook site.yml \
-i inventory/production.ini \
-e "deploy_version=${{ github.sha }}" \
-v
最佳实践与避坑指南
✅ 应该做的
- 使用角色(Roles)组织代码:将每个功能封装为独立角色,便于复用
- 先 dry-run 再执行:始终使用
--check --diff预览变更 - 版本控制 Playbook:像管理代码一样管理基础设施
- 最小权限原则:SSH 用户使用 sudo 而非 root
- 使用 Ansible Vault 加密敏感信息:密码、API Key 等绝不明文存储
# 加密敏感变量
ansible-vault encrypt group_vars/secrets.yml
ansible-vault edit group_vars/secrets.yml # 编辑加密文件
# 运行时解密
ansible-playbook site.yml --ask-vault-pass
❌ 避免的
- 不要过度使用
raw模块:优先使用标准模块 - 不要在 Playbook 中硬编码 IP 地址:使用 Inventory 管理
- 不要忽略错误处理:使用
ignore_errors要谨慎 - 不要一次性修改太多主机:先在单台机器上测试
- 不要跳过文档:每个 Playbook 都应该有清晰的注释
成本对比:手动 vs Ansible
| 指标 | 手动运维 | Ansible 自动化 |
|---|---|---|
| 10 台 VPS 初始配置 | ~8 小时 | ~30 分钟 |
| 批量安全补丁更新 | ~4 小时 | ~5 分钟 |
| 新增服务器上线 | ~2 小时 | ~10 分钟 |
| 出错概率 | 高(人为失误) | 极低(一致执行) |
| 审计追踪 | 无 | 完整日志记录 |
| 月度节省时间 | - | 20+ 小时 |
进阶:Ansible AWX / Tower
当管理规模超过 50 台 VPS 时,可以考虑引入 AWX(Ansible 的企业版 Web UI):
# awx-deploy.yml
---
- name: 部署 AWX 管理面板
hosts: localhost
connection: local
tasks:
- name: 克隆 AWX 仓库
git:
repo: https://github.com/ansible/awx.git
dest: /opt/awx
version: latest
- name: 构建 AWX
shell: make deploy
args:
chdir: /opt/awx
AWX 提供:
- Web 图形界面管理所有 Playbook
- 可视化 Inventory 和主机分组
- 定时任务和调度器
- 用户权限管理
- 执行历史和日志审计
总结
Ansible 是你 VPS 运维的瑞士军刀——一次编写,处处执行。从单机加固到多机集群,从容器编排到证书管理,Ansible 都能胜任。
行动建议:
- 今天就在你的第一台 VPS 上安装 Ansible
- 将你最常重复的操作写成 Playbook
- 逐步将其他 VPS 纳入管理
- 使用 Vault 保护敏感信息
- 将 Playbook 推入 Git 版本控制
记住:最好的自动化,是从解决一个痛点开始的。 不要试图一次性自动化一切,从小处着手,逐步扩展。
喜欢这篇文章?关注 selfvps.net 获取更多自托管和 VPS 省钱技巧!
