⚙️ Ansible 入门
服务器配置自动化、Playbook 编写、Role 复用——Terraform 买机器,Ansible 配机器
🤔 Terraform vs Ansible
| 维度 | Terraform | Ansible |
| 核心能力 | 创建/管理云资源 | 配置已有的服务器 |
| 范式 | 声明式("我要什么") | 过程式("执行这些步骤") |
| 状态 | 有 State 文件 | 无状态(幂等任务) |
| Agent | 不需要 | 不需要(SSH) |
| 适用场景 | 买 VPS、DNS、CDN | 装软件、改配置、打补丁 |
| 配合方式 | Terraform 创建 VPS → Ansible 配置 VPS |
📐 项目结构
ansible/
├── ansible.cfg # Ansible 配置
├── inventory.ini # 主机清单
├── group_vars/
│ ├── all.yml # 全局变量
│ └── production.yml # 生产环境变量
├── playbooks/
│ ├── setup.yml # 初始化服务器
│ ├── deploy.yml # 部署应用
│ └── security.yml # 安全加固
└── roles/
├── common/ # 通用配置
├── docker/ # Docker 安装
├── nginx/ # Nginx 配置
└── security/ # 安全加固
# ansible.cfg
[defaults]
inventory = inventory.ini
roles_path = roles
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
# inventory.ini
[production]
prod-server ansible_host=1.2.3.4
[staging]
staging-server ansible_host=5.6.7.8
[servers:children]
production
staging
[servers:vars]
ansible_user=root
ansible_ssh_private_key_file=~/.ssh/id_ed25519
🎮 Playbook 编写
# playbooks/setup.yml — 服务器初始化
---
- name: 初始化生产服务器
hosts: production
become: yes
roles:
- common
- docker
- security
# roles/common/tasks/main.yml
---
- name: 更新 apt 缓存
apt:
update_cache: yes
cache_valid_time: 3600
- name: 安装基础软件
apt:
name:
- curl
- git
- htop
- tmux
- vim
- ufw
- fail2ban
- unattended-upgrades
- python3-pip
- rsync
state: present
- name: 设置时区
timezone:
name: Asia/Shanghai
- name: 设置 hostname
hostname:
name: "{{ inventory_hostname }}"
- name: 创建部署用户
user:
name: deploy
shell: /bin/bash
groups: docker,sudo
append: yes
- name: 部署 SSH 公钥
authorized_key:
user: deploy
key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
- name: 配置 swappiness
sysctl:
name: vm.swappiness
value: "10"
state: present
# roles/docker/tasks/main.yml
---
- name: 添加 Docker GPG Key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: 添加 Docker apt 仓库
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present
- name: 安装 Docker
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: 添加 deploy 用户到 docker 组
user:
name: deploy
groups: docker
append: yes
🛡️ 安全加固 Role
# roles/security/tasks/main.yml
---
- name: 禁用 root SSH 登录
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
notify: restart sshd
- name: 禁用密码登录
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
notify: restart sshd
- name: 修改 SSH 端口
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^Port '
line: 'Port {{ ssh_port | default(22) }}'
notify: restart sshd
- name: 配置 UFW 防火墙
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "{{ ssh_port | default(22) }}"
- "80"
- "443"
- name: 启用 UFW
ufw:
state: enabled
policy: deny
- name: 配置 Fail2ban
template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
notify: restart fail2ban
- name: 启用自动安全更新
template:
src: 50unattended-upgrades.j2
dest: /etc/apt/apt.conf.d/50unattended-upgrades
- name: 安装 CrowdSec(入侵检测)
shell: |
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | bash
apt-get install -y crowdsec
args:
creates: /etc/crowdsec/config.yaml
# roles/security/handlers/main.yml
---
- name: restart sshd
systemd:
name: sshd
state: restarted
- name: restart fail2ban
systemd:
name: fail2ban
state: restarted
🚀 部署 Playbook
# playbooks/deploy.yml — 零停机部署
---
- name: 部署应用
hosts: production
become: yes
become_user: deploy
tasks:
- name: 拉取最新代码
git:
repo: https://github.com/yourorg/app.git
dest: /home/deploy/app
version: "{{ branch | default('main') }}"
- name: 复制 .env 文件
template:
src: env.j2
dest: /home/deploy/app/.env
mode: '0600'
- name: 拉取 Docker 镜像
shell: docker compose pull
args:
chdir: /home/deploy/app
- name: 滚动更新服务
shell: |
docker compose up -d --no-deps --build app
docker compose up -d --no-deps --build api
docker compose up -d --no-deps --build worker
args:
chdir: /home/deploy/app
- name: 等待健康检查
shell: |
for i in $(seq 1 30); do
if curl -sf http://localhost:3000/api/health > /dev/null; then
echo "Healthy"
exit 0
fi
sleep 2
done
echo "Health check failed"
exit 1
- name: 清理旧镜像
shell: docker image prune -f
# 运行
ansible-playbook playbooks/deploy.yml -e "branch=v2.1.0"
💡 Terraform + Ansible 的完美配合
1. Terraform 创建 VPS → 输出 IP 到 inventory 文件 2. Ansible 读取 inventory → 配置新 VPS 3. 每次变更:先 terraform apply 更新基础设施,再 ansible-playbook 更新配置。用 terraform output -json 动态生成 Ansible inventory,两者零摩擦衔接。
🔗 相关专题
🏗️ Terraform 入门 · 🛡️ 服务器加固 · 🐳 Docker Compose · 🏗️ 返回首页