Featured image of post Ansible VPS 自动化运维完全指南:从入门到批量管理百台服务器

Ansible VPS 自动化运维完全指南:从入门到批量管理百台服务器

Ansible 是无代理的 IT 自动化工具,通过 SSH 管理任意规模的服务器集群。本文从零开始,涵盖安装配置、Playbook 编写、角色复用、批量部署与故障排查,助你在 1 小时内完成百台 VPS 的统一配置。

为什么选择 Ansible?

在自托管和 VPS 运维领域,随着服务器数量增长,手动 SSH 登录每台机器执行命令的方式越来越不可持续。Ansible 提供了一个简洁而强大的解决方案——无需在被管理节点安装代理,只需通过 SSH 连接,就能批量执行配置、部署应用、管理资产。

与 Puppet、Chef、SaltStack 等竞争对手相比,Ansible 的核心优势在于:

  • 无代理架构:被管理节点只需 SSH 和 Python,无需额外守护进程
  • 声明式语法:Playbook 使用 YAML,可读性极强,新手友好
  • 幂等性保证:重复执行相同 Playbook 不会产生副作用
  • 丰富的模块生态:6000+ 内置模块覆盖几乎所有常见运维场景
  • 渐进式采用:从单台服务器开始,逐步扩展到集群规模

一、Ansible 快速入门

1.1 安装 Ansible

Ansible 支持所有主流 Linux 发行版、macOS 和 Windows(通过 WSL)。

# Ubuntu/Debian
sudo apt update
sudo apt install -y ansible

# CentOS/RHEL/Fedora
sudo dnf install -y ansible

# macOS (Homebrew)
brew install ansible

# 使用 pip 安装(推荐,版本最新)
pip install ansible-core

验证安装:

ansible --version

1.2 配置库存文件(Inventory)

库存文件定义了你需要管理的所有主机。创建 inventory.ini:

# 主机组划分
[webservers]
web1.example.com ansible_host=192.168.1.10
web2.example.com ansible_host=192.168.1.11
web3.example.com ansible_host=192.168.1.12

[dbservers]
db1.example.com ansible_host=192.168.1.20

[monitoring]
monitor1.example.com ansible_host=192.168.1.30

# 组变量:所有 web 服务器共享的配置
[webservers:vars]
http_port=80
nginx_version=1.24

# 全部主机组
[all:vars]
ansible_user=admin
ansible_ssh_private_key_file=~/.ssh/id_ed25519
ansible_python_interpreter=/usr/bin/python3

1.3 首次连通测试

# 测试所有主机连通性
ansible all -i inventory.ini -m ping

# 测试特定组
ansible webservers -i inventory.ini -m ping

# 查看组内主机列表
ansible webservers --list-hosts -i inventory.ini

预期输出:

web1.example.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
web2.example.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

二、Playbook 核心概念

Playbook 是 Ansible 的配置描述文件,使用 YAML 格式。一个典型的 Playbook 包含以下结构:

---
- name: 配置 Web 服务器
  hosts: webservers
  become: true          # 使用 sudo 执行
  gather_facts: true    # 收集目标主机事实

  vars:
    nginx_version: "1.24"
    app_port: 8080

  tasks:
    # 任务列表...

  handlers:
    # 处理器(由任务触发)...

2.1 常用模块速查

模块用途示例
apt / yum / dnf包管理apt: name=nginx state=present
service / systemd服务管理systemd: name=nginx state=restarted
copy复制文件copy: src=nginx.conf dest=/etc/nginx/
templateJinja2 模板template: src=app.conf.j2 dest=/etc/app/
git代码拉取git: repo=https://... dest=/opt/app
user用户管理user: name=deploy groups=sudo
file文件操作file: path=/data mode=0755 state=directory
lineinfile文件行编辑lineinfile: path=/etc/hosts line="10.0.0.1 db"
shell / command执行命令shell: docker ps --format json
debug调试输出debug: msg="变量值为 {{ my_var }}"

2.2 编写第一个 Playbook

创建一个基础系统加固 Playbook:

---
- name: VPS 基础安全加固
  hosts: all
  become: true
  vars:
    ntp_server: "pool.ntp.org"
    fail2ban_enabled: true

  tasks:
    - name: 更新系统软件包
      apt:
        update_cache: true
        upgrade: dist
      tags: ['update']

    - name: 安装必要工具
      apt:
        name:
          - curl
          - git
          - htop
          - fail2ban
          - ufw
        state: present
      tags: ['packages']

    - name: 配置防火墙规则
      ufw:
        rule: allow
        port: "{{ item }}"
        proto: tcp
      loop: [22, 80, 443]
      tags: ['firewall']

    - name: 禁用 root 远程登录
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: 重启 SSH 服务
      tags: ['ssh']

    - name: 启动并启用 fail2ban
      systemd:
        name: fail2ban
        state: started
        enabled: true
      tags: ['fail2ban']

  handlers:
    - name: 重启 SSH 服务
      systemd:
        name: sshd
        state: restarted

运行 Playbook:

ansible-playbook -i inventory.ini harden.yml --check --diff
ansible-playbook -i inventory.ini harden.yml

--check 模式(干跑)不会实际修改系统,--diff 显示具体变更内容。


三、进阶技巧与最佳实践

3.1 条件判断与循环

- name: 根据系统类型安装包
  package:
    name: "{{ item }}"
    state: present
  loop:
    - curl
    - git
  when: ansible_os_family == "Debian"

- name: 创建多个用户
  user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
    shell: /bin/bash
  loop: "{{ users_list }}"

3.2 Jinja2 模板

模板文件 templates/nginx.conf.j2:

server {
    listen {{ http_port }};
    server_name {{ inventory_hostname }};

    root {{ app_root }};
    index index.html;

    {% if ssl_enabled %}
    ssl_certificate /etc/ssl/certs/{{ domain }}.crt;
    ssl_certificate_key /etc/ssl/private/{{ domain }}.key;
    {% endif %}

    location / {
        proxy_pass http://127.0.0.1:{{ app_port }};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

在 Playbook 中引用:

- name: 部署 Nginx 配置
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/sites-available/default
    mode: '0644'
  notify: 重载 Nginx

3.3 角色(Roles)复用

角色是 Ansible 代码复用的核心机制。目录结构:

roles/
└── webserver/
    ├── tasks/
    │   ├── main.yml
    │   └── nginx.yml
    ├── handlers/
    │   └── main.yml
    ├── templates/
    │   └── nginx.conf.j2
    ├── vars/
    │   └── main.yml
    ├── defaults/
    │   └── main.yml
    └── meta/
        └── main.yml

roles/webserver/tasks/main.yml:

---
- name: 安装 Nginx
  import_tasks: nginx.yml

- name: 部署应用
  copy:
    src: app/
    dest: /var/www/app

在 Playbook 中使用角色:

---
- name: 部署 Web 服务
  hosts: webservers
  roles:
    - webserver
  vars:
    app_version: "2.1.0"

3.4 变量优先级

Ansible 变量按以下优先级从低到高:

  1. Role defaults(最低)
  2. Inventory 变量
  3. Play vars
  4. Host facts(gather_facts)
  5. Role vars
  6. Task vars
  7. Extra vars(-e 命令行参数,最高)

四、批量部署实战场景

4.1 一键部署 Docker Compose 服务

---
- name: 部署 Docker Compose 应用栈
  hosts: webservers
  become: true
  vars:
    compose_dir: /opt/apps/{{ app_name }}
    apps:
      - name: traefik
        stack: traefik
      - name: monitoring
        stack: monitoring

  tasks:
    - name: 确保 Docker 已安装
      ansible.builtin.package:
        name: docker.io
        state: present

    - name: 将用户加入 docker 组
      user:
        name: "{{ ansible_user }}"
        groups: docker
        append: true

    - name: 创建应用目录
      file:
        path: "{{ compose_dir }}"
        state: directory
        mode: '0755'

    - name: 部署 docker-compose 文件
      template:
        src: "{{ item.stack }}.yml.j2"
        dest: "{{ compose_dir }}/docker-compose.yml"
      loop: "{{ apps }}"

    - name: 启动服务
      community.docker.docker_compose_v2:
        project_src: "{{ compose_dir }}"
        state: present
        pull: always

4.2 批量系统升级与 reboot 控制

---
- name: 批量系统升级并安全重启
  hosts: all
  serial: 3          # 每次只处理 3 台主机
  gather_facts: false

  tasks:
    - name: 升级系统包
      apt:
        upgrade: dist
        update_cache: true
      when: ansible_distribution == "Ubuntu"

    - name: 检查是否需要重启
      command: needs-restarting -r
      register: needs_reboot
      changed_when: false
      failed_when: false

    - name: 重启需要重启的主机
      reboot:
        reboot_timeout: 300
      when: needs_reboot.rc == 1

serial: 3 确保每次只升级 3 台服务器,避免全部宕机导致服务中断。

4.3 配置 drift 检测与修复

---
- name: 检测并修复配置漂移
  hosts: all
  become: true

  tasks:
    - 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: '^X11Forwarding', line: 'X11Forwarding no' }

    - name: 确保关键文件权限正确
      file:
        path: "{{ item.path }}"
        mode: "{{ item.mode }}"
      loop:
        - { path: /etc/ssh/sshd_config, mode: '0600' }
        - { path: /etc/ssh/ssh_known_hosts, mode: '0644' }
        - { path: /etc/crontab, mode: '0600' }

五、性能优化与大规模部署

5.1 连接优化

# ansible.cfg
[defaults]
forks = 50              # 并行 50 个任务
timeout = 30
retry_files_enabled = false
inventory = ./inventory.ini

[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
pipelining = true       # SSH 管道化,大幅提升性能

5.2 分片执行

对于超大集群,使用 --limit 和 --tags 分片:

# 只执行特定标签的任务
ansible-playbook deploy.yml --tags 'nginx,ssl'

# 限制到特定主机
ansible-playbook deploy.yml --limit 'web[1:5]'

# 跳过特定标签
ansible-playbook deploy.yml --skip-tags 'database'

5.3 Ansible Vault 加密敏感信息

# 创建加密变量文件
ansible-vault create group_vars/all/secrets.yml

# 编辑现有加密文件
ansible-vault edit group_vars/all/secrets.yml

# 运行时解密
ansible-playbook deploy.yml --ask-vault-pass

加密文件示例:

# group_vars/all/secrets.yml(加密存储)
db_password: "s3cur3P@ssw0rd"
api_key: "ak_live_xxxxxxxx"
ssl_cert_key: "{{ vault_ssl_key }}"

六、常见故障排查

6.1 连接失败

# 详细调试输出
ansible all -m ping -vvv

# 测试 SSH 连接
ansible all -m debug -a "msg='SSH test'" -vvv

# 检查 Python 路径
ansible all -m setup -a "filter=ansible_python*"

常见问题及解决:

症状原因解决方案
SSH: hostname could not be resolvedDNS 问题检查 /etc/hosts 或使用 ansible_host
Permission denied (publickey)SSH 密钥问题确认 ansible_ssh_private_key_file 路径正确
Python not found缺少 Python指定 ansible_python_interpreter 路径
MODULE FAILURE模块依赖缺失在被管理节点安装对应依赖

6.2 幂等性问题

# ❌ 非幂等操作:每次执行都会追加
- shell: echo "new_line" >> /etc/config

# ✅ 幂等操作:使用 lineinfile
- lineinfile:
    path: /etc/config
    line: "new_line"
    state: present

七、总结

Ansible 是自托管 VPS 运维中不可或缺的自动化工具。通过本文,你学到了:

  • 基础:安装、库存配置、连通测试
  • 核心:Playbook 编写、模块使用、条件循环
  • 进阶:角色复用、模板引擎、变量管理
  • 实战:批量部署、升级控制、配置漂移修复
  • 优化:连接调优、分片执行、Vault 加密
  • 排错:常见问题诊断与解决方案

从单台 VPS 到百台集群,Ansible 都能提供一致、可重复、可审计的配置管理体验。记住关键原则:声明式优于命令式,幂等性至关重要,角色化促进复用。

立即开始吧——在你的第一台 VPS 上运行 ansible all -m ping,自动化之旅就此开启。

📺 看视频版教程 → DuckDB Lab YouTube

Subscribe for more DuckDB & AI automation tutorials