358 lines
13 KiB
Bash
Executable File
358 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
|
# 自动镜像修复系统 - 针对当前环境的定制化部署
|
|
# 基于现有 OrbStack 配置,保留所有现有设置
|
|
|
|
set -e
|
|
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
RED='\033[0;31m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
|
|
log_warning() { echo -e "${YELLOW}[!]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[✗]${NC} $1"; }
|
|
log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ORBSTACK_CONFIG="$HOME/.orbstack/config/docker.json"
|
|
HARBOR_MIRROR="http://harbor.omniverseai.net:8080"
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_info "自动镜像修复系统 - 定制化部署"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# 显示当前环境
|
|
log_step "1/4 环境检查"
|
|
echo ""
|
|
|
|
if [[ -f "$ORBSTACK_CONFIG" ]]; then
|
|
log_success "OrbStack 配置文件存在"
|
|
|
|
# 检查 registry-mirrors
|
|
MIRRORS_COUNT=$(jq '.["registry-mirrors"] | length' "$ORBSTACK_CONFIG" 2>/dev/null || echo "0")
|
|
if [[ "$MIRRORS_COUNT" -eq 0 ]]; then
|
|
log_warning "Registry Mirrors: 未配置 (将添加)"
|
|
else
|
|
log_success "Registry Mirrors: 已配置 $MIRRORS_COUNT 个"
|
|
fi
|
|
|
|
# 检查 insecure-registries
|
|
INSECURE_COUNT=$(jq '.["insecure-registries"] | length' "$ORBSTACK_CONFIG" 2>/dev/null || echo "0")
|
|
log_success "Insecure Registries: 已配置 $INSECURE_COUNT 个"
|
|
else
|
|
log_error "OrbStack 配置文件不存在"
|
|
exit 1
|
|
fi
|
|
|
|
# 检查 kubectl alias
|
|
if grep -q "kubectl-auto-fix" "$HOME/.zshrc" 2>/dev/null; then
|
|
log_success "kubectl wrapper: 已安装"
|
|
KUBECTL_INSTALLED=true
|
|
else
|
|
log_warning "kubectl wrapper: 未安装 (将添加)"
|
|
KUBECTL_INSTALLED=false
|
|
fi
|
|
|
|
# 检查 LaunchAgent
|
|
if [[ -f "$HOME/Library/LaunchAgents/com.k8s.image-watcher.plist" ]]; then
|
|
log_success "后台监控: 已安装"
|
|
WATCHER_INSTALLED=true
|
|
else
|
|
log_warning "后台监控: 未安装 (可选)"
|
|
WATCHER_INSTALLED=false
|
|
fi
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_step "2/4 配置 Registry Mirror(保留现有配置)"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# 备份现有配置
|
|
BACKUP="${ORBSTACK_CONFIG}.backup.$(date +%Y%m%d_%H%M%S)"
|
|
cp "$ORBSTACK_CONFIG" "$BACKUP"
|
|
log_success "已备份配置到: $BACKUP"
|
|
|
|
# 使用 jq 安全地添加 registry-mirrors,保留所有其他配置
|
|
jq --arg mirror "$HARBOR_MIRROR" \
|
|
'.["registry-mirrors"] = [$mirror]' \
|
|
"$ORBSTACK_CONFIG" > "${ORBSTACK_CONFIG}.tmp"
|
|
|
|
mv "${ORBSTACK_CONFIG}.tmp" "$ORBSTACK_CONFIG"
|
|
|
|
log_success "已添加 Registry Mirror: $HARBOR_MIRROR"
|
|
echo ""
|
|
log_info "更新后的配置:"
|
|
cat "$ORBSTACK_CONFIG" | jq '.'
|
|
echo ""
|
|
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_step "3/4 安装 kubectl wrapper"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
if [[ "$KUBECTL_INSTALLED" == "true" ]]; then
|
|
log_warning "kubectl wrapper 已安装,跳过"
|
|
else
|
|
# 检查脚本是否存在
|
|
if [[ ! -f "$SCRIPT_DIR/kubectl-auto-fix" ]]; then
|
|
log_error "kubectl-auto-fix 脚本不存在"
|
|
exit 1
|
|
fi
|
|
|
|
# 确保脚本可执行
|
|
chmod +x "$SCRIPT_DIR/kubectl-auto-fix"
|
|
|
|
# 添加 alias 到 .zshrc
|
|
cat >> "$HOME/.zshrc" << EOF
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# kubectl auto-fix wrapper (添加时间: $(date '+%Y-%m-%d %H:%M:%S'))
|
|
# 自动检测并修复 ImagePullBackOff 错误
|
|
# ═══════════════════════════════════════════════════════════════
|
|
alias kubectl="$SCRIPT_DIR/kubectl-auto-fix"
|
|
|
|
EOF
|
|
|
|
log_success "已添加 kubectl alias 到 ~/.zshrc"
|
|
echo ""
|
|
log_info "生效方式:"
|
|
echo " 1. 当前终端: source ~/.zshrc"
|
|
echo " 2. 新终端会自动生效"
|
|
fi
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_step "4/4 配置后台监控服务(可选)"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
if [[ "$WATCHER_INSTALLED" == "true" ]]; then
|
|
log_warning "后台监控已安装,跳过"
|
|
else
|
|
read -p "是否安装后台监控服务? (y/n) " -n 1 -r
|
|
echo
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
# 检查脚本是否存在
|
|
if [[ ! -f "$SCRIPT_DIR/watch-and-fix-images.sh" ]]; then
|
|
log_error "watch-and-fix-images.sh 脚本不存在"
|
|
else
|
|
chmod +x "$SCRIPT_DIR/watch-and-fix-images.sh"
|
|
|
|
PLIST_FILE="$HOME/Library/LaunchAgents/com.k8s.image-watcher.plist"
|
|
|
|
cat > "$PLIST_FILE" << 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>$SCRIPT_DIR/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>
|
|
<key>EnvironmentVariables</key>
|
|
<dict>
|
|
<key>PATH</key>
|
|
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin</string>
|
|
</dict>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
|
|
log_success "已创建 LaunchAgent: $PLIST_FILE"
|
|
|
|
read -p "是否立即启动后台监控? (y/n) " -n 1 -r
|
|
echo
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
launchctl load "$PLIST_FILE" 2>/dev/null || true
|
|
log_success "后台监控已启动"
|
|
echo ""
|
|
log_info "查看日志: tail -f /tmp/image-watch.log"
|
|
else
|
|
log_info "稍后启动: launchctl load $PLIST_FILE"
|
|
fi
|
|
fi
|
|
else
|
|
log_info "跳过后台监控安装"
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_success "部署完成"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# 显示摘要
|
|
echo "📋 部署摘要:"
|
|
echo ""
|
|
echo " ✅ Layer 1: OrbStack Registry Mirror"
|
|
echo " - Harbor: $HARBOR_MIRROR"
|
|
echo " - 配置: $ORBSTACK_CONFIG"
|
|
echo " - 需重启: orb restart"
|
|
echo ""
|
|
|
|
if [[ "$KUBECTL_INSTALLED" == "false" ]]; then
|
|
echo " ✅ Layer 2: kubectl wrapper (新安装)"
|
|
echo " - 脚本: $SCRIPT_DIR/kubectl-auto-fix"
|
|
echo " - 生效: source ~/.zshrc"
|
|
echo ""
|
|
fi
|
|
|
|
if [[ -f "$HOME/Library/LaunchAgents/com.k8s.image-watcher.plist" ]]; then
|
|
echo " ✅ Layer 3: 后台监控"
|
|
echo " - 日志: /tmp/image-watch.log"
|
|
echo " - 间隔: 30秒"
|
|
echo ""
|
|
fi
|
|
|
|
echo " ✅ Layer 4: Claude Code 集成"
|
|
echo " - 配置: /Users/brunogao/work/codes/tools/macos/CLAUDE.md"
|
|
echo " - 自动: Claude 遇到 ImagePull 错误时自动执行"
|
|
echo ""
|
|
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_warning "下一步操作"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo "1️⃣ 重启 OrbStack (使 Registry Mirror 生效)"
|
|
echo " orb restart"
|
|
echo ""
|
|
echo "2️⃣ 刷新当前终端 (使 kubectl wrapper 生效)"
|
|
echo " source ~/.zshrc"
|
|
echo ""
|
|
echo "3️⃣ 测试镜像拉取 (验证 Registry Mirror)"
|
|
echo " docker pull nginx:alpine"
|
|
echo " docker pull redis:7-alpine"
|
|
echo ""
|
|
echo "4️⃣ 测试 kubectl wrapper (验证自动修复)"
|
|
echo " kubectl apply -f test-deployment.yaml"
|
|
echo ""
|
|
echo "5️⃣ 验证工作流程"
|
|
echo " kubectl get pods --all-namespaces | grep -i imagepull"
|
|
echo ""
|
|
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_info "工作原理"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo "当拉取镜像时:"
|
|
echo ""
|
|
echo " 1. Docker/K8s 请求 docker.io/nginx:alpine"
|
|
echo " 2. OrbStack 自动转发到 $HARBOR_MIRROR"
|
|
echo " 3. 如果本地 Harbor 有缓存 → 直接返回 ✅"
|
|
echo " 4. 如果本地没有 → Harbor 从上游拉取并缓存"
|
|
echo " 5. 后续请求直接使用本地缓存 🚀"
|
|
echo ""
|
|
echo "如果仍然失败:"
|
|
echo ""
|
|
echo " 6. kubectl wrapper 检测到 ImagePullBackOff"
|
|
echo " 7. 自动调用 cache-image.sh 从 EU Harbor 拉取"
|
|
echo " 8. 推送到本地 Harbor"
|
|
echo " 9. 更新 Deployment 使用本地镜像"
|
|
echo " 10. Pod 自动重启并成功拉取 ✅"
|
|
echo ""
|
|
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_info "故障排查"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo "• Registry Mirror 不工作:"
|
|
echo " docker info | grep -A 5 'Registry Mirrors'"
|
|
echo ""
|
|
echo "• kubectl wrapper 日志:"
|
|
echo " tail -f /tmp/kubectl-auto-fix.log"
|
|
echo ""
|
|
echo "• 后台监控日志:"
|
|
echo " tail -f /tmp/image-watch.log"
|
|
echo ""
|
|
echo "• 停止后台监控:"
|
|
echo " launchctl unload ~/Library/LaunchAgents/com.k8s.image-watcher.plist"
|
|
echo ""
|
|
echo "• 手动缓存镜像:"
|
|
echo " cd $SCRIPT_DIR"
|
|
echo " ./cache-image.sh nginx:alpine"
|
|
echo " ./cache-image.sh --update-deployment namespace/deployment"
|
|
echo ""
|
|
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
log_success "🎉 部署成功!现在你的系统已具备自动镜像修复能力"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# 询问是否立即重启 OrbStack
|
|
read -p "是否立即重启 OrbStack? (y/n) " -n 1 -r
|
|
echo
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
log_info "正在重启 OrbStack..."
|
|
|
|
# 退出 OrbStack 应用
|
|
osascript -e 'quit app "OrbStack"' 2>/dev/null || pkill -9 OrbStack
|
|
|
|
log_info "等待 OrbStack 完全退出..."
|
|
sleep 3
|
|
|
|
# 重新启动 OrbStack
|
|
open -a OrbStack
|
|
|
|
log_success "OrbStack 已重启"
|
|
echo ""
|
|
log_info "等待 OrbStack 启动(约 10 秒)..."
|
|
|
|
# 等待 Docker 守护进程就绪
|
|
for i in {1..20}; do
|
|
if docker info &>/dev/null; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
sleep 3
|
|
|
|
# 验证
|
|
log_info "验证 Registry Mirror 配置..."
|
|
if docker info 2>/dev/null | grep -q "Registry Mirrors"; then
|
|
log_success "Registry Mirror 配置已生效"
|
|
echo ""
|
|
docker info 2>/dev/null | grep -A 3 "Registry Mirrors"
|
|
else
|
|
log_warning "未检测到 Registry Mirror,可能需要等待更长时间"
|
|
log_info "手动检查: docker info | grep -A 3 'Registry Mirrors'"
|
|
fi
|
|
|
|
echo ""
|
|
log_info "现在可以测试镜像拉取:"
|
|
echo " docker pull nginx:alpine"
|
|
else
|
|
echo ""
|
|
log_warning "请稍后手动重启 OrbStack:"
|
|
echo ""
|
|
echo " 方式 1: 使用命令行"
|
|
echo " osascript -e 'quit app \"OrbStack\"'"
|
|
echo " sleep 3"
|
|
echo " open -a OrbStack"
|
|
echo ""
|
|
echo " 方式 2: 使用 GUI"
|
|
echo " OrbStack 菜单栏 → Quit OrbStack"
|
|
echo " 然后重新打开 OrbStack 应用"
|
|
fi
|
|
|
|
echo ""
|