Grafana-Feishu 镜像拉取故障排障记录



Grafana-Feishu 镜像拉取故障排障记录



logging 命名空间部署 grafana-feishu 时,Pod 一直无法正常启动。

最初使用的镜像为:

1
image: allanchain/grafana-feishu:latest

Pod 状态表现为:

  • ErrImagePull
  • ImagePullBackOff

通过 kubectl describe pod 查看事件后,发现核心报错为:

  • 节点从 Docker Hub 拉取 allanchain/grafana-feishu:latest 超时
  • 报错类似:
    • failed to resolve reference
    • Head "https://registry-1.docker.io/v2/...": dial tcp ...:443: i/o timeout

这说明问题不在 Deployment 语法,而在于 集群节点无法访问 Docker Hub


第一阶段:尝试本地打包镜像并传到节点


思路

因为本地电脑可以成功 docker pull allanchain/grafana-feishu:latest,所以最开始的思路是:

  1. 在本地把镜像拉下来
  2. docker save 成 tar 包
  3. 把 tar 包传到 Kubernetes 节点
  4. 在节点上执行 docker load

遇到的问题

在服务器上执行:

1
docker load -i /root/grafana-feishu.tar

结果提示:

1
Command 'docker' not found

说明当前登录的机器 prod-server-ci 并不是容器运行时节点,或者至少这台机器上没有 Docker CLI。

进一步分析后确认:

  • Pod 实际被调度到的节点是:
    • cn-shanghai.10.71.45.249
    • cn-shanghai.10.71.45.250
  • 镜像拉取动作发生在这些节点上的 kubelet/container runtime
  • 因此,应该把镜像导入到 实际运行 Pod 的节点,而不是随便一台运维机

再次遇到的问题

尝试用 scp 把 tar 包传到节点,但传不过去。说明:

  • 节点可能不开放 SSH
  • 或者当前机器到节点网络不通
  • 或者该集群环境不适合走"手工 SSH 上节点导入镜像"这条路

于是放弃了手工上传节点镜像的方案。


第二阶段:改走阿里云 ACR 镜像仓库


既然集群节点无法访问 Docker Hub,那更合理的办法是:

  1. 在本地把镜像推送到阿里云 ACR
  2. 再让集群从 ACR 拉取镜像

初始误区

一开始把 ACR 仓库地址当成 SSH 主机来用,尝试:

1
2
scp grafana-feishu.tar xxx@xxx-registry.cn-shanghai.cr.aliyuncs.com:/root/
ssh xxx@xxx-registry.cn-shanghai.cr.aliyuncs.com

结果报错:

1
ssh: connect to host ... port 22: Network is unreachable

后来明确了:

ACR 是镜像仓库,不是给 ssh/scp 登录的机器。

正确用法应该是:

  • docker login
  • docker tag
  • docker push

第三阶段:推送镜像到 ACR


登录仓库

本地执行:

1
docker login --username=xxx http://xxx-registry.cn-shanghai.cr.aliyuncs.com/

虽然中间有一条 Docker Desktop 凭据提示异常,但最终结果是:

1
Login Succeeded

说明登录态已经成功建立。

第一次推送失败

先尝试打 tag 并推送到:

1
xxx-registry.cn-shanghai.cr.aliyuncs.com/logging/grafana-feishu:latest

执行:

1
2
docker tag allanchain/grafana-feishu:latest xxx-registry.cn-shanghai.cr.aliyuncs.com/logging/grafana-feishu:latest
docker push xxx-registry.cn-shanghai.cr.aliyuncs.com/logging/grafana-feishu:latest

结果失败,报错:

  • repository does not exist or may require authorization
  • insufficient_scope: authorization failed

说明这个仓库路径不对,或者当前账号对该 repo 没有权限。

第二次推送成功

改成:

1
2
docker tag allanchain/grafana-feishu:latest xxx-registry.cn-shanghai.cr.aliyuncs.com/xxx/grafana-feishu:latest
docker push xxx-registry.cn-shanghai.cr.aliyuncs.com/xxx/grafana-feishu:latest

这次成功:

1
latest: digest: sha256:...

至此确认,正确可用的仓库地址为:

1
xxx-registry.cn-shanghai.cr.aliyuncs.com/xxx/grafana-feishu:latest

第四阶段:Kubernetes 改用 ACR 地址,但仍然失败


修改镜像地址

将 Deployment 中的镜像改为:

1
image: xxx-registry.cn-shanghai.cr.aliyuncs.com/xxx/grafana-feishu:latest

然后执行 rollout。

新问题:仍然拉不到镜像

Pod 事件显示:

  • 不是鉴权失败
  • 而是网络超时

核心报错:

1
2
Head "https://xxx-registry.cn-shanghai.cr.aliyuncs.com/v2/.../manifests/latest":
dial tcp 139.224.244.151:443: i/o timeout

这说明:

集群节点到 ACR 公网地址的 443 也不通。

也就是说:

  • Docker Hub 不通
  • ACR 公网地址也不通

但用户进一步确认后发现:

集群节点能访问的是 ACR 内网 / VPC 地址,而不是公网地址


第五阶段:切换到 ACR VPC 内网地址


确认正确的内网仓库地址为:

1
xxx-registry-vpc.cn-shanghai.cr.aliyuncs.com

因此,Deployment 中镜像地址应改成:

1
2
image: xxx-registry-vpc.cn-shanghai.cr.aliyuncs.com/xxx/grafana-feishu:latest
imagePullPolicy: IfNotPresent

第六阶段:切到 VPC 地址后,网络问题解决,但出现认证问题


这一步 Pod 事件发生了变化。不再是 i/o timeout,而是:

  • FailedToRetrieveImagePullSecret
  • pull access denied
  • insufficient_scope: authorization failed

典型报错为:

1
Unable to retrieve some image pull secrets (acr-secret)

以及:

1
2
pull access denied, repository does not exist or may require authorization:
server message: insufficient_scope: authorization failed

这说明:

  1. 网络已经通了
  2. 现在真正的问题变成了:
    • Pod 想使用 acr-secret
    • logging 命名空间下根本没有这个 Secret
    • 所以 kubelet 拿不到认证信息去拉私有仓库

第七阶段:确认根因 —— acr-secret 不存在


执行检查:

1
kubectl -n logging get secret acr-secret

返回:

1
Error from server (NotFound): secrets "acr-secret" not found

至此彻底破案:

根因

Deployment 模板里已经引用了:

1
2
imagePullSecrets:
- name: acr-secret

但实际上 logging 命名空间里并没有这个 Secret,导致:

  • kubelet 无法获取镜像仓库认证信息
  • 拉取私有仓库镜像失败
  • ACR 返回 insufficient_scope

第八阶段:创建正确的 imagePullSecret


正确做法是用 VPC 地址 创建 docker-registry Secret:

1
2
3
4
5
kubectl -n logging create secret docker-registry acr-secret \
--docker-server=xxx-registry-vpc.cn-shanghai.cr.aliyuncs.com \
--docker-username=xxx \
--docker-password='ACR密码' \
--docker-email='none@example.com'

关键点:

  • --docker-server 必须与 Deployment 中实际使用的镜像域名一致
  • 也就是必须写成:xxx-registry-vpc.cn-shanghai.cr.aliyuncs.com
  • 不能再写公网地址

第九阶段:最终修复成功


在 Secret 创建完成后,执行:

1
kubectl -n logging rollout restart deployment/grafana-feishu

这次成功。

说明此时整条链路已经打通:

  1. 镜像已成功推送到阿里云 ACR
  2. Deployment 已改为使用 ACR VPC 内网镜像地址
  3. 集群节点可以访问该 VPC 地址
  4. acr-secret 已存在,且可供 kubelet 获取
  5. 私有仓库拉取认证成功
  6. grafana-feishu Deployment 成功完成滚动重启

总结


阶段 问题 解决方案
1 Docker Hub 超时 改用国内镜像仓库
2-3 不了解 ACR 用法 使用 docker login/tag/push
4 ACR 公网不通 切换到 VPC 内网地址
5-8 imagePullSecret 缺失 创建正确的 docker-registry Secret

核心教训:排查镜像拉取问题时,要分清是网络问题还是认证问题,逐层排查。