4. 容器应用定义与部署

把应用真正跑在 Azure 容器应用(Azure Container Apps,ACA)上,核心链路只有四步:镜像构建 → 镜像入库 → 应用定义 → 部署与验证。本节以一条可复现的路径,把 Dockerfile、Azure CLI、Bicep、Terraform 和 GitHub Actions 串起来,完成一次从本地代码到 ACA 上可访问应用的首次部署。

一、Dockerfile:把应用固化成可移植镜像

ACA 只接受容器镜像,因此第一步是让应用具备可构建的 Dockerfile。以 Node.js 服务为例,采用多阶段构建可以显著减小镜像体积并降低攻击面:

# 构建阶段
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .

# 运行阶段
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app ./
EXPOSE 3000
CMD ["node", "server.js"]

关键约定有三点:监听端口必须与后续 ACA 的 targetPort 一致(示例为 3000);进程必须前台运行,不能后台化,否则容器会被判定为退出;镜像标签不要只用 latest,建议使用 Git 短 SHA,例如 myacr.azurecr.io/orders-api:1a2b3c4,便于回滚与追踪。

二、镜像入库:ACR 与身份认证

镜像需要推送到 Azure 容器注册表(ACR)。首次部署时,先创建注册表并登录:

az acr create -g rg-aca-demo -n myacrdemo --sku Basic
az acr login -n myacrdemo
docker build -t myacrdemo.azurecr.io/orders-api:1a2b3c4 .
docker push myacrdemo.azurecr.io/orders-api:1a2b3c4

ACA 拉取镜像时不应使用管理员密码,而应通过托管标识 + AcrPull 角色授权。这是生产环境的基本要求,也是后续 Bicep/Terraform 中必须体现的配置项。

三、应用定义:环境、修订与入口

ACA 的资源模型分三层:环境(Environment)提供共享的网络与日志底座;容器应用(Container App)承载应用定义;修订(Revision)是每次变更产生的不可变快照。首次部署时,需要明确以下参数:

  • ingress:是否启用外部入口、目标端口、传输协议(http/https)。
  • resources:CPU 与内存,例如 0.5 vCPU / 1 GiB。
  • scale:最小/最大副本数,示例 minReplicas=0, maxReplicas=3,可缩容到零以节省成本。
  • registry:镜像地址与托管标识凭据。
  • env:环境变量,敏感值应引用 Key Vault 或 ACA Secret。

下图展示了从代码到 ACA 应用的完整链路,以及各工具在链路中的位置:

从 Dockerfile 到 ACA 应用的部署链路 源代码 + Dockerfile 多阶段构建 端口 3000 Azure 容器注册表 orders-api:1a2b3c4 AcrPull 托管标识 ACA 应用定义 ingress / resources scale / env / secrets ACA 环境 + 修订 Revision 不可变快照 FQDN 对外访问 部署工具(同一目标,不同抽象层级) Azure CLI(命令式) Bicep(ARM 声明式) Terraform(多云声明式) GitHub Actions(CI/CD) 部署后验证 ① az containerapp show 查看 provisioningState = Succeeded ② 访问 FQDN 健康检查端点 /healthz 返回 200 ③ 查看 Revision 与副本数是否符合预期 ④ 检查日志中无镜像拉取或端口错误

四、Azure CLI:最快完成首次部署

CLI 适合验证链路是否通畅。以下命令创建环境并部署应用,注意 --target-port 与 Dockerfile 的 3000 保持一致:

az containerapp env create -g rg-aca-demo -n aca-env-demo --location eastasia

az containerapp create -g rg-aca-demo -n orders-api \
  --environment aca-env-demo \
  --image myacrdemo.azurecr.io/orders-api:1a2b3c4 \
  --registry-server myacrdemo.azurecr.io \
  --target-port 3000 --ingress external \
  --cpu 0.5 --memory 1Gi \
  --min-replicas 0 --max-replicas 3

执行后可用 az containerapp show -n orders-api -g rg-aca-demo --query properties.configuration.ingress.fqdn -o tsv 获取访问地址。若返回 provisioningState: Failed,优先检查镜像标签是否存在、托管标识是否具备 AcrPull 权限、目标端口是否与容器监听端口一致。

五、Bicep 与 Terraform:把定义变成可复用资产

CLI 命令难以版本化,声明式工具更适合规模化。Bicep 直接编译为 ARM 模板,与 Azure 资源模型贴合;Terraform 则适合已有 HCL 工作流的团队。两者都需要显式声明环境、应用、注册表凭据与缩放规则。以 Bicep 为例,核心资源片段如下:

resource app 'Microsoft.App/containerApps@2024-03-01' = {
  name: 'orders-api'
  location: location
  properties: {
    environmentId: env.id
    configuration: {
      ingress: { external: true, targetPort: 3000 }
      registries: [{
        server: 'myacrdemo.azurecr.io'
        identity: managedIdentity.id
      }]
    }
    template: {
      containers: [{
        name: 'orders-api'
        image: 'myacrdemo.azurecr.io/orders-api:1a2b3c4'
        resources: { cpu: json('0.5'), memory: '1Gi' }
      }]
      scale: { minReplicas: 0, maxReplicas: 3 }
    }
  }
}

Terraform 中对应使用 azurerm_container_app 资源,字段语义基本一致,差异主要在引用方式与状态管理。选择建议:纯 Azure 团队优先 Bicep,已有 Terraform 体系则保持一致,不要在同一环境混用两套状态源。

六、GitHub Actions:把首次部署变成可重复流水线

CI/CD 的目标是让每次提交自动产出新修订。推荐使用 OIDC 联合凭据登录 Azure,避免在仓库中存放长期密钥。工作流关键步骤:

- uses: azure/login@v2
  with:
    client-id: ${{ secrets.AZURE_CLIENT_ID }}
    tenant-id: ${{ secrets.AZURE_TENANT_ID }}
    subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- run: |
    az acr build -r myacrdemo -t orders-api:${{ github.sha }} .
    az containerapp update -n orders-api -g rg-aca-demo \
      --image myacrdemo.azurecr.io/orders-api:${{ github.sha }}

使用 az acr build 可在云端构建,无需在 Runner 上安装 Docker。az containerapp update 会生成新修订,配合单修订模式或流量拆分即可实现灰度发布。

首次部署建议先用 CLI 打通链路,再把相同参数固化到 Bicep 或 Terraform,最后接入 GitHub Actions。这样出现问题时能快速定位是镜像、权限、端口还是定义层面的问题。
常见失败点:镜像标签写成 latest 导致无法追踪;未授予 AcrPull 导致镜像拉取失败;targetPort 与容器监听端口不一致导致健康检查失败;minReplicas=0 时首次请求会有冷启动延迟,需在验收时纳入预期。

完成首次部署后,判断成功的标准不是命令返回 0,而是:provisioningState 为 Succeeded、FQDN 可访问且健康检查返回 200、修订记录与预期镜像标签一致、日志中无拉取或端口错误。这四点同时满足,才说明从 Dockerfile 到 ACA 应用的链路真正闭环。