优化服务重构建速度
This commit is contained in:
227
deploy.sh
227
deploy.sh
@@ -4,15 +4,21 @@
|
||||
# 用法: ./deploy.sh [选项]
|
||||
#
|
||||
# 选项:
|
||||
# --build 强制重新构建所有镜像
|
||||
# --skip-build 跳过镜像构建 (使用已有镜像)
|
||||
# --pull 拉取最新的基础镜像
|
||||
# --clean 停止并清理所有容器和数据 (危险!)
|
||||
# --stop 停止所有服务
|
||||
# --restart 重启所有服务
|
||||
# --logs 查看所有服务日志
|
||||
# --status 查看服务运行状态
|
||||
# --help 显示帮助信息
|
||||
# --registry URL 从镜像仓库拉取 (跳过源码构建, 2分钟部署)
|
||||
# --tag TAG 指定镜像标签 (配合 --registry, 默认 latest)
|
||||
# --build 强制重新构建所有镜像
|
||||
# --skip-build 跳过镜像构建 (使用已有镜像)
|
||||
# --pull 拉取最新的基础镜像
|
||||
# --clean 停止并清理所有容器和数据 (危险!)
|
||||
# --stop 停止所有服务
|
||||
# --restart 重启所有服务
|
||||
# --logs 查看所有服务日志
|
||||
# --status 查看服务运行状态
|
||||
# --help 显示帮助信息
|
||||
#
|
||||
# 示例:
|
||||
# ./deploy.sh # 源码构建部署
|
||||
# ./deploy.sh --registry registry.cn-hangzhou.aliyuncs.com/my-ns # 镜像部署
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
@@ -22,6 +28,10 @@ cd "$SCRIPT_DIR"
|
||||
|
||||
ENV_FILE=".env"
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
COMPOSE_FILE_REGISTRY="docker-compose.registry.yml"
|
||||
USE_REGISTRY=false
|
||||
REGISTRY_URL=""
|
||||
IMAGE_TAG="${TAG:-latest}"
|
||||
|
||||
ADMIN_PORT="${ADMIN_PORT:-2443}"
|
||||
APP_PORT="${APP_PORT:-3010}"
|
||||
@@ -479,6 +489,109 @@ pull_base_images() {
|
||||
"$(format_time $(($(date +%s) - STAGE_START)))"
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Registry 模式: 拉取预构建镜像
|
||||
# ============================================
|
||||
|
||||
pull_registry_images() {
|
||||
next_stage
|
||||
stage_header "从镜像仓库拉取预构建镜像" 120
|
||||
|
||||
COMPOSE_FILE="$COMPOSE_FILE_REGISTRY"
|
||||
|
||||
echo -e " ${DIM}仓库: ${REGISTRY_URL}${NC}"
|
||||
echo -e " ${DIM}标签: ${IMAGE_TAG}${NC}"
|
||||
echo ""
|
||||
|
||||
# 并行拉取
|
||||
local pulls=()
|
||||
local images=(
|
||||
"youdu-wiki-api"
|
||||
"youdu-wiki-consumer"
|
||||
"youdu-wiki-admin"
|
||||
"youdu-wiki-app"
|
||||
)
|
||||
|
||||
for img in "${images[@]}"; do
|
||||
local full_img="${REGISTRY_URL}/${img}:${IMAGE_TAG}"
|
||||
echo -e " ${DIM}拉取 ${full_img}${NC}"
|
||||
docker pull "$full_img" &
|
||||
pulls+=($!)
|
||||
done
|
||||
|
||||
# 等待全部拉取完成
|
||||
start_spinner "并行拉取 4 个镜像 ..."
|
||||
for pid in "${pulls[@]}"; do
|
||||
wait "$pid" 2>/dev/null
|
||||
done
|
||||
stop_spinner
|
||||
|
||||
local elapsed=$(($(date +%s) - STAGE_START))
|
||||
clear_line
|
||||
printf " ${GREEN}✓${NC} 镜像拉取完成 ${DIM}(耗时 %s)${NC}\n" "$(format_time $elapsed)"
|
||||
|
||||
echo ""
|
||||
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" \
|
||||
| grep -E "youdu-wiki|REPOSITORY" \
|
||||
| while IFS= read -r line; do echo " $line"; done
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# 本地镜像文件加载
|
||||
# ============================================
|
||||
|
||||
load_local_images() {
|
||||
local dir="$1"
|
||||
local tag="${2:-latest}"
|
||||
|
||||
next_stage
|
||||
stage_header "从本地文件加载镜像" 60
|
||||
|
||||
if [ ! -d "$dir" ]; then
|
||||
log_error "目录不存在: $dir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e " ${DIM}目录: ${dir}${NC}"
|
||||
echo -e " ${DIM}标签: ${tag}${NC}"
|
||||
echo ""
|
||||
|
||||
local images=(
|
||||
"youdu-wiki-api"
|
||||
"youdu-wiki-consumer"
|
||||
"youdu-wiki-admin"
|
||||
"youdu-wiki-app"
|
||||
)
|
||||
|
||||
for img in "${images[@]}"; do
|
||||
local tar_file="${dir}/${img}-${tag}.tar"
|
||||
local gz_file="${tar_file}.gz"
|
||||
|
||||
if [ -f "$gz_file" ]; then
|
||||
echo -e " ${YELLOW}加载 (gzip):${NC} ${gz_file}"
|
||||
gunzip -c "$gz_file" | docker load
|
||||
elif [ -f "$tar_file" ]; then
|
||||
echo -e " ${YELLOW}加载:${NC} ${tar_file}"
|
||||
docker load -i "$tar_file"
|
||||
else
|
||||
log_error "未找到: ${tar_file} 或 ${gz_file}"
|
||||
echo " 请确认文件名格式: ${img}-${tag}.tar[.gz]"
|
||||
exit 1
|
||||
fi
|
||||
echo -e " ${GREEN}✓${NC} ${img} 加载完成"
|
||||
echo ""
|
||||
done
|
||||
|
||||
local elapsed=$(($(date +%s) - STAGE_START))
|
||||
clear_line
|
||||
printf " ${GREEN}✓${NC} 镜像加载完成 ${DIM}(耗时 %s)${NC}\n" "$(format_time $elapsed)"
|
||||
|
||||
echo ""
|
||||
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" \
|
||||
| grep -E "youdu-wiki|REPOSITORY" \
|
||||
| while IFS= read -r line; do echo " $line"; done
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# 7. 启动基础设施
|
||||
# ============================================
|
||||
@@ -487,25 +600,24 @@ start_infra() {
|
||||
next_stage
|
||||
stage_header "启动基础设施 (PostgreSQL, Redis, NATS, MinIO)" 60
|
||||
|
||||
# 启动基础服务
|
||||
local compose_cmd="docker compose -f $COMPOSE_FILE"
|
||||
if [ "$USE_REGISTRY" = true ]; then
|
||||
compose_cmd="REGISTRY=${REGISTRY_URL} TAG=${IMAGE_TAG} docker compose -f $COMPOSE_FILE"
|
||||
fi
|
||||
|
||||
start_spinner "启动容器 ..."
|
||||
docker compose -f "$COMPOSE_FILE" up -d postgres redis nats minio >/dev/null 2>&1
|
||||
eval "$compose_cmd up -d postgres redis nats minio" >/dev/null 2>&1
|
||||
stop_spinner
|
||||
log_info "容器已创建"
|
||||
|
||||
# 等待 PostgreSQL 就绪 (带进度条)
|
||||
echo ""
|
||||
if wait_with_progress "PostgreSQL 启动" 60 \
|
||||
"docker compose -f $COMPOSE_FILE ps postgres 2>/dev/null | grep -q healthy"; then
|
||||
log_info "PostgreSQL 就绪"
|
||||
else
|
||||
log_error "PostgreSQL 启动超时"
|
||||
echo ""
|
||||
echo " 排查: docker compose logs postgres"
|
||||
exit 1
|
||||
log_error "PostgreSQL 启动超时"; echo ""; echo " 排查: docker compose -f $COMPOSE_FILE logs postgres"; exit 1
|
||||
fi
|
||||
|
||||
# 等待 Redis 就绪
|
||||
if wait_with_progress "Redis 启动 " 30 \
|
||||
"docker compose -f $COMPOSE_FILE exec -T redis redis-cli -a ${REDIS_PASSWORD:-ChangeMe123!} ping 2>/dev/null | grep -q PONG"; then
|
||||
log_info "Redis 就绪"
|
||||
@@ -526,22 +638,22 @@ start_app() {
|
||||
next_stage
|
||||
stage_header "启动业务服务 (API, Consumer, Admin, App)" 60
|
||||
|
||||
# 启动业务容器
|
||||
local compose_cmd="docker compose -f $COMPOSE_FILE"
|
||||
if [ "$USE_REGISTRY" = true ]; then
|
||||
compose_cmd="REGISTRY=${REGISTRY_URL} TAG=${IMAGE_TAG} docker compose -f $COMPOSE_FILE"
|
||||
fi
|
||||
|
||||
start_spinner "启动容器 ..."
|
||||
docker compose -f "$COMPOSE_FILE" up -d api consumer admin app >/dev/null 2>&1
|
||||
eval "$compose_cmd up -d api consumer admin app" >/dev/null 2>&1
|
||||
stop_spinner
|
||||
log_info "容器已创建"
|
||||
|
||||
# 等待 API (数据库迁移 + 启动)
|
||||
echo ""
|
||||
if wait_with_progress "API 服务启动 (含数据库迁移)" 45 \
|
||||
"curl -sf http://localhost:${API_PORT}/api/v1/health 2>/dev/null"; then
|
||||
log_info "API 服务就绪"
|
||||
else
|
||||
log_error "API 服务启动超时"
|
||||
echo ""
|
||||
echo " 排查: docker compose logs api | tail -30"
|
||||
exit 1
|
||||
log_error "API 服务启动超时"; echo ""; echo " 排查: docker compose -f $COMPOSE_FILE logs api | tail -30"; exit 1
|
||||
fi
|
||||
|
||||
local elapsed=$(( $(date +%s) - STAGE_START ))
|
||||
@@ -659,36 +771,43 @@ clean_all() {
|
||||
main() {
|
||||
local DO_BUILD=true
|
||||
local DO_PULL=false
|
||||
local LOAD_DIR=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--build) DO_BUILD=true; shift ;;
|
||||
--skip-build) DO_BUILD=false; shift ;;
|
||||
--pull) DO_PULL=true; shift ;;
|
||||
--clean) banner; clean_all; exit 0 ;;
|
||||
--stop) banner; stop_services; exit 0 ;;
|
||||
--restart) banner; restart_services; show_info; exit 0 ;;
|
||||
--logs) show_logs; exit 0 ;;
|
||||
--status) banner; show_status; exit 0 ;;
|
||||
--load) LOAD_DIR="${2:-mirror}"; DO_BUILD=false; [ $# -gt 1 ] && [[ "$2" != --* ]] && shift; shift ;;
|
||||
--registry) USE_REGISTRY=true; REGISTRY_URL="$2"; DO_BUILD=false; COMPOSE_FILE="$COMPOSE_FILE_REGISTRY"; shift 2 ;;
|
||||
--tag) IMAGE_TAG="$2"; shift 2 ;;
|
||||
--build) DO_BUILD=true; shift ;;
|
||||
--skip-build) DO_BUILD=false; shift ;;
|
||||
--pull) DO_PULL=true; shift ;;
|
||||
--clean) banner; clean_all; exit 0 ;;
|
||||
--stop) banner; stop_services; exit 0 ;;
|
||||
--restart) banner; restart_services; show_info; exit 0 ;;
|
||||
--logs) show_logs; exit 0 ;;
|
||||
--status) banner; show_status; exit 0 ;;
|
||||
--help|-h)
|
||||
banner
|
||||
echo " 用法: $0 [选项]"
|
||||
echo ""
|
||||
echo " 选项:"
|
||||
echo " --build 强制重新构建所有镜像 (默认)"
|
||||
echo " --skip-build 跳过镜像构建步骤"
|
||||
echo " --pull 拉取最新的基础镜像"
|
||||
echo " --clean 停止并清理所有容器和数据 (危险!)"
|
||||
echo " --stop 停止所有服务"
|
||||
echo " --restart 重启所有服务"
|
||||
echo " --logs 查看所有服务日志"
|
||||
echo " --status 查看服务运行状态"
|
||||
echo " --help 显示此帮助信息"
|
||||
echo " --load [DIR] 从本地目录加载镜像 tar (默认 ./mirror, 约1分钟)"
|
||||
echo " --registry URL 从远程镜像仓库拉取 (约2分钟)"
|
||||
echo " --tag TAG 指定镜像标签 (配合 --load/--registry)"
|
||||
echo " --build 源码构建所有镜像 (首次 20-30min)"
|
||||
echo " --skip-build 跳过镜像构建/加载步骤"
|
||||
echo " --pull 拉取最新的基础镜像"
|
||||
echo " --clean 停止并清理所有容器和数据 (危险!)"
|
||||
echo " --stop 停止所有服务"
|
||||
echo " --restart 重启所有服务"
|
||||
echo " --logs 查看所有服务日志"
|
||||
echo " --status 查看服务运行状态"
|
||||
echo " --help 显示此帮助信息"
|
||||
echo ""
|
||||
echo " 示例:"
|
||||
echo " $0 # 完整部署 (构建 + 启动)"
|
||||
echo " $0 --skip-build # 跳过构建,直接启动"
|
||||
echo " $0 --restart # 重启已部署的服务"
|
||||
echo " 三种部署方式 (由快到慢):"
|
||||
echo " $0 --load ./images # 本地镜像文件 (最快)"
|
||||
echo " $0 --registry registry.cn-hangzhou.aliyuncs.com/my-ns # 远程拉取"
|
||||
echo " $0 # 源码构建 (慢)"
|
||||
exit 0
|
||||
;;
|
||||
*) log_error "未知选项: $1"; echo " 使用 --help 查看帮助"; exit 1 ;;
|
||||
@@ -709,8 +828,10 @@ main() {
|
||||
|
||||
OVERALL_START=$(date +%s)
|
||||
|
||||
# 如果跳过构建,调整总阶段数
|
||||
if [ "$DO_BUILD" = false ]; then
|
||||
# 根据模式调整阶段数
|
||||
if [ -n "$LOAD_DIR" ] || [ "$USE_REGISTRY" = true ]; then
|
||||
TOTAL_STAGES=5
|
||||
elif [ "$DO_BUILD" = false ]; then
|
||||
TOTAL_STAGES=4
|
||||
fi
|
||||
|
||||
@@ -722,18 +843,22 @@ main() {
|
||||
pull_base_images
|
||||
fi
|
||||
|
||||
if [ "$DO_BUILD" = true ]; then
|
||||
if [ -n "$LOAD_DIR" ]; then
|
||||
load_local_images "$LOAD_DIR" "$IMAGE_TAG"
|
||||
elif [ "$USE_REGISTRY" = true ]; then
|
||||
pull_registry_images
|
||||
elif [ "$DO_BUILD" = true ]; then
|
||||
build_images
|
||||
else
|
||||
next_stage
|
||||
stage_header "跳过镜像构建" 1
|
||||
stage_header "跳过镜像步骤" 1
|
||||
local missing=()
|
||||
for img in youdu-wiki-api youdu-wiki-consumer youdu-wiki-admin youdu-wiki-app; do
|
||||
docker image inspect "${img}:latest" &>/dev/null || missing+=("$img")
|
||||
docker image inspect "${img}:${IMAGE_TAG}" &>/dev/null || missing+=("$img")
|
||||
done
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
log_error "缺少镜像: ${missing[*]}"
|
||||
echo " 请先运行 ./deploy.sh (不带 --skip-build) 构建镜像"
|
||||
echo " 请先构建: ./build-push.sh --output ./images"
|
||||
exit 1
|
||||
fi
|
||||
log_info "所有镜像已存在"
|
||||
|
||||
Reference in New Issue
Block a user