GitLab CI中docker login登录AWS ECR失败如何排查解决
GitLab CI 推送镜像至AWS ECR时docker login执行失败修复方案
报错根因
三个登录命令的报错原因分别如下:
- 带
-p参数直接传密码的命令返回Denied: not authorized:你通过py-pip安装的是1.x版本的awscli,get-login-password是awscli 2.x版本才支持的接口,旧版本执行该命令不会返回有效授权令牌,直接传空/错误值给docker就会报无权限。另外你单独执行的aws ecr get-login --no-include-email是1.x版本的旧命令,执行后会直接输出完整的docker login执行语句,你没有执行该语句的输出内容,这行配置完全无效。 - 两个带
--password-stdin参数的命令返回Cannot perform an interactive login from a non TTY device:使用该参数时必须通过标准输入传入密码,你没有通过管道把密码传给docker进程,docker在非交互的CI环境下等不到密码输入就会直接抛出该错误。 - 额外隐性问题:你当前配置没有指定
DOCKER_HOST变量,docker客户端可能无法正常连接dind服务,会触发额外的连接类报错;原配置中注册ECS任务定义的命令写错了服务名,把ecs写成了ecr,执行时也会报错。
修复步骤
- 替换awscli安装源:不要通过pip安装旧版awscli,直接用alpine官方源内置的awscli 2.x版本,避免版本兼容问题。
- 修正docker login写法:通过管道把
aws ecr get-login-password的输出传给docker login的标准输入,不要单独使用--password-stdin参数。 - 校验AWS权限:确认GitLab CI中配置的
AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY对应的身份(或OIDC关联角色)持有以下ECR权限:ecr:GetAuthorizationToken、ecr:BatchCheckLayerAvailability、ecr:InitiateLayerUpload、ecr:UploadLayerPart、ecr:CompleteLayerUpload、ecr:PutImage,跨账号推送时还要额外确认目标ECR仓库的资源策略允许当前身份推送。 - 补充dind必要配置:添加
DOCKER_HOST变量指向dind服务,如遇TLS证书报错可加DOCKER_TLS_CERTDIR: ""关闭TLS校验(仅内网CI环境可用)。
修正后的配置参考
image: docker:latest services: - docker:dind variables: DOCKER_HOST: tcp://docker:2376 DOCKER_TLS_CERTDIR: "/certs" AWS_REGION: us-west-2 PRIVATE_ECR_REGISTRY: 775362094965.dkr.ecr.us-west-2.amazonaws.com # 公有ECR登录必须指定us-east-1区域 # PUBLIC_ECR_REGISTRY: public.ecr.aws/u1c1h9j4 before_script: - apk add --update --no-cache jq awscli # 登录私有ECR - aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $PRIVATE_ECR_REGISTRY # 如需登录公有ECR放开下面注释 # - aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin $PUBLIC_ECR_REGISTRY stages: - build - deploy build-job: stage: build script: - docker build -t $PRIVATE_ECR_REGISTRY/$REPOSITORY_URL:$IMAGE_TAG . - docker push $PRIVATE_ECR_REGISTRY/$REPOSITORY_URL:$IMAGE_TAG only: - main deploy-job: stage: deploy script: - aws ecs describe-task-definition --task-definition $CI_AWS_ECS_TASK_DEFINITION --region $AWS_REGION > input.json - cat input.json | jq '.taskDefinition.containerDefinitions[].image="'$PRIVATE_ECR_REGISTRY'/'$REPOSITORY_URL':'$IMAGE_TAG'"' | jq '.taskDefinition' > input.json - cat input.json | jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' > input.json - aws ecs register-task-definition --cli-input-json file://input.json --region $AWS_REGION - revision=$(aws ecs describe-task-definition --task-definition $CI_AWS_ECS_TASK_DEFINITION --region $AWS_REGION | jq -r '.taskDefinition.revision') - aws ecs update-service --cluster $CI_AWS_ECS_CLUSTER --service $CI_AWS_ECS_SERVICE --task-definition $CI_AWS_ECS_TASK_DEFINITION:$revision --region $AWS_REGION
额外注意事项
- 镜像地址不要带
https://前缀,直接写注册表域名即可。 - 公有ECR的登录接口全局部署在us-east-1区域,不管你实际仓库在哪个区域,登录公有ECR时必须指定
--region us-east-1,否则会报域名解析错误或权限错误。 - 不建议使用长期AK/SK,优先配置GitLab与AWS的OIDC身份提供商,用临时角色凭证访问ECR,避免密钥泄露风险。
内容的提问来源于stack exchange,提问作者MP32
相关产品推荐
相关产品推荐

