架构咨询

控制台点出来的环境,没人说得清它是怎么来的

IaC 解决的不只是效率问题,更是可追溯性问题。每一次基础设施变更都有 commit、有 review、有回滚点。

Terraform 还是 CDK

选 Terraform

  • 团队里运维背景多于开发背景
  • 需要管理多云或云外资源(如 DNS、SaaS 配置)
  • 偏好声明式配置,不想引入编程语言的复杂度
  • 生态成熟,Module 丰富,社区资料多

选 CDK

  • 团队以开发为主,熟悉 TypeScript 或 Python
  • 需要复杂的条件逻辑与抽象复用
  • 主要在 AWS 生态内,深度使用原生服务
  • 希望用同一语言写基础设施与应用代码

Terraform 目录结构与模块化

bash project-structure.txt
infrastructure/
├── modules/                        # 可复用模块,不含环境特定值
│   ├── vpc/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── README.md               # 每个模块必须有用法说明
│   ├── eks-cluster/
│   ├── rds-instance/
│   ├── alb-service/
│   └── observability/
│
├── environments/                   # 环境入口,只做模块编排与参数注入
│   ├── prod/
│   │   ├── main.tf
│   │   ├── terraform.tfvars
│   │   ├── backend.tf              # 独立 state,独立账号
│   │   └── providers.tf
│   ├── staging/
│   └── dev/
│
├── global/                         # 跨环境共享资源
│   ├── organizations/              # 账号结构与 SCP
│   ├── iam-identity-center/        # SSO 权限集
│   └── route53-zones/              # 公共 DNS
│
├── policies/                       # 策略即代码
│   ├── sentinel/                   # 或 OPA / Checkov 规则
│   └── checkov-baseline.yaml
│
├── scripts/
│   ├── plan-all.sh                 # 批量 plan,用于 CI 检查
│   └── drift-detect.sh             # 定期检测配置漂移
│
└── .github/workflows/
    ├── terraform-plan.yml          # PR 时自动 plan 并评论
    └── terraform-apply.yml         # 合并后 apply,需人工批准

关键约定:
  1. 每个环境独立 state 文件,独立 AWS 账号,物理隔离
  2. state 存 S3 + DynamoDB 锁,开启版本控制与加密
  3. 生产环境 apply 必须走 CI,禁止本地执行
  4. 模块版本用 git tag 锁定,不用 main 分支
  5. 敏感值走 Secrets Manager 或 SSM,不进代码库
  6. 每周跑一次 drift 检测,发现手工改动立即告警

CI 中的 plan 与策略检查

yaml .github/workflows/terraform-plan.yml
name: Terraform Plan

on:
  pull_request:
    paths: ['infrastructure/**']

permissions:
  contents: read
  pull-requests: write
  id-token: write

jobs:
  plan:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        env: [dev, staging, prod]
    steps:
      - uses: actions/checkout@v4

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9.8      # 锁定版本,避免行为差异

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets[format('TF_PLAN_ROLE_{0}', matrix.env)] }}
          aws-region: ap-northeast-1

      - name: Format check
        run: terraform fmt -check -recursive
        working-directory: infrastructure

      - name: Init
        run: terraform init -input=false
        working-directory: infrastructure/environments/${{ matrix.env }}

      - name: Validate
        run: terraform validate
        working-directory: infrastructure/environments/${{ matrix.env }}

      - name: Plan
        id: plan
        run: |
          terraform plan -input=false -no-color -out=tfplan \
            | tee plan.txt
          terraform show -json tfplan > plan.json
        working-directory: infrastructure/environments/${{ matrix.env }}

      # 静态安全扫描:拦截公开访问、缺失加密等问题
      - name: Checkov scan
        uses: bridgecrewio/checkov-action@master
        with:
          file: infrastructure/environments/${{ matrix.env }}/plan.json
          framework: terraform_plan
          soft_fail: false
          config_file: infrastructure/policies/checkov-baseline.yaml

      # 检测破坏性变更:删除数据库、S3 桶这类操作需要人工确认
      - name: Check destructive changes
        run: |
          DESTROY_COUNT=$(jq '[.resource_changes[]
            | select(.change.actions | index("delete"))
            | select(.type | test("aws_(db_instance|s3_bucket|rds_cluster|efs_file_system)"))]
            | length' plan.json)
          if [ "$DESTROY_COUNT" -gt 0 ]; then
            echo "::warning::检测到 $DESTROY_COUNT 个有状态资源将被删除,需要人工确认"
            jq -r '.resource_changes[]
              | select(.change.actions | index("delete"))
              | "  - " + .address' plan.json
          fi
        working-directory: infrastructure/environments/${{ matrix.env }}

      - name: Comment plan on PR
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const plan = fs.readFileSync(
              'infrastructure/environments/${{ matrix.env }}/plan.txt', 'utf8'
            );
            const truncated = plan.length > 60000
              ? plan.slice(0, 60000) + '\n... (输出过长已截断)'
              : plan;
            await github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `### Terraform Plan · \`${{ matrix.env }}\`\n\n<details><summary>展开查看</summary>\n\n\`\`\`hcl\n${truncated}\n\`\`\`\n\n</details>`
            });

破坏性变更检测这一步很关键。Terraform 的 plan 输出很长,人容易看漏一行「will be destroyed」。

下一步

把云的复杂度交给我们,你只管做业务

留下需求,沐杉云的解决方案架构师会在一个工作日内联系你,提供免费的现状评估、迁移方案草案与 TCO 测算表。