You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Terraform+GitHub Actions创建独立Azure容器实例遇资源替换问题

问题

我正尝试基于GitHub Actions实现自助流水线,通过Terraform部署Azure容器实例(ACI)等基础设施,目标为每个feature/**分支触发部署同名容器组,且所有资源需共存直至手动销毁。

目前遇到的问题是:当分支名称(对应资源名称)变更时,Terraform会销毁原有容器组并创建新资源,而非新增独立资源。我未使用Terraform Cloud,想到的临时方案是通过bash脚本向backend.tf注入变量,为每个分支创建独立Azure远程后端存储状态,但Terraform本身不支持在backend配置中使用内置变量,不确定是否有更优方案。

当前GitHub Actions工作流如下:

permissions:
  id-token: write # required to use OIDC authentication
  contents: read # required to checkout the code from the repo

name: feature-deploy

on:
  push:
    branches:
      - "feature/**"

jobs:
   build:
     name: build-feature
     # ... 构建Docker镜像并上传到Azure容器注册表的工作流

  deploy-aci:
    name: deploy-aci
    runs-on: ubuntu-latest
    env:
      BRANCH_NAME: ${{ github.ref_name }}
      ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
      ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
      ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
      ARM_USE_OIDC: true
    defaults:
      run:
        working-directory: aci/terraform/azure-container-instances
    needs: build
    
    steps:
    - name: Checkout aci terraform repo
      uses: actions/checkout@v3
      with:
        repository: MyOrg/azure-feature-environments
        path: aci
        token: ${{ secrets.ACI_REPOSITORY_ACCESS_TOKEN }}

    - name: Setup terraform ENV variables
      run: echo "TF_VAR_branch_name=${{ env.BRANCH_NAME }}" >> $GITHUB_ENV

    - name: Setup terraform
      uses: hashicorp/setup-terraform@v2

    - name: Terraform Init
      id: init
      run: terraform init

    - name: Terraform Validate
      id: validate
      run: terraform validate -no-color

    - name: Terraform Plan
      id: plan
      run: terraform plan -no-color -input=false

    - name: Terraform Apply
      run: terraform apply -auto-approve -input=false

已尝试操作:假设Terraform已部署名为branch1的资源,推送branch2分支触发工作流,传入分支名称作为环境变量。
预期结果:创建名为branch2的新容器组及配套资源,不销毁branch1资源。
实际结果:Terraform销毁branch1资源,替换为branch2资源。


原因分析

问题的核心是所有分支共用同一个Terraform状态文件。Terraform通过状态文件跟踪已部署的资源,当你切换分支运行apply时,Terraform会对比当前代码定义的资源(对应新分支)和状态文件中的资源(对应旧分支),认为旧分支的资源已被移除,因此会销毁旧资源并创建新资源。

要实现分支间资源共存,必须让每个分支拥有独立的Terraform状态文件,确保各分支的资源状态互不干扰。


解决方案

以下是两种无需Terraform Cloud的可行方案,均能实现分支独立部署:

方案1:使用Terraform Workspaces

Terraform Workspaces允许在同一个配置下维护多个独立状态,每个Workspace对应一个分支。Azure Blob Storage作为后端时,会自动为每个Workspace创建独立的状态文件路径。

修改步骤:

  1. 更新GitHub Actions工作流,在Terraform Init步骤前添加Workspace选择/创建逻辑:

    - name: Select or Create Terraform Workspace
      run: |
        terraform workspace select ${{ env.BRANCH_NAME }} || terraform workspace new ${{ env.BRANCH_NAME }}
    

    此命令会尝试切换到与分支同名的Workspace,若不存在则自动创建。

  2. 确保Terraform资源命名唯一,在代码中使用var.branch_name作为资源名称的前缀或组成部分,避免跨Workspace资源冲突:

    variable "branch_name" {
      type        = string
      description = "Name of the feature branch, used to unique resource names"
    }
    
    resource "azurerm_container_group" "aci" {
      name                = "${var.branch_name}-container-group"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      ip_address_type     = "Public"
      dns_name_label      = "${var.branch_name}-aci-dns" # 需确保全局唯一
      os_type             = "Linux"
    
      container {
        name   = "app-container"
        image  = "myacr.azurecr.io/myapp:${var.branch_name}"
        cpu    = "1.0"
        memory = "1.5"
    
        ports {
          port     = 80
          protocol = "TCP"
        }
      }
    }
    

方案2:动态指定Backend状态文件路径

通过terraform init的-backend-config参数,为每个分支指定独立的状态文件存储路径,避免共用同一个状态文件。

修改步骤:

  1. 更新GitHub Actions的Terraform Init步骤,动态传入状态文件的key路径:

    - name: Terraform Init
      id: init
      run: terraform init -backend-config="key=aci/${{ env.BRANCH_NAME }}/terraform.tfstate"
    

    此配置会将每个分支的状态文件存储到Azure Blob容器的aci/[分支名]/terraform.tfstate路径下,实现状态隔离。

  2. 同方案1,确保Terraform资源名称包含var.branch_name,避免资源命名冲突。


额外注意事项
  1. 分支名称特殊字符处理:Azure资源名称不允许包含/、@等特殊字符,需在GitHub Actions中预处理分支名:

    env:
      BRANCH_NAME: ${{ replace(github.ref_name, '/', '-') }}
    

    将分支名中的/替换为-,符合Azure命名规则。

  2. 权限控制:确保GitHub Actions使用的OIDC身份对Azure存储账户拥有Storage Blob Data Contributor权限,能读写对应的状态文件路径。

  3. 资源清理:如需销毁某个分支的资源,可在对应分支运行terraform destroy,或直接删除该分支对应的Workspace/状态文件后手动清理Azure资源。

内容的提问来源于stack exchange,提问作者alig227

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 21:55:21