如何使用terraform配置Azure应用服务以从ACR中拉取镜像?

10
我有以下terraform模块,用于在同一计划下设置应用服务:
provider "azurerm" {
}

variable "env" {
    type = string
    description = "The SDLC environment (qa, dev, prod, etc...)"
}

variable "appsvc_names" {
    type = list(string)
    description = "The names of the app services to create under the same app service plan"
}

locals {
    location = "eastus2"
    resource_group_name = "app505-dfpg-${var.env}-web-${local.location}"
    acr_name = "app505dfpgnedeploycr88836"
}

resource "azurerm_app_service_plan" "asp" {
    name                = "${local.resource_group_name}-asp"
    location            = local.location
    resource_group_name = local.resource_group_name
    kind                = "Linux"
    reserved            = true

    sku {
        tier = "Basic"
        size = "B1"
    }
}

resource "azurerm_app_service" "appsvc" {
    for_each            = toset(var.appsvc_names)

    name                = "${local.resource_group_name}-${each.value}-appsvc"
    location            = local.location
    resource_group_name = local.resource_group_name
    app_service_plan_id = azurerm_app_service_plan.asp.id

    site_config {
        linux_fx_version = "DOCKER|${local.acr_name}/${each.value}:latest"
    }

    app_settings = {
        DOCKER_REGISTRY_SERVER_URL = "https://${local.acr_name}.azurecr.io"
    } 
}

output "hostnames" {
  value = {
    for appsvc in azurerm_app_service.appsvc: appsvc.name => appsvc.default_site_hostname
  }
}

我正在通过以下配置来调用它:
terraform {
    backend "azurerm" {
    }
}

locals {
    appsvc_names = ["gateway"]
}

module "web" {
    source = "../../modules/web"
    env = "qa"
    appsvc_names = local.appsvc_names
}

output "hostnames" {
    description = "The hostnames of the created app services"
    value       = module.web.hostnames
}

容器注册表中有我需要的镜像:

C:\> az acr login --name app505dfpgnedeploycr88836
Login Succeeded
C:\> az acr repository list  --name app505dfpgnedeploycr88836
[
  "gateway"
]
C:\> az acr repository show-tags --name app505dfpgnedeploycr88836 --repository gateway
[
  "latest"
]
C:\>

当我应用terraform配置时,一切都被成功创建了,但是在Azure门户中检查创建的应用服务资源时,发现其容器设置没有显示docker镜像:

enter image description here

现在,我可以手动切换到另一个ACR,然后再切回到我想要的ACR,但只能得到这个结果:

enter image description here

Cannot perform credential operations for /subscriptions/0f1c414a-a389-47df-aab8-a351876ecd47/resourceGroups/app505-dfpg-ne-deploy-eastus2/providers/Microsoft.ContainerRegistry/registries/app505dfpgnedeploycr88836 as admin user is disabled. Kindly enable admin user as per docs: https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication#admin-account

这让我感到困惑。根据https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication#admin-account,不应使用管理员用户,因此我的ACR没有管理员用户。另一方面,我了解到需要以某种方式配置应用服务与ACR进行身份验证。
那么正确的方法是什么呢?
2个回答

10
这是自 Azure RM 提供程序的 v2.71 版本以来的新功能。需要完成以下几件事情:
  1. 将托管标识分配给应用程序(也可以使用用户分配,但需要更多工作)
  2. site_config.acr_use_managed_identity_credentials 属性设置为 true
  3. 授予应用程序标识在容器上的 ACRPull 权限。
下面是上述代码的修改版本,未经测试但应该可以正常运行。
provider "azurerm" {
}

variable "env" {
    type = string
    description = "The SDLC environment (qa, dev, prod, etc...)"
}

variable "appsvc_names" {
    type = list(string)
    description = "The names of the app services to create under the same app service plan"
}

locals {
    location = "eastus2"
    resource_group_name = "app505-dfpg-${var.env}-web-${local.location}"
    acr_name = "app505dfpgnedeploycr88836"
}

resource "azurerm_app_service_plan" "asp" {
    name                = "${local.resource_group_name}-asp"
    location            = local.location
    resource_group_name = local.resource_group_name
    kind                = "Linux"
    reserved            = true

    sku {
        tier = "Basic"
        size = "B1"
    }
}

resource "azurerm_app_service" "appsvc" {
    for_each            = toset(var.appsvc_names)

    name                = "${local.resource_group_name}-${each.value}-appsvc"
    location            = local.location
    resource_group_name = local.resource_group_name
    app_service_plan_id = azurerm_app_service_plan.asp.id

    site_config {
        linux_fx_version = "DOCKER|${local.acr_name}/${each.value}:latest"
        acr_use_managed_identity_credentials = true
    }

    app_settings = {
        DOCKER_REGISTRY_SERVER_URL = "https://${local.acr_name}.azurecr.io"
    }

    identity {
        type = "SystemAssigned"
    }   
}

data "azurerm_container_registry" "this" {
  name                = local.acr_name
  resource_group_name = local.resource_group_name
}

resource "azurerm_role_assignment" "acr" {
  for_each             = azurerm_app_service.appsvc
  
  role_definition_name = "AcrPull"
  scope                = azurerm_container_registry.this.id
  principal_id         = each.value.identity[0].principal_id
}

output "hostnames" {
  value = {
    for appsvc in azurerm_app_service.appsvc: appsvc.name => appsvc.default_site_hostname
  }
}

2021年12月21日更新 关于值被Azure重置的MS文档问题现已解决,您还可以通过门户控制托管标识。


值得一提的是,使用系统分配的标识进行 ACR 认证存在持续问题。https://github.com/MicrosoftDocs/azure-docs/issues/64660 - Percolator
@Percolator 这就是样例代码下面的段落(和链接)所指的 - 最新信息是除了西欧和南部中心美国之外的所有地区都已经修补,不会有重置问题,一旦所有地区都得到修复,我会更新。 - Paul Hatcher

5

您可以使用服务主体身份验证与应用程序服务,但您必须创建服务主体并授予其对注册表的ACRpull权限,并在应用程序服务站点配置中使用服务主体登录\密码。

DOCKER_REGISTRY_SERVER_USERNAME
DOCKER_REGISTRY_SERVER_PASSWORD


2
但这意味着将其密码存储在版本控制中。我可以将其作为变量使用,然后在Azure DevOps服务器上安排一个秘密变量。 - mark
这实际上非常令人恼火,微软在这种情况下颠覆了他们的托管身份的整个理念 - 为什么需要提供用户名/密码对,引用他们自己的网站“托管身份已通过Azure AD进行身份验证,因此您不必在代码中存储任何凭据。” - Qrilka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接