Kubernetes从GCR拉取镜像单副本报401 Unauthorized错误咨询
核心成因
同一Deployment下仅单个副本报GCR镜像拉取401鉴权失败、其余副本正常运行,问题必然出在异常副本所在工作节点与正常节点的配置/状态差异,全局配置(Deployment、imagePullSecret、GCR仓库权限、镜像本身)不存在问题,否则所有副本都会拉取失败。常见触发场景如下:
- 节点GCR访问凭证配置不一致
若集群未配置Pod级imagePullSecret,依赖节点内置凭证拉取GCR镜像:异常节点绑定的GCE服务账号可能缺失storage.objectViewer等GCR拉取必需权限,或节点上容器运行时(containerd/docker)存储的GCR访问凭证已过期、损坏,无法通过GCR鉴权;正常节点凭证有效,调度到正常节点的副本可正常拉取运行。 - 节点到GCR的网络链路异常
异常节点配置了错误的HTTP/HTTPS代理、出口防火墙拦截了到GCR鉴权服务(gcr.io、oauth2.googleapis.com)的请求,或节点DNS解析异常将GCR域名指向非官方地址,导致鉴权请求未送达GCR官方服务,返回虚假401响应。 - 节点容器运行时凭证缓存异常
异常节点上的kubelet或容器运行时缓存了过期的GCR临时鉴权token,未触发自动刷新逻辑,即使全局凭证配置正确,拉取时仍携带旧token请求,触发401报错。 - 单节点元数据服务访问异常
GCP节点通过访问本地元数据服务获取GCR临时访问凭证,若异常节点本地元数据服务临时故障、或访问链路被阻断,节点无法获取有效临时凭证,拉取镜像时就会返回401。
排查步骤
- 定位异常副本所在节点
执行命令获取Pod调度信息,区分异常副本与正常副本所在节点:
后续所有排查操作仅需针对定位到的异常节点开展,无需调整全局Kubernetes资源配置。kubectl get pod <异常Pod名> -n <命名空间> -o wide - 节点层面手动复现拉取行为
登录异常节点,使用与kubelet相同的容器运行时手动拉取目标镜像,验证问题是否可复现:- containerd运行时执行:
crictl pull gcr.io/xxx:yyy - Docker运行时执行:
docker pull gcr.io/xxx:yyy
若手动拉取同样返回401,可100%确认问题出在节点侧,与Kubernetes控制面、Deployment配置无关。
- containerd运行时执行:
- 校验节点GCR访问权限
- GKE集群场景:对比异常节点与正常节点绑定的GCE虚拟机服务账号配置,确认异常节点的服务账号未被单独移除GCR镜像拉取所需的
roles/storage.objectViewer角色,服务账号密钥未过期。 - 自建集群场景:对比异常节点与正常节点的容器运行时凭证配置(通常路径为
/var/lib/kubelet/config.json或/root/.docker/config.json),确认异常节点未配置错误、过期的GCR访问凭证。
- GKE集群场景:对比异常节点与正常节点绑定的GCE虚拟机服务账号配置,确认异常节点的服务账号未被单独移除GCR镜像拉取所需的
- 校验节点到GCR的网络连通性
在异常节点上执行以下检查:- DNS校验:执行
nslookup gcr.io、nslookup oauth2.googleapis.com,确认解析结果与正常节点一致,不存在域名劫持、解析错误问题。 - 链路校验:执行
curl -I https://gcr.io/v2/,未携带凭证时正常返回401为预期结果,若返回连接超时、连接重置、非GCR官方响应头,说明节点出口链路存在代理、防火墙、路由配置错误。
- DNS校验:执行
- 清理节点拉取缓存重试
若手动拉取可偶发成功、仅kubelet拉取持续失败,可清理容器运行时镜像缓存与凭证缓存,重启相关服务后重试:# containerd环境示例 crictl rmi gcr.io/xxx:yyy systemctl restart containerd systemctl restart kubelet
快速恢复方案
需紧急恢复业务时,可先将异常节点标记为不可调度,驱逐节点上的Pod,让副本重新调度到正常节点即可快速恢复:
kubectl cordon <异常节点名> kubectl drain <异常节点名> --ignore-daemonsets --delete-emptydir-data
待节点侧问题修复验证通过后,执行kubectl uncordon <异常节点名>即可恢复该节点的调度能力。
内容的提问来源于stack exchange,提问作者Soundarya
相关产品推荐
相关产品推荐

