⚙️ Ansible 入门

服务器配置自动化、Playbook 编写、Role 复用——Terraform 买机器,Ansible 配机器

🤔 Terraform vs Ansible

维度TerraformAnsible
核心能力创建/管理云资源配置已有的服务器
范式声明式("我要什么")过程式("执行这些步骤")
状态有 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 · 🏗️ 返回首页