向AWS ECR推送Docker镜像时额外生成untagged镜像如何解决

问题根因
你看到的untagged镜像不是build或push命令错误导致的,这是Amazon ECR的默认机制:
ECR的标签是独立于镜像层存在的引用指针,当你向已经存在的标签(比如你脚本里的latest_$BITBUCKET_BRANCH)推送新镜像时,ECR只会把标签的指向切换到新上传的镜像,原本关联这个标签的旧镜像不会被同步删除,只是失去了绑定的标签,就变成了untagged状态。
解决方案
方案1:配置ECR生命周期规则(推荐,一劳永逸无需改动流水线)
这是最简便的处理方式,只需要在ECR仓库侧配置自动清理规则,不需要修改现有Bitbucket Pipeline脚本:
- 进入AWS控制台,打开目标ECR仓库的详情页
- 左侧导航栏选择「生命周期策略」,点击创建规则
- 按如下参数配置规则:
- 规则优先级:填1(最高优先级,优先执行)
- 匹配条件:选择「未标记镜像(Untagged images)」
- 过期规则:推荐设置为镜像推送后1天过期,既可以自动清理无用的无标镜像,也不会误删刚推送、正在被拉取的临时镜像
你也可以直接导入以下JSON格式的策略配置:
{ "rules": [ { "rulePriority": 1, "description": "自动清理超过1天的未标记镜像", "selection": { "tagStatus": "untagged", "countType": "sinceImagePushed", "countUnit": "days", "countNumber": 1 }, "action": { "type": "expire" } } ] }
注意:不要把仓库标签可变性设置为「Immutable(不可变)」,该配置会导致同标签镜像推送直接失败,不符合你覆盖原有镜像的需求。
方案2:流水线内主动删除旧镜像(适合不想配置生命周期规则的场景)
你也可以在执行push命令前,通过AWS CLI先删除当前标签绑定的旧镜像,从根源避免无标镜像产生,修改后的流水线脚本如下:
# 配置AWS默认区域 export AWS_DEFAULT_REGION=us-west-2 export REPO_NAME=myorg/myapp export IMAGE_TAG=latest_$BITBUCKET_BRANCH # 查询当前标签绑定的旧镜像digest OLD_DIGEST=$(aws ecr describe-images \ --repository-name $REPO_NAME \ --image-ids imageTag=$IMAGE_TAG \ --query 'imageDetails[0].imageDigest' \ --output text 2>/dev/null) # 旧镜像存在则先删除 if [ -n "$OLD_DIGEST" ] && [ "$OLD_DIGEST" != "None" ]; then aws ecr batch-delete-image \ --repository-name $REPO_NAME \ --image-ids imageDigest=$OLD_DIGEST fi # 执行原有构建推送逻辑 docker build . -t 211012356392.dkr.ecr.us-west-2.amazonaws.com/$REPO_NAME:$IMAGE_TAG docker push 211012356392.dkr.ecr.us-west-2.amazonaws.com/$REPO_NAME:$IMAGE_TAG
使用该方案需要给Bitbucket Pipelines绑定的IAM角色额外授予两个权限:ecr:DescribeImages、ecr:BatchDeleteImage,否则删除操作会报权限错误。
内容的提问来源于stack exchange,提问作者user2395365
相关产品推荐
相关产品推荐

