
Cursor+GitOps 自动化运维实战:智能编写 Ansible 与 Terraform
目录
- 摘要
- 一、开发环境搭建与工具链初始化配置
- [1.1 硬件与操作系统要求](#1.1 硬件与操作系统要求)
- [1.2 Cursor IDE 安装与基础配置](#1.2 Cursor IDE 安装与基础配置)
- [1.3 Git 环境配置与 SSH 密钥生成](#1.3 Git 环境配置与 SSH 密钥生成)
- [1.4 Ansible 安装与连接验证](#1.4 Ansible 安装与连接验证)
- [1.5 Terraform 安装与 Provider 初始化](#1.5 Terraform 安装与 Provider 初始化)
- [1.6 辅助工具链安装(Python、Docker、kubectl)](#1.6 辅助工具链安装(Python、Docker、kubectl))
- [1.7 项目目录结构规划](#1.7 项目目录结构规划)
- [二、Cursor 核心功能解析与 AI 上下文设定](#二、Cursor 核心功能解析与 AI 上下文设定)
- [2.1 Cursor 编辑器核心界面与快捷键](#2.1 Cursor 编辑器核心界面与快捷键)
- [2.2 AI 对话面板与 Composer 模式](#2.2 AI 对话面板与 Composer 模式)
- [2.3 上下文管理:@符号引用与文件索引](#2.3 上下文管理:@符号引用与文件索引)
- [2.4 .cursorrules 文件编写规范](#2.4 .cursorrules 文件编写规范)
- [2.5 自定义 Prompt 模板与运维场景适配](#2.5 自定义 Prompt 模板与运维场景适配)
- [2.6 模型选择策略与 Token 管理](#2.6 模型选择策略与 Token 管理)
- [三、利用 Cursor 快速生成标准化 Ansible 剧本](#三、利用 Cursor 快速生成标准化 Ansible 剧本)
- [3.1 Ansible 基础概念与目录规范](#3.1 Ansible 基础概念与目录规范)
- [3.2 使用自然语言生成 Playbook 骨架](#3.2 使用自然语言生成 Playbook 骨架)
- [3.3 Roles 角色化拆分与 AI 辅助重构](#3.3 Roles 角色化拆分与 AI 辅助重构)
- [3.4 变量管理与 Vault 加密配置](#3.4 变量管理与 Vault 加密配置)
- [3.5 Jinja2 模板生成与条件逻辑编写](#3.5 Jinja2 模板生成与条件逻辑编写)
- [3.6 Handler 与幂等性保障](#3.6 Handler 与幂等性保障)
- [3.7 完整实战:Web 服务自动化部署 Playbook](#3.7 完整实战:Web 服务自动化部署 Playbook)
- [四、基于自然语言描述构建 Terraform 基础设施代码](#四、基于自然语言描述构建 Terraform 基础设施代码)
- [4.1 Terraform 核心概念:Provider、Resource、State](#4.1 Terraform 核心概念:Provider、Resource、State)
- [4.2 自然语言到 HCL 代码的转换技巧](#4.2 自然语言到 HCL 代码的转换技巧)
- [4.3 VPC 网络基础设施代码生成](#4.3 VPC 网络基础设施代码生成)
- [4.4 计算资源(EC2/ECS)自动化创建](#4.4 计算资源(EC2/ECS)自动化创建)
- [4.5 模块化设计与变量参数化](#4.5 模块化设计与变量参数化)
- [4.6 State 管理与远程后端配置](#4.6 State 管理与远程后端配置)
- [4.7 完整实战:多云环境基础设施编排](#4.7 完整实战:多云环境基础设施编排)
- [五、集成 Git 工作流实现代码版本管理与协作](#五、集成 Git 工作流实现代码版本管理与协作)
- [5.1 GitOps 核心理念与运维场景映射](#5.1 GitOps 核心理念与运维场景映射)
- [5.2 仓库结构设计与分支策略](#5.2 仓库结构设计与分支策略)
- [5.3 Commit 规范与自动化提交信息生成](#5.3 Commit 规范与自动化提交信息生成)
- [5.4 Pull Request 审查流程与 AI 辅助 Code Review](#5.4 Pull Request 审查流程与 AI 辅助 Code Review)
- [5.5 Git Hooks 与 Pre-commit 自动化检查](#5.5 Git Hooks 与 Pre-commit 自动化检查)
- [5.6 多环境分支管理与标签策略](#5.6 多环境分支管理与标签策略)
- [六、搭建 CI/CD 流水线自动执行部署脚本](#六、搭建 CI/CD 流水线自动执行部署脚本)
- [6.1 CI/CD 流水线架构设计](#6.1 CI/CD 流水线架构设计)
- [6.2 GitHub Actions 工作流配置](#6.2 GitHub Actions 工作流配置)
- [6.3 Ansible 自动化执行 Pipeline](#6.3 Ansible 自动化执行 Pipeline)
- [6.4 Terraform Plan/Apply 自动化流程](#6.4 Terraform Plan/Apply 自动化流程)
- [6.5 密钥管理与 Secrets 注入](#6.5 密钥管理与 Secrets 注入)
- [6.6 通知与回滚机制](#6.6 通知与回滚机制)
- 七、全流程实操:从代码生成到云端资源交付
- [7.1 项目需求分析与架构设计](#7.1 项目需求分析与架构设计)
- [7.2 使用 Cursor 生成全部基础设施代码](#7.2 使用 Cursor 生成全部基础设施代码)
- [7.3 本地验证与 Lint 检查](#7.3 本地验证与 Lint 检查)
- [7.4 推送代码触发 CI/CD](#7.4 推送代码触发 CI/CD)
- [7.5 云端资源验证与监控接入](#7.5 云端资源验证与监控接入)
- [7.6 端到端测试与交付确认](#7.6 端到端测试与交付确认)
- [八、常见语法报错分析与 AI 辅助排错技巧](#八、常见语法报错分析与 AI 辅助排错技巧)
- [8.1 Ansible 常见报错与解决方案](#8.1 Ansible 常见报错与解决方案)
- [8.2 Terraform 常见报错与解决方案](#8.2 Terraform 常见报错与解决方案)
- [8.3 Git 冲突处理与合并策略](#8.3 Git 冲突处理与合并策略)
- [8.4 CI/CD 流水线故障排查](#8.4 CI/CD 流水线故障排查)
- [8.5 利用 Cursor AI 进行智能排错](#8.5 利用 Cursor AI 进行智能排错)
- [8.6 日志分析与错误模式识别](#8.6 日志分析与错误模式识别)
- 九、提升脚本安全性的最佳实践与审查要点
- [9.1 密钥与敏感信息管理](#9.1 密钥与敏感信息管理)
- [9.2 最小权限原则与 IAM 策略](#9.2 最小权限原则与 IAM 策略)
- [9.3 代码静态安全扫描](#9.3 代码静态安全扫描)
- [9.4 Ansible 安全加固实践](#9.4 Ansible 安全加固实践)
- [9.5 Terraform 安全基线配置](#9.5 Terraform 安全基线配置)
- [9.6 审计日志与合规检查](#9.6 审计日志与合规检查)
- 十、进阶技巧:自定义规则优化运维代码质量
- [10.1 自定义 .cursorrules 运维规则集](#10.1 自定义 .cursorrules 运维规则集)
- [10.2 Ansible Lint 规则定制](#10.2 Ansible Lint 规则定制)
- [10.3 Terraform 自定义策略(Sentinel/OPA)](#10.3 Terraform 自定义策略(Sentinel/OPA))
- [10.4 代码生成质量评估与迭代优化](#10.4 代码生成质量评估与迭代优化)
- [10.5 团队知识库与 Prompt 工程](#10.5 团队知识库与 Prompt 工程)
- [10.6 自动化文档生成与知识沉淀](#10.6 自动化文档生成与知识沉淀)
- 常见陷阱与问题排除
- 总结
- 详细参考资料
- 附录
摘要
随着云原生时代的全面到来,基础设施即代码(Infrastructure as Code, IaC)已成为现代运维的核心范式。Ansible 作为配置管理的利器,Terraform 作为基础设施编排的标准,二者结合构成了企业级自动化运维的基石。然而,编写高质量的 IaC 代码仍然面临学习曲线陡峭、语法繁琐、调试困难等挑战。
Cursor 作为一款深度集成 AI 能力的代码编辑器,为运维工程师带来了革命性的开发体验。通过自然语言描述需求,AI 可以自动生成符合最佳实践的 Ansible Playbook 和 Terraform 配置文件,将原本数小时的编码工作压缩到几分钟内完成。
本文将手把手带你从零开始,完整掌握 Cursor + GitOps + Ansible + Terraform 的全栈自动化运维工作流。从环境搭建到代码生成,从版本管理到 CI/CD 流水线,从安全审查到进阶优化,每一个环节都配有详细的代码示例、操作截图说明和常见问题解答。无论你是刚接触运维的新手,还是希望提升效率的资深工程师,都能从本文中获得切实可行的实践指导。
适用读者:运维工程师、DevOps 工程师、SRE、后端开发人员、对自动化运维感兴趣的技术爱好者
前置要求:基本的 Linux 命令行操作能力、了解 YAML/HCL 基本语法(文中会详细讲解)
预计学习时间:通读约 3-4 小时,实操练习约 2-3 天
一、开发环境搭建与工具链初始化配置
1.1 硬件与操作系统要求
在开始之前,确保你的开发环境满足以下最低要求:
硬件要求:
| 组件 | 最低配置 | 推荐配置 |
|---|---|---|
| CPU | 4 核 | 8 核及以上 |
| 内存 | 8 GB RAM | 16 GB RAM |
| 磁盘 | 50 GB SSD | 100 GB NVMe SSD |
| 网络 | 稳定的互联网连接 | 带宽 ≥ 50 Mbps |
操作系统支持:
- Linux:Ubuntu 22.04 LTS / CentOS Stream 9 / Fedora 39+(推荐)
- macOS:macOS 13 Ventura 及以上
- Windows:Windows 11(需安装 WSL2)
新手提示:如果你使用 Windows 系统,强烈建议安装 WSL2(Windows Subsystem for Linux 2),在 Linux 子系统中进行所有操作。Ansible 原生不支持 Windows 作为控制节点。
1.2 Cursor IDE 安装与基础配置
1.2.1 下载与安装 Cursor
Linux (Ubuntu/Debian):
bash
# 下载 Cursor AppImage(以 x86_64 为例)
wget https://download.cursor.sh/linux/appimage/latest -O cursor.AppImage
# 添加执行权限
chmod +x cursor.AppImage
# 运行 Cursor(首次运行)
./cursor.AppImage
# 可选:移动到系统目录方便后续使用
sudo mkdir -p /opt/cursor
sudo mv cursor.AppImage /opt/cursor/
sudo ln -s /opt/cursor/cursor.AppImage /usr/local/bin/cursor
macOS:
bash
# 使用 Homebrew 安装(如果有 cask)
brew install --cask cursor
# 或者从官网下载 .dmg 文件,拖入 Applications 文件夹
# 访问 https://cursor.sh 下载最新版本
Windows (WSL2 环境):
powershell
# 在 PowerShell 中安装 WSL2(如果尚未安装)
wsl --install -d Ubuntu-22.04
# 重启电脑后,在 WSL2 中按照 Linux 步骤安装
# Windows 原生版本可直接从 cursor.sh 下载安装包
1.2.2 首次启动配置
安装完成后,首次启动 Cursor 会引导你完成以下配置:
- 选择主题:推荐 Dark+ 或 One Dark Pro(运维场景下长时间使用深色主题更护眼)
- 导入 VS Code 配置:如果你之前使用 VS Code,可以选择导入设置和扩展
- 登录账号:注册并登录 Cursor 账号以激活 AI 功能
- 选择 AI 模型:初始推荐选择 Claude 3.5 Sonnet 或 GPT-4o
1.2.3 必装扩展
在 Cursor 中安装以下扩展(通过 Ctrl+Shift+X 打开扩展面板):
# YAML 支持(Ansible 依赖)
- redhat.vscode-yaml
- redhat.ansible
# Terraform 支持
- hashicorp.terraform
# Git 增强
- eamodio.gitlens
- mhutchie.git-graph
# 代码质量
- ms-python.python(Ansible 依赖 Python)
- streetsidesoftware.code-spell-checker
# 终端增强
- pkief.material-icon-theme
使用命令行批量安装:
bash
# 安装 Ansible 相关扩展
cursor --install-extension redhat.vscode-yaml
cursor --install-extension redhat.ansible
# 安装 Terraform 扩展
cursor --install-extension hashicorp.terraform
# 安装 Git 增强扩展
cursor --install-extension eamodio.gitlens
cursor --install-extension mhutchie.git-graph
1.3 Git 环境配置与 SSH 密钥生成
1.3.1 Git 安装与全局配置
bash
# Ubuntu/Debian
sudo apt update
sudo apt install -y git
# CentOS/RHEL
sudo dnf install -y git
# macOS
brew install git
# 验证安装
git --version
# 输出示例:git version 2.43.0
配置全局用户信息:
bash
# 设置用户名(替换为你的真实姓名或 GitHub 用户名)
git config --global user.name "Zhang San"
# 设置邮箱(必须与 GitHub/GitLab 账号邮箱一致)
git config --global user.email "zhangsan@example.com"
# 设置默认分支名为 main
git config --global init.defaultBranch main
# 设置默认编辑器为 Cursor
git config --global core.editor "cursor --wait"
# 启用颜色输出
git config --global color.ui auto
# 设置 pull 策略为 rebase(保持提交历史线性)
git config --global pull.rebase true
# 查看配置
git config --global --list
1.3.2 SSH 密钥生成与添加
bash
# 生成 Ed25519 类型的 SSH 密钥(推荐)
ssh-keygen -t ed25519 -C "zhangsan@example.com" -f ~/.ssh/id_ed25519_gitops
# 如果系统较旧不支持 ed25519,使用 RSA
# ssh-keygen -t rsa -b 4096 -C "zhangsan@example.com" -f ~/.ssh/id_rsa_gitops
# 启动 ssh-agent 并添加密钥
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519_gitops
# 查看公钥内容(复制到 GitHub/GitLab)
cat ~/.ssh/id_ed25519_gitops.pub
配置 SSH config 文件 ~/.ssh/config:
# ~/.ssh/config - SSH 连接配置
# GitHub 配置
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_gitops
PreferredAuthentications publickey
# GitLab 配置(如果使用)
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/id_ed25519_gitops
PreferredAuthentications publickey
# 通用设置
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
bash
# 设置 SSH 配置文件权限
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/id_ed25519_gitops
chmod 644 ~/.ssh/id_ed25519_gitops.pub
# 测试 SSH 连接
ssh -T git@github.com
# 成功输出:Hi username! You've successfully authenticated...
1.4 Ansible 安装与连接验证
1.4.1 安装 Ansible
bash
# 方法一:使用 pip 安装(推荐,版本最新)
# 首先确保 Python 3.9+ 已安装
python3 --version
# 创建虚拟环境(推荐做法,避免污染系统 Python)
python3 -m venv ~/ansible-env
source ~/ansible-env/bin/activate
# 安装 Ansible
pip install ansible==9.5.1 # 指定稳定版本
# 或者安装最新版
# pip install ansible
# 方法二:使用系统包管理器
# Ubuntu/Debian
sudo apt update
sudo apt install -y ansible
# CentOS/RHEL
sudo dnf install -y ansible-core
# 验证安装
ansible --version
# 输出示例:
# ansible [core 2.16.x]
# config file = /etc/ansible/ansible.cfg
# python version = 3.11.x
1.4.2 基础配置
创建 Ansible 配置文件:
bash
# 创建项目目录
mkdir -p ~/gitops-project
cd ~/gitops-project
# 创建 ansible.cfg
cat > ansible.cfg << 'EOF'
[defaults]
# 清单文件路径
inventory = ./inventory/hosts.yml
# 角色路径
roles_path = ./roles
# 禁用 host key 检查(开发环境,生产环境请启用)
host_key_checking = False
# 设置默认远程用户
remote_user = deploy
# 并行连接数
forks = 20
# 超时设置(秒)
timeout = 30
# 日志路径
log_path = ./logs/ansible.log
# 禁用 cowsay(如果安装了的话,避免输出干扰)
nocows = 1
# 重试文件保存路径
retry_files_enabled = False
# 使用 YAML 回调插件(更美观的输出)
stdout_callback = yaml
# 收集事实时使用的子集
gather_subset = !all,!min,network,hardware
[privilege_escalation]
# 提权设置
become = True
become_method = sudo
become_user = root
become_ask_pass = False
[ssh_connection]
# SSH 长连接复用(大幅提升性能)
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null
pipelining = True
control_path = /tmp/ansible-ssh-%%h-%%p-%%r
EOF
# 创建日志目录
mkdir -p logs
1.4.3 创建测试清单并验证连接
bash
# 创建 inventory 目录
mkdir -p inventory
# 创建测试清单文件
cat > inventory/hosts.yml << 'EOF'
---
# Ansible 清单文件 - 定义受管节点
all:
children:
# Web 服务器组
webservers:
hosts:
web-01:
ansible_host: 192.168.1.101
ansible_port: 22
web-02:
ansible_host: 192.168.1.102
ansible_port: 22
vars:
http_port: 80
https_port: 443
# 数据库服务器组
dbservers:
hosts:
db-01:
ansible_host: 192.168.1.201
vars:
db_port: 5432
# 开发环境
development:
hosts:
localhost:
ansible_connection: local
ansible_python_interpreter: "{{ ansible_playbook_python }}"
EOF
# 测试本地连接
ansible localhost -m ping
# 成功输出:
# localhost | SUCCESS => {
# "changed": false,
# "ping": "pong"
# }
# 测试清单解析
ansible-inventory --list
1.5 Terraform 安装与 Provider 初始化
1.5.1 安装 Terraform
bash
# Ubuntu/Debian - 使用官方仓库
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
# macOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# CentOS/RHEL
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install terraform
# 验证安装
terraform version
# 输出示例:Terraform v1.8.x on linux_amd64
1.5.2 配置自动补全与格式化
bash
# Bash 自动补全
terraform -install-autocomplete
# 或者手动添加到 ~/.bashrc
echo 'complete -C /usr/bin/terraform terraform' >> ~/.bashrc
source ~/.bashrc
# 配置默认格式化
cat > ~/.terraformrc << 'EOF'
# Terraform CLI 配置
provider_installation {
# 使用文件系统镜像(离线环境)
# filesystem_mirror {
# path = "/opt/terraform/providers"
# include = ["*/*"]
# }
# 默认从 registry 下载
direct {
exclude = []
}
}
# 插件缓存(避免重复下载)
plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"
EOF
# 创建插件缓存目录
mkdir -p ~/.terraform.d/plugin-cache
1.5.3 初始化测试项目
bash
# 在项目中创建 Terraform 目录
mkdir -p ~/gitops-project/terraform
cd ~/gitops-project/terraform
# 创建基础 main.tf
cat > main.tf << 'EOF'
# Terraform 基础配置
terraform {
# 指定 Terraform 最低版本
required_version = ">= 1.6.0"
# 指定需要的 Provider
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# 配置 AWS Provider
provider "aws" {
region = var.aws_region
profile = var.aws_profile
# 默认标签(所有资源都会带上)
default_tags {
tags = {
Environment = var.environment
Project = "gitops-demo"
ManagedBy = "terraform"
}
}
}
# 变量定义
variable "aws_region" {
description = "AWS 区域"
type = string
default = "ap-southeast-1"
}
variable "aws_profile" {
description = "AWS CLI Profile 名称"
type = string
default = "default"
}
variable "environment" {
description = "部署环境标识"
type = string
default = "development"
}
# 输出
output "aws_region" {
description = "当前部署的 AWS 区域"
value = var.aws_region
}
EOF
# 初始化 Terraform(下载 Provider)
terraform init
# 验证配置语法
terraform validate
# 预览执行计划(不会实际创建资源)
terraform plan
1.6 辅助工具链安装(Python、Docker、kubectl)
bash
# ===== Python 环境 =====
# Ubuntu/Debian
sudo apt install -y python3 python3-pip python3-venv
# 安装常用 Python 工具
pip install yamllint ansible-lint jinja2-cli
# ===== Docker(用于本地测试)=====
# Ubuntu/Debian
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 将当前用户加入 docker 组(免 sudo)
sudo usermod -aG docker $USER
newgrp docker
# 验证
docker --version
docker compose version
# ===== kubectl(如果需要管理 K8s)=====
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client
# ===== 其他实用工具 =====
# jq - JSON 处理
sudo apt install -y jq
# tree - 目录结构查看
sudo apt install -y tree
# hcl2json - HCL 格式转换
# go install github.com/tmccombs/hcl2json@latest
1.7 项目目录结构规划
一个良好的项目结构是 GitOps 实践的基础。以下是推荐的标准目录结构:
gitops-project/
├── .cursorrules # Cursor AI 规则配置
├── .gitignore # Git 忽略规则
├── .pre-commit-config.yaml # Pre-commit 钩子配置
├── README.md # 项目说明文档
├── Makefile # 常用命令快捷入口
│
├── ansible/ # Ansible 相关配置
│ ├── ansible.cfg # Ansible 主配置
│ ├── inventory/ # 清单文件
│ │ ├── hosts.yml # 主清单
│ │ ├── group_vars/ # 组变量
│ │ │ ├── all.yml
│ │ │ ├── webservers.yml
│ │ │ └── dbservers.yml
│ │ └── host_vars/ # 主机变量
│ │ ├── web-01.yml
│ │ └── db-01.yml
│ ├── playbooks/ # Playbook 文件
│ │ ├── site.yml # 主入口 Playbook
│ │ ├── deploy-web.yml # Web 部署
│ │ └── setup-monitoring.yml # 监控配置
│ ├── roles/ # 角色目录
│ │ ├── nginx/
│ │ │ ├── tasks/main.yml
│ │ │ ├── handlers/main.yml
│ │ │ ├── templates/
│ │ │ ├── files/
│ │ │ ├── vars/main.yml
│ │ │ └── defaults/main.yml
│ │ └── postgresql/
│ └── collections/ # 自定义集合
│ └── requirements.yml
│
├── terraform/ # Terraform 相关配置
│ ├── environments/ # 多环境配置
│ │ ├── development/
│ │ │ ├── main.tf
│ │ │ ├── variables.tf
│ │ │ ├── outputs.tf
│ │ │ └── terraform.tfvars
│ │ ├── staging/
│ │ └── production/
│ ├── modules/ # 可复用模块
│ │ ├── vpc/
│ │ │ ├── main.tf
│ │ │ ├── variables.tf
│ │ │ └── outputs.tf
│ │ ├── ec2/
│ │ ├── rds/
│ │ └── security-group/
│ └── backend/ # 后端配置
│ └── s3-backend.tf
│
├── .github/ # GitHub Actions
│ └── workflows/
│ ├── ansible-deploy.yml
│ ├── terraform-plan.yml
│ └── terraform-apply.yml
│
├── scripts/ # 辅助脚本
│ ├── setup.sh # 环境初始化
│ ├── validate.sh # 代码验证
│ └── cleanup.sh # 资源清理
│
├── docs/ # 文档
│ ├── architecture.md
│ ├── runbook.md
│ └── troubleshooting.md
│
└── logs/ # 日志目录(不提交到 Git)
├── ansible.log
└── terraform.log
创建此目录结构的命令:
bash
#!/bin/bash
# scripts/init-project.sh - 项目目录初始化脚本
set -euo pipefail
PROJECT_DIR="gitops-project"
echo "🚀 初始化 GitOps 项目目录结构..."
# 创建顶层目录
mkdir -p ${PROJECT_DIR}/{ansible,terraform,scripts,docs,logs}
# Ansible 目录结构
mkdir -p ${PROJECT_DIR}/ansible/{inventory/{group_vars,host_vars},playbooks,roles,collections}
# Terraform 目录结构
mkdir -p ${PROJECT_DIR}/terraform/{environments/{development,staging,production},modules/{vpc,ec2,rds,security-group},backend}
# GitHub Actions
mkdir -p ${PROJECT_DIR}/.github/workflows
# 创建 .gitignore
cat > ${PROJECT_DIR}/.gitignore << 'GITIGNORE'
# Terraform
*.tfstate
*.tfstate.*
*.tfstate.backup
.terraform/
.terraform.lock.hcl
crash.log
override.tf
override.tf.json
*_override.tf
*_override.tf.json
*.tfvars
!example.tfvars
# Ansible
*.retry
logs/
.vault_pass
# Python
__pycache__/
*.py[cod]
*$py.class
*.egg-info/
dist/
build/
venv/
.venv/
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# 敏感信息
*.pem
*.key
.env
secrets/
GITIGNORE
echo "✅ 项目结构初始化完成!"
tree -L 3 ${PROJECT_DIR}/
二、Cursor 核心功能解析与 AI 上下文设定
2.1 Cursor 编辑器核心界面与快捷键
Cursor 基于 VS Code 构建,保留了 VS Code 的所有操作习惯,同时增加了 AI 专属功能。
核心界面布局:
┌─────────────────────────────────────────────────────────┐
│ 菜单栏 / 命令面板 (Ctrl+Shift+P) │
├──────────┬──────────────────────────────┬───────────────┤
│ │ │ │
│ 文件 │ 编辑器主区域 │ AI 面板 │
│ 资源 │ (代码编辑) │ (Chat/ │
│ 管理器 │ │ Composer) │
│ │ │ │
│ │ │ │
├──────────┴──────────────────────────────┴───────────────┤
│ 终端 / 输出 / 问题 / 调试控制台 │
├─────────────────────────────────────────────────────────┤
│ 状态栏 (分支名、编码、行号等) │
└─────────────────────────────────────────────────────────┘
核心快捷键速查表:
| 功能 | 快捷键 (Linux/Win) | 快捷键 (macOS) |
|---|---|---|
| 打开 AI 聊天 | Ctrl + L |
Cmd + L |
| 打开 Composer | Ctrl + I |
Cmd + I |
| 行内 AI 编辑 | Ctrl + K |
Cmd + K |
| AI 生成代码 | Ctrl + Shift + L |
Cmd + Shift + L |
| 命令面板 | Ctrl + Shift + P |
Cmd + Shift + P |
| 终端 | ``Ctrl + ``` | ``Cmd + ``` |
| 文件搜索 | Ctrl + P |
Cmd + P |
| 全局搜索 | Ctrl + Shift + F |
Cmd + Shift + F |
| 接受 AI 建议 | Tab |
Tab |
| 拒绝 AI 建议 | Esc |
Esc |
| 多行光标 | Alt + Click |
Option + Click |
2.2 AI 对话面板与 Composer 模式
2.2.1 Chat 模式(Ctrl+L)
Chat 模式适合提问、咨询和获取代码片段。AI 不会直接修改文件,而是在聊天面板中给出建议。
运维场景示例:
用户输入:
"请帮我写一个 Ansible task,检查 Nginx 是否正在运行,
如果没有运行则启动它,并注册服务开机自启"
AI 输出:
```yaml
# tasks/check_nginx.yml - 检查并确保 Nginx 运行
- name: 检查 Nginx 服务状态
ansible.builtin.service_facts:
register: service_status
- name: 确保 Nginx 服务正在运行且开机自启
ansible.builtin.systemd:
name: nginx
state: started
enabled: yes
when: "'nginx.service' not in service_status.ansible_facts.services
or service_status.ansible_facts.services['nginx.service'].state != 'running'"
2.2.2 Composer 模式(Ctrl+I)
Composer 模式是 Cursor 最强大的功能之一。AI 可以直接创建、修改多个文件,适合大规模代码生成。
使用技巧:
- 打开 Composer(
Ctrl+I) - 描述你的需求(越详细越好)
- AI 会展示将要进行的文件变更
- 逐一审查后点击 "Accept All" 或逐个接受
示例 Prompt:
创建一个完整的 Ansible Role 用于部署 Nginx 反向代理:
- 安装 nginx 包
- 配置反向代理到后端应用(端口 8080)
- 配置 SSL(使用 Let's Encrypt)
- 设置 systemd 服务管理
- 包含健康检查 handler
- 使用变量参数化所有可配置项
2.2.3 行内编辑(Ctrl+K)
选中一段代码后按 Ctrl+K,可以直接对选中内容进行 AI 修改。
场景: 选中一段 Ansible task,输入"添加错误处理和重试机制",AI 会自动添加 retries、delay、register、until 等关键字。
2.3 上下文管理:@符号引用与文件索引
Cursor 支持通过 @ 符号向 AI 提供精确上下文:
| 符号 | 功能 | 示例 |
|---|---|---|
@filename |
引用特定文件 | @main.tf 这个文件有什么错误? |
@folder |
引用整个文件夹 | @roles/nginx 优化这个角色 |
@code |
引用选中的代码 | @code 重构这段代码 |
@docs |
引用外部文档 | @docs terraform aws_instance |
@git |
引用 Git 信息 | @git 最近的变更有什么风险? |
@web |
联网搜索 | @web ansible 2.16 新特性 |
@codebase |
引用整个代码库 | @codebase 找出所有硬编码的 IP 地址 |
最佳实践:
# 好的 Prompt(提供充分上下文)
"@ansible/playbooks/deploy-web.yml @ansible/roles/nginx/tasks/main.yml
请检查这个部署流程是否有遗漏的步骤,特别是 SSL 证书更新后的重载"
# 不好的 Prompt(上下文不足)
"帮我修一下这个 bug"
2.4 .cursorrules 文件编写规范
.cursorrules 文件放在项目根目录,用于告诉 AI 项目的规范、偏好和约束。这是提升 AI 生成代码质量的关键。
markdown
# .cursorrules - GitOps 自动化运维项目 AI 规则
## 项目概述
这是一个基于 GitOps 的自动化运维项目,使用 Ansible 进行配置管理,
Terraform 进行基础设施编排。所有基础设施变更必须通过 Git 提交触发。
## 代码规范
### Ansible 规范
- 所有 Playbook 和 Task 文件必须使用 YAML 格式
- 文件以 `---` 开头
- 使用完整模块名(如 `ansible.builtin.copy` 而非 `copy`)
- 每个 task 必须有 `name` 字段,使用中文描述
- 变量使用 snake_case 命名
- 敏感信息必须使用 Ansible Vault 加密
- 使用 `when` 条件而非 `ignore_errors`
- Handler 用于服务重启等有副作用的操作
- 优先使用 `ansible.builtin` 集合中的模块
- 每个 Role 必须包含 defaults/main.yml 定义默认变量
### Terraform 规范
- 使用 HCL2 语法
- 每个资源必须有 `tags` 标签
- 变量必须有 `description`、`type`、`default`(如适用)
- 输出值必须有 `description`
- 使用 `terraform fmt` 格式化
- 敏感输出标记 `sensitive = true`
- 使用模块化设计,避免重复代码
- State 文件绝不提交到 Git
- 使用 `terraform.tfvars.example` 提供变量示例
### Git 规范
- 提交信息遵循 Conventional Commits 规范
- 格式:`type(scope): description`
- type: feat/fix/docs/refactor/chore/ci
- 分支命名:feature/xxx, fix/xxx, hotfix/xxx
## 安全要求
- 绝不在代码中硬编码密码、密钥、Token
- 使用环境变量或 Vault 管理敏感信息
- AWS 安全组必须限制入站规则
- 所有 S3 桶必须启用加密和版本控制
- Terraform 中禁止使用 `0.0.0.0/0` 作为入站规则(除特殊说明)
## 输出偏好
- 代码注释使用中文
- 解释说明使用中文
- 提供完整的可运行代码,不使用省略号
- 复杂逻辑添加行内注释
- 给出多种方案时说明各自优缺点
2.5 自定义 Prompt 模板与运维场景适配
在 Cursor 中,你可以创建常用的 Prompt 模板,提高日常工作效率。
模板一:Ansible Role 生成器
请为我创建一个 Ansible Role,要求如下:
【角色名称】:{{role_name}}
【目标系统】:{{target_os}} (Ubuntu 22.04 / CentOS 9)
【功能描述】:{{description}}
【需要安装的软件包】:{{packages}}
【需要配置的端口】:{{ports}}
【配置文件路径】:{{config_path}}
【服务管理】:使用 systemd
【变量化要求】:所有可能变化的值都提取为变量
【幂等性】:确保多次执行结果一致
【Handler】:配置变更后自动重启服务
请生成完整的 Role 目录结构,包含 tasks、handlers、templates、
defaults、vars、meta 所有子目录的文件内容。
模板二:Terraform 模块生成器
请为我创建一个 Terraform 模块,要求如下:
【模块名称】:{{module_name}}
【云提供商】:{{provider}} (AWS / Alicloud / Azure)
【资源类型】:{{resource_type}}
【核心功能】:{{description}}
【输入变量】:
- 环境标识 (environment)
- 项目名称 (project_name)
- 区域/可用区
- {{custom_vars}}
【输出值】:
- 资源 ID
- 资源名称
- {{custom_outputs}}
【标签要求】:
- Environment
- Project
- ManagedBy = "terraform"
- CreatedAt
【安全要求】:{{security_requirements}}
请生成 main.tf、variables.tf、outputs.tf、README.md 四个文件。
模板三:故障排查助手
我遇到了以下运维问题,请帮我分析和解决:
【错误信息】:
{{error_message}}
【执行环境】:
- 操作系统:{{os}}
- 工具版本:{{tool_version}}
- 执行命令:{{command}}
【已尝试的解决方案】:
{{attempted_solutions}}
【相关配置文件】:
{{config_content}}
请分析:
1. 错误的根本原因
2. 推荐的解决方案(按优先级排序)
3. 如何避免此类问题再次发生
4. 相关的最佳实践建议
2.6 模型选择策略与 Token 管理
不同场景的模型选择建议:
| 任务类型 | 推荐模型 | 原因 |
|---|---|---|
| 简单代码补全 | Claude 3.5 Haiku / GPT-4o-mini | 速度快,成本低 |
| Playbook 编写 | Claude 3.5 Sonnet / GPT-4o | 理解能力强,代码质量高 |
| 复杂架构设计 | Claude 3.5 Opus / GPT-4 | 推理能力最强 |
| 代码审查 | Claude 3.5 Sonnet | 细致,能发现潜在问题 |
| 错误排查 | Claude 3.5 Sonnet / GPT-4o | 需要广泛的知识库 |
Token 管理技巧:
- 精简上下文 :只引用必要的文件,避免
@codebase引入过多无关代码 - 分步执行:将大任务拆分为小步骤,每步独立对话
- 利用 .cursorrules:将规范写入规则文件,减少每次重复描述
- 及时开启新对话:上下文过长时,AI 性能会下降
三、利用 Cursor 快速生成标准化 Ansible 剧本
3.1 Ansible 基础概念与目录规范
在开始生成代码之前,确保你理解 Ansible 的核心概念:
- Playbook:定义"做什么"的 YAML 文件,包含一个或多个 Play
- Task:Playbook 中的最小执行单元,调用一个模块
- Role:可复用的 Playbook 组织单元
- Inventory:定义受管主机的清单
- Module:Ansible 执行具体操作的代码单元
- Handler:被通知时触发的特殊 Task(如重启服务)
- Variable:参数化配置
- Template:Jinja2 模板文件
标准 Role 目录结构:
roles/
└── nginx/
├── defaults/
│ └── main.yml # 默认变量(优先级最低)
├── vars/
│ └── main.yml # 角色变量(优先级较高)
├── tasks/
│ ├── main.yml # 任务入口
│ ├── install.yml # 安装相关任务
│ ├── configure.yml # 配置相关任务
│ └── service.yml # 服务管理任务
├── handlers/
│ └── main.yml # Handler 定义
├── templates/
│ ├── nginx.conf.j2 # Jinja2 模板
│ └── vhost.conf.j2 # 虚拟主机模板
├── files/
│ └── index.html # 静态文件
├── meta/
│ └── main.yml # 角色元数据(依赖关系)
├── tests/
│ ├── inventory
│ └── test.yml # 测试 Playbook
└── README.md # 角色说明文档
3.2 使用自然语言生成 Playbook 骨架
在 Cursor Composer 中输入以下 Prompt:
创建一个 Ansible Playbook 用于在 Ubuntu 22.04 服务器上部署 Nginx Web 服务:
要求:
1. 更新 apt 缓存
2. 安装 nginx 和必要工具(curl, vim)
3. 配置 nginx 主配置文件(使用模板)
4. 创建一个简单的虚拟主机配置
5. 确保 nginx 服务启动并设置开机自启
6. 配置 UFW 防火墙允许 80 和 443 端口
7. 所有操作需要幂等
8. 使用 become 提权
9. 添加适当的 tags 便于选择性执行
AI 生成的代码:
yaml
---
# playbooks/deploy-nginx.yml
# Nginx Web 服务自动化部署 Playbook
# 目标系统:Ubuntu 22.04 LTS
# 用法:ansible-playbook playbooks/deploy-nginx.yml -i inventory/hosts.yml
- name: 部署 Nginx Web 服务
hosts: webservers
become: true # 提权执行
gather_facts: true # 收集目标主机信息
vars:
nginx_version: "latest" # Nginx 版本
http_port: 80 # HTTP 端口
https_port: 443 # HTTPS 端口
server_name: "example.com" # 服务器名称
web_root: "/var/www/html" # Web 根目录
worker_processes: "auto" # Worker 进程数(auto=CPU核心数)
worker_connections: 1024 # 每个 Worker 最大连接数
tasks:
# ========== 系统准备阶段 ==========
- name: 更新 apt 软件包缓存
ansible.builtin.apt:
update_cache: yes # 等同于 apt-get update
cache_valid_time: 3600 # 缓存有效期 1 小时,避免频繁更新
tags:
- system
- prepare
- name: 安装基础依赖工具
ansible.builtin.apt:
name:
- curl # HTTP 请求工具
- vim # 文本编辑器
- gnupg2 # GPG 工具
- software-properties-common # 软件源管理
state: present # 确保已安装
tags:
- system
- prepare
# ========== Nginx 安装阶段 ==========
- name: 安装 Nginx
ansible.builtin.apt:
name: "nginx={{ nginx_version }}" if nginx_version != "latest" else "nginx"
state: "{{ 'present' if nginx_version == 'latest' else 'present' }}"
update_cache: no # 前面已更新,无需重复
tags:
- nginx
- install
- name: 确保 Nginx 服务已启动并设置开机自启
ansible.builtin.systemd:
name: nginx
state: started # 确保运行中
enabled: yes # 开机自启
daemon_reload: yes # 重载 systemd 配置
tags:
- nginx
- service
# ========== Nginx 配置阶段 ==========
- name: 创建 Web 根目录
ansible.builtin.file:
path: "{{ web_root }}"
state: directory # 确保目录存在
owner: www-data # 属主
group: www-data # 属组
mode: "0755" # 权限
tags:
- nginx
- configure
- name: 部署 Nginx 主配置文件
ansible.builtin.template:
src: templates/nginx.conf.j2 # Jinja2 模板源
dest: /etc/nginx/nginx.conf # 目标路径
owner: root
group: root
mode: "0644"
backup: yes # 修改前备份原文件
notify: Reload Nginx # 配置变更时触发 Handler
tags:
- nginx
- configure
- name: 部署默认虚拟主机配置
ansible.builtin.template:
src: templates/vhost.conf.j2
dest: "/etc/nginx/sites-available/{{ server_name }}.conf"
owner: root
group: root
mode: "0644"
notify: Reload Nginx
tags:
- nginx
- configure
- name: 启用虚拟主机(创建符号链接)
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ server_name }}.conf"
dest: "/etc/nginx/sites-enabled/{{ server_name }}.conf"
state: link # 创建符号链接
notify: Reload Nginx
tags:
- nginx
- configure
- name: 移除默认站点配置(避免冲突)
ansible.builtin.file:
path: /etc/nginx/sites-enabled/default
state: absent # 确保不存在
notify: Reload Nginx
tags:
- nginx
- configure
# ========== 防火墙配置阶段 ==========
- name: 配置 UFW 允许 HTTP 流量
community.general.ufw:
rule: allow
port: "{{ http_port }}"
proto: tcp
comment: "Allow HTTP traffic"
tags:
- firewall
- security
- name: 配置 UFW 允许 HTTPS 流量
community.general.ufw:
rule: allow
port: "{{ https_port }}"
proto: tcp
comment: "Allow HTTPS traffic"
tags:
- firewall
- security
- name: 确保 UFW 防火墙已启用
community.general.ufw:
state: enabled
policy: deny # 默认拒绝所有入站
tags:
- firewall
- security
# ========== 验证阶段 ==========
- name: 等待 Nginx 端口就绪
ansible.builtin.wait_for:
port: "{{ http_port }}"
host: "127.0.0.1"
delay: 2 # 等待 2 秒后开始检查
timeout: 30 # 最多等待 30 秒
state: started # 等待端口处于监听状态
tags:
- nginx
- verify
- name: 验证 Nginx 响应
ansible.builtin.uri:
url: "http://127.0.0.1:{{ http_port }}"
status_code: 200 # 期望返回 200
return_content: no
register: nginx_check
retries: 3 # 失败重试 3 次
delay: 5 # 每次重试间隔 5 秒
until: nginx_check.status == 200
tags:
- nginx
- verify
handlers:
- name: Reload Nginx
ansible.builtin.systemd:
name: nginx
state: reloaded # 优雅重载,不中断连接
- name: Restart Nginx
ansible.builtin.systemd:
name: nginx
state: restarted # 完全重启
3.3 Roles 角色化拆分与 AI 辅助重构
当 Playbook 变得复杂时,需要拆分为 Role。在 Cursor 中,你可以让 AI 帮你重构:
Prompt:
@playbooks/deploy-nginx.yml
请将这个 Playbook 重构为标准的 Ansible Role 结构,
拆分为 install、configure、service 三个任务文件,
并创建对应的 templates 和 defaults。
AI 重构后的文件结构:
yaml
# roles/nginx/tasks/main.yml
---
# Nginx 角色 - 任务入口文件
# 按顺序引入各子任务文件
- name: 引入安装任务
ansible.builtin.import_tasks: install.yml
tags:
- nginx
- install
- name: 引入配置任务
ansible.builtin.import_tasks: configure.yml
tags:
- nginx
- configure
- name: 引入服务管理任务
ansible.builtin.import_tasks: service.yml
tags:
- nginx
- service
yaml
# roles/nginx/tasks/install.yml
---
# Nginx 安装相关任务
- name: 更新 apt 缓存
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: 安装 Nginx 及依赖
ansible.builtin.apt:
name:
- nginx
- curl
state: present
when: ansible_os_family == "Debian"
- name: 安装 Nginx (RedHat 系列)
ansible.builtin.yum:
name:
- nginx
- curl
state: present
when: ansible_os_family == "RedHat"
yaml
# roles/nginx/tasks/configure.yml
---
# Nginx 配置相关任务
- name: 创建必要目录
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: "0755"
loop:
- "{{ nginx_web_root }}"
- /etc/nginx/conf.d
- /etc/nginx/snippets
- name: 部署主配置文件
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: "0644"
backup: yes
validate: "nginx -t -c %s" # 部署前验证配置语法
notify: Reload Nginx
- name: 部署站点配置
ansible.builtin.template:
src: vhost.conf.j2
dest: "/etc/nginx/sites-available/{{ nginx_server_name }}.conf"
owner: root
group: root
mode: "0644"
backup: yes
notify: Reload Nginx
- name: 启用站点
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ nginx_server_name }}.conf"
dest: "/etc/nginx/sites-enabled/{{ nginx_server_name }}.conf"
state: link
notify: Reload Nginx
- name: 移除默认站点
ansible.builtin.file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload Nginx
when: nginx_remove_default_site | bool
yaml
# roles/nginx/defaults/main.yml
---
# Nginx 角色 - 默认变量
# 这些变量优先级最低,可在 inventory 或 playbook 中覆盖
# 基础配置
nginx_server_name: "example.com"
nginx_web_root: "/var/www/html"
nginx_http_port: 80
nginx_https_port: 443
# 性能配置
nginx_worker_processes: "auto"
nginx_worker_connections: 1024
nginx_keepalive_timeout: 65
nginx_client_max_body_size: "10m"
# 安全配置
nginx_server_tokens: "off" # 隐藏版本号
nginx_remove_default_site: true # 移除默认站点
# SSL 配置(默认关闭)
nginx_ssl_enabled: false
nginx_ssl_certificate: ""
nginx_ssl_certificate_key: ""
# 日志配置
nginx_access_log: "/var/log/nginx/access.log"
nginx_error_log: "/var/log/nginx/error.log"
nginx_log_format: "combined"
# 防火墙配置
nginx_configure_firewall: true
nginx_allowed_ips: [] # 空数组表示允许所有
yaml
# roles/nginx/handlers/main.yml
---
# Nginx Handler 定义
# Handler 只在被 notify 触发时执行,且每个 Play 结束前只执行一次
- name: Reload Nginx
ansible.builtin.systemd:
name: nginx
state: reloaded
listen: "nginx reload" # 使用 listen 允许多个名称触发
- name: Restart Nginx
ansible.builtin.systemd:
name: nginx
state: restarted
listen: "nginx restart"
- name: Test Nginx Config
ansible.builtin.command: nginx -t
changed_when: false # 此操作不会改变系统状态
listen: "nginx test"
3.4 变量管理与 Vault 加密配置
yaml
# inventory/group_vars/webservers.yml
---
# Web 服务器组变量
# 应用配置
app_name: "my-webapp"
app_version: "2.1.0"
app_port: 8080
# Nginx 配置覆盖
nginx_server_name: "web.example.com"
nginx_worker_connections: 2048
# 部署配置
deploy_user: "deploy"
deploy_dir: "/opt/{{ app_name }}"
# 监控配置
enable_monitoring: true
monitoring_port: 9100
yaml
# inventory/group_vars/all/vault.yml (加密前)
---
# 敏感信息 - 必须使用 ansible-vault 加密
vault_db_password: "SuperSecret123!"
vault_api_key: "sk-xxxxxxxxxxxxxxxxxxxx"
vault_ssl_private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY-----
bash
# 使用 Ansible Vault 加密敏感文件
ansible-vault encrypt inventory/group_vars/all/vault.yml
# 创建 vault 密码文件(用于 CI/CD 自动解密)
echo "my-vault-password" > ~/.vault_pass
chmod 600 ~/.vault_pass
# 在 ansible.cfg 中配置自动使用密码文件
# [defaults]
# vault_password_file = ~/.vault_pass
# 编辑加密文件
ansible-vault edit inventory/group_vars/all/vault.yml
# 查看加密文件内容
ansible-vault view inventory/group_vars/all/vault.yml
3.5 Jinja2 模板生成与条件逻辑编写
jinja2
{# roles/nginx/templates/nginx.conf.j2 #}
{# Nginx 主配置模板 - 由 Ansible 管理,请勿手动修改 #}
{# 生成时间:{{ ansible_date_time.iso8601 }} #}
{# 目标主机:{{ inventory_hostname }} #}
user www-data;
worker_processes {{ nginx_worker_processes }};
pid /run/nginx.pid;
{# 错误日志配置 #}
error_log {{ nginx_error_log }} warn;
events {
worker_connections {{ nginx_worker_connections }};
multi_accept on;
use epoll;
}
http {
{# ===== 基础设置 ===== #}
include /etc/nginx/mime.types;
default_type application/octet-stream;
{# ===== 日志格式 ===== #}
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time';
access_log {{ nginx_access_log }} main;
{# ===== 性能优化 ===== #}
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout {{ nginx_keepalive_timeout }};
types_hash_max_size 2048;
client_max_body_size {{ nginx_client_max_body_size }};
{# ===== 安全设置 ===== #}
server_tokens {{ nginx_server_tokens }};
{# 隐藏不必要的响应头 #}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
{# ===== Gzip 压缩 ===== #}
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json
application/javascript text/xml application/xml
application/xml+rss text/javascript image/svg+xml;
{# ===== 速率限制 ===== #}
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s;
{# ===== SSL 全局设置(如果启用)===== #}
{% if nginx_ssl_enabled | bool %}
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
{% endif %}
{# ===== 包含虚拟主机配置 ===== #}
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
jinja2
{# roles/nginx/templates/vhost.conf.j2 #}
{# 虚拟主机配置模板 #}
{# HTTP 服务器块 #}
server {
listen {{ nginx_http_port }};
listen [::]:{{ nginx_http_port }};
server_name {{ nginx_server_name }};
{% if nginx_ssl_enabled | bool %}
{# 如果启用 SSL,HTTP 重定向到 HTTPS #}
return 301 https://$server_name$request_uri;
{% else %}
root {{ nginx_web_root }};
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
{# API 代理(如果配置了后端)#}
{% if app_port is defined %}
location /api/ {
proxy_pass http://127.0.0.1:{{ app_port }}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
{# 超时设置 #}
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
{% endif %}
{# 健康检查端点 #}
location /health {
access_log off;
return 200 "OK\n";
add_header Content-Type text/plain;
}
{# 禁止访问隐藏文件 #}
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
{% endif %}
}
{% if nginx_ssl_enabled | bool %}
{# HTTPS 服务器块 #}
server {
listen {{ nginx_https_port }} ssl http2;
listen [::]:{{ nginx_https_port }} ssl http2;
server_name {{ nginx_server_name }};
ssl_certificate {{ nginx_ssl_certificate }};
ssl_certificate_key {{ nginx_ssl_certificate_key }};
root {{ nginx_web_root }};
index index.html index.htm;
{# HSTS 头 #}
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
try_files $uri $uri/ =404;
}
}
{% endif %}
3.6 Handler 与幂等性保障
幂等性是 Ansible 的核心原则。以下是确保幂等性的关键技巧:
yaml
# 幂等性最佳实践示例
# ✅ 正确:使用 state 参数确保状态
- name: 确保目录存在(幂等)
ansible.builtin.file:
path: /opt/app/data
state: directory
mode: "0755"
# ❌ 错误:使用 command 创建目录(不幂等)
- name: 创建目录(不幂等,每次都会执行)
ansible.builtin.command: mkdir -p /opt/app/data
# ✅ 正确:使用 creates/removes 参数
- name: 初始化数据库(仅在数据目录不存在时执行)
ansible.builtin.command: postgresql-setup initdb
args:
creates: /var/lib/pgsql/data/PG_VERSION
# ✅ 正确:使用 lineinfile 确保配置存在
- name: 确保 SSH 禁止 root 登录
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PermitRootLogin"
line: "PermitRootLogin no"
state: present
notify: Restart SSHD
# ✅ 正确:使用 stat 检查后再操作
- name: 检查配置文件是否存在
ansible.builtin.stat:
path: /etc/app/config.yml
register: config_file
- name: 备份现有配置
ansible.builtin.copy:
src: /etc/app/config.yml
dest: "/etc/app/config.yml.bak.{{ ansible_date_time.date }}"
remote_src: yes
when: config_file.stat.exists
3.7 完整实战:Web 服务自动化部署 Playbook
yaml
---
# playbooks/site.yml - 主入口 Playbook
# 用法:ansible-playbook playbooks/site.yml -i inventory/hosts.yml --limit webservers
- name: 基础系统配置
ansible.builtin.import_playbook: common.yml
tags:
- common
- base
- name: Web 服务部署
ansible.builtin.import_playbook: deploy-web.yml
tags:
- web
- deploy
- name: 监控配置
ansible.builtin.import_playbook: setup-monitoring.yml
tags:
- monitoring
yaml
---
# playbooks/deploy-web.yml - Web 服务完整部署
- name: 部署 Web 应用服务
hosts: webservers
become: true
gather_facts: true
serial: "30%" # 滚动部署,每次 30% 的主机
max_fail_percentage: 20 # 失败超过 20% 则中止
pre_tasks:
- name: 验证目标主机连通性
ansible.builtin.ping:
- name: 检查磁盘空间(至少 2GB 可用)
ansible.builtin.shell: |
df -BG / | awk 'NR==2 {print $4}' | tr -d 'G'
register: disk_space
changed_when: false
- name: 磁盘空间不足则中止
ansible.builtin.fail:
msg: "磁盘空间不足!可用空间 {{ disk_space.stdout }}GB,需要至少 2GB"
when: disk_space.stdout | int < 2
roles:
- role: nginx
tags: [nginx]
- role: app-deploy
tags: [app]
post_tasks:
- name: 执行健康检查
ansible.builtin.uri:
url: "http://localhost/health"
status_code: 200
register: health_check
retries: 5
delay: 10
until: health_check.status == 200
- name: 部署成功通知
ansible.builtin.debug:
msg: "✅ {{ inventory_hostname }} 部署成功!版本:{{ app_version }}"
四、基于自然语言描述构建 Terraform 基础设施代码
4.1 Terraform 核心概念:Provider、Resource、State
核心概念图解:
┌─────────────────────────────────────────────────────────┐
│ Terraform 工作流 │
├─────────────────────────────────────────────────────────┤
│ │
│ 编写 .tf 文件 → terraform init → terraform plan │
│ │ │ │
│ │ ▼ │
│ │ terraform apply │
│ │ │ │
│ ▼ ▼ │
│ HCL 声明式语法 实际云资源创建/修改/删除 │
│ (期望状态) │ │
│ ▼ │
│ State 文件记录实际状态 │
│ (.tfstate) │
└─────────────────────────────────────────────────────────┘
关键术语:
- Provider:与云平台 API 交互的插件(AWS、Azure、Alicloud 等)
- Resource:要管理的基础设施对象(EC2 实例、VPC、S3 桶等)
- Data Source:读取已有基础设施信息(不创建资源)
- State:记录 Terraform 管理的所有资源的当前状态
- Module:可复用的 Terraform 配置包
- Variable:输入参数
- Output:输出值
- Backend:State 文件的存储位置
4.2 自然语言到 HCL 代码的转换技巧
有效的 Prompt 编写技巧:
# ❌ 模糊的描述
"帮我创建一个服务器"
# ✅ 精确的描述
"在 AWS ap-southeast-1 区域创建一台 EC2 实例:
- 实例类型:t3.medium
- AMI:Ubuntu 22.04 LTS(使用 data source 查找最新 AMI)
- VPC:使用已有 VPC(ID 通过变量传入)
- 子网:公共子网
- 安全组:允许 22(SSH)、80(HTTP)、443(HTTPS) 入站
- 根卷:50GB gp3
- 标签:Name=web-server-01, Environment=production
- 启用详细监控
- 关联 Elastic IP"
转换对照表:
| 自然语言 | HCL 对应 |
|---|---|
| "创建一台服务器" | resource "aws_instance" "web" {} |
| "在 VPC 内" | vpc_id = var.vpc_id |
| "允许 80 端口" | ingress { from_port = 80 ... } |
| "使用最新的 Ubuntu" | data "aws_ami" "ubuntu" {} |
| "标签" | tags = { ... } |
| "输出 IP 地址" | output "public_ip" { value = ... } |
4.3 VPC 网络基础设施代码生成
Cursor Prompt:
创建一个 AWS VPC 模块,包含:
- VPC(CIDR: 10.0.0.0/16)
- 2 个公有子网(跨 AZ)
- 2 个私有子网(跨 AZ)
- Internet Gateway
- NAT Gateway(每个 AZ 一个)
- 路由表(公有、私有各一个)
- 所有资源带标准标签
生成的代码:
hcl
# terraform/modules/vpc/main.tf
# AWS VPC 网络基础设施模块
# 提供完整的网络隔离和 NAT 出口能力
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# ===== 数据源:获取可用区信息 =====
data "aws_availability_zones" "available" {
state = "available"
}
# ===== VPC 主体 =====
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_support = true # 启用 DNS 解析
enable_dns_hostnames = true # 启用 DNS 主机名
tags = {
Name = "${var.project_name}-vpc"
}
}
# ===== Internet Gateway(VPC 互联网出口)=====
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-igw"
}
}
# ===== 公有子网(可访问互联网)=====
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true # 自动分配公网 IP
tags = {
Name = "${var.project_name}-public-${count.index + 1}"
Type = "public"
# K8s 需要的标签(如果使用 EKS)
"kubernetes.io/role/elb" = "1"
}
}
# ===== 私有子网(仅内网访问)=====
resource "aws_subnet" "private" {
count = length(var.private_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnet_cidrs[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.project_name}-private-${count.index + 1}"
Type = "private"
"kubernetes.io/role/internal-elb" = "1"
}
}
# ===== Elastic IP(NAT Gateway 使用)=====
resource "aws_eip" "nat" {
count = var.nat_gateway_count
domain = "vpc"
tags = {
Name = "${var.project_name}-nat-eip-${count.index + 1}"
}
depends_on = [aws_internet_gateway.main]
}
# ===== NAT Gateway(私有子网出网)=====
resource "aws_nat_gateway" "main" {
count = var.nat_gateway_count
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id # NAT 必须在公有子网
tags = {
Name = "${var.project_name}-nat-${count.index + 1}"
}
depends_on = [aws_internet_gateway.main]
}
# ===== 公有路由表 =====
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
# 默认路由指向 Internet Gateway
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${var.project_name}-public-rt"
}
}
# ===== 私有路由表 =====
resource "aws_route_table" "private" {
count = var.nat_gateway_count
vpc_id = aws_vpc.main.id
# 默认路由指向 NAT Gateway
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main[count.index].id
}
tags = {
Name = "${var.project_name}-private-rt-${count.index + 1}"
}
}
# ===== 路由表关联 =====
# 公有子网关联公有路由表
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# 私有子网关联私有路由表
resource "aws_route_table_association" "private" {
count = length(aws_subnet.private)
subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private[count.index % var.nat_gateway_count].id
}
hcl
# terraform/modules/vpc/variables.tf
# VPC 模块输入变量定义
variable "project_name" {
description = "项目名称,用于资源命名前缀"
type = string
}
variable "vpc_cidr" {
description = "VPC CIDR 地址段"
type = string
default = "10.0.0.0/16"
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "VPC CIDR 格式无效,请使用标准 CIDR 表示法,如 10.0.0.0/16"
}
}
variable "public_subnet_cidrs" {
description = "公有子网 CIDR 列表"
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
variable "private_subnet_cidrs" {
description = "私有子网 CIDR 列表"
type = list(string)
default = ["10.0.10.0/24", "10.0.11.0/24"]
}
variable "nat_gateway_count" {
description = "NAT Gateway 数量(建议与 AZ 数量一致)"
type = number
default = 2
validation {
condition = var.nat_gateway_count >= 1 && var.nat_gateway_count <= 3
error_message = "NAT Gateway 数量必须在 1-3 之间"
}
}
hcl
# terraform/modules/vpc/outputs.tf
# VPC 模块输出值
output "vpc_id" {
description = "VPC ID"
value = aws_vpc.main.id
}
output "vpc_cidr" {
description = "VPC CIDR 地址段"
value = aws_vpc.main.cidr_block
}
output "public_subnet_ids" {
description = "公有子网 ID 列表"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "私有子网 ID 列表"
value = aws_subnet.private[*].id
}
output "internet_gateway_id" {
description = "Internet Gateway ID"
value = aws_internet_gateway.main.id
}
output "nat_gateway_ids" {
description = "NAT Gateway ID 列表"
value = aws_nat_gateway.main[*].id
}
4.4 计算资源(EC2/ECS)自动化创建
hcl
# terraform/modules/ec2/main.tf
# EC2 实例模块 - 支持单台或多台实例
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# 查找最新的 Ubuntu 22.04 AMI
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical 官方账号 ID
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
}
# 安全组
resource "aws_security_group" "instance" {
name_prefix = "${var.project_name}-${var.instance_name}-sg"
vpc_id = var.vpc_id
description = "Security group for ${var.instance_name}"
# SSH 入站(限制来源 IP)
dynamic "ingress" {
for_each = var.allowed_ssh_cidrs
content {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [ingress.value]
description = "SSH access from ${ingress.value}"
}
}
# HTTP 入站
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP access"
}
# HTTPS 入站
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS access"
}
# 所有出站
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound"
}
tags = {
Name = "${var.project_name}-${var.instance_name}-sg"
}
lifecycle {
create_before_destroy = true # 先创建新 SG 再删除旧的
}
}
# EC2 实例
resource "aws_instance" "main" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
subnet_id = var.subnet_id
vpc_security_group_ids = [aws_security_group.instance.id]
key_name = var.ssh_key_name
# 根卷配置
root_block_device {
volume_type = "gp3"
volume_size = var.root_volume_size
encrypted = true
delete_on_termination = true
iops = 3000
throughput = 125
}
# 监控
monitoring = var.enable_detailed_monitoring
# 元数据服务安全配置(IMDSv2)
metadata_options {
http_endpoint = "enabled"
http_tokens = "required" # 强制 IMDSv2
http_put_response_hop_limit = 1
}
# 用户数据(初始化脚本)
user_data = templatefile("${path.module}/templates/user_data.sh.tpl", {
hostname = var.instance_name
app_port = var.app_port
environment = var.environment
})
tags = {
Name = "${var.project_name}-${var.instance_name}"
Environment = var.environment
Role = var.instance_role
}
# 生命周期规则
lifecycle {
ignore_changes = [
user_data, # 忽略 user_data 变更(避免重建)
]
}
}
# Elastic IP(可选)
resource "aws_eip" "instance" {
count = var.assign_eip ? 1 : 0
instance = aws_instance.main.id
domain = "vpc"
tags = {
Name = "${var.project_name}-${var.instance_name}-eip"
}
}
4.5 模块化设计与变量参数化
hcl
# terraform/environments/development/main.tf
# 开发环境 - 主配置文件
# 组合各模块构建完整基础设施
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# 远程 State 存储(S3 + DynamoDB 锁)
backend "s3" {
bucket = "gitops-terraform-state"
key = "development/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = "development"
Project = var.project_name
ManagedBy = "terraform"
Team = "platform"
}
}
}
# ===== VPC 模块 =====
module "vpc" {
source = "../../modules/vpc"
project_name = var.project_name
vpc_cidr = "10.0.0.0/16"
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnet_cidrs = ["10.0.10.0/24", "10.0.11.0/24"]
nat_gateway_count = 1 # 开发环境只需 1 个 NAT(节省成本)
}
# ===== Web 服务器模块 =====
module "web_server" {
source = "../../modules/ec2"
project_name = var.project_name
instance_name = "web-01"
instance_type = "t3.medium"
environment = "development"
instance_role = "webserver"
vpc_id = module.vpc.vpc_id
subnet_id = module.vpc.public_subnet_ids[0]
ssh_key_name = var.ssh_key_name
allowed_ssh_cidrs = var.allowed_ssh_cidrs
root_volume_size = 50
assign_eip = true
app_port = 8080
}
# ===== 数据库模块(示例)=====
# module "database" {
# source = "../../modules/rds"
# ...
# }
4.6 State 管理与远程后端配置
State 文件是 Terraform 的核心数据,记录了所有受管资源的实际状态。在生产环境中,必须使用远程后端存储 State,避免本地丢失或团队冲突。
hcl
# terraform/backend/s3-backend-setup.tf
# 此文件用于一次性创建 State 存储基础设施
# 执行:terraform apply -target=aws_s3_bucket.terraform_state
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-southeast-1"
}
# ===== S3 存储桶:存放 Terraform State 文件 =====
resource "aws_s3_bucket" "terraform_state" {
bucket = "gitops-terraform-state-2024"
# 防止意外删除
lifecycle {
prevent_destroy = true
}
tags = {
Name = "terraform-state-bucket"
Purpose = "Terraform State Storage"
ManagedBy = "manual"
}
}
# 启用版本控制(可恢复误删的 State)
resource "aws_s3_bucket_versioning" "state_versioning" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
# 服务端加密(保护 State 中的敏感数据)
resource "aws_s3_bucket_server_side_encryption_configuration" "state_encryption" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms" # 使用 KMS 加密
}
bucket_key_enabled = true
}
}
# 阻止所有公共访问
resource "aws_s3_bucket_public_access_block" "state_access" {
bucket = aws_s3_bucket.terraform_state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# 生命周期规则:旧版本 State 90 天后转入冷存储
resource "aws_s3_bucket_lifecycle_configuration" "state_lifecycle" {
bucket = aws_s3_bucket.terraform_state.id
rule {
id = "state-versioning-lifecycle"
status = "Enabled"
# 非当前版本 90 天后转为 IA 存储
noncurrent_version_transition {
noncurrent_days = 90
storage_class = "STANDARD_IA"
}
# 非当前版本 365 天后删除
noncurrent_version_expiration {
noncurrent_days = 365
}
}
}
# ===== DynamoDB 表:State 锁(防止并发操作冲突)=====
resource "aws_dynamodb_table" "terraform_lock" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST" # 按需付费(锁操作频率低)
hash_key = "LockID" # 锁的唯一标识
attribute {
name = "LockID"
type = "S" # String 类型
}
tags = {
Name = "terraform-state-lock"
Purpose = "Terraform State Locking"
ManagedBy = "manual"
}
}
# ===== 输出 =====
output "state_bucket_name" {
description = "State 存储桶名称"
value = aws_s3_bucket.terraform_state.id
}
output "lock_table_name" {
description = "State 锁表名称"
value = aws_dynamodb_table.terraform_lock.id
}
在各环境中引用远程后端:
hcl
# terraform/environments/production/main.tf(头部)
terraform {
required_version = ">= 1.6.0"
backend "s3" {
# State 文件在 S3 中的路径
bucket = "gitops-terraform-state-2024"
key = "production/terraform.tfstate"
region = "ap-southeast-1"
# DynamoDB 锁表(防止多人同时 apply)
dynamodb_table = "terraform-state-lock"
# 加密
encrypt = true
# 可选:使用 KMS 自定义密钥
# kms_key_id = "arn:aws:kms:ap-southeast-1:123456789:key/xxx"
}
}
State 管理常用命令:
bash
# 查看当前 State 中的资源列表
terraform state list
# 查看某个资源的详细属性
terraform state show aws_instance.web
# 从 State 中移除资源(不销毁实际资源)
terraform state rm aws_instance.old_server
# 导入已有资源到 State
terraform import aws_instance.existing i-1234567890abcdef0
# 备份 State(重要操作前必做)
terraform state pull > backup_$(date +%Y%m%d_%H%M%S).tfstate
# 强制解锁(仅在确认无人操作时使用)
terraform force-unlock LOCK_ID
# State 迁移(更换后端时使用)
terraform init -migrate-state
4.7 完整实战:多云环境基础设施编排
以下是一个完整的生产级 Terraform 项目,编排 AWS 上的完整 Web 应用基础设施:
hcl
# terraform/environments/production/main.tf
# 生产环境 - 完整基础设施编排
# 包含:VPC + EC2 + RDS + ALB + Route53 + CloudWatch
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.6"
}
}
backend "s3" {
bucket = "gitops-terraform-state-2024"
key = "production/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
# ===== Provider 配置 =====
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = "production"
Project = var.project_name
ManagedBy = "terraform"
Team = "platform-engineering"
CostCenter = "engineering"
}
}
}
# 生成随机后缀(避免资源名冲突)
resource "random_string" "suffix" {
length = 6
special = false
upper = false
}
# ===== 数据源 =====
# 获取当前账号信息
data "aws_caller_identity" "current" {}
# 获取可用区
data "aws_availability_zones" "available" {
state = "available"
}
# ===== 网络层 =====
module "network" {
source = "../../modules/vpc"
project_name = var.project_name
vpc_cidr = "10.100.0.0/16"
public_subnet_cidrs = ["10.100.1.0/24", "10.100.2.0/24"]
private_subnet_cidrs = ["10.100.10.0/24", "10.100.11.0/24"]
nat_gateway_count = 2 # 生产环境每个 AZ 一个 NAT
}
# ===== 安全组 =====
module "security_groups" {
source = "../../modules/security-group"
project_name = var.project_name
vpc_id = module.network.vpc_id
# ALB 安全组
alb_security_group_name = "${var.project_name}-alb-sg"
alb_ingress_rules = [
{
port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP"
},
{
port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS"
}
]
# 应用服务器安全组
app_security_group_name = "${var.project_name}-app-sg"
app_ingress_rules = [
{
port = 8080
protocol = "tcp"
source_security_group_id = module.security_groups.alb_sg_id
description = "App traffic from ALB"
},
{
port = 22
protocol = "tcp"
cidr_blocks = var.bastion_allowed_cidrs
description = "SSH from bastion"
}
]
# 数据库安全组
db_security_group_name = "${var.project_name}-db-sg"
db_ingress_rules = [
{
port = 5432
protocol = "tcp"
source_security_group_id = module.security_groups.app_sg_id
description = "PostgreSQL from app servers"
}
]
}
# ===== 应用服务器 =====
module "app_servers" {
source = "../../modules/ec2"
for_each = toset(["web-01", "web-02"]) # 创建 2 台
project_name = var.project_name
instance_name = each.value
instance_type = "t3.large"
environment = "production"
instance_role = "webserver"
vpc_id = module.network.vpc_id
subnet_id = module.network.private_subnet_ids[index(keys(toset(["web-01", "web-02"])), each.value)]
ssh_key_name = var.ssh_key_name
allowed_ssh_cidrs = var.bastion_allowed_cidrs
root_volume_size = 100
assign_eip = false # 私有子网不需要 EIP
app_port = 8080
}
# ===== 应用负载均衡器 =====
module "alb" {
source = "../../modules/alb"
project_name = var.project_name
vpc_id = module.network.vpc_id
subnet_ids = module.network.public_subnet_ids
security_groups = [module.security_groups.alb_sg_id]
# 目标组配置
target_group_port = 8080
target_group_protocol = "HTTP"
health_check_path = "/health"
health_check_interval = 30
# 监听器配置
http_listener = true
https_listener = true
ssl_certificate_arn = var.ssl_certificate_arn
}
# ===== 数据库 =====
module "database" {
source = "../../modules/rds"
project_name = var.project_name
environment = "production"
instance_class = "db.t3.medium"
engine = "postgres"
engine_version = "15.4"
allocated_storage = 100
vpc_id = module.network.vpc_id
subnet_ids = module.network.private_subnet_ids
security_group_id = module.security_groups.db_sg_id
db_name = "appdb"
username = "appadmin"
# 生产环境配置
multi_az = true # 多 AZ 高可用
deletion_protection = true # 防止误删
backup_retention = 7 # 备份保留 7 天
storage_encrypted = true # 存储加密
}
# ===== DNS 配置 =====
resource "aws_route53_record" "app" {
zone_id = var.route53_zone_id
name = "app.${var.domain_name}"
type = "A"
alias {
name = module.alb.dns_name
zone_id = module.alb.zone_id
evaluate_target_health = true
}
}
# ===== CloudWatch 告警 =====
resource "aws_cloudwatch_metric_alarm" "high_cpu" {
alarm_name = "${var.project_name}-high-cpu"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 3
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
alarm_description = "CPU 使用率超过 80% 持续 15 分钟"
alarm_actions = [var.sns_topic_arn]
dimensions = {
InstanceId = module.app_servers["web-01"].instance_id
}
tags = {
Name = "${var.project_name}-cpu-alarm"
}
}
hcl
# terraform/environments/production/variables.tf
# 生产环境变量定义
variable "aws_region" {
description = "AWS 部署区域"
type = string
default = "ap-southeast-1"
}
variable "project_name" {
description = "项目名称"
type = string
default = "gitops-webapp"
}
variable "domain_name" {
description = "应用域名"
type = string
default = "example.com"
}
variable "ssh_key_name" {
description = "EC2 SSH 密钥对名称"
type = string
sensitive = true
}
variable "bastion_allowed_cidrs" {
description = "允许 SSH 访问的 CIDR 列表"
type = list(string)
default = [] # 默认为空,必须显式配置
validation {
condition = length(var.bastion_allowed_cidrs) > 0
error_message = "必须至少配置一个允许 SSH 访问的 CIDR 地址"
}
}
variable "ssl_certificate_arn" {
description = "ACM SSL 证书 ARN"
type = string
sensitive = true
}
variable "route53_zone_id" {
description = "Route53 托管区域 ID"
type = string
}
variable "sns_topic_arn" {
description = "告警通知 SNS Topic ARN"
type = string
}
hcl
# terraform/environments/production/outputs.tf
# 生产环境输出值
output "vpc_id" {
description = "VPC ID"
value = module.network.vpc_id
}
output "alb_dns_name" {
description = "应用负载均衡器 DNS 名称"
value = module.alb.dns_name
}
output "app_url" {
description = "应用访问 URL"
value = "https://app.${var.domain_name}"
}
output "database_endpoint" {
description = "数据库连接地址"
value = module.database.endpoint
sensitive = true # 标记为敏感,不会在终端显示
}
output "app_server_ids" {
description = "应用服务器实例 ID"
value = { for k, v in module.app_servers : k => v.instance_id }
}
五、集成 Git 工作流实现代码版本管理与协作
5.1 GitOps 核心理念与运维场景映射
GitOps 是一种以 Git 仓库为唯一事实来源(Single Source of Truth)管理基础设施和应用的运维方法论。
GitOps 四大原则:
| 原则 | 含义 | 运维映射 |
|---|---|---|
| 声明式 | 用代码描述期望状态 | Terraform/Ansible 配置 |
| 版本化 | 所有变更通过 Git 提交 | 每次部署都有记录 |
| 自动同步 | 自动将实际状态向期望状态收敛 | CI/CD 自动执行 |
| 可审计 | 所有变更可追溯 | Git log + PR 审查 |
传统运维 vs GitOps 运维:
传统运维:
工程师 → SSH 到服务器 → 手动修改 → 祈祷不出错
问题:无记录、不可复现、无法回滚
GitOps 运维:
工程师 → 修改代码 → Git 提交 → PR 审查 → 合并 → CI/CD 自动执行
优势:有记录、可复现、秒级回滚、多人协作
5.2 仓库结构设计与分支策略
推荐的仓库结构(Mono-repo 模式):
gitops-infrastructure/
├── .github/
│ ├── workflows/ # CI/CD 流水线
│ ├── CODEOWNERS # 代码所有者
│ └── pull_request_template.md
├── ansible/ # 配置管理
├── terraform/ # 基础设施编排
├── docs/ # 文档
├── scripts/ # 工具脚本
├── .cursorrules # AI 规则
├── .pre-commit-config.yaml # 提交前检查
├── Makefile # 命令入口
└── README.md
分支策略(Git Flow 简化版):
main (生产环境)
│
├── develop (开发/测试环境)
│ │
│ ├── feature/add-monitoring ← 新功能
│ ├── feature/upgrade-nginx ← 新功能
│ └── fix/security-patch ← 修复
│
├── release/v2.1.0 ← 发布准备
│
└── hotfix/critical-db-fix ← 紧急修复(从 main 拉出)
分支保护规则(GitHub Settings → Branches):
yaml
# main 分支保护
- 禁止直接推送
- 必须通过 Pull Request
- 至少 1 人审查通过
- 所有 CI 检查必须通过
- 必须签名提交(可选)
# develop 分支保护
- 禁止直接推送(管理员除外)
- 必须通过 Pull Request
- CI 检查通过
5.3 Commit 规范与自动化提交信息生成
Conventional Commits 规范:
<type>(<scope>): <subject>
[body]
[footer]
Type 类型说明:
| Type | 含义 | 示例 |
|---|---|---|
feat |
新功能 | feat(nginx): 添加 SSL 自动续期配置 |
fix |
修复 | fix(terraform): 修复安全组规则冲突 |
docs |
文档 | docs(ansible): 更新部署手册 |
refactor |
重构 | refactor(vpc): 拆分子网模块 |
chore |
杂务 | chore(deps): 升级 Ansible 到 2.16 |
ci |
CI/CD | ci(github): 添加 Terraform plan 步骤 |
perf |
性能 | perf(nginx): 优化 worker 连接数 |
security |
安全 | security(iam): 收紧 S3 访问策略 |
使用 Cursor AI 生成 Commit Message:
在 Cursor 中,暂存文件后,打开 AI 聊天(Ctrl+L),输入:
请根据以下 git diff 生成符合 Conventional Commits 规范的提交信息:
@git
配置 commitlint 强制规范:
bash
# 安装 commitlint
npm install -g @commitlint/cli @commitlint/config-conventional
# 创建配置文件
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
// type 必须是以下之一
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'chore', 'ci', 'security', 'revert'
]],
// scope 最大长度
'scope-max-length': [2, 'always', 20],
// subject 最大长度
'subject-max-length': [2, 'always', 72],
// subject 不以句号结尾
'subject-full-stop': [2, 'never', '.'],
// body 最大行长度
'body-max-line-length': [1, 'always', 100],
}
};
EOF
5.4 Pull Request 审查流程与 AI 辅助 Code Review
PR 模板(.github/pull_request_template.md):
markdown
## 变更描述
<!-- 简要描述本次变更的内容和目的 -->
## 变更类型
- [ ] 新功能 (feat)
- [ ] 修复 (fix)
- [ ] 重构 (refactor)
- [ ] 配置变更 (chore)
- [ ] 文档更新 (docs)
- [ ] 安全修复 (security)
## 影响范围
<!-- 本次变更影响哪些环境/服务 -->
- [ ] Development
- [ ] Staging
- [ ] Production
## 测试验证
- [ ] 本地 `terraform plan` 通过
- [ ] 本地 `ansible-playbook --syntax-check` 通过
- [ ] 已在开发环境验证
- [ ] 回滚方案已确认
## 变更详情
<!-- 列出主要变更点 -->
1.
2.
3.
## 风险评估
<!-- 是否有破坏性变更?是否需要停机? -->
风险等级:低 / 中 / 高
## 回滚方案
<!-- 如果部署失败,如何回滚 -->
## 截图/日志
<!-- 附上关键输出 -->
使用 Cursor AI 辅助 Code Review:
Prompt:
请审查以下 Terraform 代码变更,关注:
1. 安全问题(开放端口、过度权限)
2. 成本影响(不必要的资源、过大的实例)
3. 最佳实践违反(缺少标签、缺少加密)
4. 潜在的部署风险(破坏性变更)
@git 最近的 diff
5.5 Git Hooks 与 Pre-commit 自动化检查
yaml
# .pre-commit-config.yaml
# Pre-commit 钩子配置
# 安装:pip install pre-commit && pre-commit install
repos:
# ===== 通用检查 =====
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace # 去除行尾空格
- id: end-of-file-fixer # 确保文件以换行结尾
- id: check-yaml # YAML 语法检查
args: ['--allow-multiple-documents']
- id: check-json # JSON 语法检查
- id: check-merge-conflict # 检查未解决的合并冲突
- id: detect-private-key # 检测私钥文件
- id: check-added-large-files # 检查大文件
args: ['--maxkb=1000']
- id: no-commit-to-branch # 禁止直接提交到 main
args: ['--branch', 'main']
# ===== YAML Lint =====
- repo: https://github.com/adrienverge/yamllint
rev: v1.33.0
hooks:
- id: yamllint
args: ['-d', '{extends: relaxed, rules: {line-length: {max: 150}}}']
files: \.(yml|yaml)$
# ===== Ansible Lint =====
- repo: https://github.com/ansible/ansible-lint
rev: v6.22.0
hooks:
- id: ansible-lint
files: ansible/
args: ['-c', 'ansible/.ansible-lint']
# ===== Terraform 检查 =====
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.86.0
hooks:
- id: terraform_fmt # 格式化检查
- id: terraform_validate # 语法验证
- id: terraform_docs # 自动更新文档
args: ['--args=--lockfile=false']
- id: terraform_tflint # Lint 检查
args:
- '--args=--only=terraform_deprecated_interpolation'
- '--args=--only=terraform_unused_declarations'
- '--args=--only=terraform_naming_convention'
- id: terraform_checkov # 安全扫描
args: ['--args=--quiet']
# ===== 密钥检测 =====
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
bash
# 安装 pre-commit
pip install pre-commit
# 初始化(安装所有钩子)
cd gitops-project
pre-commit install
# 手动运行所有检查
pre-commit run --all-files
# 仅运行特定钩子
pre-commit run terraform_fmt --all-files
# 更新钩子到最新版本
pre-commit autoupdate
5.6 多环境分支管理与标签策略
环境对应关系:
分支/标签 → 环境 → 触发方式
─────────────────────────────────────────────────
develop → Development → 推送自动部署
release/* → Staging → 推送自动部署
main → Production → 手动审批后部署
v*.*.* → 版本快照 → 打标签时归档
标签规范:
bash
# 版本标签格式:v主版本.次版本.补丁号
git tag -a v2.1.0 -m "Release v2.1.0: 添加监控告警功能"
# 环境快照标签
git tag -a prod-2024-01-15 -m "Production snapshot 2024-01-15"
# 推送标签
git push origin v2.1.0
git push origin --tags
# 查看所有标签
git tag -l "v*"
# 查看标签详情
git show v2.1.0
六、搭建 CI/CD 流水线自动执行部署脚本
6.1 CI/CD 流水线架构设计
┌─────────────────────────────────────────────────────────────┐
│ CI/CD 流水线架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 开发者推送代码 │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Lint & │───▶│ Plan & │───▶│ Apply & │ │
│ │ Validate │ │ Review │ │ Deploy │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 语法检查 │ │ 变更预览 │ │ 实际部署 │ │
│ │ 安全扫描 │ │ PR 评论 │ │ 健康检查 │ │
│ │ 格式验证 │ │ 人工审批 │ │ 通知推送 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 触发条件: │
│ - Push to develop → Lint + Plan (dev) │
│ - PR to main → Lint + Plan + 审批 │
│ - Merge to main → Apply (production) │
│ - Tag v* → 归档 + 通知 │
└─────────────────────────────────────────────────────────────┘
6.2 GitHub Actions 工作流配置
yaml
# .github/workflows/terraform-plan.yml
# Terraform Plan 工作流 - 在 PR 中预览变更
# 触发条件:PR 修改了 terraform/ 目录下的文件
name: "Terraform Plan"
on:
pull_request:
branches: [main, develop]
paths:
- 'terraform/**'
- '.github/workflows/terraform-plan.yml'
# 并发控制:同一 PR 只运行一个 Plan
concurrency:
group: terraform-plan-${{ github.ref }}
cancel-in-progress: true
# 权限设置(最小权限原则)
permissions:
contents: read
pull-requests: write
env:
TF_VERSION: "1.7.0"
AWS_REGION: "ap-southeast-1"
WORKING_DIR: "terraform/environments"
jobs:
# ===== 代码质量检查 =====
terraform-lint:
name: "🔍 Terraform Lint & Validate"
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装 Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Terraform Format Check
id: fmt
run: terraform fmt -check -recursive ${{ env.WORKING_DIR }}
continue-on-error: true
- name: Terraform Init (validate 需要)
run: |
for dir in ${{ env.WORKING_DIR }}/*/; do
if [ -f "$dir/main.tf" ]; then
echo "Initializing $dir"
cd "$dir"
terraform init -backend=false
cd -
fi
done
- name: Terraform Validate
id: validate
run: |
for dir in ${{ env.WORKING_DIR }}/*/; do
if [ -f "$dir/main.tf" ]; then
echo "Validating $dir"
cd "$dir"
terraform validate -no-color
cd -
fi
done
- name: TFLint 检查
uses: terraform-linters/setup-tflint@v4
with:
tflint_version: latest
- name: Run TFLint
run: |
for dir in ${{ env.WORKING_DIR }}/*/; do
if [ -f "$dir/main.tf" ]; then
cd "$dir"
tflint --init
tflint --format compact
cd -
fi
done
- name: 发布 Lint 结果到 PR
if: steps.fmt.outcome == 'failure'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '⚠️ Terraform 格式检查未通过,请运行 `terraform fmt -recursive` 修复'
})
# ===== Terraform Plan =====
terraform-plan:
name: "📋 Terraform Plan (${{ matrix.environment }})"
runs-on: ubuntu-latest
needs: terraform-lint
strategy:
matrix:
environment: [development, staging, production]
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装 Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: 配置 AWS 凭证
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Terraform Init
working-directory: ${{ env.WORKING_DIR }}/${{ matrix.environment }}
run: terraform init
- name: Terraform Plan
id: plan
working-directory: ${{ env.WORKING_DIR }}/${{ matrix.environment }}
run: |
terraform plan -no-color -out=tfplan \
-var-file=terraform.tfvars 2>&1 | tee plan_output.txt
continue-on-error: true
- name: 发布 Plan 结果到 PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const planOutput = fs.readFileSync(
'${{ env.WORKING_DIR }}/${{ matrix.environment }}/plan_output.txt',
'utf8'
);
const output = `## 📋 Terraform Plan - ${{ matrix.environment }}
\`\`\`
${planOutput.substring(0, 60000)}
\`\`\`
*由 GitHub Actions 自动生成*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
});
- name: Plan 失败则标记
if: steps.plan.outcome == 'failure'
run: exit 1
6.3 Ansible 自动化执行 Pipeline
yaml
# .github/workflows/ansible-deploy.yml
# Ansible 部署工作流
# 触发条件:合并到 main 分支且修改了 ansible/ 目录
name: "Ansible Deploy"
on:
push:
branches: [main]
paths:
- 'ansible/**'
workflow_dispatch: # 允许手动触发
inputs:
environment:
description: '部署目标环境'
required: true
default: 'development'
type: choice
options:
- development
- staging
- production
playbook:
description: '要执行的 Playbook'
required: true
default: 'site.yml'
type: string
limit:
description: '限制目标主机(可选)'
required: false
type: string
env:
ANSIBLE_VERSION: "9.5.1"
PYTHON_VERSION: "3.11"
jobs:
# ===== 语法检查 =====
ansible-lint:
name: "🔍 Ansible Lint"
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装 Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: 安装 Ansible 和 Lint 工具
run: |
pip install ansible==${{ env.ANSIBLE_VERSION }} ansible-lint yamllint
- name: YAML 语法检查
run: |
yamllint -d relaxed ansible/
- name: Ansible 语法检查
run: |
cd ansible
ansible-playbook playbooks/site.yml --syntax-check
- name: Ansible Lint
run: |
cd ansible
ansible-lint playbooks/ roles/
# ===== 部署执行 =====
ansible-deploy:
name: "🚀 Deploy to ${{ github.event.inputs.environment || 'production' }}"
runs-on: ubuntu-latest
needs: ansible-lint
environment: ${{ github.event.inputs.environment || 'production' }}
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装 Python 和 Ansible
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: 安装 Ansible
run: |
pip install ansible==${{ env.ANSIBLE_VERSION }}
- name: 安装 Ansible Collections
run: |
cd ansible
ansible-galaxy collection install -r collections/requirements.yml
- name: 配置 SSH 密钥
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H ${{ secrets.TARGET_HOSTS }} >> ~/.ssh/known_hosts 2>/dev/null || true
- name: 配置 Vault 密码
run: |
echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > .vault_pass
chmod 600 .vault_pass
- name: 执行 Ansible Playbook
working-directory: ansible
run: |
ENVIRONMENT="${{ github.event.inputs.environment || 'production' }}"
PLAYBOOK="${{ github.event.inputs.playbook || 'site.yml' }}"
LIMIT="${{ github.event.inputs.limit || '' }}"
ANSIBLE_CMD="ansible-playbook playbooks/${PLAYBOOK} \
-i inventory/hosts.yml \
--vault-password-file ../.vault_pass \
-e target_environment=${ENVIRONMENT} \
-v"
# 如果指定了 limit
if [ -n "$LIMIT" ]; then
ANSIBLE_CMD="${ANSIBLE_CMD} --limit ${LIMIT}"
fi
echo "执行命令: ${ANSIBLE_CMD}"
eval ${ANSIBLE_CMD}
- name: 清理敏感文件
if: always()
run: |
rm -f ~/.ssh/deploy_key
rm -f .vault_pass
6.4 Terraform Plan/Apply 自动化流程
yaml
# .github/workflows/terraform-apply.yml
# Terraform Apply 工作流 - 实际创建/修改云资源
# 触发条件:PR 合并到 main 或手动触发(需审批)
name: "Terraform Apply"
on:
push:
branches: [main]
paths:
- 'terraform/**'
workflow_dispatch:
inputs:
environment:
description: '目标环境'
required: true
type: choice
options:
- development
- staging
- production
auto_approve:
description: '跳过人工审批(仅限 development)'
required: false
type: boolean
default: false
permissions:
contents: read
id-token: write # 用于 OIDC 认证
env:
TF_VERSION: "1.7.0"
AWS_REGION: "ap-southeast-1"
jobs:
# ===== Plan 阶段 =====
terraform-plan:
name: "📋 Plan (${{ matrix.environment }})"
runs-on: ubuntu-latest
strategy:
matrix:
environment: [development, staging, production]
outputs:
plan_result: ${{ steps.plan.outputs.exitcode }}
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装 Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: 配置 AWS(使用 OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Terraform Init
working-directory: terraform/environments/${{ matrix.environment }}
run: terraform init
- name: Terraform Plan
id: plan
working-directory: terraform/environments/${{ matrix.environment }}
run: |
terraform plan -no-color -out=tfplan
echo "exitcode=$?" >> $GITHUB_OUTPUT
- name: 上传 Plan 文件
uses: actions/upload-artifact@v4
with:
name: tfplan-${{ matrix.environment }}
path: terraform/environments/${{ matrix.environment }}/tfplan
retention-days: 5
# ===== Apply 阶段(需要审批)=====
terraform-apply:
name: "🚀 Apply (${{ matrix.environment }})"
runs-on: ubuntu-latest
needs: terraform-plan
# 生产环境需要人工审批
environment: ${{ matrix.environment }}
strategy:
matrix:
environment: [development, staging, production]
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装 Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: 配置 AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: 下载 Plan 文件
uses: actions/download-artifact@v4
with:
name: tfplan-${{ matrix.environment }}
path: terraform/environments/${{ matrix.environment }}
- name: Terraform Init
working-directory: terraform/environments/${{ matrix.environment }}
run: terraform init
- name: Terraform Apply
working-directory: terraform/environments/${{ matrix.environment }}
run: |
terraform apply -auto-approve -no-color tfplan
- name: 输出部署结果
working-directory: terraform/environments/${{ matrix.environment }}
run: |
echo "## 部署输出" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
terraform output -no-color >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
6.5 密钥管理与 Secrets 注入
GitHub Secrets 配置清单:
| Secret 名称 | 用途 | 来源 |
|---|---|---|
AWS_ACCESS_KEY_ID |
AWS 访问密钥 | IAM 用户 |
AWS_SECRET_ACCESS_KEY |
AWS 密钥 | IAM 用户 |
AWS_ROLE_ARN |
OIDC 角色 ARN | IAM Role |
DEPLOY_SSH_KEY |
部署用 SSH 私钥 | 手动生成 |
ANSIBLE_VAULT_PASSWORD |
Vault 解密密码 | 手动设置 |
SLACK_WEBHOOK_URL |
通知 Webhook | Slack App |
TARGET_HOSTS |
目标主机 IP | 运维配置 |
推荐使用 AWS OIDC 代替长期密钥:
yaml
# 在 workflow 中使用 OIDC(更安全)
- name: 配置 AWS(OIDC 方式)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: ap-southeast-1
role-session-name: GitHubActions-${{ github.run_id }}
6.6 通知与回滚机制
yaml
# 添加到 workflow 末尾的通知步骤
# ===== 部署通知 =====
notify:
name: "📢 部署通知"
runs-on: ubuntu-latest
needs: [terraform-apply]
if: always() # 无论成功失败都通知
steps:
- name: 发送 Slack 通知
uses: 8398a7/action-slack@v3
with:
status: ${{ needs.terraform-apply.result }}
fields: repo,commit,author,action,workflow
text: |
🔄 Terraform 部署 ${{ needs.terraform-apply.result == 'success' && '成功 ✅' || '失败 ❌' }}
环境: production
提交: ${{ github.event.head_commit.message }}
操作人: ${{ github.actor }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
# ===== 自动回滚 =====
rollback:
name: "⏪ 自动回滚"
runs-on: ubuntu-latest
needs: [terraform-apply]
if: failure() # 仅在 Apply 失败时触发
steps:
- name: 检出代码
uses: actions/checkout@v4
with:
ref: ${{ github.event.before }} # 回滚到上一个提交
- name: 安装 Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: 配置 AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: 执行回滚
working-directory: terraform/environments/production
run: |
echo "⚠️ 检测到部署失败,正在回滚到上一个版本..."
terraform init
terraform apply -auto-approve -no-color
- name: 回滚通知
run: |
echo "⏪ 已自动回滚到提交 ${{ github.event.before }}"
七、全流程实操:从代码生成到云端资源交付
7.1 项目需求分析与架构设计
实战场景: 为一家电商公司部署 Web 应用基础设施
需求:
- 2 台 Web 服务器(Nginx + Node.js)
- 1 台 PostgreSQL 数据库
- VPC 网络隔离
- 负载均衡器
- SSL/TLS 加密
- 自动化监控告警
- 通过 Git 提交自动部署
架构图:
┌─────────────┐
│ Route53 │
│ (DNS) │
└──────┬──────┘
│
┌──────▼──────┐
│ ALB │
│ (负载均衡) │
└──┬──────┬──┘
│ │
┌────────▼┐ ┌▼────────┐
│ Web-01 │ │ Web-02 │ ← 私有子网
│ (Nginx) │ │ (Nginx) │
└────┬────┘ └────┬────┘
│ │
└─────┬──────┘
│
┌──────▼──────┐
│ PostgreSQL │ ← 私有子网
│ (RDS) │
└─────────────┘
7.2 使用 Cursor 生成全部基础设施代码
Step 1:打开 Cursor Composer(Ctrl+I),输入:
根据以下架构需求,生成完整的 Terraform 配置:
1. VPC:10.200.0.0/16,2个公有子网,2个私有子网
2. ALB:面向公网,HTTP/HTTPS 监听
3. 2台 EC2(t3.medium)在私有子网,运行 Nginx 反向代理
4. RDS PostgreSQL 15(db.t3.medium)在私有子网
5. 安全组:ALB 允许 80/443,EC2 只允许 ALB 访问 8080,RDS 只允许 EC2 访问 5432
6. CloudWatch 告警:CPU > 80%
7. 所有资源带 Environment/Project/ManagedBy 标签
目标环境:staging
AWS 区域:ap-southeast-1
Step 2:AI 生成代码后,审查并调整
Step 3:生成对应的 Ansible Playbook:
为上述 2 台 Web 服务器生成 Ansible Playbook:
1. 安装并配置 Nginx 作为反向代理(代理到 localhost:3000)
2. 安装 Node.js 20 LTS
3. 部署示例 Node.js 应用
4. 配置 PM2 进程管理
5. 设置 logrotate
6. 配置 fail2ban 防暴力破解
7.3 本地验证与 Lint 检查
bash
#!/bin/bash
# scripts/validate.sh - 本地验证脚本
# 用法:./scripts/validate.sh
set -euo pipefail
echo "=========================================="
echo " GitOps 项目本地验证"
echo "=========================================="
ERRORS=0
# ===== 1. Terraform 验证 =====
echo ""
echo "📦 [1/5] Terraform 验证..."
cd terraform/environments/staging
# 格式化检查
echo " → 检查格式..."
if ! terraform fmt -check -recursive .; then
echo " ❌ 格式不正确,运行 'terraform fmt' 修复"
ERRORS=$((ERRORS + 1))
else
echo " ✅ 格式正确"
fi
# 初始化(不连接后端)
echo " → 初始化..."
terraform init -backend=false -input=false > /dev/null 2>&1
# 语法验证
echo " → 语法验证..."
if terraform validate -no-color; then
echo " ✅ 语法正确"
else
echo " ❌ 语法错误"
ERRORS=$((ERRORS + 1))
fi
cd ../../..
# ===== 2. Ansible 验证 =====
echo ""
echo "📦 [2/5] Ansible 验证..."
cd ansible
# YAML 语法检查
echo " → YAML 语法检查..."
if yamllint -d relaxed playbooks/ roles/ inventory/ 2>/dev/null; then
echo " ✅ YAML 语法正确"
else
echo " ⚠️ 存在 YAML 警告"
fi
# Playbook 语法检查
echo " → Playbook 语法检查..."
if ansible-playbook playbooks/site.yml --syntax-check > /dev/null 2>&1; then
echo " ✅ Playbook 语法正确"
else
echo " ❌ Playbook 语法错误"
ERRORS=$((ERRORS + 1))
fi
# Ansible Lint
echo " → Ansible Lint..."
if ansible-lint playbooks/ roles/ --quiet 2>/dev/null; then
echo " ✅ Lint 通过"
else
echo " ⚠️ 存在 Lint 警告"
fi
cd ..
# ===== 3. 密钥检测 =====
echo ""
echo "📦 [3/5] 密钥泄露检测..."
if command -v detect-secrets > /dev/null 2>&1; then
if detect-secrets scan --baseline .secrets.baseline > /dev/null 2>&1; then
echo " ✅ 未检测到密钥泄露"
else
echo " ❌ 检测到可能的密钥泄露!"
ERRORS=$((ERRORS + 1))
fi
else
echo " ⚠️ detect-secrets 未安装,跳过"
fi
# ===== 4. Git 状态检查 =====
echo ""
echo "📦 [4/5] Git 状态检查..."
if [ -n "$(git status --porcelain)" ]; then
echo " ⚠️ 存在未提交的变更"
else
echo " ✅ 工作区干净"
fi
# ===== 5. 文件权限检查 =====
echo ""
echo "📦 [5/5] 文件权限检查..."
INSECURE_FILES=$(find . -name "*.pem" -o -name "*.key" -o -name "id_rsa*" | head -5)
if [ -n "$INSECURE_FILES" ]; then
echo " ⚠️ 发现敏感文件,请确保已加入 .gitignore"
echo "$INSECURE_FILES"
else
echo " ✅ 未发现敏感文件"
fi
# ===== 汇总 =====
echo ""
echo "=========================================="
if [ $ERRORS -eq 0 ]; then
echo " ✅ 所有验证通过!可以提交代码。"
else
echo " ❌ 发现 ${ERRORS} 个错误,请修复后再提交。"
exit 1
fi
echo "=========================================="
7.4 推送代码触发 CI/CD
bash
# 完整的提交流程
# 1. 确保所有变更已保存
git status
# 2. 运行本地验证
./scripts/validate.sh
# 3. 暂存所有变更
git add -A
# 4. 提交(遵循 Conventional Commits)
git commit -m "feat(infrastructure): 添加 staging 环境完整基础设施
- 新增 VPC 网络配置(2 AZ)
- 新增 ALB 负载均衡器
- 新增 2 台 Web 服务器(Nginx 反向代理)
- 新增 RDS PostgreSQL 数据库
- 新增 CloudWatch CPU 告警
- 配置 Ansible 自动化部署 Playbook
Closes #42"
# 5. 推送到远程
git push origin develop
# 6. 在 GitHub 上创建 PR(develop → main)
# 或使用 GitHub CLI:
gh pr create \
--title "feat(infrastructure): 添加 staging 环境完整基础设施" \
--body "## 变更内容
- 新增完整的 staging 环境 Terraform 配置
- 新增 Ansible 部署 Playbook
## 测试验证
- [x] terraform plan 通过
- [x] ansible --syntax-check 通过
- [x] 本地 Docker 环境验证通过
## 风险评估
风险等级:低(新环境,不影响生产)" \
--base main \
--head develop
7.5 云端资源验证与监控接入
bash
# 部署完成后的验证清单
# 1. 验证 Terraform 输出
cd terraform/environments/staging
terraform output
# 2. 验证 EC2 实例状态
aws ec2 describe-instances \
--filters "Name=tag:Environment,Values=staging" \
--query "Reservations[].Instances[].[InstanceId,State.Name,PrivateIpAddress]" \
--output table
# 3. 验证 ALB 健康状态
aws elbv2 describe-target-health \
--target-group-arn $(terraform output -raw target_group_arn) \
--query "TargetHealthDescriptions[].{Target:Target.Id,Health:TargetHealth.State}" \
--output table
# 4. 验证 RDS 状态
aws rds describe-db-instances \
--db-instance-identifier $(terraform output -raw db_instance_id) \
--query "DBInstances[0].{Status:DBInstanceStatus,Endpoint:Endpoint.Address}" \
--output table
# 5. 验证 DNS 解析
dig +short app-staging.example.com
# 6. 验证 HTTP 响应
curl -sI https://app-staging.example.com | head -20
# 7. 验证 SSL 证书
echo | openssl s_client -connect app-staging.example.com:443 2>/dev/null | \
openssl x509 -noout -dates -subject
7.6 端到端测试与交付确认
yaml
# ansible/playbooks/e2e-test.yml
# 端到端验证 Playbook - 部署完成后执行
# 用法:ansible-playbook playbooks/e2e-test.yml -e app_url=https://app-staging.example.com
---
- name: 端到端部署验证
hosts: localhost
gather_facts: false
connection: local
vars:
app_url: "https://app-staging.example.com"
expected_status: 200
timeout: 30
ssl_min_days: 30 # SSL 证书最少剩余天数
max_response_time: 5 # 最大响应时间(秒)
test_results: [] # 收集测试结果
tasks:
# ===== 1. 基础连通性测试 =====
- name: 验证应用首页可访问
ansible.builtin.uri:
url: "{{ app_url }}"
status_code: "{{ expected_status }}"
timeout: "{{ timeout }}"
validate_certs: true
follow_redirects: all
register: homepage_check
retries: 3
delay: 5
until: homepage_check.status == expected_status | int
failed_when: false
- name: 记录首页测试结果
ansible.builtin.set_fact:
test_results: "{{ test_results + [{
'name': '首页访问',
'status': 'PASS' if homepage_check.status == expected_status | int else 'FAIL',
'detail': 'HTTP ' + (homepage_check.status | default('N/A') | string)
}] }}"
# ===== 2. 健康检查端点 =====
- name: 验证健康检查端点
ansible.builtin.uri:
url: "{{ app_url }}/health"
status_code: 200
timeout: "{{ timeout }}"
return_content: true
register: health_check
retries: 3
delay: 5
until: health_check.status == 200
failed_when: false
- name: 记录健康检查结果
ansible.builtin.set_fact:
test_results: "{{ test_results + [{
'name': '健康检查',
'status': 'PASS' if health_check.status | default(0) == 200 else 'FAIL',
'detail': health_check.content | default('无响应')
}] }}"
# ===== 3. API 端点验证 =====
- name: 验证 API 状态端点
ansible.builtin.uri:
url: "{{ app_url }}/api/v1/status"
status_code: 200
method: GET
timeout: "{{ timeout }}"
headers:
Accept: "application/json"
User-Agent: "E2E-Test/1.0"
register: api_check
failed_when: false
- name: 记录 API 测试结果
ansible.builtin.set_fact:
test_results: "{{ test_results + [{
'name': 'API 状态端点',
'status': 'PASS' if api_check.status | default(0) == 200 else 'FAIL',
'detail': api_check.json | default({}) | to_nice_json
}] }}"
# ===== 4. SSL 证书验证 =====
- name: 获取 SSL 证书信息
ansible.builtin.shell: |
echo | openssl s_client -connect {{ app_url | regex_replace('https?://', '') }}:443 \
-servername {{ app_url | regex_replace('https?://', '') }} 2>/dev/null | \
openssl x509 -noout -enddate -subject 2>/dev/null
register: ssl_info
changed_when: false
failed_when: false
- name: 检查 SSL 证书有效期
ansible.builtin.shell: |
END_DATE=$(echo | openssl s_client -connect {{ app_url | regex_replace('https?://', '') }}:443 \
-servername {{ app_url | regex_replace('https?://', '') }} 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
END_EPOCH=$(date -d "$END_DATE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (END_EPOCH - NOW_EPOCH) / 86400 ))
echo $DAYS_LEFT
register: ssl_days
changed_when: false
failed_when: false
- name: 记录 SSL 测试结果
ansible.builtin.set_fact:
test_results: "{{ test_results + [{
'name': 'SSL 证书',
'status': 'PASS' if (ssl_days.stdout | default('0') | int) >= ssl_min_days else 'WARN',
'detail': '剩余 ' + (ssl_days.stdout | default('未知')) + ' 天'
}] }}"
# ===== 5. 响应时间测试 =====
- name: 测量响应时间
ansible.builtin.shell: |
curl -o /dev/null -s -w "%{time_total}" {{ app_url }}
register: response_time
changed_when: false
- name: 记录响应时间结果
ansible.builtin.set_fact:
test_results: "{{ test_results + [{
'name': '响应时间',
'status': 'PASS' if (response_time.stdout | float) <= max_response_time else 'WARN',
'detail': response_time.stdout + 's (阈值: ' + max_response_time | string + 's)'
}] }}"
# ===== 6. 数据库连接验证(通过 API)=====
- name: 验证数据库连接(通过应用 API)
ansible.builtin.uri:
url: "{{ app_url }}/api/v1/db/health"
status_code: 200
timeout: 10
register: db_health
failed_when: false
- name: 记录数据库测试结果
ansible.builtin.set_fact:
test_results: "{{ test_results + [{
'name': '数据库连接',
'status': 'PASS' if db_health.status | default(0) == 200 else 'FAIL',
'detail': db_health.json | default({'error': '无法连接'}) | to_nice_json
}] }}"
# ===== 7. 生成测试报告 =====
- name: 输出测试报告
ansible.builtin.debug:
msg: |
╔══════════════════════════════════════════════════╗
║ 端到端测试报告 ║
╠══════════════════════════════════════════════════╣
{% for result in test_results %}
║ {{ '%-2s' | format(loop.index) }}. {{ '%-12s' | format(result.name) }}
{{ '%-6s' | format(result.status) }} {{ result.detail }}
{% endfor %}
╠══════════════════════════════════════════════════╣
║ 总计: {{ test_results | length }} 项测试
║ 通过: {{ test_results | selectattr('status', 'eq', 'PASS') | list | length }} 项
║ 失败: {{ test_results | selectattr('status', 'eq', 'FAIL') | list | length }} 项
║ 警告: {{ test_results | selectattr('status', 'eq', 'WARN') | list | length }} 项
╚══════════════════════════════════════════════════╝
# ===== 8. 失败则中止 =====
- name: 检查是否有失败项
ansible.builtin.fail:
msg: "❌ 端到端测试存在失败项,请检查!"
when: test_results | selectattr('status', 'eq', 'FAIL') | list | length > 0
交付确认清单(Checklist):
markdown
## 📋 部署交付确认清单
### 基础设施验证
- [ ] Terraform apply 成功,无错误
- [ ] 所有 EC2 实例状态为 running
- [ ] ALB 目标组健康检查全部通过
- [ ] RDS 实例状态为 available
- [ ] VPC 路由表配置正确
- [ ] 安全组规则符合预期
### 应用验证
- [ ] 首页返回 HTTP 200
- [ ] /health 端点正常
- [ ] API 接口响应正确
- [ ] SSL 证书有效且未过期
- [ ] 响应时间在可接受范围内
### 运维验证
- [ ] CloudWatch 告警已配置
- [ ] 日志收集正常
- [ ] 备份策略已生效
- [ ] 监控面板可访问
### 文档更新
- [ ] README 已更新
- [ ] 变更记录已填写
- [ ] 回滚方案已确认
- [ ] 相关方已通知
### 安全验证
- [ ] 无不必要的开放端口
- [ ] 密钥未暴露在代码中
- [ ] IAM 权限符合最小原则
- [ ] 安全组无 0.0.0.0/0 入站规则(除 80/443)
八、常见语法报错分析与 AI 辅助排错技巧
8.1 Ansible 常见报错与解决方案
8.1.1 YAML 语法错误
错误示例 1:缩进不一致
ERROR! Syntax Error while loading YAML.
mapping values are not allowed in this context
The error appears to be in '/playbooks/deploy.yml': line 12, column 8
错误代码:
yaml
# ❌ 错误:冒号后缺少空格,或缩进混乱
- name: 安装软件包
ansible.builtin.apt:
name: nginx
state: present # 缩进多了一级
正确代码:
yaml
# ✅ 正确:统一使用 2 空格缩进
- name: 安装软件包
ansible.builtin.apt:
name: nginx
state: present
错误示例 2:特殊字符未转义
yaml
# ❌ 错误:包含特殊字符的字符串未加引号
- name: 设置环境变量
ansible.builtin.lineinfile:
path: /etc/environment
line: PATH=/usr/local/bin:$PATH:/opt/app/bin # $ 可能被解析
# ✅ 正确:使用引号包裹
- name: 设置环境变量
ansible.builtin.lineinfile:
path: /etc/environment
line: "PATH=/usr/local/bin:$PATH:/opt/app/bin"
错误示例 3:Tab 与空格混用
ERROR! Syntax Error while loading YAML.
found character that cannot start any token
bash
# 解决方案:将所有 Tab 替换为空格
sed -i 's/\t/ /g' playbooks/*.yml
# 或在 Cursor 中设置:
# Settings → Editor → Insert Spaces: true
# Settings → Editor → Tab Size: 2
8.1.2 模块参数错误
错误:使用已废弃的模块参数
[WARNING]: The value "yes" for "state" is deprecated. Use "true" instead.
ERROR! Invalid options for ansible.builtin.apt: update-cache
yaml
# ❌ 错误:使用连字符(旧语法)
- name: 更新缓存
ansible.builtin.apt:
update-cache: yes # 连字符语法已废弃
# ✅ 正确:使用下划线(新语法)
- name: 更新缓存
ansible.builtin.apt:
update_cache: true # 下划线 + 布尔值
错误:模块名不完整
ERROR! couldn't resolve module/action 'copy'. This often indicates a misspelling...
yaml
# ❌ 可能出错(取决于配置)
- name: 复制文件
copy:
src: file.txt
dest: /tmp/
# ✅ 推荐:使用完整模块名
- name: 复制文件
ansible.builtin.copy:
src: file.txt
dest: /tmp/
owner: root
group: root
mode: "0644"
8.1.3 变量与模板错误
错误:变量未定义
fatal: [web-01]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'app_port' is undefined"}
yaml
# 解决方案 1:设置默认值
- name: 配置应用端口
ansible.builtin.template:
src: app.conf.j2
dest: /etc/app/config.conf
vars:
app_port: "{{ app_port | default(8080) }}" # 默认 8080
# 解决方案 2:使用 when 条件跳过
- name: 配置应用端口
ansible.builtin.template:
src: app.conf.j2
dest: /etc/app/config.conf
when: app_port is defined
# 解决方案 3:在 defaults 中定义
# roles/app/defaults/main.yml
# app_port: 8080
错误:Jinja2 模板语法错误
AnsibleError: template error while templating string: unexpected '{'
jinja2
{# ❌ 错误:JSON 花括号与 Jinja2 冲突 #}
config = { "key": "{{ value }}" }
{# ✅ 正确:使用 raw 块或转义 #}
config = {% raw %}{% endraw %}{ "key": "{{ value }}" }
{# 或者使用 set 变量 #}
{% set config = {"key": value} %}
config = {{ config | to_json }}
8.1.4 连接与权限错误
错误:SSH 连接超时
fatal: [web-01]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.1.101 port 22: Connection timed out"}
bash
# 排查步骤:
# 1. 检查网络连通性
ping 192.168.1.101
# 2. 检查 SSH 端口
nc -zv 192.168.1.101 22
# 3. 检查防火墙
sudo iptables -L -n | grep 22
# 4. 检查 SSH 服务
ssh -vvv user@192.168.1.101 # 详细调试模式
# 5. 增加超时时间(ansible.cfg)
# [defaults]
# timeout = 60
错误:权限不足
fatal: [web-01]: FAILED! => {"msg": "Permission denied (publickey)."}
yaml
# 解决方案:确保使用正确的用户和密钥
# inventory/hosts.yml
webservers:
hosts:
web-01:
ansible_host: 192.168.1.101
ansible_user: deploy # 指定用户
ansible_ssh_private_key_file: ~/.ssh/deploy_key # 指定密钥
ansible_become: true # 需要提权
ansible_become_method: sudo
8.2 Terraform 常见报错与解决方案
8.2.1 Provider 初始化错误
错误:Provider 下载失败
Error: Failed to install provider
Could not retrieve the list of available versions for provider hashicorp/aws
bash
# 解决方案 1:检查网络/代理
export HTTPS_PROXY=http://proxy.company.com:8080
terraform init
# 解决方案 2:使用镜像源
# ~/.terraformrc
provider_installation {
filesystem_mirror {
path = "/opt/terraform/providers"
include = ["registry.terraform.io/*/*"]
}
direct {
exclude = ["registry.terraform.io/*/*"]
}
}
# 解决方案 3:清除缓存重新初始化
rm -rf .terraform .terraform.lock.hcl
terraform init
8.2.2 State 锁冲突
错误:State 被锁定
Error acquiring the state lock
Lock Info:
ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Path: production/terraform.tfstate
Operation: OperationTypePlan
Who: user@hostname
Version: 1.7.0
Created: 2024-01-15 10:30:00 +0000 UTC
bash
# 解决方案 1:等待锁释放(其他人正在操作)
# 等待几分钟后重试
# 解决方案 2:确认无人操作后强制解锁
terraform force-unlock a1b2c3d4-e5f6-7890-abcd-ef1234567890
# ⚠️ 警告:强制解锁前必须确认没有其他人正在执行 terraform 操作
# 否则可能导致 State 损坏
# 解决方案 3:检查 DynamoDB 表中的锁记录
aws dynamodb scan \
--table-name terraform-state-lock \
--filter-expression "LockID = :id" \
--expression-attribute-values '{":id": {"S": "production/terraform.tfstate"}}'
8.2.3 资源属性冲突
错误:资源已存在
Error: creating EC2 Instance: InvalidParameterValue: Value (web-01) for parameter groupId is invalid
hcl
# 解决方案 1:使用 data source 引用已有资源
data "aws_security_group" "existing" {
filter {
name = "tag:Name"
values = ["existing-sg"]
}
}
# 解决方案 2:导入已有资源
terraform import aws_security_group.web sg-0123456789abcdef0
# 解决方案 3:使用 lifecycle 忽略特定属性
resource "aws_instance" "web" {
# ...
lifecycle {
ignore_changes = [
tags, # 忽略标签变更
ami, # 忽略 AMI 变更(避免重建)
]
}
}
8.2.4 变量类型错误
错误:类型不匹配
Error: Incorrect attribute value type
Inappropriate value for attribute "cidr_blocks": element 0: string required.
hcl
# ❌ 错误:传入列表而非字符串
ingress {
cidr_blocks = var.allowed_ips # 如果 allowed_ips 是 list(list)
}
# ✅ 正确:确保类型匹配
variable "allowed_ips" {
type = list(string) # 明确声明类型
default = ["10.0.0.0/8", "172.16.0.0/12"]
}
ingress {
cidr_blocks = var.allowed_ips # 直接使用 list(string)
}
8.2.5 循环依赖错误
错误:Cycle 检测
Error: Cycle: aws_instance.web, aws_security_group.web, aws_vpc.main
hcl
# 解决方案:打破循环依赖
# 方法 1:使用 depends_on 明确依赖顺序
resource "aws_security_group" "web" {
vpc_id = aws_vpc.main.id
# 不引用 instance
}
resource "aws_instance" "web" {
vpc_security_group_ids = [aws_security_group.web.id]
# 依赖 SG,SG 不依赖 instance
}
# 方法 2:拆分资源到不同文件/模块
# 将安全组和实例分到不同模块中
8.3 Git 冲突处理与合并策略
8.3.1 Terraform 文件冲突
<<<<<<< HEAD
resource "aws_instance" "web" {
instance_type = "t3.medium"
ami = "ami-0123456789"
=======
resource "aws_instance" "web" {
instance_type = "t3.large"
ami = "ami-9876543210"
>>>>>>> feature/upgrade-instance
解决策略:
bash
# 1. 查看冲突文件
git status
# 2. 在 Cursor 中打开冲突文件(有可视化冲突解决器)
cursor terraform/main.tf
# 3. 选择保留的版本或手动合并
# 4. 标记冲突已解决
git add terraform/main.tf
# 5. 完成合并
git commit -m "fix(terraform): 合并实例配置冲突,采用 t3.large"
# 6. 重要:合并后必须重新验证
terraform plan # 确认变更符合预期
8.3.2 预防冲突的最佳实践
bash
# 1. 频繁拉取最新代码
git pull --rebase origin main
# 2. 小而频繁的提交(避免大范围修改)
git add -p # 分块暂存,精确控制每次提交内容
# 3. 使用 .gitattributes 统一行尾
cat > .gitattributes << 'EOF'
*.tf text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.sh text eol=lf
*.md text eol=lf
EOF
# 4. 模块化设计减少文件冲突
# 不同人负责不同模块,减少修改同一文件的概率
8.4 CI/CD 流水线故障排查
常见 CI/CD 失败原因及解决:
| 错误类型 | 典型信息 | 解决方案 |
|---|---|---|
| 权限不足 | AccessDenied |
检查 IAM 策略和 Secrets |
| 超时 | Job timed out |
增加 timeout 或优化步骤 |
| 依赖缺失 | command not found |
在 steps 中安装依赖 |
| State 锁 | state lock |
等待或 force-unlock |
| 网络问题 | connection refused |
检查安全组和网络 ACL |
yaml
# 调试 CI/CD 流水线技巧
# 在 workflow 中添加调试步骤
- name: 调试信息输出
run: |
echo "=== 环境信息 ==="
echo "工作目录: $(pwd)"
echo "文件列表:"
ls -la
echo ""
echo "=== 版本信息 ==="
terraform version
python3 --version
echo ""
echo "=== 网络测试 ==="
curl -sI https://registry.terraform.io | head -5
- name: 带详细日志的 Terraform Plan
run: |
export TF_LOG=DEBUG
export TF_LOG_PATH=/tmp/terraform-debug.log
terraform plan -no-color
continue-on-error: true
- name: 上传调试日志
if: failure()
uses: actions/upload-artifact@v4
with:
name: debug-logs
path: /tmp/terraform-debug.log
8.5 利用 Cursor AI 进行智能排错
排错 Prompt 模板:
我遇到了以下错误,请帮我分析原因并给出解决方案:
【错误信息】:
Error: creating DB Instance: Cannot modify engine version from 14.9 to 15.4
in a single apply. Please perform a major version upgrade separately.
【相关代码】:
@terraform/modules/rds/main.tf
【期望行为】:
将 PostgreSQL 从 14.9 升级到 15.4
【约束条件】:
- 不能停机超过 5 分钟
- 必须保留所有数据
- 生产环境
AI 辅助排错工作流:
步骤 1:复制完整错误信息
步骤 2:在 Cursor 中打开相关文件
步骤 3:Ctrl+L 打开 AI 聊天
步骤 4:粘贴错误 + @引用相关文件
步骤 5:让 AI 分析根因
步骤 6:让 AI 给出修复方案
步骤 7:在 Composer 中应用修复
步骤 8:本地验证
实用排错 Prompt 示例:
# Prompt 1:解释错误
"请解释这个 Terraform 错误的根本原因,以及为什么会出现:
[粘贴错误信息]"
# Prompt 2:对比分析
"@main.tf @main.tf.backup 请对比这两个文件的差异,
找出可能导致部署失败的变更"
# Prompt 3:生成修复
"请修复这个 Ansible Playbook 中的幂等性问题,
确保重复执行不会产生副作用:@deploy.yml"
# Prompt 4:性能诊断
"这个 Ansible Playbook 执行太慢(超过 30 分钟),
请分析可能的性能瓶颈并优化:@site.yml"
8.6 日志分析与错误模式识别
bash
#!/bin/bash
# scripts/analyze-logs.sh - 日志分析辅助脚本
LOG_DIR="./logs"
TODAY=$(date +%Y-%m-%d)
echo "===== Ansible 日志分析 (${TODAY}) ====="
# 统计执行结果
echo ""
echo "📊 执行统计:"
grep -c "ok=" ${LOG_DIR}/ansible.log 2>/dev/null | xargs -I{} echo " 成功任务: {}"
grep -c "changed=" ${LOG_DIR}/ansible.log 2>/dev/null | xargs -I{} echo " 变更任务: {}"
grep -c "failed=" ${LOG_DIR}/ansible.log 2>/dev/null | xargs -I{} echo " 失败任务: {}"
grep -c "unreachable=" ${LOG_DIR}/ansible.log 2>/dev/null | xargs -I{} echo " 不可达主机: {}"
# 提取错误信息
echo ""
echo "❌ 错误详情:"
grep -A 5 "FAILED\|ERROR\|UNREACHABLE" ${LOG_DIR}/ansible.log 2>/dev/null | tail -30
# Terraform 日志
echo ""
echo "===== Terraform 日志分析 ====="
if [ -f "${LOG_DIR}/terraform.log" ]; then
echo "错误条目:"
grep -i "error\|fatal" ${LOG_DIR}/terraform.log | tail -10
echo ""
echo "警告条目:"
grep -i "warning" ${LOG_DIR}/terraform.log | tail -5
fi
九、提升脚本安全性的最佳实践与审查要点
9.1 密钥与敏感信息管理
9.1.1 敏感信息分类
| 类别 | 示例 | 管理方式 |
|---|---|---|
| 云凭证 | AWS Access Key、Service Account | IAM Role / OIDC |
| 密码 | 数据库密码、API Key | Ansible Vault / Secrets Manager |
| 证书 | SSL 私钥、SSH 私钥 | 加密存储 / KMS |
| Token | GitHub Token、Slack Webhook | CI/CD Secrets |
| 连接串 | 数据库 URL、Redis URL | 环境变量 / Vault |
9.1.2 Ansible Vault 完整实践
bash
# 创建加密的变量文件
ansible-vault create inventory/group_vars/production/vault.yml
# 文件内容示例(加密前):
# ---
# vault_db_admin_password: "Pr0d_S3cur3_P@ssw0rd!"
# vault_api_secret_key: "sk-prod-xxxxxxxxxxxxxxxx"
# vault_jwt_signing_key: "hs256-secret-key-here"
# 在 Playbook 中引用加密变量
# 注意:vault 变量名必须以 vault_ 前缀开头(最佳实践)
yaml
# inventory/group_vars/production/main.yml(非加密)
---
# 引用 vault 变量(间接引用,避免暴露)
db_admin_password: "{{ vault_db_admin_password }}"
api_secret_key: "{{ vault_api_secret_key }}"
# 非敏感配置直接写
db_host: "db.internal.example.com"
db_port: 5432
db_name: "production_app"
yaml
# 在 Playbook 中使用加密变量
- name: 配置数据库连接
ansible.builtin.template:
src: db_config.j2
dest: /etc/app/database.yml
owner: app
group: app
mode: "0600" # 严格权限:仅属主可读写
vars:
db_password: "{{ vault_db_admin_password }}"
no_log: true # 不在日志中输出此任务详情
9.1.3 Terraform 敏感变量处理
hcl
# 标记敏感变量
variable "db_password" {
description = "数据库管理员密码"
type = string
sensitive = true # 不会在 plan/apply 输出中显示
}
variable "api_key" {
description = "外部 API 密钥"
type = string
sensitive = true
}
# 敏感输出
output "db_connection_string" {
description = "数据库连接字符串"
value = "postgresql://${var.db_user}:${var.db_password}@${aws_db_instance.main.endpoint}/${var.db_name}"
sensitive = true # terraform output 不会直接显示
}
# 查看敏感输出(需要显式指定)
# terraform output -raw db_connection_string
9.1.4 CI/CD 中的密钥注入
yaml
# GitHub Actions - 安全的密钥使用方式
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# ✅ 方式 1:使用 OIDC(最安全,无长期密钥)
- name: Configure AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-southeast-1
# ✅ 方式 2:使用 GitHub Secrets
- name: Deploy
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
API_KEY: ${{ secrets.API_KEY }}
run: |
# 密钥通过环境变量传递,不出现在日志中
ansible-playbook deploy.yml -e "db_password=${DB_PASSWORD}"
# ❌ 绝对禁止:硬编码密钥
# run: ansible-playbook deploy.yml -e "db_password=MySecret123"
9.2 最小权限原则与 IAM 策略
hcl
# terraform/modules/iam/main.tf
# 最小权限 IAM 策略示例
# Terraform 执行角色(仅允许管理特定资源)
resource "aws_iam_role" "terraform_role" {
name = "terraform-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/token.actions.githubusercontent.com"
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
"token.actions.githubusercontent.com:sub" = "repo:myorg/gitops-infrastructure:ref:refs/heads/main"
}
}
}
]
})
}
# 精确到具体操作的策略
resource "aws_iam_role_policy" "terraform_policy" {
name = "terraform-minimal-policy"
role = aws_iam_role.terraform_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "EC2Management"
Effect = "Allow"
Action = [
"ec2:DescribeInstances",
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:CreateTags",
"ec2:DescribeImages",
"ec2:DescribeSecurityGroups",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupIngress"
]
Resource = "*"
Condition = {
StringEquals = {
"aws:RequestedRegion" = "ap-southeast-1"
}
}
},
{
Sid = "S3StateAccess"
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
]
Resource = [
"arn:aws:s3:::gitops-terraform-state-2024",
"arn:aws:s3:::gitops-terraform-state-2024/*"
]
},
{
Sid = "DynamoDBLock"
Effect = "Allow"
Action = [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
]
Resource = "arn:aws:dynamodb:*:*:table/terraform-state-lock"
}
]
})
}
9.3 代码静态安全扫描
yaml
# 集成 Checkov(Terraform 安全扫描)到 CI/CD
# .github/workflows/security-scan.yml
name: "Security Scan"
on:
pull_request:
branches: [main]
jobs:
checkov:
name: "🔒 Checkov Security Scan"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/
framework: terraform
output_format: sarif
soft_fail: false
# 跳过的检查(需有正当理由)
skip_check: CKV_AWS_18 # S3 访问日志(开发环境不需要)
trivy:
name: "🔒 Trivy IaC Scan"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
scan-type: 'config'
scan-ref: 'terraform/'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
ansible-security:
name: "🔒 Ansible Security Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install tools
run: pip install ansible-lint
- name: Run security-focused lint
run: |
cd ansible
ansible-lint --profile security playbooks/ roles/
9.4 Ansible 安全加固实践
yaml
# roles/security-hardening/tasks/main.yml
---
# 系统安全加固任务
# ===== SSH 加固 =====
- name: 配置 SSH 安全选项
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
backup: yes
loop:
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
- { regexp: '^#?PermitEmptyPasswords', line: 'PermitEmptyPasswords no' }
- { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
- { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
- { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
- { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
- { regexp: '^#?Protocol', line: 'Protocol 2' }
notify: Restart SSHD
# ===== 防火墙配置 =====
- name: 配置 UFW 默认策略
community.general.ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
loop:
- { direction: incoming, policy: deny }
- { direction: outgoing, policy: allow }
# ===== 禁用不必要的服务 =====
- name: 禁用不必要的服务
ansible.builtin.systemd:
name: "{{ item }}"
state: stopped
enabled: false
loop:
- telnet.socket
- rsh.socket
- rlogin.socket
failed_when: false # 某些系统可能没有这些服务
# ===== 文件权限加固 =====
- name: 设置关键文件权限
ansible.builtin.file:
path: "{{ item.path }}"
owner: root
group: root
mode: "{{ item.mode }}"
loop:
- { path: /etc/passwd, mode: "0644" }
- { path: /etc/shadow, mode: "0000" }
- { path: /etc/group, mode: "0644" }
- { path: /etc/gshadow, mode: "0000" }
- { path: /etc/ssh/sshd_config, mode: "0600" }
# ===== 安装并配置 Fail2Ban =====
- name: 安装 Fail2Ban
ansible.builtin.apt:
name: fail2ban
state: present
- name: 配置 Fail2Ban SSH 防护
ansible.builtin.copy:
content: |
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
dest: /etc/fail2ban/jail.local
owner: root
mode: "0644"
notify: Restart Fail2Ban
9.5 Terraform 安全基线配置
hcl
# terraform/modules/security-baseline/main.tf
# 安全基线模块 - 所有环境必须包含
# ===== S3 桶安全基线 =====
resource "aws_s3_bucket" "secure_bucket" {
bucket = var.bucket_name
# 强制 SSL 访问
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "EnforceSSL"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = [
"arn:aws:s3:::${var.bucket_name}",
"arn:aws:s3:::${var.bucket_name}/*"
]
Condition = {
Bool = {
"aws:SecureTransport" = "false"
}
}
}
]
})
}
# 阻止公共访问
resource "aws_s3_bucket_public_access_block" "block" {
bucket = aws_s3_bucket.secure_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# 启用加密
resource "aws_s3_bucket_server_side_encryption_configuration" "encrypt" {
bucket = aws_s3_bucket.secure_bucket.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
# ===== 安全组基线(禁止全开)=====
resource "aws_security_group" "restricted" {
name_prefix = "${var.project_name}-restricted-"
vpc_id = var.vpc_id
# 默认不添加任何入站规则
# 通过变量精确控制允许的入站
dynamic "ingress" {
for_each = var.allowed_ingress_rules
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
description = lookup(ingress.value, "description", "Managed by Terraform")
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound"
}
tags = {
Name = "${var.project_name}-restricted-sg"
}
}
# ===== CloudTrail(审计日志)=====
resource "aws_cloudtrail" "audit" {
name = "${var.project_name}-audit-trail"
s3_bucket_name = aws_s3_bucket.secure_bucket.id
include_global_service_events = true
is_multi_region_trail = true
enable_log_file_validation = true # 日志完整性验证
event_selector {
read_write_type = "All"
include_management_events = true
}
}
9.6 审计日志与合规检查
yaml
# ansible/playbooks/audit-check.yml
---
# 安全审计检查 Playbook
# 定期执行,确保系统符合安全基线
- name: 安全合规审计
hosts: all
become: true
gather_facts: true
tasks:
# 检查是否有无密码用户
- name: 检查空密码用户
ansible.builtin.shell: |
awk -F: '($2 == "" ) { print $1 }' /etc/shadow
register: empty_password_users
changed_when: false
failed_when: false
- name: 报告空密码用户
ansible.builtin.fail:
msg: "⚠️ 发现空密码用户: {{ empty_password_users.stdout_lines }}"
when: empty_password_users.stdout_lines | length > 0
# 检查 SSH 配置
- name: 检查 SSH 是否禁止 root 登录
ansible.builtin.shell: |
grep -E "^PermitRootLogin no" /etc/ssh/sshd_config
register: root_login_check
changed_when: false
failed_when: false
- name: 报告 root 登录状态
ansible.builtin.debug:
msg: "{{ '✅ SSH root 登录已禁止' if root_login_check.rc == 0 else '❌ SSH root 登录未禁止!' }}"
# 检查开放端口
- name: 获取当前监听端口
ansible.builtin.shell: |
ss -tlnp | awk '{print $4}' | grep -oE '[0-9]+$' | sort -un
register: listening_ports
changed_when: false
- name: 检查是否有非预期端口
ansible.builtin.debug:
msg: |
当前监听端口: {{ listening_ports.stdout_lines | join(', ') }}
预期端口: 22, 80, 443, 8080
when: listening_ports.stdout_lines | difference(['22', '80', '443', '8080']) | length > 0
# 检查系统更新
- name: 检查待更新的安全补丁
ansible.builtin.shell: |
apt list --upgradable 2>/dev/null | grep -i security | wc -l
register: pending_updates
changed_when: false
when: ansible_os_family == "Debian"
- name: 报告安全更新状态
ansible.builtin.debug:
msg: "待安装安全补丁: {{ pending_updates.stdout | default('0') }} 个"
十、进阶技巧:自定义规则优化运维代码质量
10.1 自定义 .cursorrules 运维规则集
随着项目发展,.cursorrules 需要不断迭代。以下是进阶版规则:
markdown
# .cursorrules - 进阶运维 AI 规则 v2.0
## 项目上下文
- 项目类型:企业级 GitOps 自动化运维平台
- 技术栈:Ansible 2.16 + Terraform 1.7 + GitHub Actions
- 目标环境:AWS (ap-southeast-1)
- 团队规模:5 名运维工程师
- 合规要求:SOC2、ISO 27001
## Ansible 高级规范
### 任务编写
- 每个 task 的 name 必须使用中文,格式为"动词 + 对象 + 条件"
- 示例:"安装 Nginx 软件包"、"配置 SSL 证书(仅生产环境)"
- 使用 block/rescue/always 处理错误
- 所有 shell/command 模块必须有 changed_when 或 creates/removes
- 循环优先使用 loop 而非 with_items(新语法)
- 复杂条件使用 set_fact 预计算
### 变量管理
- 角色默认变量放在 defaults/main.yml
- 环境差异变量放在 inventory/group_vars/
- 敏感变量必须以 vault_ 前缀命名
- 变量命名:角色名_用途,如 nginx_worker_processes
### 性能优化
- 使用 gather_subset 限制收集的事实
- 大量文件操作使用 synchronize 替代 copy
- 使用 pipeline 和 ControlPersist 加速 SSH
- 合理使用 serial 进行滚动部署
## Terraform 高级规范
### 代码组织
- 每个模块必须有 README.md 说明用法
- 使用 terraform-docs 自动生成文档
- 模块输入变量不超过 15 个(过多则拆分)
- 使用 locals 块计算复杂表达式
### 安全强制
- 所有安全组入站规则必须有 description
- RDS 必须启用 deletion_protection
- S3 必须启用版本控制和加密
- IAM 策略禁止使用 Action: "*"
- 禁止在代码中硬编码账号 ID(使用 data source)
### 状态管理
- 每个环境独立的 state 文件
- 使用 workspace 或目录隔离环境
- 重要操作前备份 state
- 使用 moved 块处理资源重命名
## Git 提交规范(强制)
- feat: 新增基础设施或配置
- fix: 修复部署问题
- refactor: 代码重构(不改变功能)
- security: 安全相关变更(需要 2 人审查)
- ci: CI/CD 流水线变更
- docs: 文档更新
- chore: 依赖升级、工具配置
## 代码审查检查清单
AI 在审查代码时必须检查:
1. 是否有硬编码的密钥或密码
2. 安全组是否过于宽松
3. 是否缺少必要的标签
4. 变量是否有默认值和描述
5. 是否处理了错误情况
6. 幂等性是否得到保证
7. 是否有不必要的资源(成本)
8. 命名是否规范一致
## 输出格式要求
- Terraform 代码必须通过 terraform fmt 格式化
- Ansible YAML 使用 2 空格缩进
- 所有代码块标注语言类型
- 复杂逻辑添加中文注释
- 提供使用说明和注意事项
10.2 Ansible Lint 规则定制
yaml
# ansible/.ansible-lint
# 自定义 Ansible Lint 规则配置
profile: production # 使用生产级别规则集
# 排除路径
exclude_paths:
- .cache/
- collections/
- tests/fixtures/
# 跳过的规则(需注释理由)
skip_list:
- yaml[line-length] # 允许长行(某些 URL 很长)
- name[casing] # 允许中文任务名
# 警告级别规则
warn_list:
- experimental # 实验性规则仅警告
- no-changed-when # 某些 command 确实无法判断变更
# 启用额外规则
enable_list:
- no-log-password # 强制密码操作使用 no_log
- no-same-owner # 检查文件属主一致性
# 自定义规则
rules:
# 强制使用完整模块名
- id: fqcn-required
severity: HIGH
# 禁止使用 shell 模块(除非必要)
- id: avoid-shell
severity: MEDIUM
10.3 Terraform 自定义策略(Sentinel/OPA)
hcl
# terraform/policies/security.sentinel
# Sentinel 策略示例(Terraform Cloud/Enterprise)
# 策略 1:所有 EC2 必须加密
rule "ec2_must_be_encrypted" {
condition = all tfplan.resource_changes as _, rc {
rc.type is not "aws_instance" or
rc.change.after.root_block_device[0].encrypted is true
}
error_message = "所有 EC2 实例的根卷必须启用加密"
}
# 策略 2:安全组禁止全开入站
rule "no_open_ingress" {
condition = all tfplan.resource_changes as _, rc {
rc.type is not "aws_security_group" or
all rc.change.after.ingress as _, rule {
rule.cidr_blocks is not ["0.0.0.0/0"] or
rule.from_port is in [80, 443] # 仅 80/443 允许全开
}
}
error_message = "安全组入站规则不允许 0.0.0.0/0(80/443 除外)"
}
# 策略 3:所有资源必须有标签
rule "mandatory_tags" {
condition = all tfplan.resource_changes as _, rc {
rc.type is not "aws_instance" or
(rc.change.after.tags includes "Environment" and
rc.change.after.tags includes "Project" and
rc.change.after.tags includes "ManagedBy")
}
error_message = "所有资源必须包含 Environment、Project、ManagedBy 标签"
}
使用 OPA (Open Policy Agent) 的替代方案:
rego
# terraform/policies/security.rego
# OPA 策略文件
package terraform.security
import future.keywords.in
# 违规:安全组全开
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_security_group"
ingress := resource.change.after.ingress[_]
"0.0.0.0/0" in ingress.cidr_blocks
not ingress.from_port in [80, 443]
msg := sprintf("安全组 %s 存在全开入站规则(端口 %d)", [resource.name, ingress.from_port])
}
# 违规:缺少加密
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_db_instance"
not resource.change.after.storage_encrypted
msg := sprintf("RDS 实例 %s 未启用存储加密", [resource.name])
}
# 违规:缺少删除保护
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_db_instance"
not resource.change.after.deletion_protection
msg := sprintf("RDS 实例 %s 未启用删除保护", [resource.name])
}
bash
# 在 CI/CD 中运行 OPA 检查
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
opa eval \
--data terraform/policies/security.rego \
--input plan.json \
--format pretty \
"data.terraform.security.deny"
10.4 代码生成质量评估与迭代优化
AI 生成代码的质量评估清单:
markdown
## AI 生成代码审查清单
### 功能性 (40%)
- [ ] 代码是否能正确实现需求
- [ ] 边界条件是否处理
- [ ] 错误处理是否完善
- [ ] 幂等性是否保证
### 安全性 (25%)
- [ ] 无硬编码密钥
- [ ] 权限最小化
- [ ] 输入验证
- [ ] 无已知漏洞
### 可维护性 (20%)
- [ ] 命名清晰规范
- [ ] 注释充分
- [ ] 模块化设计
- [ ] 无重复代码
### 性能 (15%)
- [ ] 无不必要的资源
- [ ] 执行效率合理
- [ ] 无冗余操作
迭代优化 Prompt 技巧:
# 第一轮:生成基础代码
"创建一个 Nginx 反向代理配置"
# 第二轮:优化安全性
"@vhost.conf.j2 请加强安全配置:添加速率限制、安全响应头、
隐藏版本号、限制请求体大小"
# 第三轮:优化可维护性
"@roles/nginx 请将硬编码的值提取为变量,
添加条件判断支持多环境部署"
# 第四轮:添加监控
"@nginx.conf.j2 请添加 stub_status 监控端点,
配置访问日志的 JSON 格式便于日志分析"
10.5 团队知识库与 Prompt 工程
建立团队 Prompt 库:
markdown
# docs/prompt-library.md
# 团队 Prompt 模板库
## 常用运维场景 Prompt
### 场景 1:新服务部署
请为 服务名 创建完整的部署配置:
-
目标系统:Ubuntu 22.04 / CentOS 9
-
部署方式:Docker / 裸机 / K8s
-
端口:端口号
-
依赖:依赖列表
-
配置项:需要参数化的配置
-
监控:健康检查端点
-
回滚:回滚策略
场景 2:故障恢复
当前故障:描述
影响范围:受影响的服务
已尝试:已执行的恢复步骤
请给出:
-
根因分析
-
紧急恢复步骤
-
长期修复方案
-
预防措施
场景 3:性能优化
当前性能指标:CPU/内存/响应时间
目标指标:期望值
瓶颈分析:已知瓶颈
请优化以下配置:@相关文件
10.6 自动化文档生成与知识沉淀
yaml
# .github/workflows/docs-generation.yml
# 自动生成文档的工作流
name: "Auto Generate Docs"
on:
push:
branches: [main]
paths:
- 'terraform/modules/**'
- 'ansible/roles/**'
jobs:
generate-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 生成 Terraform 模块文档
uses: terraform-docs/gh-actions@v1
with:
working-dir: terraform/modules/
output-file: README.md
output-method: inject
git-push: true
- name: 生成 Ansible Role 文档
run: |
pip install ansible-docgen
for role in ansible/roles/*/; do
role_name=$(basename $role)
ansible-docgen -r $role -o docs/roles/${role_name}.md 2>/dev/null || true
done
- name: 提交文档更新
run: |
git config user.name "docs-bot"
git config user.email "docs-bot@example.com"
git add docs/ terraform/modules/*/README.md
git diff --cached --quiet || git commit -m "docs: 自动更新模块文档"
git push
使用 Cursor AI 生成 Runbook:
Prompt:
@terraform/environments/production/ @ansible/playbooks/site.yml
请根据以上代码生成完整的运维 Runbook,包含:
1. 系统架构概述
2. 日常运维操作手册
3. 故障处理流程(按严重程度分级)
4. 扩缩容操作步骤
5. 备份恢复流程
6. 监控告警说明
7. 联系方式和升级路径
常见陷阱与问题排除
陷阱一:State 文件泄露
问题描述: 将 .tfstate 文件提交到 Git 仓库,导致敏感信息(密码、密钥)泄露。
解决方案:
bash
# 1. 确保 .gitignore 包含
*.tfstate
*.tfstate.*
.terraform/
# 2. 如果已经提交,立即从历史中移除
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch *.tfstate*' \
--prune-empty --tag-name-filter cat -- --all
# 3. 轮换所有泄露的密钥
# 4. 启用远程后端(S3 + 加密)
陷阱二:Ansible Vault 密码丢失
问题描述: 忘记了 Vault 密码,无法解密敏感变量。
预防措施:
bash
# 1. Vault 密码存储在安全的位置(如密码管理器)
# 2. CI/CD 中使用 GitHub Secrets 存储
# 3. 团队中至少 2 人知道密码
# 4. 定期备份加密前的内容(在安全环境中)
# 如果密码丢失:
# - 检查 CI/CD Secrets 中是否有
# - 检查团队成员的本地 ~/.vault_pass
# - 最坏情况:重新创建加密文件(需要重新设置所有密码)
陷阱三:Terraform 资源漂移
问题描述: 有人手动修改了云资源,导致实际状态与 State 不一致。
bash
# 检测漂移
terraform plan -detailed-exitcode
# 退出码 2 表示存在差异
# 解决方案 1:将手动变更纳入管理
terraform import <resource_type>.<name> <resource_id>
# 解决方案 2:恢复为代码定义的状态
terraform apply # 将实际状态改回代码定义
# 预防措施:
# - 使用 IAM 策略限制控制台手动修改
# - 设置 Config Rules 检测漂移
# - 定期运行 terraform plan 检查
陷阱四:CI/CD 中的并发部署冲突
问题描述: 多个 PR 同时触发部署,导致资源冲突。
yaml
# 解决方案:使用并发控制
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false # 不取消,等待完成
# 或使用环境锁
jobs:
deploy:
environment:
name: production
url: https://app.example.com
# GitHub Environment 会自动排队
陷阱五:AI 生成代码的隐含假设
问题描述: AI 生成的代码可能假设特定环境存在,但实际环境中不存在。
yaml
# 示例:AI 假设已安装 python3-pip
- name: 安装 Python 包
ansible.builtin.pip:
name: requests
# 如果目标机器没有 pip,会失败
# 解决:添加依赖检查
- name: 确保 pip 已安装
ansible.builtin.apt:
name: python3-pip
state: present
when: ansible_os_family == "Debian"
- name: 安装 Python 包
ansible.builtin.pip:
name: requests
陷阱六:过度依赖 AI 不做审查
问题描述: 直接使用 AI 生成的代码而不审查,可能引入安全漏洞或逻辑错误。
最佳实践:
1. AI 生成 → 人工审查 → 本地测试 → 提交 PR → 同事审查 → 合并
2. 永远不要将 AI 输出直接部署到生产环境
3. 重点审查:安全配置、权限设置、资源规格(成本)
4. 使用 Lint 工具自动检查
5. 在开发环境充分测试后再推进
问题排除速查表
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
terraform init 失败 |
网络问题/版本不兼容 | 检查代理、清除缓存重试 |
| Ansible 连接超时 | 防火墙/SSH 配置 | 检查安全组、sshd_config |
| Playbook 执行慢 | gather_facts/串行执行 | 限制 facts、增加 forks |
| CI/CD 超时 | 资源创建慢 | 增加 timeout、使用 -target |
| State 损坏 | 并发操作/网络中断 | 从 S3 版本恢复 |
| 模块版本冲突 | 依赖不兼容 | 锁定版本、更新 lock 文件 |
| Vault 解密失败 | 密码错误/文件损坏 | 检查密码、重新加密 |
| 安全组不生效 | 规则优先级/关联错误 | 检查 NACL、规则顺序 |
总结
本文从零开始,完整介绍了如何利用 Cursor AI 编辑器结合 GitOps 理念,实现 Ansible 与 Terraform 的智能化、自动化运维。让我们回顾核心要点:
核心收获
1. 工具链搭建是基础
- Cursor IDE + Git + Ansible + Terraform 构成完整的工具链
- 合理的项目目录结构是长期维护的保障
- 环境配置一次做好,后续效率倍增
2. AI 是加速器而非替代品
- Cursor AI 能将编码效率提升 5-10 倍
- 但人工审查不可省略,特别是安全相关配置
.cursorrules是提升 AI 输出质量的关键杠杆
3. GitOps 是协作的基石
- 所有变更通过 Git 管理,可追溯、可回滚
- 分支策略 + PR 审查 + CI/CD 构成完整的交付流水线
- 自动化检查(Lint、安全扫描)是质量门禁
4. 安全是不可妥协的底线
- 密钥管理、最小权限、加密存储缺一不可
- 安全扫描应集成到 CI/CD 中,而非事后补救
- 定期审计确保持续合规
5. 持续优化是长期实践
- 自定义规则集随项目演进不断迭代
- 团队知识库沉淀最佳实践
- 从错误中学习,完善排错流程
推荐学习路径
第 1 周:环境搭建 + Cursor 基础 + 简单 Playbook
第 2 周:Ansible Role 开发 + Terraform 基础
第 3 周:Git 工作流 + CI/CD 流水线
第 4 周:完整项目实战 + 安全加固
第 5 周起:进阶优化 + 团队推广
最后的建议
"自动化运维的终极目标不是消除人的参与,而是将人的精力从重复劳动中解放出来,投入到更有价值的架构设计、性能优化和创新探索中。"
AI 工具正在深刻改变运维工程师的工作方式。掌握 Cursor + GitOps + IaC 的组合,你将在 DevOps 时代拥有显著的竞争优势。但请记住:工具在变,原则不变------可靠性、安全性、可维护性永远是运维工作的核心追求。
详细参考资料
官方文档
| 工具 | 文档地址 | 说明 |
|---|---|---|
| Cursor | https://docs.cursor.sh | AI 编辑器官方文档 |
| Ansible | https://docs.ansible.com | 配置管理权威指南 |
| Terraform | https://developer.hashicorp.com/terraform/docs | IaC 标准参考 |
| GitHub Actions | https://docs.github.com/en/actions | CI/CD 工作流 |
| Git | https://git-scm.com/doc | 版本控制基础 |
推荐书籍
- 《Ansible 权威指南》 - 深入理解 Ansible 架构与最佳实践
- 《Terraform: Up & Running》 (第 3 版) - Terraform 实战经典
- 《GitOps and Kubernetes》 - GitOps 理念与云原生实践
- 《The Phoenix Project》 - DevOps 思维启蒙
- 《Infrastructure as Code》 (第 2 版) - IaC 设计原则
社区资源
- Ansible Galaxy:https://galaxy.ansible.com - 角色和集合共享平台
- Terraform Registry:https://registry.terraform.io - 模块和 Provider 仓库
- HashiCorp Discuss:https://discuss.hashicorp.com - 官方社区论坛
- r/devops:https://reddit.com/r/devops - DevOps 社区讨论
- CNCF Slack:云原生相关技术讨论
在线课程
- HashiCorp Learn:https://developer.hashicorp.com/well-architected-framework
- Ansible 官方 Getting Started:https://www.ansible.com/resources/get-started
- GitHub Actions 实验室:https://skills.github.com
附录
附录 A:完整 .gitignore 模板
gitignore
# ===== Terraform =====
# State 文件(绝不提交)
*.tfstate
*.tfstate.*
*.tfstate.backup
# Provider 目录
.terraform/
.terraform.lock.hcl
# 崩溃日志
crash.log
crash.*.log
# 变量文件(可能包含敏感信息)
*.tfvars
*.tfvars.json
!example.tfvars
!example.tfvars.json
# 覆盖文件
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# CLI 配置
.terraformrc
terraform.rc
# Plan 文件
*.tfplan
tfplan
# ===== Ansible =====
*.retry
*.vault_pass
.vault_pass
logs/
*.log
# ===== Python =====
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
.venv/
env/
*.egg-info/
dist/
build/
*.egg
# ===== IDE =====
.idea/
.vscode/
*.swp
*.swo
*~
.DS_Store
# ===== 敏感信息 =====
*.pem
*.key
*.crt
*.p12
*.pfx
.env
.env.*
secrets/
credentials/
*.credential
# ===== OS =====
Thumbs.db
.DS_Store
Desktop.ini
# ===== 临时文件 =====
tmp/
temp/
*.tmp
*.bak
*.orig
附录 B:Makefile 快捷命令
makefile
# Makefile - 项目常用命令快捷入口
# 用法:make <target>
.PHONY: help init validate plan apply deploy lint clean
# 默认目标
help: ## 显示帮助信息
@echo "GitOps 自动化运维项目 - 可用命令:"
@echo ""
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
# ===== 初始化 =====
init: ## 初始化项目(安装依赖)
@echo "🚀 初始化项目..."
pip install -r requirements.txt
pre-commit install
@echo "✅ 初始化完成"
# ===== 验证 =====
validate: ## 验证所有配置
@echo "🔍 运行验证..."
@./scripts/validate.sh
lint: ## 运行 Lint 检查
@echo "📝 运行 Lint..."
cd ansible && ansible-lint playbooks/ roles/
cd terraform && terraform fmt -check -recursive .
pre-commit run --all-files
# ===== Terraform =====
tf-init: ## Terraform Init(开发环境)
cd terraform/environments/development && terraform init
tf-plan: ## Terraform Plan(开发环境)
cd terraform/environments/development && terraform plan
tf-apply: ## Terraform Apply(开发环境,需确认)
cd terraform/environments/development && terraform apply
tf-destroy: ## ⚠️ Terraform Destroy(危险操作)
@echo "⚠️ 即将销毁所有资源!"
@read -p "确认?(yes/no): " confirm && [ "$$confirm" = "yes" ]
cd terraform/environments/development && terraform destroy
# ===== Ansible =====
deploy-dev: ## 部署到开发环境
cd ansible && ansible-playbook playbooks/site.yml \
-i inventory/hosts.yml \
-e target_environment=development
deploy-staging: ## 部署到预发环境
cd ansible && ansible-playbook playbooks/site.yml \
-i inventory/hosts.yml \
-e target_environment=staging
deploy-prod: ## 部署到生产环境(需确认)
@echo "⚠️ 即将部署到生产环境!"
@read -p "确认?(yes/no): " confirm && [ "$$confirm" = "yes" ]
cd ansible && ansible-playbook playbooks/site.yml \
-i inventory/hosts.yml \
-e target_environment=production
# ===== Git =====
git-clean: ## 清理 Git 未跟踪文件(预览)
git clean -fdn
git-reset: ## 重置到上一次提交(保留文件)
git reset --soft HEAD~1
# ===== 清理 =====
clean: ## 清理临时文件
rm -rf .terraform/
rm -f *.tfplan
rm -rf logs/*
find . -name "*.retry" -delete
find . -name "__pycache__" -type d -exec rm -rf {} +
@echo "✅ 清理完成"
附录 C:常用 Ansible 模块速查
| 模块 | 用途 | 常用参数 |
|---|---|---|
ansible.builtin.apt |
Debian 包管理 | name, state, update_cache |
ansible.builtin.yum |
RedHat 包管理 | name, state |
ansible.builtin.copy |
复制文件 | src, dest, mode, owner |
ansible.builtin.template |
模板渲染 | src, dest, vars |
ansible.builtin.file |
文件/目录管理 | path, state, mode |
ansible.builtin.service |
服务管理 | name, state, enabled |
ansible.builtin.systemd |
Systemd 管理 | name, state, daemon_reload |
ansible.builtin.command |
执行命令 | cmd, creates, removes |
ansible.builtin.shell |
执行 Shell | cmd, executable |
ansible.builtin.uri |
HTTP 请求 | url, method, status_code |
ansible.builtin.wait_for |
等待条件 | port, timeout, state |
ansible.builtin.lineinfile |
修改文件行 | path, regexp, line |
ansible.builtin.blockinfile |
修改文件块 | path, block, marker |
ansible.builtin.user |
用户管理 | name, groups, shell |
ansible.builtin.cron |
定时任务 | name, minute, job |
ansible.builtin.git |
Git 操作 | repo, dest, version |
ansible.builtin.docker_container |
Docker 容器 | name, image, state |
附录 D:Terraform 命令速查
bash
# ===== 基础操作 =====
terraform init # 初始化(下载 Provider)
terraform validate # 语法验证
terraform plan # 预览变更
terraform apply # 执行变更
terraform destroy # 销毁资源
terraform output # 查看输出
terraform show # 显示当前状态
# ===== State 管理 =====
terraform state list # 列出资源
terraform state show <resource> # 查看资源详情
terraform state rm <resource> # 移除资源(不销毁)
terraform state mv <old> <new> # 重命名/移动资源
terraform import <resource> <id> # 导入已有资源
terraform state pull > backup.tfstate # 备份 State
terraform state push backup.tfstate # 恢复 State
# ===== 工作区 =====
terraform workspace list # 列出工作区
terraform workspace new <name> # 创建工作区
terraform workspace select <name> # 切换工作区
terraform workspace show # 当前工作区
# ===== 调试 =====
terraform plan -target=<resource> # 只规划特定资源
terraform apply -auto-approve # 跳过确认
terraform fmt -recursive # 格式化所有文件
terraform graph | dot -Tpng > graph.png # 生成依赖图
TF_LOG=DEBUG terraform plan # 调试日志
# ===== 版本管理 =====
terraform version # 查看版本
terraform providers # 列出 Provider
terraform providers lock -platform=linux_amd64 # 锁定版本
附录 E:GitHub Actions 表达式参考
yaml
# 条件表达式
if: github.ref == 'refs/heads/main' # 仅 main 分支
if: github.event_name == 'pull_request' # 仅 PR 事件
if: contains(github.event.head_commit.message, '[skip ci]') # 跳过
if: success() # 前序成功
if: failure() # 前序失败
if: always() # 始终执行
if: cancelled() # 被取消
# 上下文变量
${{ github.actor }} # 触发者
${{ github.ref }} # 分支/标签引用
${{ github.sha }} # 提交 SHA
${{ github.event_name }} # 事件类型
${{ github.run_id }} # 运行 ID
${{ github.workflow }} # 工作流名称
${{ matrix.environment }} # 矩阵变量
${{ secrets.MY_SECRET }} # 密钥
${{ vars.MY_VAR }} # 仓库变量
${{ needs.job1.outputs.result }} # 跨 Job 输出
# 常用函数
join(array, separator) # 拼接数组
contains(search, item) # 包含判断
startsWith(str, prefix) # 前缀匹配
format(string, args) # 格式化
toJson(obj) # 转 JSON
fromJSON(str) # 解析 JSON
附录 F:项目 requirements.txt
# requirements.txt - Python 依赖
# 安装:pip install -r requirements.txt
# Ansible 核心
ansible==9.5.1
ansible-core==2.16.6
# 代码质量
ansible-lint==6.22.0
yamllint==1.33.0
# Pre-commit
pre-commit==3.6.0
# 密钥检测
detect-secrets==1.4.0
# Jinja2(模板引擎)
jinja2==3.1.3
# YAML 处理
pyyaml==6.0.1
# AWS SDK(Ansible AWS 模块需要)
boto3==1.34.14
botocore==1.34.14
# 工具
python-dotenv==1.0.0
rich==13.7.0 # 美观终端输出
附录 G:故障恢复快速参考卡
┌─────────────────────────────────────────────────────────┐
│ 🚨 紧急故障恢复速查卡 │
├─────────────────────────────────────────────────────────┤
│ │
│ 1️⃣ 确认影响范围 │
│ → 哪些服务受影响?多少用户? │
│ → 通知相关方(Slack/邮件) │
│ │
│ 2️⃣ 回滚到上一个已知正常版本 │
│ Git: git revert <commit> && git push │
│ TF: git checkout <good-commit> -- terraform/ │
│ terraform apply │
│ Ansible: git checkout <good> -- ansible/ │
│ ansible-playbook site.yml │
│ │
│ 3️⃣ 验证恢复 │
│ → 健康检查通过? │
│ → 监控恢复正常? │
│ → 用户可正常访问? │
│ │
│ 4️⃣ 事后复盘(48小时内) │
│ → 根因分析(5 Whys) │
│ → 时间线记录 │
│ → 改进措施 │
│ → 更新 Runbook │
│ │
│ 📞 升级路径: │
│ L1 值班 → L2 团队 Lead → L3 CTO │
│ 超时标准:15min / 30min / 1h │
│ │
└─────────────────────────────────────────────────────────┘
本文完
版本:v1.0 | 最后更新:2026 年 8 月
适用工具版本:Cursor 0.45+ / Ansible 2.16+ / Terraform 1.7+ / Git 2.40+