Azure容器应用部署:自定义域名与托管证书自动化困境求解
解决方案:分阶段自动化部署流程
核心思路
把部署拆成三个独立且衔接的阶段,通过GitHub Actions的多Job/多步骤依次执行,用Bicep的条件部署和输出变量传递资源ID,破解“鸡生蛋”矛盾:
第一阶段:部署容器应用并配置自定义域名(无证书绑定)
先完成域名与容器应用的关联,满足托管证书创建的前置条件,暂不绑定证书。
示例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'第二阶段:创建托管证书
依赖第一阶段的输出,创建与容器应用、目标域名绑定的托管证书。
示例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第三阶段:更新容器应用绑定证书
依赖前两个阶段的输出,给容器应用的自定义域名添加证书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
相关产品推荐
相关产品推荐

