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

使用Pulumi分两步创建带系统分配托管标识的Azure ContainerApp时遭遇「无法创建已存在资源」错误的咨询

Pulumi分两步创建带系统分配托管标识的Azure ContainerApp时遭遇「无法创建已存在资源」错误的咨询

背景

我正在使用 Pulumi(Python)结合pulumi-azure-native和pulumi-azuread部署一个带有系统分配托管标识的Azure容器应用,该标识需要加入一个已有的Entra ID组(该组已拥有ACR的AcrPull权限和Key Vault的Key Vault Secrets User权限)。

由于托管标识的principal_id只有在容器应用创建后才存在,而ACR注册表配置要求标识在应用拉取私有镜像前已拥有AcrPull权限,我尝试采用三步法:

  1. 创建带有系统分配标识和公共引导镜像的容器应用(不配置ACR)。
  2. 将标识的服务主体加入已有的Entra组。
  3. 更新容器应用,配置私有镜像并设置registries[].identity = "system"。

我将步骤1和3建模为两个独立的ContainerApp Pulumi资源,指向同一个Azure资源名称,最终资源设置了parent=bootstrap和depends_on=[membership]。

问题

pulumi up在第二个ContainerApp资源上失败,错误信息如下:

error: cannot create already existing resource
  '/subscriptions/xxx/resourceGroups/rg-demo/providers/Microsoft.App/containerApps/orchestrator-demo'

这是合理的:Pulumi试图创建orchestrator-final作为新资源,但Azure资源已由orchestrator-bootstrap创建,orchestrator-final资源从未进入状态。

代码

# __main__.py
import pulumi
import pulumi_azure_native as azure_native
import pulumi_azuread as azuread
from pulumi_azure_native.app import (
    ConfigurationArgs,
    ContainerApp,
    ContainerArgs,
    ContainerResourcesArgs,
    ManagedServiceIdentityArgs,
    ManagedServiceIdentityType,
    RegistryCredentialsArgs,
    ScaleArgs,
    TemplateArgs,
)

# Minimal repro goal:
# - Existing Container App Environment and ACR
# - New Container App with system-assigned managed identity
# - Add that identity's service principal to an existing Entra group
# - Use group-based AcrPull instead of a direct role assignment on the identity

config = pulumi.Config()

resource_group_name = config.require("resourceGroupName")
location = config.require("location")
container_app_env_name = config.require("containerAppEnvironmentName")
container_app_name = config.get("containerAppName")
entra_group_display_name = config.require("entraGroupDisplayName")
acr_name = config.require("acrName")
acr_resource_group_name = config.require("acrResourceGroupName")
private_image = config.require("privateImage")

bootstrap_image = (
    config.get("bootstrapImage")
    or "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest"
)

managed_environment = azure_native.app.get_managed_environment_output(
    environment_name=container_app_env_name,
    resource_group_name=resource_group_name,
)

acr = azure_native.containerregistry.get_registry_output(
    registry_name=acr_name,
    resource_group_name=acr_resource_group_name,
)

entra_group = azuread.get_group_output(display_name=entra_group_display_name)

bootstrap = ContainerApp(
    "orchestrator-bootstrap",
    container_app_name=container_app_name,
    resource_group_name=resource_group_name,
    location=location,
    managed_environment_id=managed_environment.id,
    identity=ManagedServiceIdentityArgs(type=ManagedServiceIdentityType.SYSTEM_ASSIGNED),
    configuration=ConfigurationArgs(
        ingress=None,
        active_revisions_mode="Single",
    ),
    template=TemplateArgs(
        containers=[
            ContainerArgs(
                name=container_app_name,
                image=bootstrap_image,
                resources=ContainerResourcesArgs(cpu=0.25, memory="0.5Gi"),
            )
        ],
        scale=ScaleArgs(min_replicas=0, max_replicas=1),
    ),
    opts=pulumi.ResourceOptions(
        # The update resource below manages template/configuration.
        ignore_changes=["configuration", "template"],
    ),
)

membership = azuread.GroupMember(
    "orchestrator-group-membership",
    group_object_id=entra_group.object_id,
    member_object_id=bootstrap.identity.principal_id,
    opts=pulumi.ResourceOptions(
        depends_on=[bootstrap],
        # First run can fail if identity propagation in Entra is not complete.
        custom_timeouts=pulumi.CustomTimeouts(create="10m"),
    ),
)

app = ContainerApp(
    "orchestrator-final",
    container_app_name=container_app_name,
    resource_group_name=resource_group_name,
    location=location,
    managed_environment_id=managed_environment.id,
    identity=ManagedServiceIdentityArgs(type=ManagedServiceIdentityType.SYSTEM_ASSIGNED),
    configuration=ConfigurationArgs(
        ingress=None,
        active_revisions_mode="Single",
        registries=[
            RegistryCredentialsArgs(
                server=acr.login_server,
                identity="system",
            )
        ],
    ),
    template=TemplateArgs(
        containers=[
            ContainerArgs(
                name=container_app_name,
                image=private_image,
                resources=ContainerResourcesArgs(cpu=0.25, memory="0.5Gi"),
            )
        ],
        scale=ScaleArgs(min_replicas=1, max_replicas=1),
    ),
    opts=pulumi.ResourceOptions(
        parent=bootstrap,
        depends_on=[membership],
    ),
)

pulumi.export("managedIdentityPrincipalId", app.identity.principal_id)
pulumi.export("groupObjectId", entra_group.object_id)
pulumi.export("acrLoginServer", acr.login_server)

错误信息

pulumi up命令失败,输出如下:

pulumi up

View in Browser (Ctrl+O): https://app.pulumi.com/xxx/so-containerapp-mi-group/example/updates/2

     Type                                 Name                              Status                  Info
     pulumi:pulumi:Stack                  so-containerapp-mi-group-example  **failed**              1 error
 +   ├─ azure-native:app:ContainerApp     orchestrator-bootstrap            created (17s)           
 +   │  └─ azure-native:app:ContainerApp  orchestrator-final                **creating failed**     1 error
 +   └─ azuread:index:GroupMember         orchestrator-group-membership     created (1s)            

Diagnostics:
  azure-native:app:ContainerApp (orchestrator-final):
    error: cannot create already existing resource '/subscriptions/xxx/resourceGroups/rg-demo/providers/Microsoft.App/containerApps/orchestrator-demo'

  pulumi:pulumi:Stack (so-containerapp-mi-group-example):
    error: update failed

错误后的栈详情:

pulumi stack

Current stack is example:
    Owner: laurent-laporte-pro-org
    Last updated: 1 minute ago (2026-03-03 18:41:24.392413 +0100 CET)
    Pulumi version used: v3.224.0
Current stack resources (5):
    TYPE                                      NAME
    pulumi:pulumi:Stack                       so-containerapp-mi-group-example
    ├─ azure-native:app:ContainerApp          orchestrator-bootstrap
    ├─ azuread:index/groupMember:GroupMember  orchestrator-group-membership
    ├─ pulumi:providers:azure-native          default_3_13_0
    └─ pulumi:providers:azuread               default_6_8_1

Current stack outputs (0):
    No output values currently in this stack

已考虑的方案

  • 使用单个ContainerApp资源并依赖GroupMember——但我无法在应用创建前将标识加入组,也无法在标识拥有权限前配置ACR访问。
  • 在最终资源上使用import / pulumi.ResourceOptions(import_=...)——但这感觉不够优雅,我不确定这是正确的模式。

问题

  1. 这种双ContainerApp资源模式(引导+最终)是否是正确的方法?如果是,我该如何告诉Pulumiorchestrator-final应该更新已存在的资源而非尝试创建它?
  2. 或者,是否有更简洁的Pulumi原生模式来处理这种循环依赖(需要资源存在以获取其标识,需要标识拥有权限后资源才能使用它)?

环境

  • pulumi: v3.224.0
  • pulumi-azure-native: 3.13.0
  • pulumi-azuread: 6.8.1
  • Python 3.12

备注:内容来源于stack exchange,提问作者Laurent LAPORTE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 18:14:39