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

Azure容器应用部署:自定义域名与托管证书自动化困境求解

解决方案:分阶段自动化部署流程

核心思路

把部署拆成三个独立且衔接的阶段,通过GitHub Actions的多Job/多步骤依次执行,用Bicep的条件部署和输出变量传递资源ID,破解“鸡生蛋”矛盾:

  1. 第一阶段:部署容器应用并配置自定义域名(无证书绑定)
    先完成域名与容器应用的关联,满足托管证书创建的前置条件,暂不绑定证书。
    示例Bicep片段:

    resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
      name: 'api-app'
      location: resourceGroup().location
      properties: {
        environmentId: containerAppEnv.id
        configuration: {
          customDomains: [
            {
              name: 'api.example.com'
              bindingType: 'SniEnabled'
              // 暂不指定certificateId
            }
          ]
        }
        // 其他容器应用配置(镜像、资源配额等)
      }
    }
    
    // 输出后续步骤需要的资源信息
    output containerAppId string = containerApp.id
    output customDomainName string = 'api.example.com'
    
  2. 第二阶段:创建托管证书
    依赖第一阶段的输出,创建与容器应用、目标域名绑定的托管证书。
    示例Bicep片段:

    param containerAppId string
    param customDomainName string
    
    resource managedCertificate 'Microsoft.App/managedCertificates@2023-05-01' = {
      name: 'api-cert'
      location: resourceGroup().location
      properties: {
        containerAppId: containerAppId
        domainControlValidation: 'Http' // 按需选择Http/Dns验证方式
        subjectName: customDomainName
      }
    }
    
    output certificateId string = managedCertificate.id
    
  3. 第三阶段:更新容器应用绑定证书
    依赖前两个阶段的输出,给容器应用的自定义域名添加证书ID绑定。
    示例Bicep片段:

    param containerAppId string
    param customDomainName string
    param certificateId string
    
    resource containerApp 'Microsoft.App/containerApps@2023-05-01' existing = {
      name: split(containerAppId, '/')[8] // 从资源ID提取应用名称
      properties: {
        configuration: {
          customDomains: [
            {
              name: customDomainName
              bindingType: 'SniEnabled'
              certificateId: certificateId
            }
          ]
        }
      }
    }
    

GitHub Actions 自动化配置

用三个Job依次执行,通过needs保证执行顺序,用outputs传递变量:

name: Deploy Container App with Custom Domain & Cert
on: [push]

jobs:
  deploy-app-with-domain:
    runs-on: ubuntu-latest
    outputs:
      container_app_id: ${{ steps.deploy.outputs.containerAppId }}
      custom_domain: ${{ steps.deploy.outputs.customDomainName }}
    steps:
      - uses: actions/checkout@v4
      - name: Azure Login
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Deploy App with Custom Domain
        id: deploy
        uses: azure/arm-deploy@v2
        with:
          resourceGroupName: 'your-resource-group'
          template: './infra/app-with-domain.bicep'
          parameters: './infra/app-params.json'

  create-managed-cert:
    runs-on: ubuntu-latest
    needs: deploy-app-with-domain
    outputs:
      certificate_id: ${{ steps.create-cert.outputs.certificateId }}
    steps:
      - uses: actions/checkout@v4
      - name: Azure Login
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Create Managed Certificate
        id: create-cert
        uses: azure/arm-deploy@v2
        with:
          resourceGroupName: 'your-resource-group'
          template: './infra/managed-cert.bicep'
          parameters: |
            containerAppId=${{ needs.deploy-app-with-domain.outputs.container_app_id }}
            customDomainName=${{ needs.deploy-app-with-domain.outputs.custom_domain }}

  bind-cert-to-app:
    runs-on: ubuntu-latest
    needs: [deploy-app-with-domain, create-managed-cert]
    steps:
      - uses: actions/checkout@v4
      - name: Azure Login
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Wait for Certificate Readiness
        run: |
          az resource wait --ids ${{ needs.create-managed-cert.outputs.certificate_id }} --custom "properties.provisioningState=='Succeeded'" --timeout 300
      - name: Bind Certificate to App
        uses: azure/arm-deploy@v2
        with:
          resourceGroupName: 'your-resource-group'
          template: './infra/bind-cert.bicep'
          parameters: |
            containerAppId=${{ needs.deploy-app-with-domain.outputs.container_app_id }}
            customDomainName=${{ needs.deploy-app-with-domain.outputs.custom_domain }}
            certificateId=${{ needs.create-managed-cert.outputs.certificate_id }}

关键注意事项

  • 域名验证:选择Http验证时,Azure容器应用会自动处理/.well-known/acme-challenge/路由,无需额外配置;选择Dns验证时,需提前通过Bicep或手动在DNS提供商处添加TXT记录。
  • 幂等性:所有Bicep模板需保证重复执行不报错,比如用existing关键字引用现有资源,仅修改必要字段。
  • 等待机制:证书创建需数分钟,第三阶段添加的az resource wait命令可确保证书就绪后再执行绑定操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:33:23