Azure开发者CLI实战:分层基础设施实现容器应用开发到生产的“一次构建,随处部署”

本文详细介绍了如何使用Azure Developer CLI v1.20.0的新功能(如azd publish和分层基础设施),在Azure容器应用中实现“一次构建,随处部署”模式,涵盖从开发环境搭建到生产环境CI/CD管道的完整技术架构。

本文通过一个示例,介绍如何使用Azure Developer CLI v1.20.0的新增功能azd publish和分层基础设施(Alpha特性),在Azure容器应用(Azure Container Apps)中实现“一次构建,随处部署”的模式。你将学会如何将相同的容器化应用程序部署到多个环境,并实现适当的关注点分离。 这是Azure Developer CLI系列的第三篇文章,建立在我们之前的探索之上:Azure应用服务和GitHub Actions、Azure DevOps管道。

一次构建,随处部署

我们所解决的挑战 如果你在生产环境中使用过容器,很可能遇到过这种情况:azd deploy将所有操作捆绑在一起——构建容器、推送到注册表、以及部署——一气呵成。这对于开发来说非常方便,但给生产场景带来了一些麻烦:

  • 你希望在所有环境中使用同一个Azure容器注册表
  • 你需要一次构建,随处部署,无需重建容器
  • 你需要安全控制来管理哪些特定容器版本可以部署到生产环境
  • 你需要灵活性,以便在不同环境中使用不同的配置部署相同的容器

从本系列之前的文章中学习 在我们前两篇关于Azure应用服务开发到生产模式的博客文章之后,我们意识到azd对Azure容器应用的支持存在一些限制,阻碍了团队有效实施相同的“一次构建,随处部署”模式。azd团队在最近的版本中解决了这些问题。 Azure Developer CLI v1.20.0引入了两项解决这些挑战的能力:

  1. 分离的容器操作
    • azd publish:构建容器并将其推送到注册表
    • azd deploy --from-package:将特定的容器版本部署到环境(无需重建)
  2. 分层基础设施(Alpha特性)
    • 按顺序分层部署基础设施,并进行适当的依赖管理
    • 在环境中共享如ACR等资源,同时将特定于环境的内容分开
    • 早期层的输出自动成为后续层的输入

我将通过一个从Azure应用服务迁移到Azure容器应用的Flask应用示例,向你展示其工作原理。

示例应用

我们构建的内容 示例应用是一个简单的基于Flask的文件管理器,用于演示关键概念:

  • 功能:上传文件、列出文件和查看文件(所有操作都基于Azure Blob存储)
  • 安全方法:使用Azure托管标识(不存储任何连接字符串)

基础设施的组织方式 与其将所有内容塞进一个大模板,我使用了分层方法来组织,将共享内容与特定于环境的资源分开:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
┌─────────────────────────────────────────────────────────────────┐
│                     Shared Resources                            │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ Resource Group: rg-acr-shared                               ││
│  │ ┌─────────────────────────────────────────────────────────┐ ││
│  │ │ Azure Container Registry (Basic SKU)                    │ ││
│  │ │ - Stores container images for all environments          │ ││
│  │ │ - Single source of truth for application containers     │ ││
│  │ └─────────────────────────────────────────────────────────┘ ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│                   Development Environment                       │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ Resource Group: rg-dev-environment                          ││
│  │ ┌─────────────────────────────────────────────────────────┐ ││
│  │ │ Container Apps Environment                              │ ││
│  │ │ ┌─────────────────────────────────────────────────────┐ │ ││
│  │ │ │ Container App (Flask Application)                   │ │ ││
│  │ │ │ - Managed Identity for ACR access                   │ │ ││
│  │ │ │ - Auto-scaling enabled                              │ │ ││
│  │ │ └─────────────────────────────────────────────────────┘ │ ││
│  │ └─────────────────────────────────────────────────────────┘ ││
│  │ Azure Storage Account | Key Vault | Application Insights    ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│                  Production Environment                         │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ Resource Group: rg-prod-environment                         ││
│  │ ┌─────────────────────────────────────────────────────────┐ ││
│  │ │ Container Apps Environment (VNET-integrated)            │ ││
│  │ │ ┌─────────────────────────────────────────────────────┐ │ ││
│  │ │ │ Container App (Same Image as Dev)                   │ │ ││
│  │ │ │ - Enhanced security configuration                   │ │ ││
│  │ │ │ - Production-grade scaling rules                    │ │ ││
│  │ │ └─────────────────────────────────────────────────────┘ │ ││
│  │ └─────────────────────────────────────────────────────────┘ ││
│  │ VNET | Storage | Key Vault | App Insights | Monitoring      ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

分层基础设施配置 以下是azure.yaml文件中定义的层序列:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Azure Container Apps Demo: "Build Once, Deploy Everywhere" with Shared ACR
name: dev-prod

# Layered Infrastructure Deployment Strategy
infra:
  layers:
    # Layer 1: Foundation - Core infrastructure for each environment
    - name: foundation
      path: infra/foundation

    # Layer 2: Shared ACR - Single registry for all environments
    - name: shared-acr
      path: infra/shared-acr

    # Layer 3: ACR Role Assignment - Security configuration
    - name: acr-role
      path: infra/acr-role

    # Layer 4: Container App - Application deployment
    - name: container-app
      path: infra/container-app

services:
  app:
    project: .
    host: containerapp
    language: python

这种分层方法解决了容器部署中经典的“先有鸡还是先有蛋”问题。开发和生成都需要共享同一个ACR。你的生产容器应用需要从ACR拉取的权限,但在容器应用标识和ACR实际存在之前,你无法分配这些权限。通过以正确的顺序配置资源,我们确保每个资源都能获得所需的权限。

以下是各层的工作方式:

  • 基础层:根据你的AZURE_ENV_TYPE设置核心资源——这包括容器应用环境和托管标识。
  • 共享ACR层:创建你的集中式容器注册表(除非你已有一个)。
  • ACR角色分配层:这是魔法发生的地方——给你的托管标识赋予正确的权限(开发环境获得推送+拉取,生产环境仅获得拉取权限)。
  • 容器应用层:最终部署你的应用程序,现在它拥有适当的ACR访问权限。

每一层都会输出后续层需要的东西——资源ID、端点等——azd会自动将这些输出作为输入传递给下一层。

例如,如果你查看infra/acr-role/main.parameters.json,你会看到AZURE_CONTAINER_REGISTRY_NAME如何从共享ACR层流入ACR角色分配层: "AZURE_CONTAINER_REGISTRY_NAME": { "value": "${AZURE_CONTAINER_REGISTRY_NAME}"}

尝试一下

生产环境现实检查 虽然我向你展示了如何使用azd up进行本地部署,但对于生产部署,请使用CI/CD管道。我这里演示的本地工作流非常适合快速原型设计和开发,但对于任何重要的事务,你都需要适当的CI/CD控制。

先决条件

  • Azure Developer CLI v1.20.0或更高版本(在此下载)
  • Docker(用于本地容器测试)

1. 克隆示例仓库

1
azd init -t https://github.com/puicchan/azd-dev-prod-aca-storage

2. 设置你的开发环境 开发环境设置使用你可能已经熟悉的azd up工作流:

1
2
3
4
5
6
7
8
9
# 启用分层基础设施的Alpha特性
azd config set alpha.layers on

# 创建并配置开发环境
azd env new myapp-dev
azd env set AZURE_ENV_TYPE dev

# 部署所有内容:基础设施 + 构建 + 推送 + 部署
azd up

3. 准备你的生产基础设施 现在,你需要设置生产环境基础设施。这通常是在设置CI/CD管道之前的一次性操作:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 创建生产环境
azd env new myapp-prod
azd env set AZURE_ENV_TYPE prod

# 引用现有的共享ACR(替换为来自开发部署的实际值)
azd env set ACR_RESOURCE_GROUP_NAME rg-shared-acr-resource-group-name
azd env set AZURE_CONTAINER_REGISTRY_ENDPOINT shared-acr-endpoint

# 仅预配基础设施(不构建/推送/部署)
azd provision

关于基础设施的关键说明

  • 我在这里本地使用azd provision来在应用上线前设置基础设施。在你的CI/CD管道中,绝不应该运行azd provision——只使用azd deploy。生产环境的基础设施变更应通过适当的审批流程,因为意外修改可能导致服务中断。
  • envType = 'prod'时,基础设施会自动包含VNET集成。出于演示目的(便于测试),我在aca-environment.bicep第42行设置了internal: false,因此你的应用保持公开可访问,同时计算是隔离的。对于真正私有的环境,你应将其切换为internal: true并添加反向代理。

4. 设置你的CI/CD管道 现在是精彩部分——让我们看看管道如何运作!进行一个简单的代码更改并提交。 例如,修改index.html中的<h1>标签,然后运行:

1
2
3
4
# 选择你的开发环境并配置管道
azd env select myapp-dev
# 当提示时,确保选择GitHub作为管道提供商
azd pipeline config

以下是需要关注的地方:

  • GitHub Actions选项卡:前往你仓库的Actions选项卡
  • 构建阶段:观察容器如何以唯一标签构建
  • 开发部署:看到它自动部署到开发环境
  • 同一容器,各处部署:检查两个环境——它们运行的是完全相同的容器镜像

GitHub Actions工作流的运作方式 工作流遵循清晰的三阶段模式:构建 → 部署-开发 → 部署-生产

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
┌─────────────────────────────────────────────────────────────────┐
                        GitHub Actions Workflow                  
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
 Job 1: BUILD                                                    
 ┌─────────────────────────────────────────────────────────────┐ 
  1. Enable alpha features (layered infrastructure)            
  2. Set environment names (dev/prod)                          
  3. Log in with Azure (Federated Credentials)                 
  4. Provision Infrastructure (dev environment)                
  5. Build & Publish Container to ACR                          
     └─ azd publish app                                        
     └─ Get image: azd env get-value SERVICE_APP_IMAGE_NAME    
 └─────────────────────────────────────────────────────────────┘ 
                                                                 
 Outputs:                                                        
   container-image: crXXXX.azurecr.io/app:azd-deploy-123456     
   dev-env-name: myapp-dev                                      
   prod-env-name: myapp-prod                                    
└──────────────────────────────┬──────────────────────────────────┘
                               
                               
┌─────────────────────────────────────────────────────────────────┐
 Job 2: DEPLOY-DEV                                               
 ┌─────────────────────────────────────────────────────────────┐ 
  1. Enable alpha features (layered infrastructure)            
  2. Log in with Azure (Federated Credentials)                 
  3. Deploy to Development                                     
     └─ azd deploy app --from-package <container-image>        
  4. Validate Application                                      
     └─ Run validation tests, smoke tests                      
 └─────────────────────────────────────────────────────────────┘ 
└──────────────────────────────┬──────────────────────────────────┘
                               
                               
┌─────────────────────────────────────────────────────────────────┐
 Job 3: DEPLOY-PROD                                              
 ┌─────────────────────────────────────────────────────────────┐ 
  1. Enable alpha features (layered infrastructure)            
  2. Log in with Azure (Federated Credentials)                 
  3. Deploy to Production                                      
     └─ azd deploy app --from-package <same container-image>   
     └─ Uses shared ACR from environment variables             
 └─────────────────────────────────────────────────────────────┘ 
└─────────────────────────────────────────────────────────────────┘

Key: Same container image (built once) deployed to both environments

你可以在仓库的azure-dev.yml文件中查看完整的工作流实现。

需要注意的关键点:

  • 容器在构建阶段仅构建一次
  • azd env get-value SERVICE_APP_IMAGE_NAME获取已发布的镜像名称
  • 开发和生成部署完全相同的容器镜像
  • 验证步骤充当阶段之间的质量关卡

注意:此工作流使用GitHub Actions作业输出在作业之间传递容器镜像名称。这只适用于GitHub托管的运行器。如果你使用自托管运行器,则需要不同的方法——也许将镜像名称存储在制品中,或使用其他方法在作业之间共享数据。

总结 本文介绍了如何使用Azure Developer CLI v1.20.0中的新功能,在Azure容器应用中实现“一次构建,随处部署”的模式。建立在我们之前关于Azure应用服务的文章之上,这种容器应用方法展示了相同的核心原则如何在不同的Azure计算服务中发挥作用。 分层基础设施和分离的容器操作(azd publish + azd deploy --from-package)的结合,为你提供了一个坚实的基础,当你准备好超越azd up的简单性,但仍希望保持熟悉的azd开发者体验时。

我们涵盖的内容:

  • 容器应用集成:azd如何开箱即用地与Azure容器应用协同工作
  • 分层基础设施:具有适当依赖管理的顺序部署
  • 环境分离:在保持开发便利性的同时,添加生产就绪的控制

并没有一种放之四海而皆准的生产部署方法,根据组织的需求,甚至有更复杂的方法。高级网络、复杂的合规要求、不同的部署策略等;具体的实现将根据你团队的情况而有所不同。我们希望这能给你一个起点和一个可供遵循的示例。 我们将继续探索和验证Azure Developer CLI的生产部署场景,确保随着你的应用程序从开发发展到生产,azd能够提供可靠的模式。

有关实现的问题或想分享你自己的方法?请在此加入讨论。 如需更多Azure Developer CLI内容,请关注Azure Developer CLI博客并查看官方文档。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计