ClawSkills logoClawSkills

Ansible

使用 Ansible 进行基础设施自动化。用于服务器配置、配置管理、应用部署和多主机编排。包括

介绍

# Ansible Skill

用于服务器置备、配置管理和编排的基础设施即代码(IaC)自动化。

## 快速开始

### 前置条件

```bash # Install Ansible pip install ansible

# Or on macOS brew install ansible

# Verify ansible --version ```

### 运行你的第一个 Playbook

```bash # Test connection ansible all -i inventory/hosts.yml -m ping

# Run playbook ansible-playbook -i inventory/hosts.yml playbooks/site.yml

# Dry run (check mode) ansible-playbook -i inventory/hosts.yml playbooks/site.yml --check

# With specific tags ansible-playbook -i inventory/hosts.yml playbooks/site.yml --tags "security,nodejs" ```

## 目录结构

``` skills/ansible/ ├── SKILL.md # This file ├── inventory/ # Host inventories │ ├── hosts.yml # Main inventory │ └── group_vars/ # Group variables ├── playbooks/ # Runnable playbooks │ ├── site.yml # Master playbook │ ├── openclaw-vps.yml # OpenClaw VPS setup │ └── security.yml # Security hardening ├── roles/ # Reusable roles │ ├── common/ # Base system setup │ ├── security/ # Hardening (SSH, fail2ban, UFW) │ ├── nodejs/ # Node.js installation │ └── openclaw/ # OpenClaw installation └── references/ # Documentation ├── best-practices.md ├── modules-cheatsheet.md └── troubleshooting.md ```

## 核心概念

### Inventory(清单)

在 `inventory/hosts.yml` 中定义主机:

```yaml all: children: vps: hosts: eva: ansible_host: 217.13.104.208 ansible_user: root ansible_ssh_pass: "{{ vault_eva_password }}" plane: ansible_host: 217.13.104.99 ansible_user: asdbot ansible_ssh_private_key_file: ~/.ssh/id_ed25519_plane openclaw: hosts: eva: ```

### Playbooks(剧本)

自动化的入口点:

```yaml # playbooks/site.yml - Master playbook --- - name: Configure all servers hosts: all become: yes roles: - common - security

- name: Setup OpenClaw servers hosts: openclaw become: yes roles: - nodejs - openclaw ```

### Roles(角色)

可重用的模块化配置:

```yaml # roles/common/tasks/main.yml --- - name: Update apt cache ansible.builtin.apt: update_cache: yes cache_valid_time: 3600 when: ansible_os_family == "Debian"

- name: Install essential packages ansible.builtin.apt: name: - curl - wget - git - htop - vim - unzip state: present ```

## 包含的角色

### 1. common 基础系统配置: - 系统更新 - 基础软件包 - 时区配置 - 使用 SSH 密钥创建用户

### 2. security 遵循 CIS 基准的安全加固: - SSH 加固(仅限密钥,禁用 root) - fail2ban 暴力破解防护 - UFW 防火墙配置 - 自动安全更新

### 3. nodejs 通过 NodeSource 安装 Node.js: - 可配置版本(默认:22.x LTS) - npm 全局包 - pm2 进程管理器(可选)

### 4. openclaw 完整的 OpenClaw 设置: - Node.js(通过 nodejs 角色) - OpenClaw npm 安装 - Systemd 服务 - 配置文件设置

## 使用模式

### 模式 1:新 VPS 设置(OpenClaw)

```bash # 1. Add host to inventory cat >> inventory/hosts.yml << 'EOF' newserver: ansible_host: 1.2.3.4 ansible_user: root ansible_ssh_pass: "initial_password" deploy_user: asdbot deploy_ssh_pubkey: "ssh-ed25519 AAAA... asdbot" EOF

# 2. Run OpenClaw playbook ansible-playbook -i inventory/hosts.yml playbooks/openclaw-vps.yml \ --limit newserver \ --ask-vault-pass

# 3. After initial setup, update inventory to use key auth # ansible_user: asdbot # ansible_ssh_private_key_file: ~/.ssh/id_ed25519 ```

### 模式 2:仅安全加固

```bash ansible-playbook -i inventory/hosts.yml playbooks/security.yml \ --limit production \ --tags "ssh,firewall" ```

### 模式 3:滚动更新

```bash # Update one server at a time ansible-playbook -i inventory/hosts.yml playbooks/update.yml \ --serial 1 ```

### 模式 4:临时命令(Ad-hoc Commands)

```bash # Check disk space on all servers ansible all -i inventory/hosts.yml -m shell -a "df -h"

# Restart service ansible openclaw -i inventory/hosts.yml -m systemd -a "name=openclaw state=restarted"

# Copy file ansible all -i inventory/hosts.yml -m copy -a "src=./file.txt dest=/tmp/" ```

## 变量与密钥

### 组变量

```yaml # inventory/group_vars/all.yml --- timezone: Europe/Budapest deploy_user: asdbot ssh_port: 22

# Security security_ssh_password_auth: false security_ssh_permit_root: false security_fail2ban_enabled: true security_ufw_enabled: true security_ufw_allowed_ports: - 22 - 80 - 443

# Node.js nodejs_version: "22.x" ```

### Vault 用于密钥

```bash # Create encrypted vars file ansible-vault create inventory/group_vars/all/vault.yml

# Edit encrypted file ansible-vault edit inventory/group_vars/all/vault.yml

# Run with vault ansible-playbook site.yml --ask-vault-pass

# Or use vault password file ansible-playbook site.yml --vault-password-file ~/.vault_pass ```

Vault 文件结构: ```yaml # inventory/group_vars/all/vault.yml --- vault_eva_password: "y8UGHR1qH" vault_deploy_ssh_key: | -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY----- ```

## 常用模块

| 模块 | 用途 | 示例 | |--------|---------|---------| | `apt` | 包管理 | `apt: name=nginx state=present` | | `yum` | 包管理 | `yum: name=nginx state=present` | | `copy` | 复制文件 | `copy: src=file dest=/path/` | | `template` | 模板文件 | `template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf` | | `file` | 文件/目录管理 | `file: path=/dir state=directory mode=0755` | | `user` | 用户管理 | `user: name=asdbot groups=sudo shell=/bin/bash` | | `authorized_key` | SSH 密钥 | `authorized_key: user=asdbot key="{{ ssh_key }}"` | | `systemd` | 服务管理 | `systemd: name=nginx state=started enabled=yes` | | `ufw` | 防火墙 | `ufw: rule=allow port=22 proto=tcp` | | `lineinfile` | 编辑单行 | `lineinfile: path=/etc/ssh/sshd_config regexp='^PermitRootLogin' line='PermitRootLogin no'` | | `git` | 克隆仓库 | `git: repo=https://github.com/x/y.git dest=/opt/y` | | `npm` | npm 包 | `npm: name=openclaw global=yes` | | `command` | 运行命令 | `command: /opt/script.sh` | | `shell` | 运行 Shell 命令 | `shell: cat /etc/passwd \| grep root` |

## 最佳实践

### 1. 始终命名任务 ```yaml # Good - name: Install nginx web server apt: name: nginx state: present

# Bad - apt: name=nginx ```

### 2. 使用 FQCN(完全限定集合名称) ```yaml # Good - ansible.builtin.apt: name: nginx

# Acceptable but less clear - apt: name: nginx ```

### 3. 明确状态 ```yaml # Good - explicit state - ansible.builtin.apt: name: nginx state: present

# Bad - implicit state - ansible.builtin.apt: name: nginx ```

### 4. 幂等性 编写可以安全运行多次的任务: ```yaml # Good - idempotent - name: Ensure config line exists ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^PasswordAuthentication' line: 'PasswordAuthentication no'

# Bad - not idempotent - name: Add config line ansible.builtin.shell: echo "PasswordAuthentication no" >> /etc/ssh/sshd_config ```

### 5. 使用 Handlers 进行重启 ```yaml # tasks/main.yml - name: Update SSH config ansible.builtin.template: src: sshd_config.j2 dest: /etc/ssh/sshd_config notify: Restart SSH

# handlers/main.yml - name: Restart SSH ansible.builtin.systemd: name: sshd state: restarted ```

### 6. 使用 Tags 进行选择性运行 ```yaml - name: Security tasks ansible.builtin.include_tasks: security.yml tags: [security, hardening]

- name: App deployment ansible.builtin.include_tasks: deploy.yml tags: [deploy, app] ```

## 故障排除

### 连接问题

```bash # Test SSH connection manually ssh -v user@host

# Debug Ansible connection ansible host -i inventory -m ping -vvv

# Check inventory parsing ansible-inventory -i inventory --list ```

### 常见错误

**“Permission denied(权限被拒绝)”** - 检查 SSH 密钥权限:`chmod 600 ~/.ssh/id_*` - 验证用户是否具有 sudo 访问权限 - 在 playbook 中添加 `become: yes`

**“Host key verification failed(主机密钥验证失败)”** - 添加到 ansible.cfg:`host_key_checking = False` - 或添加主机密钥:`ssh-keyscan -H host >> ~/.ssh/known_hosts`

**“Module not found(未找到模块)”** - 使用 FQCN:例如使用 `ansible.builtin.apt` 代替 `apt` - 安装集合:`ansible-galaxy collection install community.general`

### 调试 Playbooks

```bash # Verbose output ansible-playbook site.yml -v # Basic ansible-playbook site.yml -vv # More ansible-playbook site.yml -vvv # Maximum

# Step through tasks ansible-playbook site.yml --step

# Start at specific task ansible-playbook site.yml --start-at-task="Install nginx"

# Check mode (dry run) ansible-playbook site.yml --check --diff ```

## 与 OpenClaw 集成

### 从 OpenClaw Agent

```bash # Run playbook via exec tool exec command="ansible-playbook -i skills/ansible/inventory/hosts.yml skills/ansible/playbooks/openclaw-vps.yml --limit eva"

# Ad-hoc command exec command="ansible eva -i skills/ansible/inventory/hosts.yml -m shell -a 'systemctl status openclaw'" ```

### 存储凭据

使用 OpenClaw 的 Vaultwarden 集成: ```bash # Get password from vault cache PASSWORD=$(.secrets/get-secret.sh "VPS - Eva")

# Use in ansible (not recommended - use ansible-vault instead) ansible-playbook site.yml -e "ansible_ssh_pass=$PASSWORD" ```

更好的做法:存储在 Ansible Vault 中并使用 `--ask-vault-pass`。

## 参考资料

- `references/best-practices.md` - 详细的最佳实践指南 - `references/modules-cheatsheet.md` - 常用模块快速参考 - `references/troubleshooting.md` - 扩展故障排除指南

## 外部资源

- [Ansible 文档](https://docs.ansible.com/) - [Ansible Galaxy](https://galaxy.ansible.com/) - 社区角色 - [geerlingguy roles](https://github.com/geerlingguy?tab=repositories&q=ansible-role) - 高质量角色 - [Ansible for DevOps](https://www.ansiblefordevops.com/) - Jeff Geerling 的著作

更多产品