Azure DevOps构建流水线:不使用标准任务运行Docker命令
问题背景
需要在Azure DevOps构建流水线中运行docker build、docker push等命令,但每次流水线运行要使用新的ACR。现成的imagebuildingInfo@1任务要求使用Docker Registry类型的服务连接,而这种连接需要为每个新ACR创建服务主体,无法动态实现。尝试用AzureCLI@2任务执行az acr login时,遇到Docker守护进程未运行的错误:
WARNING: You may want to use 'az acr login -n <acr_name> --expose-token' to get an access token, which does not require Docker to be installed.
ERROR: 2024-03-20 10:22:28.619871 An error occurred: DOCKER_COMMAND_ERROR
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
可行方案
1. 替代az acr login:用令牌直接登录Docker
不需要依赖Docker守护进程状态,通过Azure CLI获取ACR令牌,直接传给Docker登录:
- task: AzureCLI@2 displayName: Docker Login to ACR inputs: azureSubscription: '你的Azure RM服务连接' scriptType: 'bash' inlineScript: | REGISTRY_NAME="你的新ACR名称" # 获取ACR登录令牌 ACR_TOKEN=$(az acr login -n $REGISTRY_NAME --expose-token --output tsv --query accessToken) # 用令牌登录Docker echo $ACR_TOKEN | docker login $REGISTRY_NAME.azurecr.io --username 00000000-0000-0000-0000-000000000000 --password-stdin
注:用户名固定为00000000-0000-0000-0000-000000000000,这是Azure ACR的通用服务主体ID
2. 确保代理上Docker守护进程运行
分两种代理场景处理:
- 微软托管代理:选择预装Docker的代理镜像,比如
ubuntu-latest、windows-latest,这些代理默认启动了Docker守护进程。如果模板强制使用无Docker的镜像,需修改代理规格。 - 自托管代理:在流水线中添加启动Docker服务的脚本:
注意:自托管代理需要有sudo权限,或者提前配置Docker无需sudo运行。- task: Bash@3 displayName: Start Docker Daemon inputs: targetType: 'inline' script: | # Ubuntu/Debian系统 sudo systemctl start docker sudo systemctl enable docker # 验证状态 docker info
3. 用Docker@2任务结合动态ACR登录
如果想用官方Docker任务,可先通过Azure CLI获取令牌,再传递给Docker@2的登录步骤:
- task: AzureCLI@2 name: GetACRToken inputs: azureSubscription: '你的Azure RM服务连接' scriptType: 'bash' inlineScript: | REGISTRY_NAME="你的新ACR名称" ACR_TOKEN=$(az acr login -n $REGISTRY_NAME --expose-token --output tsv --query accessToken) echo "##vso[task.setvariable variable=ACR_TOKEN;issecret=true]$ACR_TOKEN" echo "##vso[task.setvariable variable=REGISTRY_SERVER]$REGISTRY_NAME.azurecr.io" - task: Docker@2 displayName: Build and Push Image inputs: command: buildAndPush repository: '你的镜像仓库名' dockerfile: '**/Dockerfile' containerRegistry: username: '00000000-0000-0000-0000-000000000000' password: $(ACR_TOKEN) server: $(REGISTRY_SERVER) tags: | latest $(Build.BuildId)
关键说明
- 动态ACR场景下,避免使用Docker Registry类型服务连接,改用Azure RM服务连接结合令牌登录的方式,无需提前创建服务主体。
- 微软托管代理优先选择带Docker环境的镜像,减少手动配置成本。
内容的提问来源于stack exchange,提问作者akshay Sharma

