Terraform CI/CD 集成 #
CI/CD 概述 #
将 Terraform 集成到 CI/CD 流水线可以实现自动化部署、代码质量检查、安全扫描和合规验证。
text
┌─────────────────────────────────────────────────────────────┐
│ CI/CD 流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 代码提交 │
│ │ │
│ ▼ │
│ 格式检查 → 语法验证 → 安全扫描 │
│ │ │
│ ▼ │
│ 计划生成 │
│ │ │
│ ▼ │
│ 人工审批 │
│ │ │
│ ▼ │
│ 执行部署 │
│ │
└─────────────────────────────────────────────────────────────┘
GitHub Actions #
基本工作流 #
yaml
name: Terraform CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.6.6
- name: Terraform Init
run: terraform init
- name: Terraform Format
run: terraform fmt -check
- name: Terraform Validate
run: terraform validate
- name: Terraform Plan
run: terraform plan -out=tfplan
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: terraform apply -auto-approve tfplan
完整工作流 #
yaml
name: Terraform Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
TF_VERSION: 1.6.6
AWS_REGION: us-east-1
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Terraform Init
run: terraform init -backend=false
- name: Terraform Format
run: terraform fmt -check -recursive
- name: Terraform Validate
run: terraform validate
- name: TFLint
uses: terraform-linters/setup-tflint@v3
with:
tflint_version: v0.47.0
- run: tflint --init
- run: tflint -f compact
security:
runs-on: ubuntu-latest
needs: validate
steps:
- uses: actions/checkout@v3
- name: Run tfsec
uses: aquasecurity/tfsec-action@v1.0.0
with:
soft_fail: false
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: .
framework: terraform
soft_fail: false
plan:
runs-on: ubuntu-latest
needs: [validate, security]
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
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
run: terraform init
- name: Terraform Plan
id: plan
run: terraform plan -no-color -out=tfplan
- name: Comment Plan
uses: actions/github-script@v6
with:
script: |
const plan = `${{ steps.plan.outputs.stdout }}`;
const output = `## Terraform Plan\n\`\`\`\n${plan}\n\`\`\``;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
});
apply:
runs-on: ubuntu-latest
needs: [validate, security]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
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
run: terraform init
- name: Terraform Plan
run: terraform plan -out=tfplan
- name: Terraform Apply
run: terraform apply -auto-approve tfplan
GitLab CI #
基本配置 #
yaml
stages:
- validate
- plan
- apply
variables:
TF_ROOT: ${CI_PROJECT_DIR}
TF_IN_AUTOMATION: "true"
.terraform:
image: hashicorp/terraform:1.6.6
before_script:
- cd ${TF_ROOT}
- terraform init
validate:
extends: .terraform
stage: validate
script:
- terraform fmt -check -recursive
- terraform validate
plan:
extends: .terraform
stage: plan
script:
- terraform plan -out=tfplan
artifacts:
paths:
- ${TF_ROOT}/tfplan
expire_in: 1 week
apply:
extends: .terraform
stage: apply
script:
- terraform apply -auto-approve tfplan
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
environment:
name: production
完整配置 #
yaml
stages:
- validate
- security
- plan
- apply
- destroy
variables:
TF_ROOT: ${CI_PROJECT_DIR}
TF_IN_AUTOMATION: "true"
AWS_REGION: us-east-1
.terraform:
image: hashicorp/terraform:1.6.6
before_script:
- cd ${TF_ROOT}
- terraform init -backend-config="lockfile=false"
validate:
extends: .terraform
stage: validate
script:
- terraform fmt -check -recursive
- terraform validate
tflint:
stage: security
image: alpine:latest
script:
- apk add --no-cache curl
- curl -L https://github.com/terraform-linters/tflint/releases/download/v0.47.0/tflint_linux_amd64.zip -o tflint.zip
- unzip tflint.zip
- ./tflint --init
- ./tflint -f compact
tfsec:
stage: security
image: aquasec/tfsec:latest
script:
- tfsec . --soft-fail=false
plan:
extends: .terraform
stage: plan
script:
- terraform plan -out=tfplan -input=false
artifacts:
paths:
- ${TF_ROOT}/tfplan
- ${TF_ROOT}/.terraform
expire_in: 1 week
apply:
extends: .terraform
stage: apply
script:
- terraform apply -auto-approve tfplan
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
environment:
name: production
url: https://example.com
destroy:
extends: .terraform
stage: destroy
script:
- terraform destroy -auto-approve
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
environment:
name: production
action: stop
多环境部署 #
环境矩阵 #
yaml
name: Terraform Multi-Environment
on:
push:
branches: [main]
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy'
required: true
default: 'dev'
type: choice
options:
- dev
- staging
- prod
jobs:
terraform:
runs-on: ubuntu-latest
strategy:
matrix:
environment: [dev, staging, prod]
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Init
run: |
cd environments/${{ matrix.environment }}
terraform init
- name: Terraform Plan
run: |
cd environments/${{ matrix.environment }}
terraform plan -out=tfplan
- name: Terraform Apply
if: github.event.inputs.environment == matrix.environment
run: |
cd environments/${{ matrix.environment }}
terraform apply -auto-approve tfplan
环境保护规则 #
yaml
name: Terraform Production Deploy
on:
push:
branches: [main]
jobs:
apply:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Apply
run: terraform apply -auto-approve
最佳实践 #
1. 使用环境变量 #
yaml
env:
TF_VAR_environment: ${{ github.ref_name }}
TF_VAR_project_name: my-project
TF_IN_AUTOMATION: true
2. 缓存 Provider #
yaml
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.6.6
- name: Cache Terraform
uses: actions/cache@v3
with:
path: |
~/.terraform.d/plugin-cache
.terraform
key: ${{ runner.os }}-terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
restore-keys: |
${{ runner.os }}-terraform-
3. 使用 OIDC 认证 #
yaml
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions
aws-region: us-east-1
4. 添加审批 #
yaml
jobs:
plan:
outputs:
plan: ${{ steps.plan.outputs.stdout }}
steps:
- name: Terraform Plan
id: plan
run: terraform plan -no-color
approve:
needs: plan
runs-on: ubuntu-latest
environment: approval
steps:
- name: Approve
run: echo "Approved"
apply:
needs: approve
runs-on: ubuntu-latest
steps:
- name: Terraform Apply
run: terraform apply -auto-approve
下一步 #
掌握了 CI/CD 集成后,接下来学习 Web 应用部署,通过实战案例巩固所学知识!
最后更新:2026-03-29