关于 infrastructure-as-code
此技能帮助 Agent 使用 Terraform、Pulumi、AWS CloudFormation、AWS CDK 和 Ansible 设计与管理云基础设施代码,涵盖模块化配置、状态管理、经审查的计划与应用流程,以及漂移检测。
主要功能
- 01支持多种 IaC 工具
- 02生成可复用基础设施模块
- 03配置远程状态与锁定
- 04审查计划后再应用
- 05检测并处理配置漂移
适用场景
- 01为多个环境配置云资源
- 02生成网络与计算模块
- 03部署前审查变更计划
- 04发现并协调非代码变更
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ seb1n/ awesome-ai-agent-skills --skill infrastructure-as-code安装后在 Claude Code 中输入/infrastructure-as-code确认已加载。
详细介绍
基础设施即代码
此技能可帮助 Agent 为云环境设计、生成和管理基础设施即代码(IaC)。Agent 可以为 Terraform、Pulumi、AWS CloudFormation 和 AWS CDK 生成配置,并实现完整的计划/应用工作流,同时妥善管理状态、采用模块化设计并检测配置漂移。IaC 可确保基础设施与应用代码一同进行版本管理,从而实现可重复部署、基础设施变更的同行评审,以及跨环境自动化配置。
工作流
-
收集基础设施需求: Agent 收集所需基础设施的详细信息,包括云服务提供商(AWS、GCP、Azure)、所需资源(计算、存储、网络、数据库)、容量和性能要求、安全约束以及目标环境(开发、预发布、生产)。Agent 会识别资源之间的依赖关系,以确定正确的配置顺序。
-
选择 IaC 工具并初始化项目: Agent 根据团队的专业知识和项目约束推荐 IaC 工具。对于多云和与服务提供商无关的设置,优先选择 Terraform;对于偏好使用通用编程语言的团队,推荐 Pulumi;对于以 AWS 为主的组织,则推荐 CloudFormation 或 CDK。Agent 会初始化项目结构,并为模块、环境和共享配置分别创建目录。
-
使用模块生成基础设施代码: Agent 使用可复用模块生成结构清晰的 IaC 代码。网络(VPC、子网、安全组)、计算(EC2、ECS、Lambda)和数据(RDS、S3、DynamoDB)分别拆分为独立模块,并明确定义输入和输出。变量采用参数化配置,以便同一模块在不同环境中使用不同容量配置。
-
配置状态管理: Agent 会设置远程状态存储(例如,Terraform 使用 S3 + DynamoDB,Pulumi 使用 Pulumi Cloud),并启用状态锁定以防止并发修改。状态文件包含敏感数据,绝不会提交到版本控制中。Agent 会配置静态状态加密,并对状态后端实施严格的访问控制。
-
执行计划和应用: Agent 运行计划步骤(
terraform plan、pulumi preview),生成拟议变更的详细差异,然后在应用前将计划提交给用户审核。Agent 会确认没有意外资源将被销毁或重新创建。只有在获得明确批准后,Agent 才会执行应用步骤来配置基础设施。 -
检测并修复配置漂移: Agent 会定期运行漂移检测(
terraform plan、pulumi refresh),比较实际基础设施状态与声明的配置。通过控制台或 CLI 在代码之外进行的任何更改都会被标记,并会被还原到 IaC 定义,或显式导入状态。这可确保 IaC 代码始终是唯一事实来源。
支持的技术
- IaC 工具: Terraform(HCL)、Pulumi(TypeScript、Python、Go、C#)、AWS CloudFormation(YAML/JSON)、AWS CDK(TypeScript、Python)、Ansible
- 云服务提供商: AWS、Google Cloud Platform、Microsoft Azure、DigitalOcean、Cloudflare
- 状态后端: S3 + DynamoDB、Terraform Cloud、Pulumi Cloud、GCS、Azure Blob Storage
- CI/CD 集成: Atlantis、Spacelift、Terraform Cloud、GitHub Actions、GitLab CI
使用方法
向 Agent 提供云服务提供商、要配置的资源、容量要求,以及合规标准或成本预算等任何约束。
提示词示例:
Create Terraform configuration for an AWS environment with:
- VPC with public and private subnets across 2 AZs
- An EC2 bastion host in the public subnet
- An RDS PostgreSQL instance in the private subnet
- Security groups allowing SSH to bastion and app-to-database traffic only
示例
示例 1:用于 AWS VPC + EC2 + RDS 的 Terraform 配置
main.tf:
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
provider "aws" {
region = var.aws_region
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.0"
name = "${var.project}-vpc"
cidr = "10.0.0.0/16"
azs = ["${var.aws_region}a", "${var.aws_region}b"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.10.0/24", "10.0.20.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
tags = var.common_tags
}
resource "aws_security_group" "bastion" {
name_prefix = "${var.project}-bastion-"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.allowed_ssh_cidr]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = merge(var.common_tags, { Name = "${var.project}-bastion-sg" })
}
resource "aws_instance" "bastion" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
subnet_id = module.vpc.public_subnets[0]
vpc_security_group_ids = [aws_security_group.bastion.id]
key_name = var.key_pair_name
associate_public_ip_address = true
tags = merge(var.common_tags, { Name = "${var.project}-bastion" })
}
resource "aws_security_group" "rds" {
name_prefix = "${var.project}-rds-"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}
tags = merge(var.common_tags, { Name = "${var.project}-rds-sg" })
}
resource "aws_db_instance" "postgres" {
identifier = "${var.project}-db"
engine = "postgres"
engine_version = "16.1"
instance_class = var.db_instance_class
allocated_storage = 20
max_allocated_storage = 100
storage_encrypted = true
db_name = var.db_name
username = var.db_username
password = var.db_password
db_subnet_group_name = module.vpc.database_subnet_group_name
vpc_security_group_ids = [aws_security_group.rds.id]
skip_final_snapshot = false
final_snapshot_identifier = "${var.project}-db-final"
backup_retention_period = 7
multi_az = var.environment == "production"
tags = var.common_tags
}
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
output "bastion_public_ip" {
value = aws_instance.bastion.public_ip
}
output "rds_endpoint" {
value = aws_db_instance.postgres.endpoint
}
variables.tf:
variable "aws_region" { default = "us-east-1" }
variable "project" { default = "myproject" }
variable "environment" { default = "production" }
variable "allowed_ssh_cidr" { description = "CIDR block allowed to SSH to bastion" }
variable "key_pair_name" { description = "EC2 key pair name" }
variable "db_instance_class" { default = "db.t3.medium" }
variable "db_name" { default = "appdb" }
variable "db_username" { default = "appuser" }
variable "db_password" { sensitive = true }
variable "common_tags" {
type = map(string)
default = { ManagedBy = "terraform", Project = "myproject" }
}
示例 2:用于无服务器 API 的 Pulumi TypeScript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as apigateway from "@pulumi/aws-apigateway";
const config = new pulumi.Config();
const stage = pulumi.getStack();
// DynamoDB table for the API
const table = new aws.dynamodb.Table("items-table", {
attributes: [{ name: "id", type: "S" }],
hashKey: "id",
billingMode: "PAY_PER_REQUEST",
tags: { Environment: stage, ManagedBy: "pulumi" },
});
// Lambda function for API handlers
const lambdaRole = new aws.iam.Role("api-lambda-role", {
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: { Service: "lambda.amazonaws.com" },
}],
}),
});
new aws.iam.RolePolicyAttachment("lambda-basic", {
role: lambdaRole.name,
policyArn: aws.iam.ManagedPolicies.AWSLambdaBasicExecutionRole,
});
new aws.iam.RolePolicyAttachment("lambda-dynamodb", {
role: lambdaRole.name,
policyArn: aws.iam.ManagedPolicies.AmazonDynamoDBFullAccess,
});
const handler = new aws.lambda.Function("api-handler", {
runtime: aws.lambda.Runtime.NodeJS20dX,
handler: "index.handler",
code: new pulumi.asset.AssetArchive({
".": new pulumi.asset.FileArchive("./lambda"),
}),
role: lambdaRole.arn,
environment: {
variables: {
TABLE_NAME: table.name,
STAGE: stage,
},
},
memorySize: 256,
timeout: 30,
tags: { Environment: stage, ManagedBy: "pulumi" },
});
// API Gateway REST API
const api = new apigateway.RestAPI("items-api", {
routes: [
{ path: "/items", method: "GET", eventHandler: handler },
{ path: "/items", method: "POST", eventHandler: handler },
{ path: "/items/{id}", method: "GET", eventHandler: handler },
{ path: "/items/{id}", method: "DELETE", eventHandler: handler },
],
stageName: stage,
});
export const apiUrl = api.url;
export const tableName = table.name;
最佳实践
- 生产环境中绝不在本地存储状态: 始终使用带有状态锁定的远程后端(S3 + DynamoDB、Terraform Cloud、Pulumi Cloud)。本地状态文件可能丢失或损坏;多个团队成员并发运行 apply 时,还可能产生冲突。
- 使用模块实现复用: 将常见模式(VPC、安全组、ECS 服务)提取到带版本管理的模块中。这样可以减少重复,并确保所有环境和团队始终遵循统一的基础设施标准。
- 将密钥视为敏感变量: 在 Terraform 中将数据库密码、API 密钥和令牌标记为
sensitive,或使用 Pulumi 的密钥加密功能。绝不要在 IaC 文件中硬编码密钥。集成 AWS Secrets Manager 或 HashiCorp Vault,以便在运行时注入密钥。 - 在 CI 中运行 plan,经审批后再 apply: 将 IaC 集成到 CI/CD 流水线中,确保每个拉取请求都显示 plan 差异。使用 Atlantis 或 Spacelift 等工具自动发布 plan 评论,并要求在生产环境运行 apply 前进行人工审批。
- 统一标记所有资源: 为每项资源应用标准标签(Project、Environment、Team、ManagedBy)。标签有助于分摊成本、控制访问权限,以及自动清理孤立资源。
- 使用工作区或堆栈管理环境: 使用 Terraform 工作区或 Pulumi 堆栈,为每个环境(dev、staging、production)维护单独的状态。通过环境专用的变量文件共享同一份代码,确保环境一致。
边缘情况
- 状态锁争用: 如果上一次 apply 崩溃或中断,状态锁可能仍处于占用状态。只有在确认没有其他 apply 正在运行后,才使用
terraform force-unlock(并指定锁 ID)。对于同类情况,Pulumi 提供了pulumi cancel。 - 手动更改导致配置漂移: 通过云控制台或 CLI 修改的资源将与 IaC 状态不一致。定期运行
terraform plan检测漂移,然后撤销手动更改,或使用terraform import将其导入。避免手动更改由 IaC 管理的资源。 - 循环依赖: Terraform 无法处理循环资源引用(例如,安全组 A 引用 B,而 B 又引用 A)。可先创建不含规则的安全组,再通过单独的
aws_security_group_rule资源添加规则,以打破循环依赖。 - Provider 版本的破坏性更改: 主要版本的 Provider 更新可能会更改资源架构并导致 plan 失败。在
required_providers中固定 Provider 版本,并通过经过测试的 plan/apply 流程谨慎升级。 - 状态文件过大导致性能下降: 随着基础设施规模扩大,状态文件可能变得很大,从而拖慢 plan/apply 操作。可按状态拆分基础设施,将其组织为独立的根模块(networking、compute、data),每个模块使用自己的状态文件,并通过
terraform_remote_state数据源共享输出。