关于 ansible-coder
ansible-coder 是面向服务器配置与维护的 Ansible 编写技能,适用于从少量服务器到复杂基础设施的配置任务。它默认采用扁平、简洁的结构,并说明何时使用 Cloud-Init 或 Ansible。
主要功能
- 01优先采用单一扁平 Playbook
- 02提供静态及 Terraform 动态 Inventory 示例
- 03涵盖软件包、安全与系统配置
- 04支持 Galaxy 依赖管理
- 05提供检查模式和主机范围执行
适用场景
- 01配置少量 Web 或数据库服务器
- 02为现有服务器重复运行配置
- 03设置 Docker、SSH、Fail2ban 和防火墙
- 04通过 Terraform 输出生成 Inventory
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ majesticlabs-dev/ majestic-marketplace --skill ansible-coder安装后在 Claude Code 中输入/ansible-coder确认已加载。
附带文件references/kamal-playbook.mdreferences/provision-script.md
详细介绍
Ansible 编码器
⚠️ 简单至上——默认采用扁平结构
始终从最简单的方案开始。只有明确提出要求时,才增加复杂性。
简单(默认)与过度设计
| 方面 | ✅ 简单(默认) | ❌ 过度设计 |
|---|---|---|
| Playbook | 1 个包含内联任务的 playbook | 多个 playbook + 自定义角色 |
| 角色 | 使用 Galaxy 角色(geerlingguy.*) | 为简单任务编写自定义角色 |
| 清单 | 单个 hosts.ini | 多个清单 + group_vars 层级结构 |
| 变量 | 内联在 playbook 中或放在单个变量文件中 | 分散在 group_vars/host_vars 中 |
| 文件数量 | 总计约 3-5 个文件 | 嵌套目录中有 20 多个文件 |
适合采用简单方案的情况(90% 的情况)
- 设置 1-5 台服务器
- 标准技术栈(Docker、nginx、fail2ban、ufw)
- 单一环境或配置相同的服务器
- 每台主机都没有复杂的条件逻辑
适合采用复杂方案的情况(10% 的情况)
- 配置差异较大的大型服务器集群
- 需要隔离角色的多团队协作
- 带有依赖项的复杂编排
- 用户明确要求模块化结构
规则:如果所有内容都能放进一个 200 行的 playbook,就这样做。
何时使用 Ansible 与 Cloud-Init
| 使用 Cloud-Init 的情况 | 使用 Ansible 的情况 |
|---|---|
| 仅限首次启动 | 在现有服务器上重新运行配置 |
| 安装简单的软件包 | 复杂的多步骤配置 |
| 创建基本用户 | 基于角色的配置 |
| 不可变基础设施 | 需要更新的可变服务器 |
**经验法则:**使用 Cloud-Init 进行初始配置,使用 Ansible 进行持续管理。
目录结构
简单结构(默认)
infra/ansible/
├── playbook.yml # Single playbook with all tasks inline
├── requirements.yml # Galaxy dependencies (geerlingguy.*, etc.)
├── hosts.ini # Inventory (git-ignored)
└── hosts.ini.example # Inventory template
复杂结构(仅在确有必要时使用)
infra/ansible/
├── playbook.yml # Main playbook
├── requirements.yml # Galaxy dependencies
├── hosts.ini # Inventory (git-ignored)
├── hosts.ini.example # Inventory template
├── group_vars/
│ └── all.yml # Shared variables
└── roles/
└── custom_role/
├── tasks/main.yml
├── handlers/main.yml
└── templates/
清单
静态清单
# hosts.ini
[web]
192.168.1.1 ansible_user=root
[db]
192.168.1.2 ansible_user=root
[all:vars]
ansible_python_interpreter=/usr/bin/python3
从 Terraform 动态生成
# Generate inventory from Terraform output
SERVER_IP=$(cd infra && tofu output -raw server_ip)
cat > infra/ansible/hosts.ini << EOF
[web]
$SERVER_IP ansible_user=root
EOF
Playbook 结构
基本 Playbook
---
- name: Configure web servers
hosts: web
become: true
vars:
timezone: "UTC"
swap_size_mb: "2048"
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Install packages
ansible.builtin.apt:
name:
- docker.io
- fail2ban
- ufw
state: present
使用角色
---
- name: Configure web servers
hosts: web
become: true
vars:
security_autoupdate_reboot: true
security_autoupdate_reboot_time: "03:00"
roles:
- role: geerlingguy.swap
when: ansible_swaptotal_mb < 1
- role: geerlingguy.docker
- role: security
常见任务
软件包管理
- name: Install required packages
ansible.builtin.apt:
name:
- curl
- ca-certificates
- gnupg
- fail2ban
- ufw
- ntp
state: present
update_cache: true
Docker 安装
- name: Check if Docker is installed
ansible.builtin.command: docker --version
register: docker_installed
ignore_errors: true
changed_when: false
- name: Install Docker via convenience script
ansible.builtin.shell: curl -fsSL https://get.docker.com | sh
when: docker_installed.rc != 0
args:
creates: /usr/bin/docker
- name: Ensure Docker is running
ansible.builtin.systemd:
name: docker
state: started
enabled: true
SSH 加固
- name: Disable SSH password authentication
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PasswordAuthentication"
line: "PasswordAuthentication no"
notify: Restart ssh
- name: Disable SSH root login with password
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PermitRootLogin"
line: "PermitRootLogin prohibit-password"
notify: Restart ssh
handlers:
- name: Restart ssh
ansible.builtin.systemd:
name: ssh # Ubuntu uses 'ssh', not 'sshd'
state: restarted
Fail2ban
- name: Configure fail2ban for SSH
ansible.builtin.copy:
dest: /etc/fail2ban/jail.local
content: |
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
findtime = 600
mode: "0644"
notify: Restart fail2ban
- name: Ensure fail2ban is running
ansible.builtin.systemd:
name: fail2ban
state: started
enabled: true
handlers:
- name: Restart fail2ban
ansible.builtin.systemd:
name: fail2ban
state: restarted
UFW 防火墙
- name: Set UFW default policies
community.general.ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
loop:
- { direction: incoming, policy: deny }
- { direction: outgoing, policy: allow }
- name: Allow specified ports through UFW
community.general.ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- 22 # SSH
- 80 # HTTP
- 443 # HTTPS
- name: Enable UFW
community.general.ufw:
state: enabled
内核调优
- name: Configure sysctl for performance
ansible.posix.sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
state: present
reload: true
loop:
- { name: vm.swappiness, value: "10" }
- { name: net.core.somaxconn, value: "65535" }
时区
- name: Set timezone
community.general.timezone:
name: "{{ timezone }}"
移除 Snap(精简 Ubuntu)
- name: Remove snapd
ansible.builtin.apt:
name: snapd
state: absent
purge: true
ignore_errors: true
- name: Remove snap directories
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /snap
- /var/snap
- /var/lib/snapd
Galaxy 依赖项
requirements.yml
---
roles:
- name: geerlingguy.swap
version: 2.0.0
- name: geerlingguy.docker
version: 7.4.1
collections:
- name: community.general
- name: ansible.posix
安装
ansible-galaxy install -r requirements.yml --force
运行 Playbook
基本执行
ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i hosts.ini playbook.yml
使用变量
ansible-playbook -i hosts.ini playbook.yml \
-e "timezone=Europe/Berlin" \
-e "swap_size_mb=4096"
试运行
ansible-playbook -i hosts.ini playbook.yml --check --diff
限定特定主机
ansible-playbook -i hosts.ini playbook.yml --limit web
请参阅 Kamal 服务器准备,了解完整的 Kamal 部署服务器 playbook。
请参阅 与 Terraform 集成,了解 Terraform-Ansible-Kamal 配置流程。
故障排除
| 问题 | 原因 | 修复方法 |
|---|---|---|
ssh: connect refused | 服务器尚未就绪 | 等待或检查防火墙 |
Permission denied | SSH 密钥错误 | 使用 -i 指定 |
sudo: password required | 用户需要 NOPASSWD | 使用 become_method: sudo |
| 处理程序未运行 | 任务未产生变更 | 使用 changed_when: true |
| 找不到模块 | 缺少集合 | 从 requirements.yml 安装 |
评论
支持 Markdown