ci: Docker镜像缓存按分支隔离 - develop写回缓存, feature分支只读
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m1s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Successful in 1m28s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m1s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Successful in 1m28s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
- 核心改动:按 GITHUB_REF_NAME 判断分支,develop/main 读写缓存,feature 分支只读不写 - 防止feature分支修改requirements等依赖文件时污染主缓存,导致develop构建偶发50min+ - 新增 npm 缓存 volume,web构建 node_modules 持久化,减少 npm ci 下载时间 - 缓存 tag 从 release 改为 develop,语义更清晰 - 重构 build_with_cache 函数,消除三份重复的 buildx 命令
This commit is contained in:
@@ -3,11 +3,20 @@ set -eu
|
||||
|
||||
VERSION="${1:-${RELEASE_VERSION:-}}"
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Usage: $0 <version>"
|
||||
echo "Example: $0 v0.1.5"
|
||||
echo "Usage: $0 <version> [staging|production]"
|
||||
echo "Example: $0 v0.1.5 production"
|
||||
echo " $0 abc1234 staging"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 环境参数:staging 或 production(默认 production)
|
||||
BUILD_ENV="${2:-production}"
|
||||
case "$BUILD_ENV" in
|
||||
staging) NGINX_CONF_FILE="infra/docker/nginx-staging.conf" ;;
|
||||
*) NGINX_CONF_FILE="infra/docker/nginx-production.conf" ;;
|
||||
esac
|
||||
echo "Build environment: $BUILD_ENV → nginx config: $NGINX_CONF_FILE"
|
||||
|
||||
ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
@@ -21,7 +30,8 @@ fi
|
||||
# ---- Registry 配置 ----
|
||||
REGISTRY="${REGISTRY:-git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas}"
|
||||
CACHE_REGISTRY="${CACHE_REGISTRY:-git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas}"
|
||||
CACHE_TAG="${CACHE_TAG:-release}"
|
||||
# 主缓存 tag:develop 分支构建时写入,所有分支读取
|
||||
CACHE_TAG_PRIMARY="${CACHE_TAG:-develop}"
|
||||
|
||||
API_IMAGE="xiaoxia-saas-api:$VERSION"
|
||||
WORKER_IMAGE="xiaoxia-saas-worker:$VERSION"
|
||||
@@ -36,6 +46,7 @@ REGISTRY_WEB="${REGISTRY}/xiaoxia-saas-web:$VERSION"
|
||||
|
||||
USE_CACHE=0
|
||||
USE_PUSH=0
|
||||
CACHE_WRITE=0
|
||||
|
||||
# 检查 buildx 和 Registry 认证
|
||||
if docker buildx version >/dev/null 2>&1; then
|
||||
@@ -45,58 +56,93 @@ if docker buildx version >/dev/null 2>&1; then
|
||||
docker buildx use default 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "=== Building API image ==="
|
||||
# ---- 缓存读写策略(按分支隔离)----
|
||||
# 默认只读不写,防止 feature 分支污染主缓存
|
||||
# 只有 develop/main 分支才写回缓存
|
||||
BRANCH_NAME="${GITHUB_REF_NAME:-${CI_COMMIT_BRANCH:-unknown}}"
|
||||
if [ "$USE_CACHE" -eq 1 ]; then
|
||||
docker buildx build \
|
||||
--cache-from "type=registry,ref=${CACHE_REGISTRY}/api-cache:${CACHE_TAG},ignore-error=true" \
|
||||
--cache-to "type=registry,ref=${CACHE_REGISTRY}/api-cache:${CACHE_TAG},mode=max" \
|
||||
-f infra/docker/api.Dockerfile \
|
||||
-t "$API_IMAGE" -t "$API_LATEST" \
|
||||
--load \
|
||||
.
|
||||
else
|
||||
docker build --pull=false -f infra/docker/api.Dockerfile -t "$API_IMAGE" -t "$API_LATEST" .
|
||||
case "$BRANCH_NAME" in
|
||||
develop|main)
|
||||
CACHE_WRITE=1
|
||||
echo "Cache strategy: READ+WRITE (branch=$BRANCH_NAME, cache_tag=$CACHE_TAG_PRIMARY)"
|
||||
;;
|
||||
*)
|
||||
CACHE_WRITE=0
|
||||
echo "Cache strategy: READ-ONLY (branch=$BRANCH_NAME, cache_tag=$CACHE_TAG_PRIMARY)"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
build_with_cache() {
|
||||
# usage: build_with_cache <image_name> <dockerfile> <extra_args...>
|
||||
IMG_NAME="$1"
|
||||
DOCKERFILE="$2"
|
||||
shift 2
|
||||
EXTRA_ARGS="$*"
|
||||
|
||||
CACHE_FROM="type=registry,ref=${CACHE_REGISTRY}/${IMG_NAME}-cache:${CACHE_TAG_PRIMARY},ignore-error=true"
|
||||
|
||||
if [ "$CACHE_WRITE" -eq 1 ]; then
|
||||
CACHE_TO="type=registry,ref=${CACHE_REGISTRY}/${IMG_NAME}-cache:${CACHE_TAG_PRIMARY},mode=max"
|
||||
echo " cache: read+write from ${CACHE_REGISTRY}/${IMG_NAME}-cache:${CACHE_TAG_PRIMARY}"
|
||||
else
|
||||
CACHE_TO=""
|
||||
echo " cache: read-only from ${CACHE_REGISTRY}/${IMG_NAME}-cache:${CACHE_TAG_PRIMARY}"
|
||||
fi
|
||||
|
||||
if [ "$USE_CACHE" -eq 1 ]; then
|
||||
if [ -n "$CACHE_TO" ]; then
|
||||
docker buildx build \
|
||||
$EXTRA_ARGS \
|
||||
--cache-from "$CACHE_FROM" \
|
||||
--cache-to "$CACHE_TO" \
|
||||
-f "$DOCKERFILE" \
|
||||
-t "$IMG_NAME:$VERSION" \
|
||||
--load \
|
||||
.
|
||||
else
|
||||
docker buildx build \
|
||||
$EXTRA_ARGS \
|
||||
--cache-from "$CACHE_FROM" \
|
||||
-f "$DOCKERFILE" \
|
||||
-t "$IMG_NAME:$VERSION" \
|
||||
--load \
|
||||
.
|
||||
fi
|
||||
else
|
||||
docker build --pull=false $EXTRA_ARGS -f "$DOCKERFILE" -t "$IMG_NAME:$VERSION" .
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== Building API image ==="
|
||||
build_with_cache "api" "infra/docker/api.Dockerfile" \
|
||||
"--build-arg APP_VERSION=$VERSION"
|
||||
docker tag "$API_IMAGE" "$API_LATEST"
|
||||
|
||||
echo "=== Building Worker image ==="
|
||||
if [ "$USE_CACHE" -eq 1 ]; then
|
||||
docker buildx build \
|
||||
--cache-from "type=registry,ref=${CACHE_REGISTRY}/worker-cache:${CACHE_TAG},ignore-error=true" \
|
||||
--cache-to "type=registry,ref=${CACHE_REGISTRY}/worker-cache:${CACHE_TAG},mode=max" \
|
||||
-f infra/docker/worker.Dockerfile \
|
||||
-t "$WORKER_IMAGE" -t "$WORKER_LATEST" \
|
||||
--load \
|
||||
.
|
||||
else
|
||||
docker build --pull=false -f infra/docker/worker.Dockerfile -t "$WORKER_IMAGE" -t "$WORKER_LATEST" .
|
||||
fi
|
||||
build_with_cache "worker" "infra/docker/worker.Dockerfile" \
|
||||
"--build-arg APP_VERSION=$VERSION"
|
||||
docker tag "$WORKER_IMAGE" "$WORKER_LATEST"
|
||||
|
||||
echo "=== Building Web image (with buildx cache) ==="
|
||||
# 先构建前端产物
|
||||
# 先构建前端产物(使用持久化 npm 缓存卷)
|
||||
NPM_CACHE_VOLUME="xiaoxia-npm-cache"
|
||||
if ! docker volume inspect "$NPM_CACHE_VOLUME" >/dev/null 2>&1; then
|
||||
docker volume create "$NPM_CACHE_VOLUME" >/dev/null
|
||||
echo " Created npm cache volume: $NPM_CACHE_VOLUME"
|
||||
fi
|
||||
|
||||
docker run --rm \
|
||||
-v "$PWD:/workspace" \
|
||||
-v "$NPM_CACHE_VOLUME:/workspace/apps/web/node_modules" \
|
||||
-w /workspace/apps/web \
|
||||
docker.m.daocloud.io/library/node:20 \
|
||||
sh -lc "npm ci && npm run build"
|
||||
|
||||
test -f apps/web/dist/index.html
|
||||
|
||||
if [ "$USE_CACHE" -eq 1 ]; then
|
||||
docker buildx build \
|
||||
--cache-from "type=registry,ref=${CACHE_REGISTRY}/web-cache:${CACHE_TAG},ignore-error=true" \
|
||||
--cache-to "type=registry,ref=${CACHE_REGISTRY}/web-cache:${CACHE_TAG},mode=max" \
|
||||
-f infra/docker/web-artifact.Dockerfile \
|
||||
--build-arg NGINX_CONF=infra/docker/nginx-production.conf \
|
||||
-t "$WEB_IMAGE" \
|
||||
--load \
|
||||
.
|
||||
else
|
||||
docker build --pull=false \
|
||||
-f infra/docker/web-artifact.Dockerfile \
|
||||
--build-arg NGINX_CONF=infra/docker/nginx-production.conf \
|
||||
-t "$WEB_IMAGE" \
|
||||
.
|
||||
fi
|
||||
build_with_cache "web" "infra/docker/web-artifact.Dockerfile" \
|
||||
"--build-arg NGINX_CONF=$NGINX_CONF_FILE"
|
||||
|
||||
# Push 到 Registry
|
||||
if [ "$USE_PUSH" -eq 1 ]; then
|
||||
|
||||
Reference in New Issue
Block a user