#!/bin/bash # 通用Docker镜像构建+推送脚本(local cache为主 + registry cache兜底) # M-2优化:解决registry缓存导入慢(247s)和推送不稳定问题 # 用法: docker_build_push.sh [--no-cache] [build_arg...] set -eu NO_CACHE_FLAG="" if [ "$1" = "--no-cache" ]; then NO_CACHE_FLAG="--no-cache" shift echo "模式: --no-cache (不使用缓存,全新构建)" fi DOCKERFILE="$1" IMAGE_TAG="$2" CACHE_REF="$3" shift 3 BUILD_ARGS="" for arg in "$@"; do BUILD_ARGS="$BUILD_ARGS --build-arg $arg" done if ! docker buildx inspect ci-builder > /dev/null 2>&1; then docker buildx create --use --name ci-builder --driver docker-container echo "Created ci-builder" else docker buildx use ci-builder echo "Using existing ci-builder" fi docker buildx inspect --bootstrap # 从cache_ref中提取缓存名称(如 api-cache:develop -> api-cache-develop) CACHE_NAME=$(echo "$CACHE_REF" | tr '/' '_' | tr ':' '-') LOCAL_CACHE_DIR="/tmp/buildx-cache/${CACHE_NAME}" mkdir -p "$LOCAL_CACHE_DIR" # 缓存源:local优先(带自动修复),registry兜底 # 本地缓存损坏时自动清理后重试,避免snapshot not found导致构建全挂 build_with_cache_retry() { local attempt=1 local max_attempts=2 while [ $attempt -le $max_attempts ]; do local build_output local exit_code set +e build_output=$(docker buildx build \ $NO_CACHE_FLAG \ $BUILD_ARGS \ --cache-from "type=local,src=${LOCAL_CACHE_DIR}" \ --cache-from "type=registry,ref=${CACHE_REF},ignore-error=true" \ --cache-to "type=local,dest=${LOCAL_CACHE_DIR},mode=max" \ --cache-to "type=registry,ref=${CACHE_REF},mode=max,ignore-error=true" \ -f "${DOCKERFILE}" \ -t "${IMAGE_TAG}" \ --push \ . 2>&1) exit_code=$? set -e if [ $exit_code -eq 0 ]; then echo "$build_output" return 0 fi # 检测到缓存损坏类错误,清掉本地缓存重试 if echo "$build_output" | grep -qE "parent snapshot.*not found|snapshot.*does not exist|cache.*corrupt|failed to compute cache key"; then echo "$build_output" echo "" echo "⚠️ Local cache appears corrupted, cleaning up and retrying (attempt $attempt/$max_attempts)..." rm -rf "${LOCAL_CACHE_DIR}" mkdir -p "${LOCAL_CACHE_DIR}" # 清理buildx builder的内部snapshot状态 docker buildx prune -f -a >/dev/null 2>&1 || true attempt=$((attempt + 1)) else # 非缓存类错误,直接输出并返回 echo "$build_output" return $exit_code fi done # 重试完还是失败,不用本地缓存最后试一次(只从registry读) echo "⚠️ All cached attempts failed, building without local cache..." docker buildx build \ $NO_CACHE_FLAG \ $BUILD_ARGS \ --cache-from "type=registry,ref=${CACHE_REF},ignore-error=true" \ --cache-to "type=local,dest=${LOCAL_CACHE_DIR},mode=max" \ --cache-to "type=registry,ref=${CACHE_REF},mode=max,ignore-error=true" \ -f "${DOCKERFILE}" \ -t "${IMAGE_TAG}" \ --push \ . } echo "=== Step 1: Build & push image (local cache + registry read, with auto-repair) ===" echo "Local cache: ${LOCAL_CACHE_DIR}" echo "Registry cache: ${CACHE_REF}" echo "" build_with_cache_retry echo "" echo "Image pushed: ${IMAGE_TAG}" echo "Local cache updated" echo "" echo "Build completed: ${IMAGE_TAG}"