14 KiB
14 KiB
自动镜像缓存解决方案
方案对比
| 方案 | 透明度 | 自动化 | 复杂度 | 推荐度 |
|---|---|---|---|---|
| 1. OrbStack Registry Mirrors | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ |
| 2. Docker Pull Wrapper | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| 3. kubectl Wrapper | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| 4. K8s Mutating Webhook | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 5. Claude Code Integration | ⭐⭐⭐ | ⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐ |
⭐ 推荐方案:多层防护策略
层级 1: OrbStack Registry Mirrors(最透明)
原理: 配置 OrbStack 使用本地 Harbor 作为 registry mirror,所有镜像拉取自动走缓存。
优点:
- ✅ 完全透明,无需修改代码
- ✅ 对所有容器运行时生效
- ✅ 性能最优
- ✅ 无需 wrapper
缺点:
- ⚠️ 需要预先缓存镜像
- ⚠️ 仅支持 Docker Hub
实现: 见下文
层级 2: Docker/kubectl Wrapper(智能拦截)
原理: 创建命令 wrapper,自动检测失败并缓存镜像。
优点:
- ✅ 自动检测和修复
- ✅ 支持所有 registry
- ✅ 可记录日志
缺点:
- ⚠️ 需要使用 wrapper 命令
实现: 见下文
层级 3: Claude Code CLAUDE.md 集成(AI 辅助)
原理: 在 CLAUDE.md 中添加自动修复指令,Claude 遇到镜像问题自动执行。
优点:
- ✅ Claude 自动识别
- ✅ 无需人工干预
- ✅ 灵活智能
实现: 见下文
实现方案
方案 1: OrbStack Registry Mirrors(推荐)
配置文件位置
~/.orbstack/config/docker.json
配置内容
{
"registry-mirrors": [
"http://harbor.omniverseai.net:8080"
],
"insecure-registries": [
"harbor.omniverseai.net:8080"
]
}
自动配置脚本
#!/bin/bash
# setup-orbstack-registry-mirror.sh
ORBSTACK_CONFIG="$HOME/.orbstack/config/docker.json"
HARBOR_MIRROR="http://harbor.omniverseai.net:8080"
# 创建配置目录
mkdir -p "$(dirname "$ORBSTACK_CONFIG")"
# 生成配置
cat > "$ORBSTACK_CONFIG" << EOF
{
"registry-mirrors": [
"$HARBOR_MIRROR"
],
"insecure-registries": [
"$HARBOR_MIRROR"
],
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5
}
EOF
echo "✅ OrbStack 配置已更新"
echo "⚠️ 需要重启 OrbStack 生效"
echo ""
echo "重启命令: orb restart"
验证
# 检查配置
cat ~/.orbstack/config/docker.json
# 重启 OrbStack
orb restart
# 测试拉取
docker pull nginx:alpine
# 查看是否使用镜像
docker pull nginx:alpine 2>&1 | grep -i harbor
限制
- ⚠️ 仅适用于 Docker Hub 镜像
- ⚠️ 需要提前缓存镜像到 Harbor
- ⚠️ gcr.io, quay.io 等不走 mirror
方案 2: Docker Pull Wrapper
创建 Wrapper
#!/bin/bash
# /usr/local/bin/docker-cached
REAL_DOCKER="/usr/bin/docker"
CACHE_SCRIPT="/Users/brunogao/work/codes/tools/macos/k8s/cache-image.sh"
# 如果是 pull 命令
if [[ "$1" == "pull" ]]; then
IMAGE="$2"
echo "🔍 检查镜像: $IMAGE"
# 尝试直接拉取
if ! $REAL_DOCKER pull "$IMAGE" 2>&1 | tee /tmp/docker-pull.log | grep -q "error\|failed\|timeout"; then
echo "✅ 直接拉取成功"
exit 0
fi
# 拉取失败,使用缓存
echo "⚠️ 直接拉取失败,使用 Harbor 缓存..."
if [[ -x "$CACHE_SCRIPT" ]]; then
$CACHE_SCRIPT "$IMAGE"
# 拉取本地 Harbor 镜像
LOCAL_IMAGE="harbor.omniverseai.net:8080/library/${IMAGE##*/}"
$REAL_DOCKER pull "$LOCAL_IMAGE"
# 重新标记为原始名称
$REAL_DOCKER tag "$LOCAL_IMAGE" "$IMAGE"
echo "✅ 已从 Harbor 缓存拉取"
else
echo "❌ 缓存脚本不存在: $CACHE_SCRIPT"
exit 1
fi
else
# 其他命令直接透传
exec $REAL_DOCKER "$@"
fi
使用方式
# 方式 1: alias
alias docker='docker-cached'
# 方式 2: PATH 优先级
export PATH="/usr/local/bin:$PATH"
# 使用
docker pull nginx:alpine # 自动缓存
方案 3: kubectl Wrapper(智能检测)
创建 Wrapper
#!/bin/bash
# /usr/local/bin/kubectl-cached
REAL_KUBECTL="/usr/local/bin/kubectl"
CACHE_SCRIPT="/Users/brunogao/work/codes/tools/macos/k8s/cache-image.sh"
# 执行原始命令
$REAL_KUBECTL "$@"
EXIT_CODE=$?
# 如果是 apply/create 命令,检查 ImagePull 错误
if [[ "$1" =~ ^(apply|create)$ ]]; then
sleep 5 # 等待 Pod 创建
# 检查是否有 ImagePull 失败
FAILED_PODS=$($REAL_KUBECTL get pods --all-namespaces -o json | \
jq -r '.items[] | select(.status.containerStatuses[]?.state.waiting?.reason | test("ImagePull|ErrImage")) | "\(.metadata.namespace)/\(.metadata.name)"')
if [[ -n "$FAILED_PODS" ]]; then
echo ""
echo "⚠️ 检测到镜像拉取失败,自动修复中..."
echo ""
while IFS= read -r pod; do
NS="${pod%/*}"
POD_NAME="${pod##*/}"
# 获取 Deployment/StatefulSet
OWNER=$($REAL_KUBECTL get pod "$POD_NAME" -n "$NS" -o json | \
jq -r '.metadata.ownerReferences[]? | select(.kind | test("ReplicaSet|StatefulSet")) | .name')
if [[ "$OWNER" =~ ^(.+)-[a-z0-9]+$ ]]; then
DEPLOY_NAME="${BASH_REMATCH[1]}"
echo "🔧 修复: $NS/$DEPLOY_NAME"
$CACHE_SCRIPT --update-deployment "$NS/$DEPLOY_NAME"
fi
done <<< "$FAILED_PODS"
echo ""
echo "✅ 自动修复完成"
fi
fi
exit $EXIT_CODE
使用方式
# alias
alias kubectl='kubectl-cached'
# 部署
kubectl apply -f deployment.yaml # 自动检测并修复
方案 4: Claude Code CLAUDE.md 集成
在项目根目录添加配置
位置: /Users/brunogao/work/codes/tools/macos/CLAUDE.md
内容:
# Claude Code 配置
## 镜像拉取问题自动修复
当遇到以下情况时,自动执行镜像缓存:
### 识别条件
- Kubernetes Pod 状态为 `ImagePullBackOff` 或 `ErrImagePull`
- kubectl 命令返回镜像拉取错误
- docker pull 命令超时或失败
### 自动修复流程
1. 检测到镜像拉取失败
2. 自动执行: `/Users/brunogao/work/codes/tools/macos/k8s/cache-image.sh --update-deployment <namespace>/<deployment>`
3. 等待 Pod 重启
4. 验证修复成功
### 快速修复命令
```bash
# 自动修复 Deployment
cd /Users/brunogao/work/codes/tools/macos/k8s
./cache-image.sh --update-deployment <namespace>/<deployment>
手动缓存
# 缓存单个镜像
./cache-image.sh <image>:<tag>
# 批量缓存
./cache-image.sh <image1> <image2> <image3>
重要提示
- ✅ 优先使用
--update-deployment自动修复 - ✅ 所有镜像会缓存到
harbor.omniverseai.net:8080/library/ - ✅ 脚本支持 Docker Hub, GCR, Quay 等所有公共仓库
- ⚠️ 遇到 ImagePull 问题必须立即执行,不要等待
---
### 方案 5: 综合自动化脚本
#### 创建智能监控脚本
```bash
#!/bin/bash
# watch-and-fix-images.sh
# 持续监控并自动修复镜像拉取问题
CACHE_SCRIPT="/Users/brunogao/work/codes/tools/macos/k8s/cache-image.sh"
CHECK_INTERVAL=30
echo "🔍 启动镜像拉取监控..."
echo "检查间隔: ${CHECK_INTERVAL}s"
echo ""
while true; do
# 查找所有 ImagePull 失败的 Pods
FAILED_PODS=$(kubectl get pods --all-namespaces -o json 2>/dev/null | \
jq -r '.items[] |
select(.status.containerStatuses[]?.state.waiting?.reason |
test("ImagePull|ErrImage")) |
"\(.metadata.namespace)/\(.metadata.name)"')
if [[ -n "$FAILED_PODS" ]]; then
echo "⚠️ [$(date '+%Y-%m-%d %H:%M:%S')] 检测到镜像拉取失败"
echo ""
# 去重 Deployment
declare -A FIXED_DEPLOYS
while IFS= read -r pod; do
[[ -z "$pod" ]] && continue
NS="${pod%/*}"
POD_NAME="${pod##*/}"
# 获取 Deployment
OWNER=$(kubectl get pod "$POD_NAME" -n "$NS" -o json 2>/dev/null | \
jq -r '.metadata.ownerReferences[]? |
select(.kind | test("ReplicaSet")) | .name')
if [[ "$OWNER" =~ ^(.+)-[a-z0-9]+$ ]]; then
DEPLOY_NAME="${BASH_REMATCH[1]}"
DEPLOY_KEY="$NS/$DEPLOY_NAME"
# 避免重复修复
if [[ -z "${FIXED_DEPLOYS[$DEPLOY_KEY]}" ]]; then
echo "🔧 自动修复: $DEPLOY_KEY"
if $CACHE_SCRIPT --update-deployment "$DEPLOY_KEY" &>> /tmp/image-fix.log; then
echo " ✅ 修复成功"
FIXED_DEPLOYS[$DEPLOY_KEY]=1
else
echo " ❌ 修复失败,查看日志: /tmp/image-fix.log"
fi
echo ""
fi
fi
done <<< "$FAILED_PODS"
echo "等待 Pod 重启..."
sleep 10
fi
sleep $CHECK_INTERVAL
done
后台运行
# 启动监控
nohup ./watch-and-fix-images.sh > /tmp/image-watch.log 2>&1 &
# 查看日志
tail -f /tmp/image-watch.log
# 停止监控
pkill -f watch-and-fix-images.sh
最佳实践:组合方案
推荐配置(多层防护)
层级 1: OrbStack Registry Mirror
↓ (90% 镜像直接缓存)
层级 2: kubectl wrapper 自动检测
↓ (剩余镜像自动修复)
层级 3: Claude Code CLAUDE.md
↓ (AI 辅助决策)
层级 4: 手动 cache-image.sh
↓ (兜底方案)
实施步骤
Step 1: 配置 OrbStack Mirror
./setup-orbstack-registry-mirror.sh
orb restart
Step 2: 安装 kubectl wrapper
sudo cp kubectl-cached /usr/local/bin/
echo 'alias kubectl="kubectl-cached"' >> ~/.zshrc
source ~/.zshrc
Step 3: 配置 Claude Code
# 在项目根目录 CLAUDE.md 添加镜像修复指令
cat >> /Users/brunogao/work/codes/tools/macos/CLAUDE.md << 'EOF'
## 自动镜像缓存
遇到 ImagePullBackOff 时自动执行:
```bash
cd /Users/brunogao/work/codes/tools/macos/k8s
./cache-image.sh --update-deployment <namespace>/<deployment>
EOF
#### Step 4: (可选)启动后台监控
```bash
# 开机自启动
cat > ~/Library/LaunchAgents/com.k8s.image-watcher.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.k8s.image-watcher</string>
<key>ProgramArguments</key>
<array>
<string>/Users/brunogao/work/codes/tools/macos/k8s/watch-and-fix-images.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/image-watch.log</string>
<key>StandardErrorPath</key>
<string>/tmp/image-watch-error.log</string>
</dict>
</plist>
EOF
launchctl load ~/Library/LaunchAgents/com.k8s.image-watcher.plist
方案对比详细分析
1. OrbStack Registry Mirror
工作原理:
docker pull nginx:alpine
↓
OrbStack 拦截
↓
首先查询: harbor.omniverseai.net:8080/library/nginx:alpine
├─ 存在 → 直接使用 ✅
└─ 不存在 → 回退到 Docker Hub
优点:
- 完全透明
- 性能最高
- 无需代码修改
缺点:
- 仅支持 Docker Hub
- 需要预缓存
适用场景:
- 常用基础镜像(nginx, redis, mysql)
- 已知镜像列表
2. Docker/kubectl Wrapper
工作原理:
kubectl apply -f deployment.yaml
↓
kubectl-cached 拦截
↓
执行原始命令
↓
检测 ImagePull 错误
├─ 无错误 → 完成 ✅
└─ 有错误 → 自动执行 cache-image.sh
↓
缓存镜像
↓
更新 Deployment
↓
完成 ✅
优点:
- 自动检测
- 支持所有 registry
- 可记录日志
缺点:
- 首次部署会失败
- 需要等待修复
适用场景:
- 新镜像部署
- 不确定的镜像
3. Claude Code Integration
工作原理:
Claude 执行 kubectl apply
↓
检测到 ImagePullBackOff
↓
读取 CLAUDE.md 指令
↓
自动执行: ./cache-image.sh --update-deployment
↓
继续部署 ✅
优点:
- AI 自动决策
- 灵活智能
- 无需人工干预
缺点:
- 依赖 Claude Code
- 需要明确指令
适用场景:
- Claude 辅助开发
- 自动化部署
测试验证
测试场景 1: 新镜像部署
# 清除本地镜像
docker rmi nginx:alpine
# 测试 OrbStack mirror
docker pull nginx:alpine
# 预期: 从 Harbor 快速拉取
# 测试 kubectl wrapper
kubectl apply -f test-deployment.yaml
# 预期: 自动检测并修复
测试场景 2: GCR 镜像
# 测试 cache-image.sh
./cache-image.sh gcr.io/distroless/static:latest
# 验证缓存
docker pull harbor.omniverseai.net:8080/library/static:latest
监控和日志
查看 OrbStack Mirror 日志
# OrbStack 日志
tail -f ~/.orbstack/logs/docker.log | grep -i mirror
查看 wrapper 日志
# kubectl wrapper
tail -f /tmp/kubectl-cached.log
# docker wrapper
tail -f /tmp/docker-pull.log
查看自动修复日志
tail -f /tmp/image-fix.log
tail -f /tmp/image-watch.log
故障排查
OrbStack Mirror 不生效
# 检查配置
cat ~/.orbstack/config/docker.json
# 检查 OrbStack 状态
orb status
# 重启 OrbStack
orb restart
# 验证
docker info | grep -i mirror
Wrapper 未执行
# 检查 PATH
echo $PATH
# 检查 alias
alias | grep kubectl
# 检查权限
ls -l /usr/local/bin/kubectl-cached
总结
| 场景 | 推荐方案 |
|---|---|
| 日常使用 | OrbStack Mirror + kubectl wrapper |
| Claude 开发 | CLAUDE.md + cache-image.sh |
| 生产环境 | 所有方案组合 |
| 快速修复 | cache-image.sh --update-deployment |
最佳实践:
- 配置 OrbStack Mirror(透明加速)
- 安装 kubectl wrapper(自动修复)
- 配置 Claude Code(AI 辅助)
- 保留 cache-image.sh(兜底方案)
维护建议:
- 定期同步常用镜像到 Harbor
- 监控 wrapper 日志
- 更新 CLAUDE.md 指令
最后更新: 2025-12-24 作者: Claude AI + Bruno Gao