Ansible 自动化 VPS 管理

当您管理多台 VPS 服务器时,逐一通过 SSH 登录既无法扩展,也难以重复操作。Ansible 是一款配置管理工具,让您只需编写一次"配方",即可通过 SSH 在所有服务器上同时执行——无需在目标机器上安装任何代理程序。

什么是 Ansible,为什么要使用它?

Ansible 是 Red Hat 旗下的开源 IT 自动化工具。它使用 YAML 编写 Ansible Playbook(剧本)——这是一种声明式文件,用于描述系统应处于的状态(例如:必须安装 Nginx、某个配置文件必须存在、某个用户必须已创建)。Ansible 以幂等方式使系统达到所声明的状态——多次运行同一 Playbook(剧本)始终产生相同结果。

前提条件

在控制节点上安装 Ansible

Ubuntu / Debian

sudo apt update
sudo apt install -y ansible

macOS(Homebrew)

brew install ansible

Python pip(任意操作系统)

pip3 install ansible

验证安装结果:

ansible --version
# ansible [core 2.17.x]

创建清单文件

清单文件告诉 Ansible 有哪些服务器以及如何连接它们。

inventory.ini(基本格式)

[webservers]
web1 ansible_host=203.0.113.10 ansible_user=root
web2 ansible_host=203.0.113.11 ansible_user=root

[databases]
db1 ansible_host=203.0.113.20 ansible_user=root

[all:vars]
ansible_ssh_private_key_file=~/.ssh/id_ed25519

测试连通性

ansible -i inventory.ini all -m ping

每台主机返回 pong 响应,即确认连接正常。

编写第一个 Playbook(剧本)— 安装 Nginx

创建 setup-nginx.yml:

---
- name: Install and enable Nginx
  hosts: webservers
  become: yes

  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Install Nginx
      apt:
        name: nginx
        state: present

    - name: Start Nginx and enable on boot
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Allow port 80 in UFW
      ufw:
        rule: allow
        port: '80'
        proto: tcp

运行 Playbook(剧本):

ansible-playbook -i inventory.ini setup-nginx.yml

幂等性实践:运行此 Playbook(剧本)10 次,Nginx 也只会安装一次。Ansible 首先检查实际状态——如果软件包已存在,任务显示"ok"而非"changed",不会执行任何操作。

变量——让 Playbook(剧本)更灵活

---
- name: Install Web Stack
  hosts: webservers
  become: yes
  vars:
    php_version: "8.3"
    app_user: "www-data"

  tasks:
    - name: Install PHP {{ php_version }}
      apt:
        name: "php{{ php_version }}-fpm"
        state: present

将变量分离到文件中

# vars/main.yml
php_version: "8.3"
mysql_root_password: "SecurePass123"
app_domain: "example.com"
# In playbook
  vars_files:
    - vars/main.yml

处理程序(Handlers)— 仅在发生变更时执行任务

处理程序是一种特殊任务,只有在被其他任务"通知"时才会运行——非常适合在配置变更后重启服务。

  tasks:
    - name: Copy Nginx config
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: Restart Nginx

  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

若配置未发生变更,Nginx 将不会重启——从而减少不必要的停机时间。

角色(Roles)— 组织大型 Playbook(剧本)

ansible-galaxy init roles/nginx
# Creates structure:
# roles/nginx/
#   tasks/main.yml
#   handlers/main.yml
#   templates/
#   vars/main.yml
#   defaults/main.yml

新 VPS 安全加固 Playbook(剧本)

---
- name: Setup new VPS
  hosts: new_servers
  become: yes

  tasks:
    - name: Full system upgrade
      apt:
        upgrade: dist
        update_cache: yes

    - name: Install essential packages
      apt:
        name:
          - ufw
          - fail2ban
          - unattended-upgrades
          - curl
          - git
        state: present

    - name: Create deploy user
      user:
        name: deploy
        shell: /bin/bash
        groups: sudo
        append: yes

    - name: Add SSH public key
      authorized_key:
        user: deploy
        key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"

    - name: Disable root SSH login
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: Restart SSH

    - name: Enable UFW
      ufw:
        state: enabled
        policy: deny

    - name: Allow SSH port
      ufw:
        rule: allow
        port: '22'
        proto: tcp

  handlers:
    - name: Restart SSH
      service:
        name: ssh
        state: restarted

即席命令(Ad-hoc Commands)

# Check disk usage on all servers
ansible -i inventory.ini all -m shell -a "df -h /"

# Restart Nginx on webservers
ansible -i inventory.ini webservers -m service -a "name=nginx state=restarted" --become

# Copy a file to all servers
ansible -i inventory.ini all -m copy -a "src=app.conf dest=/etc/app.conf"

Ansible Galaxy:社区维护的角色可在 galaxy.ansible.com 获取。使用 ansible-galaxy install geerlingguy.mysql 安装后,可直接在 Playbook(剧本)中使用。

实用技巧

Ansible Vault — 安全加密密钥

当 Playbook(剧本)中包含密码、API 密钥或其他凭证时,请在提交版本控制前使用 Ansible Vault 对文件进行加密。这样既能将密钥排除在代码仓库之外,又能让 Ansible 在运行时正常访问。

创建并加密变量文件

# Create an encrypted secrets file
ansible-vault create vars/secrets.yml

# Edit an already-encrypted file
ansible-vault edit vars/secrets.yml

# Encrypt an existing plain-text file
ansible-vault encrypt vars/secrets.yml

# Temporarily decrypt to inspect content
ansible-vault decrypt vars/secrets.yml

在 Playbook(剧本)中引用加密文件

  vars_files:
    - vars/main.yml
    - vars/secrets.yml   # 加密文件 — Ansible 在运行时自动解密
# 以交互方式输入 Vault 密码运行
ansible-playbook -i inventory.ini deploy.yml --ask-vault-pass

# 使用密码文件运行(适合 CI/CD 流水线)
ansible-playbook -i inventory.ini deploy.yml --vault-password-file ~/.vault_pass

最佳实践:将加密后的 vars/secrets.yml 提交到 Git——加密使其可以安全存储在版本控制中。切勿将未加密的 secrets.yml 加入 .gitignore,否则日后可能意外提交明文版本。

Ansible 在 CI/CD 流水线中的应用

将 Ansible 与 CI/CD 工具集成后,每次推送代码时,即可自动部署到所有 VPS 服务器——无需任何手动操作。

GitHub Actions 工作流示例

# .github/workflows/deploy.yml
name: Deploy with Ansible
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Ansible
        run: pip3 install ansible

      - name: Write SSH Key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519

      - name: Run Ansible Playbook
        run: |
          ansible-playbook -i inventory.ini deploy.yml \
            --vault-password-file <(echo "${{ secrets.VAULT_PASS }}")

配置此工作流后,每次合并到 main 分支都会自动触发对清单中所有服务器的部署——无需手动 SSH 操作。

CI/CD 工具 Ansible 集成方式 复杂度
GitHub Actions在运行器中执行 pip install ansible低
GitLab CI使用预装 Ansible 的 Docker镜像低
JenkinsAnsible 插件或 shell 步骤中
AWX / Ansible Tower内置集成——专为此场景设计高(企业级)

常见问题排查

以下是初次使用 Ansible 时最常遇到的问题及其解决方案。

SSH 连接被拒绝

# Debug with maximum verbosity to see exact SSH commands
ansible -i inventory.ini all -m ping -vvv

# Add host fingerprint to known_hosts before first run
ssh-keyscan -H 203.0.113.10 >> ~/.ssh/known_hosts

执行任务时权限被拒绝

# 需要 root 权限的任务必须包含 become: yes
- name: Install package
  apt:
    name: nginx
    state: present
  become: yes   # 特权操作必须

# 或在 play 层面为所有任务设置 become
- hosts: webservers
  become: yes

被管理节点未检测到 Python

# 在清单中明确指定 Python 解释器路径
web1 ansible_host=203.0.113.10 ansible_python_interpreter=/usr/bin/python3

# 或在组变量中全局设置
[all:vars]
ansible_python_interpreter=/usr/bin/python3

调试技巧:在任何 Ansible 命令后添加 -v、-vv 或 -vvv 可提升日志详细程度。在 -vvv 级别,您能看到 Ansible 实际执行的 SSH 命令——对诊断连接问题非常有价值。

Ansible 与其他配置管理工具的对比

配置管理领域有多款工具相互竞争。了解各自的权衡取舍,有助于根据基础设施规模和团队技能选择合适的工具。

工具 是否需要代理 配置语言 适用场景
Ansible否(无代理)YAML任意规模,入门简单
Puppet是DSL大型企业服务器集群
Chef是Ruby DSL熟悉 Ruby 的团队
Terraform否HCL云基础设施资源供给

当您优先考虑简洁性、零代理开销和可读的 YAML 配置时,Ansible 是管理 VPS 服务器的最实用选择。它通过您已在使用的 SSH 连接进行操作,让任何规模的团队都能逐步采用,风险极低。

需要一台运行 Ansible 的 VPS 吗?

AsiaGB 提供具有完整 Root 权限的 Linux VPS(Ubuntu/Debian),起价 500 泰铢/月。

查看 VPS 方案

查看泰国VPS主机全部套餐 →