将 Azure 容器注册表 (ACR) 与 Azure Kubernetes 服务 (AKS) 配合使用时,需要建立身份验证机制。 可以使用 Azure CLI、Azure PowerShell 或 Azure 门户配置 ACR 和 AKS 之间所需的权限。 本文提供了使用 Azure CLI 或 Azure PowerShell 在这些 Azure 服务之间配置身份验证的示例。
AKS 与 ACR 的集成将 AcrPull 角色 分配给与您的 AKS 群集中的代理池关联的 Microsoft Entra ID 托管标识。 有关 AKS 托管标识的详细信息,请参阅托管标识摘要。
重要
附加 ACR 时,Microsoft Entra 组存在延迟问题。 如果将 AcrPull role 授予 Microsoft Entra 组,并且将 kubelet 标识添加到该组以完成 Azure 基于角色的访问控制(Azure RBAC)配置,则 RBAC 组生效之前可能会有延迟。 如果运行的自动化需要完成 Azure RBAC 配置,建议使用 使用自己的 kubelet 身份标识作为变通方法。 可以预先创建用户分配的标识,将其添加到Microsoft Entra组,然后使用标识作为 kubelet 标识来创建 AKS 群集。 此方法确保在 kubelet 生成令牌之前将标识添加到Microsoft Entra组,从而避免延迟问题。
注意
本文介绍了 AKS 和 ACR 之间的自动身份验证。 如果需要从专用外部注册表拉取映像,请使用映像拉取机密。
注意
已启用 ABAC 的 ACR 注册表不支持通过 az aks --attach-acr 的 AKS-ACR 集成,其中角色分配权限模式设置为“RBAC 注册表 + ABAC 存储库权限”。对于已启用 ABAC 的 ACR 注册表,需要 Container Registry Repository Reader 角色,而不是授予映像拉取权限的 AcrPull 角色。 对于已启用 ABAC 的 ACR 注册表,不应使用 az aks --attach-acr,而是使用 Azure 门户、Container Registry Repository Reader CLI 或Azure 资源管理器手动分配 az role assignment 角色分配。 有关已启用 ABAC 的 ACR 注册表的详细信息,请参阅Azure基于属性的访问控制。
在本演练中,将Azure Kubernetes 服务 (AKS)群集配置为从Azure 容器注册表(ACR)安全地拉取映像。 在Azure CLI中,使用 --attach-acr。 在 Terraform 中,将 AcrPull 角色分配给 AKS kubelet 托管标识。 本指南遵循与 Azure CLI 工作流相似的流程,以使用 Terraform 进行基础设施预配。
开始之前
- 在你的 Azure 订阅中,你需要具有所有者、Azure 帐户管理员或Azure 共同管理员角色。
- 为了避免对这些角色的需求,你可以改用现有的托管身份来从 AKS 对 ACR 进行身份验证。 有关详细信息,请参阅使用 Azure 托管标识向 ACR 验证身份。
- 如果你使用的是 Azure CLI,本文要求运行 Azure CLI 2.7.0 或更高版本。 若要查找版本,请运行
az --version命令。 如果需要进行安装或升级,请参阅安装 Azure CLI。
- 如果使用的是 Azure PowerShell,本文要求运行 Azure PowerShell 5.9.0 或更高版本。 若要查找版本,请运行
Get-InstalledModule -Name Az命令。 如果需要进行安装或升级,请参阅安装 Azure PowerShell。 - 在 Terraform 参考中可以找到使用 Terraform 配置 ACR 的示例和语法。
- 已安装 Terraform (
>= 1.6)。 - 请安装Azure CLI并登录到您的订阅。
- 分配角色的权限(所有者或用户访问管理员)。
在本文中,将Azure Kubernetes 服务 (AKS)群集配置为从Azure 容器注册表(ACR)安全地拉取映像。 在Azure CLI中,使用 --attach-acr。 在 Terraform 中,将 AcrPull 角色分配给 AKS kubelet 托管标识。
本文的流程与使用 Terraform 进行基础设施部署时的 Azure CLI 工作流相同。 若要验证是否已登录到正确的订阅,请使用以下Azure CLI命令:
az login
az account show
创建新 ACR
如果你没有 ACR,请使用 az acr create 命令创建一个。
注册表名称在Azure内必须全局唯一,并且包含 5-50 个字母数字字符,不包括短划线(-) 字符。 此名称是注册表的完全限定 DNS 名称的一部分。
export RANDOM_STRING=$(printf '%05d%05d' "$RANDOM" "$RANDOM")
export MYACR="mycontainerregistry$RANDOM_STRING"
export ACR_RESOURCE_GROUP="myContainerRegistryResourceGroup"
export LOCATION="westcentralus"
az group create \
--name $ACR_RESOURCE_GROUP \
--location $LOCATION
az acr create \
--name $MYACR \
--resource-group $ACR_RESOURCE_GROUP \
--sku basic
该 RANDOM_STRING 变量存储随机 10 位字符串。
MYACR 值与 RANDOM_STRING 值连接在一起,以创建一个唯一的名称。
如果你没有 ACR,请使用 New-AzContainerRegistry cmdlet 创建一个。
注册表名称在Azure内必须全局唯一,并且包含 5-50 个字母数字字符,不包括短划线(-) 字符。 此名称是注册表的完全限定 DNS 名称的一部分。
$RandomString = (Get-Random -Minimum 1000000000 -Maximum 10000000000).ToString()
$MyAcr = "mycontainerregistry$RandomString"
$AcrResourceGroup = "myContainerRegistryResourceGroup"
$Location = "westcentralus"
New-AzResourceGroup -Name $AcrResourceGroup -Location $Location
$NewAcr = @{
Name = $MyAcr
ResourceGroupName = $AcrResourceGroup
Location = $Location
Sku = "Basic"
}
New-AzContainerRegistry @NewAcr
该 $RandomString 变量存储随机 10 位字符串。
$MyAcr 值与 $RandomString 值连接在一起,以创建一个唯一的名称。
为配置创建 main.tf 文件,首先定义 Terraform 提供程序并为全局唯一的资源名称生成唯一后缀。 全局唯一名称可确保Azure 容器注册表名称不会与现有注册表冲突。
terraform {
required_version = ">= 1.6.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.6"
}
}
}
provider "azurerm" {
features {}
}
resource "random_string" "suffix" {
length = 6
upper = false
special = false
}
创建新的 AKS 群集并将其与现有 ACR 集成
使用az aks create命令和--attach-acr参数创建新的 AKS 群集,并与现有的 ACR 集成。 此命令允许您在您的订阅中授权现有的 ACR,并为托管标识配置适当的 AcrPull 角色。
export CLUSTER_NAME="myAKSCluster"
export CLUSTER_RESOURCE_GROUP="myClusterResourceGroup"
az group create \
--name $CLUSTER_RESOURCE_GROUP \
--location $LOCATION
az aks create \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--generate-ssh-keys \
--attach-acr $MYACR
在其他订阅中使用 ACR 或通过资源 ID 进行关联
如果您的 ACR 位于与 AKS 群集不同的订阅中,或者您更愿意使用 ACR 资源 ID 而不是使用 ACR 名称,请使用以下语法。 此示例使用在上一部分创建的容器注册表创建 ACR_RESOURCE_ID 变量。
ACR_RESOURCE_ID=$(az acr show \
--name $MYACR \
--resource-group $ACR_RESOURCE_GROUP \
--query id --output tsv)
az aks create \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--generate-ssh-keys \
--attach-acr $ACR_RESOURCE_ID
创建新的 AKS 群集,并使用 New-AzAksCluster cmdlet 和 -AcrNameToAttach 参数与现有 ACR 集成。 此命令允许您在您的订阅中授权现有的 ACR,并为托管标识配置适当的 AcrPull 角色。
$ClusterName = "myAKSCluster"
$ClusterResourceGroup = "myClusterResourceGroup"
New-AzResourceGroup -Name $ClusterResourceGroup -Location $Location
$NewCluster = @{
Name = $ClusterName
ResourceGroupName = $ClusterResourceGroup
GenerateSshKey = $true
AcrNameToAttach = $MyAcr
}
New-AzAksCluster @NewCluster
在其他订阅中使用 ACR 或通过资源 ID 进行关联
Azure PowerShell 仅支持使用 -AcrNameToAttach 参数将 ACR 附加到 AKS,不支持通过 resource ID 附加到 ACR。
接下来,创建资源组和Azure 容器注册表。 此注册表存储 AKS 群集稍后拉取的容器映像。
locals {
location = "westcentralus"
acr_name = "myacr${random_string.suffix.result}"
acr_resource_group = "myContainerRegistryResourceGroup"
}
resource "azurerm_resource_group" "acr_rg" {
name = local.acr_resource_group
location = local.location
}
resource "azurerm_container_registry" "acr" {
name = local.acr_name
resource_group_name = azurerm_resource_group.acr_rg.name
location = azurerm_resource_group.acr_rg.location
sku = "Basic"
admin_enabled = false
}
现在创建从注册表中获取镜像的 AKS 群集。 此群集使用 系统分配的托管标识,该标识将被授予拉取映像的权限。
locals {
aks_name = "myAKSCluster"
aks_resource_group = "myClusterResourceGroup"
}
resource "azurerm_resource_group" "aks_rg" {
name = local.aks_resource_group
location = local.location
}
resource "azurerm_kubernetes_cluster" "aks" {
name = local.aks_name
location = azurerm_resource_group.aks_rg.location
resource_group_name = azurerm_resource_group.aks_rg.name
dns_prefix = local.aks_name
identity {
type = "SystemAssigned"
}
default_node_pool {
name = "systempool"
node_count = 2
vm_size = "Standard_DS2_v2"
}
}
在此阶段,AKS 群集存在,但它尚无法访问容器注册表。 在 Azure CLI 中,使用 --attach-acr 参数。 在 Terraform 中,显式分配 AcrPull 角色。
resource "azurerm_role_assignment" "aks_acr_pull" {
scope = azurerm_container_registry.acr.id
role_definition_name = "AcrPull"
principal_id = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id
}
为现有的 AKS 群集配置 ACR 集成
可以将 ACR 附加到现有的 AKS 群集,或者如果不再需要群集访问注册表,可以将 ACR 从 AKS 群集分离。
本文中的前面的示例创建了一个 Azure 容器注册表,并将 Azure Kubernetes 服务群集附加到该注册表。 下面是有关如何从群集附加或分离容器注册表以及使用本文中创建的 ACR 和 AKS 群集的示例。 可以将变量值替换为自己的 ACR 和 AKS 群集值。
将 ACR 附加到现有的 AKS 群集
使用 az aks update 命令和 --attach-acr 参数将现有 ACR 与现有 AKS 群集集成。
# Attach using acr-name
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--attach-acr $MYACR
# Attach using acr-resource-id
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--attach-acr $ACR_RESOURCE_ID
az aks update --attach-acr 命令使用运行此命令的用户的权限来创建 ACR 角色分配。 此角色分配给 kubelet 托管标识。 有关 AKS 托管标识的详细信息,请参阅托管标识摘要。
使用 Set-AzAksCluster 命令和 -AcrNameToAttach 参数将现有 ACR 与现有 AKS 群集集成。
$AttachCluster = @{
Name = $ClusterName
ResourceGroupName = $ClusterResourceGroup
AcrNameToAttach = $MyAcr
}
Set-AzAksCluster @AttachCluster
该 Set-AzAksCluster -AcrNameToAttach cmdlet 使用运行命令的用户的权限来创建角色 ACR 分配。 此角色分配给 kubelet 托管标识。 有关 AKS 托管标识的详细信息,请参阅托管标识摘要。
如果 AKS 群集已经存在,可以通过引用这两个资源并创建相同的角色分配信息来挂载 ACR。
data "azurerm_kubernetes_cluster" "existing_aks" {
name = "myAKSCluster"
resource_group_name = "myClusterResourceGroup"
}
data "azurerm_container_registry" "existing_acr" {
name = "mycontainerregistry"
resource_group_name = "myContainerRegistryResourceGroup"
}
resource "azurerm_role_assignment" "existing_aks_acr_pull" {
scope = data.azurerm_container_registry.existing_acr.id
role_definition_name = "AcrPull"
principal_id = data.azurerm_kubernetes_cluster.existing_aks.kubelet_identity[0].object_id
}
将 ACR 从 AKS 群集分离
使用带有参数的 az aks update 命令 --detach-acr 删除 ACR 与 AKS 群集之间的集成。
# Detach using acr-name
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--detach-acr $MYACR
# Detach using acr-resource-id
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--detach-acr $ACR_RESOURCE_ID
使用带有参数的 Set-AzAksCluster 命令 -AcrNameToDetach 删除 ACR 与 AKS 群集之间的集成。
$DetachCluster = @{
Name = $ClusterName
ResourceGroupName = $ClusterResourceGroup
AcrNameToDetach = $MyAcr
}
Set-AzAksCluster @DetachCluster
若要删除访问权限,请删除授予群集拉取镜像权限的角色分配。
# Remove this resource to revoke access
# resource "azurerm_role_assignment" "existing_aks_acr_pull" {
# scope = data.azurerm_container_registry.existing_acr.id
# role_definition_name = "AcrPull"
# principal_id = data.azurerm_kubernetes_cluster.existing_aks.kubelet_identity[0].object_id
# }
初始化和部署配置
配置完成后,初始化 Terraform 并在应用之前查看执行计划。
terraform fmt
terraform init
terraform validate
terraform plan
terraform apply
此时,AKS 群集配置为从 ACR 拉取映像。
您现在可以:
- 将映像导入 ACR。
- 将工作负荷部署到 AKS。
- 验证 Pod 部署。
使用 ACR 和 AKS
将映像导入 ACR,然后将该映像部署到 AKS 群集。
将映像导入 ACR
使用 az acr import 命令将映像从 Docker Hub 导入 ACR。
az acr import \
--name $MYACR \
--source docker.io/library/nginx:latest \
--image nginx:v1
运行以下命令以验证映像是否已导入。
az acr repository show --name $MYACR --repository nginx
az acr repository show-tags --name $MYACR --repository nginx
使用 Import-AzContainerRegistryImage cmdlet 将映像从 Docker Hub 导入 ACR。
$ImportImage = @{
RegistryName = $MyAcr
ResourceGroupName = $AcrResourceGroup
SourceRegistryUri = 'docker.io'
SourceImage = 'library/nginx:latest'
TargetTag = 'nginx:v1'
}
Import-AzContainerRegistryImage @ImportImage
运行以下命令以验证映像是否已导入。
Get-AzContainerRegistryRepository -RegistryName $MyAcr
Get-AzContainerRegistryTag -RegistryName $MyAcr -Repository nginx
创建部署文件
创建一个 Kubernetes 部署,以引用导入到 ACR 中的镜像。 如果部署顺利完成且镜像已正确拉取,则 AKS 群集已与 ACR 完美集成。
使用以下示例 YAML 创建名为 acr-nginx.yaml 的文件。 在属性中 image ,将 acr-name 替换为 ACR 的名称。 在 Azure CLI 中,运行 echo $MYACR 以显示 ACR 名称。 在Azure PowerShell中,运行 $MyAcr 以显示 ACR 名称。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx0-deployment
labels:
app: nginx0-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx0
template:
metadata:
labels:
app: nginx0
spec:
containers:
- name: nginx
image: <acr-name>.azurecr.cn/nginx:v1
ports:
- containerPort: 80
获取凭据,然后执行部署程序
使用
az aks get-credentials命令确保你具有正确的 AKS 凭据。az aks get-credentials \ --resource-group $CLUSTER_RESOURCE_GROUP \ --name $CLUSTER_NAME使用
kubectl apply命令在 AKS 群集中运行部署。kubectl apply -f acr-nginx.yaml使用
kubectl get pods命令监视部署。kubectl get pods输出应显示两个正在运行的 Pod,如以下示例输出所示:
NAME READY STATUS RESTARTS AGE nginx0-deployment-669dfc4d4b-x74kr 1/1 Running 0 20s nginx0-deployment-669dfc4d4b-xdpd6 1/1 Running 0 20s
使用
Import-AzAksCredentialcmdlet 确保你具有正确的 AKS 凭据。Import-AzAksCredential -ResourceGroupName $ClusterResourceGroup -Name $ClusterName使用
kubectl apply命令在 AKS 群集中运行部署。kubectl apply -f acr-nginx.yaml使用
kubectl get pods命令监视部署。kubectl get pods输出应显示两个正在运行的 Pod,如以下示例输出所示:
NAME READY STATUS RESTARTS AGE nginx0-deployment-669dfc4d4b-x74kr 1/1 Running 0 20s nginx0-deployment-669dfc4d4b-xdpd6 1/1 Running 0 20s
疑难解答
- 使用
az aks check-acr命令验证 AKS 群集中能否访问注册表。 - 如果 AKS 群集使用 HTTP 代理,并且 ACR 使用专用链接,请将 ACR 终结点(REST 和数据)添加到群集
noProxy列表。 有关详细信息,请参阅 Azure Kubernetes 服务 (AKS) 中的 HTTP 代理支持。 - 详细了解 ACR 监控。
- 详细了解 ACR 健康。
清理资源
如果不再需要本文中创建的资源,可以删除资源组以删除所有关联的资源。 这些命令将删除 ACR 和 AKS 群集以及以开头的 MC_群集节点资源组。
az group delete --name $ACR_RESOURCE_GROUP --yes --no-wait
az group delete --name $CLUSTER_RESOURCE_GROUP --yes --no-wait
Remove-AzResourceGroup -Name $AcrResourceGroup -Force
Remove-AzResourceGroup -Name $ClusterResourceGroup -Force