DevOps Pipeline在Azure VM中拉取ACR镜像失败求助
问题描述
运行DevOps Pipeline时,已成功构建并推送Docker镜像至Azure容器注册表(ACR),但在Azure Linux虚拟机内拉取镜像时失败,报错如下:
##[error]Error response from daemon: Head "https://<ACR_NAME>.azurecr.io/v2/<IMAGE_NAME>/manifests/latest": unauthorized: {"errors":[{"code":"UNAUTHORIZED","message":"authentication required, visit https://aka.ms/acr/authorization for more information."}]}
不清楚如何通过SSH连接到Linux虚拟机并成功拉取镜像,已尝试以下步骤:
- 在VM上安装Azure CLI,并使用AzureCLI@2任务建立拉取镜像的会话
- 创建了SSH和Docker Registry的服务连接,以及用于身份验证的服务主体(Service Principal)
- 尝试过不使用Azure CLI的方式
以下是流水线文件:
variables: ACR_NAME: '<ACR_NAME>' IMAGE_NAME: '<IMAGE_NAME>' ACR_USER: '<ACR_USER>' VM_USER: '<VM_USER>' VM_HOST: '<VM_HOST>' SSH_CONN_NAME: '<SSH_CONN_NAME>' ACR_CONN_NAME: '<ACR_CONN_NAME>' RESOURCE_MANAGER_CONN: '<RESOURCE_MANAGER_CONN>' AIRFLOW_UID: '50000' stages: - stage: BuildAndDeploy displayName: 'Build and Deploy Stage' jobs: - job: BuildAndPush displayName: 'Build and Push Docker Image' pool: vmImage: 'ubuntu-latest' steps: - task: DockerInstaller@0 inputs: dockerVersion: '27.0.2' - task: Docker@2 displayName: 'Build the Docker Img' inputs: command: 'build' repository: '$(ACR_NAME).azurecr.io/$(IMAGE_NAME)' dockerfile: '$(Build.SourcesDirectory)/Dockerfile' tags: 'latest' - task: DockerCompose@0 displayName: 'Push the Docker Img' inputs: action: 'Push services' azureSubscriptionEndpoint: '$(RESOURCE_MANAGER_CONN)' azureContainerRegistry: '$(ACR_NAME)' dockerComposeFile: 'docker-compose.prod.yaml' projectName: '$(Build.Repository.Name)' additionalImageTags: | $(Build.BuildId) prod qualifyImageNames: true - job: Deploy displayName: 'Deploy to Azure VM' pool: vmImage: 'ubuntu-latest' steps: - task: AzureCLI@2 displayName: 'Azure CLI Login' inputs: azureSubscription: '$(RESOURCE_MANAGER_CONN)' scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az acr login --name $(ACR_NAME) - task: SSH@0 displayName: 'Deploy using docker-compose on Azure VM' inputs: sshEndpoint: $(SSH_CONN_NAME) runOptions: 'inline' inline: | az acr login --name $(ACR_NAME) docker stop $(IMAGE_NAME) || true docker rm $(IMAGE_NAME) || true docker pull $(ACR_NAME).azurecr.io/$(IMAGE_NAME):latest cd $(Build.Repository.LocalPath) docker-compose -f docker-compose.p.yaml up -d
解决方案
核心问题分析
流水线中的AzureCLI@2任务是在DevOps代理机器(ubuntu-latest)上执行的,凭证不会同步到Azure VM环境中。SSH任务里执行az acr login时,VM上的Azure CLI没有有效身份凭证,导致Docker拉取镜像时认证失败。
以下是几种可行的解决方法:
方法1:在VM中使用服务主体认证ACR
直接在VM上通过服务主体完成身份验证,无需依赖代理机器的凭证:
- 确保服务主体拥有**ACR拉取(AcrPull)**权限
- 在流水线中添加保密变量
SP_APP_ID、SP_PASSWORD、TENANT_ID - 修改SSH任务的inline脚本:
# 用服务主体登录Azure CLI az login --service-principal -u $(SP_APP_ID) -p $(SP_PASSWORD) --tenant $(TENANT_ID) # 登录ACR az acr login --name $(ACR_NAME) # 执行镜像操作 docker stop $(IMAGE_NAME) || true docker rm $(IMAGE_NAME) || true docker pull $(ACR_NAME).azurecr.io/$(IMAGE_NAME):latest # 注意:需先将docker-compose文件上传到VM,替换为VM上的实际路径 cd /vm/path/to/docker-compose docker-compose -f docker-compose.p.yaml up -d
方法2:使用ACR访问密钥直接登录Docker
跳过Azure CLI,直接用ACR访问密钥给Docker完成登录:
- 在ACR门户的"访问密钥"页面开启管理员账户,获取用户名和密码
- 在流水线中添加保密变量
ACR_USERNAME、ACR_PASSWORD - 修改SSH任务脚本:
# 直接登录ACR docker login $(ACR_NAME).azurecr.io -u $(ACR_USERNAME) -p $(ACR_PASSWORD) # 执行镜像操作 docker stop $(IMAGE_NAME) || true docker rm $(IMAGE_NAME) || true docker pull $(ACR_NAME).azurecr.io/$(IMAGE_NAME):latest # 替换为VM上docker-compose的实际路径 cd /vm/path/to/docker-compose docker-compose -f docker-compose.p.yaml up -d
方法3:给VM系统分配身份赋予ACR权限
如果VM启用了系统分配托管身份,可直接通过身份完成认证:
- 在Azure门户给VM的系统分配身份添加**ACR拉取(AcrPull)**角色权限
- 在VM上安装
azure-cli和docker-credential-acr-helper - 修改SSH任务脚本:
# 用托管身份登录Azure CLI az login --identity az acr login --name $(ACR_NAME) # 执行镜像操作 docker stop $(IMAGE_NAME) || true docker rm $(IMAGE_NAME) || true docker pull $(ACR_NAME).azurecr.io/$(IMAGE_NAME):latest # 替换为VM上docker-compose的实际路径 cd /vm/path/to/docker-compose docker-compose -f docker-compose.p.yaml up -d
额外注意事项
- 流水线中的
$(Build.Repository.LocalPath)是代理机器路径,VM上不存在,需通过CopyFilesOverSSH任务提前将docker-compose文件及相关资源上传到VM指定目录 - 确保VM上的Docker和Azure CLI版本兼容,避免因版本问题导致登录失败
内容的提问来源于stack exchange,提问作者dimButTries
相关产品推荐
相关产品推荐

