Files
ljwx-k8s/QUICK-FIX-IMAGEPULL.md
2026-02-20 22:50:45 +08:00

8.3 KiB
Raw Permalink Blame History

快速修复镜像拉取问题

🚨 问题识别

当你看到这些错误时,使用本指南快速修复:

# Pod 状态
kubectl get pods
NAME                        READY   STATUS             RESTARTS   AGE
myapp-xxx                   0/1     ImagePullBackOff   0          5m
myapp-yyy                   0/1     ErrImagePull       0          5m
# 错误详情
kubectl describe pod myapp-xxx
...
Events:
  Warning  Failed     2m   kubelet  Failed to pull image "nginx:alpine":
                                     Error response from daemon:
                                     Get "https://registry-1.docker.io/v2/":
                                     context deadline exceeded

⚡ 快速修复方案

方案 1: 自动修复 Deployment(推荐)

一键修复:

cd /Users/brunogao/work/codes/tools/macos/k8s
./cache-image.sh --update-deployment <namespace>/<deployment-name>

示例:

# 修复 kubernetes-dashboard
./cache-image.sh --update-deployment kubernetes-dashboard/kubernetes-dashboard

# 修复 myapp
./cache-image.sh --update-deployment default/myapp

效果:

  • ✅ 自动缓存所有镜像
  • ✅ 自动更新 Deployment
  • ✅ 自动触发 Pod 重启
  • ✅ 使用本地 Harbor 镜像

方案 2: 手动缓存镜像

步骤 1: 查看失败的镜像

kubectl describe pod <pod-name> -n <namespace> | grep "Image:"
# 输出: Image: nginx:alpine

步骤 2: 缓存镜像

./cache-image.sh nginx:alpine

步骤 3: 更新 Deployment

# 获取容器名
kubectl get deployment <deploy-name> -n <namespace> -o jsonpath='{.spec.template.spec.containers[*].name}'
# 输出: nginx

# 更新镜像
kubectl set image deployment/<deploy-name> \
  nginx=harbor.omniverseai.net:8080/library/nginx:alpine \
  -n <namespace>

方案 3: 从失败 Pod 提取镜像

适用场景: Pod 已经失败,需要批量处理

./cache-image.sh --from-pod <namespace>/<pod-name>

示例:

./cache-image.sh --from-pod kubernetes-dashboard/dashboard-xxx

效果:

  • ✅ 自动提取 Pod 所有镜像
  • ✅ 批量缓存到本地 Harbor
  • ⚠️ 需要手动更新 Deployment

📝 常见场景速查

场景 1: Dashboard 部署失败

# 错误
kubectl get pods -n kubernetes-dashboard
NAME                                        READY   STATUS             RESTARTS   AGE
kubernetes-dashboard-79cbcf9fb6-hwpxp       0/1     ImagePullBackOff   0          5m
dashboard-metrics-scraper-xxx               0/1     ImagePullBackOff   0          5m

# 修复
./cache-image.sh --update-deployment kubernetes-dashboard/kubernetes-dashboard
./cache-image.sh --update-deployment kubernetes-dashboard/dashboard-metrics-scraper

场景 2: Helm Chart 部署失败

# 查看 Helm Release 的 Pods
kubectl get pods -l app.kubernetes.io/instance=myrelease

# 获取镜像列表
helm get values myrelease | grep image

# 缓存镜像
./cache-image.sh <image1> <image2> <image3>

# 升级 Helm Release 使用本地镜像
helm upgrade myrelease ./mychart \
  --set image.repository=harbor.omniverseai.net:8080/library/myapp \
  --set image.tag=v1.0.0

场景 3: StatefulSet 失败

# 查看 StatefulSet
kubectl get statefulset <name> -n <namespace>

# 获取镜像
kubectl get statefulset <name> -n <namespace> -o jsonpath='{.spec.template.spec.containers[*].image}'

# 缓存镜像
./cache-image.sh <image>

# 更新 StatefulSet
kubectl set image statefulset/<name> \
  <container-name>=harbor.omniverseai.net:8080/library/<image>:<tag> \
  -n <namespace>

场景 4: DaemonSet 失败

# 查看 DaemonSet
kubectl get daemonset <name> -n <namespace>

# 缓存并更新(DaemonSet 需要手动处理)
./cache-image.sh <image>

kubectl set image daemonset/<name> \
  <container-name>=harbor.omniverseai.net:8080/library/<image>:<tag> \
  -n <namespace>

🔍 诊断命令

检查 Pod 状态

# 查看所有 ImagePull 失败的 Pods
kubectl get pods --all-namespaces | grep -E "ImagePull|ErrImage"

# 查看详细错误
kubectl describe pod <pod-name> -n <namespace> | grep -A 10 "Events:"

检查镜像是否已缓存

# 查询本地 Harbor
curl -u admin:admin123 \
  "http://192.168.1.83:8080/api/v2.0/projects/library/repositories" | \
  jq -r '.[].name'

验证 Deployment 使用的镜像

# 查看当前镜像
kubectl get deployment <deploy-name> -n <namespace> \
  -o jsonpath='{.spec.template.spec.containers[*].image}'

# 查看是否使用本地 Harbor
kubectl get deployment <deploy-name> -n <namespace> \
  -o jsonpath='{.spec.template.spec.containers[*].image}' | \
  grep "harbor.omniverseai.net"

💡 预防措施

1. 部署前预缓存

创建镜像清单:

# 从 YAML 提取镜像
grep "image:" deployment.yaml | awk '{print $2}' > images.txt

# 批量缓存
./cache-image.sh -f images.txt

2. 修改 YAML 使用本地镜像

原始 YAML:

spec:
  containers:
  - name: app
    image: nginx:alpine

修改后:

spec:
  containers:
  - name: app
    image: harbor.omniverseai.net:8080/library/nginx:alpine

3. 使用 imagePullPolicy

spec:
  containers:
  - name: app
    image: harbor.omniverseai.net:8080/library/nginx:alpine
    imagePullPolicy: IfNotPresent  # 优先使用本地缓存

🚀 批量修复脚本

修复整个命名空间

#!/bin/bash
# fix-namespace-images.sh

NAMESPACE="$1"

if [[ -z "$NAMESPACE" ]]; then
    echo "用法: $0 <namespace>"
    exit 1
fi

echo "=== 修复命名空间: $NAMESPACE ==="

# 获取所有 Deployment
DEPLOYMENTS=$(kubectl get deployment -n "$NAMESPACE" -o name)

for deploy in $DEPLOYMENTS; do
    deploy_name="${deploy#deployment.apps/}"
    echo "处理: $deploy_name"

    ./cache-image.sh --update-deployment "$NAMESPACE/$deploy_name"
done

echo "=== 完成 ==="

使用方式

chmod +x fix-namespace-images.sh
./fix-namespace-images.sh kubernetes-dashboard

📊 故障排查流程图

发现 ImagePullBackOff
    ↓
检查错误详情
    kubectl describe pod <pod-name>
    ↓
判断错误类型
    ├─ context deadline exceeded → 网络超时
    ├─ unauthorized → 认证失败
    └─ not found → 镜像不存在
    ↓
选择修复方案
    ├─ 自动修复(推荐)
    │   └─ ./cache-image.sh --update-deployment ns/deploy
    │
    ├─ 手动修复
    │   ├─ ./cache-image.sh <image>
    │   └─ kubectl set image ...
    │
    └─ 批量修复
        └─ ./fix-namespace-images.sh <namespace>
    ↓
验证修复
    ├─ kubectl get pods -n <namespace>
    ├─ kubectl describe deployment <deploy>
    └─ 检查 Pod 是否 Running
    ↓
✅ 完成

⏱️ 时间估算

操作 耗时
单个镜像缓存 30-60 秒
Deployment 自动修复 1-2 分钟
批量缓存 10 个镜像 5-10 分钟
整个命名空间修复 取决于 Deployment 数量

🔗 相关文档


📞 常见问题

Q: 脚本报错 "登录失败"

# 检查 Harbor 状态
curl http://192.168.1.83:8080/api/v2.0/health

# 检查 EU Harbor 连接
curl -I https://harbor.eu.lingjingwanxiang.cn

# 手动登录测试
docker login harbor.omniverseai.net:8080 -u admin -p admin123

Q: 镜像缓存成功但 Pod 仍然失败

# 检查 Deployment 是否已更新
kubectl describe deployment <deploy-name> -n <namespace> | grep Image

# 强制重启 Pod
kubectl rollout restart deployment/<deploy-name> -n <namespace>

Q: 需要缓存私有仓库的镜像怎么办?

# 脚本目前仅支持公共镜像
# 对于私有仓库,需要先配置 Docker 登录
docker login <private-registry>

# 然后手动拉取和推送
docker pull <private-registry>/<image>:<tag>
docker tag <private-registry>/<image>:<tag> \
  harbor.omniverseai.net:8080/library/<image>:<tag>
docker push harbor.omniverseai.net:8080/library/<image>:<tag>

最后更新: 2025-12-24 脚本位置: /Users/brunogao/work/codes/tools/macos/k8s/cache-image.sh