优化服务重构建速度
This commit is contained in:
239
build-push.sh
Normal file
239
build-push.sh
Normal file
@@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================
|
||||
# YouduWiki 镜像构建 & 导出脚本
|
||||
# 用法:
|
||||
# ./build-push.sh # 只构建到本地 Docker
|
||||
# ./build-push.sh --output ./images # 构建并导出为 tar 文件
|
||||
# ./build-push.sh --output ./images --compress # 导出并 gzip 压缩
|
||||
# ./build-push.sh --push registry.cn-hangzhou.aliyuncs.com/my-ns # 推送到远程仓库
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
TAG="${TAG:-latest}"
|
||||
REGISTRY=""
|
||||
DO_PUSH=false
|
||||
PLATFORM="${PLATFORM:-linux/amd64}"
|
||||
OUTPUT_DIR="mirror"
|
||||
DO_COMPRESS=false
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
|
||||
|
||||
banner() {
|
||||
echo -e "${CYAN}"
|
||||
echo " ╔══════════════════════════════════════╗"
|
||||
echo " ║ YouduWiki 镜像构建 & 导出 ║"
|
||||
echo " ╚══════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo " 用法: $0 [选项]"
|
||||
echo ""
|
||||
echo " 选项:"
|
||||
echo " --compress 导出时 gzip 压缩 (约150MB, 适合网盘分享)"
|
||||
echo " --push URL 推送到远程镜像仓库"
|
||||
echo " --tag TAG 镜像标签 (默认: latest)"
|
||||
echo " --platform ARCH 目标平台 (默认: linux/amd64)"
|
||||
echo " --help 显示帮助"
|
||||
echo ""
|
||||
echo " Linux 构建命令:"
|
||||
echo " # 标准构建 (导出到 mirror/ 目录, 4个tar文件共约300MB)"
|
||||
echo " $0"
|
||||
echo ""
|
||||
echo " # 压缩构建 (导出 .tar.gz, 约150MB, 适合网盘分享)"
|
||||
echo " $0 --compress"
|
||||
echo ""
|
||||
echo " # 指定版本号"
|
||||
echo " $0 --tag v1.0.0"
|
||||
echo ""
|
||||
|
||||
echo -e " ${DIM}镜像预估大小:${NC}"
|
||||
echo -e " ${DIM} youdu-wiki-api (Go + alpine) ~40MB${NC}"
|
||||
echo -e " ${DIM} youdu-wiki-consumer (Go + alpine) ~40MB${NC}"
|
||||
echo -e " ${DIM} youdu-wiki-admin (React + nginx) ~45MB${NC}"
|
||||
echo -e " ${DIM} youdu-wiki-app (Next.js + node) ~180MB${NC}"
|
||||
echo -e " ${DIM} ─────────────────────────────────────${NC}"
|
||||
echo -e " ${DIM} 4个镜像 tar 合计 ~300MB, .tar.gz ~150MB${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 解析参数
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--output) OUTPUT_DIR="$2"; shift 2 ;;
|
||||
--compress) DO_COMPRESS=true; shift ;;
|
||||
--push) REGISTRY="$2"; DO_PUSH=true; shift 2 ;;
|
||||
--tag) TAG="$2"; shift 2 ;;
|
||||
--platform) PLATFORM="$2"; shift 2 ;;
|
||||
--help|-h) banner; usage; exit 0 ;;
|
||||
*) echo -e "${RED}未知选项: $1${NC}"; usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 构建函数
|
||||
build_one() {
|
||||
local dockerfile="$1"
|
||||
local context="$2"
|
||||
local image_name="$3"
|
||||
local label="$4"
|
||||
local full_image="${image_name}:${TAG}"
|
||||
|
||||
echo ""
|
||||
echo -e " ${BOLD}${CYAN}━━━ ${label} ━━━${NC}"
|
||||
echo -e " ${DIM}Dockerfile: ${dockerfile}${NC}"
|
||||
echo -e " ${DIM}镜像: ${full_image}${NC}"
|
||||
|
||||
local build_start; build_start=$(date +%s)
|
||||
|
||||
docker buildx build \
|
||||
--platform "${PLATFORM}" \
|
||||
--tag "${full_image}" \
|
||||
--file "${dockerfile}" \
|
||||
--progress=plain \
|
||||
"${context}"
|
||||
|
||||
local elapsed=$(($(date +%s) - build_start))
|
||||
echo -e " ${GREEN}✓${NC} ${label} 构建完成 ${DIM}(${elapsed}s)${NC}"
|
||||
}
|
||||
|
||||
# 推送到远程仓库
|
||||
push_one() {
|
||||
local image_name="$1"
|
||||
local full_image="${image_name}:${TAG}"
|
||||
|
||||
[ -z "$REGISTRY" ] && return
|
||||
|
||||
local remote_image="${REGISTRY}/${image_name}:${TAG}"
|
||||
echo -e " ${YELLOW}推送:${NC} ${full_image} → ${DIM}${remote_image}${NC}"
|
||||
docker tag "${full_image}" "${remote_image}"
|
||||
docker push "${remote_image}"
|
||||
echo -e " ${GREEN}✓${NC} 推送完成"
|
||||
}
|
||||
|
||||
# 导出为 tar 文件
|
||||
export_one() {
|
||||
local image_name="$1"
|
||||
local full_image="${image_name}:${TAG}"
|
||||
local tar_file="${OUTPUT_DIR}/${image_name}-${TAG}.tar"
|
||||
|
||||
echo -e " ${YELLOW}导出:${NC} ${full_image} → ${DIM}${tar_file}${NC}"
|
||||
docker save -o "${tar_file}" "${full_image}"
|
||||
|
||||
local size; size=$(du -h "${tar_file}" | cut -f1)
|
||||
echo -e " ${GREEN}✓${NC} 已导出 (${size})"
|
||||
|
||||
if [ "$DO_COMPRESS" = true ]; then
|
||||
echo -e " ${YELLOW}压缩:${NC} ${tar_file}.gz"
|
||||
gzip -f "${tar_file}"
|
||||
local csize; csize=$(du -h "${tar_file}.gz" | cut -f1)
|
||||
echo -e " ${GREEN}✓${NC} 已压缩 (${csize})"
|
||||
fi
|
||||
}
|
||||
|
||||
# 前置检查
|
||||
check_prerequisites() {
|
||||
echo -e " ${DIM}确认构建环境...${NC}"
|
||||
|
||||
if ! command -v docker &>/dev/null; then
|
||||
echo -e "${RED}未找到 Docker${NC}"; exit 1
|
||||
fi
|
||||
|
||||
docker buildx version &>/dev/null || {
|
||||
echo -e "${RED}需要 Docker Buildx (Docker 19.03+)${NC}"; exit 1
|
||||
}
|
||||
|
||||
if [ -n "$OUTPUT_DIR" ]; then
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
echo -e " ${DIM}输出目录: ${OUTPUT_DIR}${NC}"
|
||||
fi
|
||||
|
||||
if [ "$DO_PUSH" = true ]; then
|
||||
local reg_host; reg_host=$(echo "$REGISTRY" | cut -d'/' -f1)
|
||||
echo -e " ${YELLOW}确保已执行 docker login ${reg_host}${NC}"
|
||||
read -rp " 已登录? [Y/n]: " confirm
|
||||
[ "$confirm" = "n" ] || [ "$confirm" = "N" ] && { echo -e "${RED}请先登录${NC}"; exit 1; }
|
||||
fi
|
||||
}
|
||||
|
||||
# 主流程
|
||||
main() {
|
||||
banner
|
||||
|
||||
echo -e " ${BOLD}构建配置:${NC}"
|
||||
echo -e " 标签: ${GREEN}${TAG}${NC}"
|
||||
echo -e " 平台: ${GREEN}${PLATFORM}${NC}"
|
||||
if [ -n "$OUTPUT_DIR" ]; then
|
||||
echo -e " 导出目录: ${GREEN}${OUTPUT_DIR}${NC}"
|
||||
[ "$DO_COMPRESS" = true ] && echo -e " 压缩: ${GREEN}gzip${NC}"
|
||||
fi
|
||||
[ "$DO_PUSH" = true ] && echo -e " 推送目标: ${GREEN}${REGISTRY}${NC}"
|
||||
|
||||
check_prerequisites
|
||||
|
||||
local total_start; total_start=$(date +%s)
|
||||
local IMAGES=(
|
||||
"backend/Dockerfile.api|./backend|youdu-wiki-api|1/4 后端 API 镜像 (Go 编译)"
|
||||
"backend/Dockerfile.consumer|./backend|youdu-wiki-consumer|2/4 后端 Consumer 镜像"
|
||||
"web/Dockerfile.admin|./web|youdu-wiki-admin|3/4 管理后台镜像 (React)"
|
||||
"web/Dockerfile.app|./web|youdu-wiki-app|4/4 Wiki 前端镜像 (Next.js)"
|
||||
)
|
||||
|
||||
for entry in "${IMAGES[@]}"; do
|
||||
IFS='|' read -r dockerfile context image_name label <<< "$entry"
|
||||
build_one "$dockerfile" "$context" "$image_name" "$label"
|
||||
[ "$DO_PUSH" = true ] && push_one "$image_name"
|
||||
[ -n "$OUTPUT_DIR" ] && export_one "$image_name"
|
||||
done
|
||||
|
||||
local total_elapsed=$(($(date +%s) - total_start))
|
||||
|
||||
echo ""
|
||||
echo -e " ${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo -e " ${GREEN}${BOLD} ✓ 全部完成${NC} ${DIM}总耗时: $((total_elapsed / 60))m$((total_elapsed % 60))s${NC}"
|
||||
echo -e " ${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo ""
|
||||
|
||||
echo " 本地镜像:"
|
||||
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" \
|
||||
| grep -E "youdu-wiki|REPOSITORY" \
|
||||
| while IFS= read -r line; do echo " $line"; done
|
||||
|
||||
if [ -n "$OUTPUT_DIR" ]; then
|
||||
echo ""
|
||||
echo -e " ${GREEN}导出文件:${NC}"
|
||||
|
||||
local ext="tar"
|
||||
[ "$DO_COMPRESS" = true ] && ext="tar.gz"
|
||||
|
||||
# 生成部署端使用说明
|
||||
cat > "${OUTPUT_DIR}/LOAD_README.txt" << READEOF
|
||||
YouduWiki Docker 镜像 - ${TAG}
|
||||
构建时间: $(date '+%Y-%m-%d %H:%M:%S')
|
||||
平台: ${PLATFORM}
|
||||
|
||||
部署端加载命令:
|
||||
cd 此目录
|
||||
docker load -i youdu-wiki-api-${TAG}.${ext}
|
||||
docker load -i youdu-wiki-consumer-${TAG}.${ext}
|
||||
docker load -i youdu-wiki-admin-${TAG}.${ext}
|
||||
docker load -i youdu-wiki-app-${TAG}.${ext}
|
||||
|
||||
或使用一键部署脚本:
|
||||
./deploy.sh --load ./mirror
|
||||
READEOF
|
||||
|
||||
echo ""
|
||||
ls -lh "${OUTPUT_DIR}/" | grep -E "youdu-wiki|LOAD" | while IFS= read -r line; do echo " $line"; done
|
||||
echo ""
|
||||
echo -e " ${YELLOW}将 ${OUTPUT_DIR}/ 整个目录复制到部署服务器,然后:${NC}"
|
||||
echo -e " ${BOLD} ./deploy.sh --load ./mirror${NC}"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user