mirror of
https://github.com/JetSprow/J-Board-Lite.git
synced 2026-05-01 01:14:10 +05:30
feat: adapt panel docker build for low resource hosts
This commit is contained in:
@@ -3,17 +3,20 @@ FROM node:20-alpine AS base
|
|||||||
# --- deps: install production + dev dependencies ---
|
# --- deps: install production + dev dependencies ---
|
||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
ARG NPM_CONFIG_JOBS=""
|
||||||
|
ENV npm_config_jobs=${NPM_CONFIG_JOBS}
|
||||||
RUN apk add --no-cache python3 make g++
|
RUN apk add --no-cache python3 make g++
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
RUN npm ci
|
RUN npm ci --no-audit --no-fund
|
||||||
|
|
||||||
# --- builder: generate Prisma client & build Next.js ---
|
# --- builder: generate Prisma client & build Next.js ---
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY . .
|
COPY . .
|
||||||
|
ARG NEXT_BUILD_NODE_OPTIONS=""
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
ENV NODE_OPTIONS=--max-old-space-size=2048
|
ENV NODE_OPTIONS=${NEXT_BUILD_NODE_OPTIONS}
|
||||||
RUN npx prisma generate
|
RUN npx prisma generate
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -128,9 +128,11 @@ SMTP 邮件服务、注册邮箱验证开关、支付方式、3x-ui 节点等业
|
|||||||
适合全新 Linux 服务器。脚本会安装基础依赖、安装 Docker 与 Compose 插件、拉取代码、生成 `.env`、初始化数据库并启动面板。
|
适合全新 Linux 服务器。脚本会安装基础依赖、安装 Docker 与 Compose 插件、拉取代码、生成 `.env`、初始化数据库并启动面板。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash <(curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/install-jboard-panel.sh)
|
bash <(curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/lite/scripts/install-jboard-panel.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
安装和更新脚本会自动检测 CPU、宿主机内存、Docker 可用内存和 Docker 数据盘空间。常规机器使用 Docker 默认构建策略;1C、低于 2GB 内存或 Docker 可用空间低于 8GB 的小机器会自动进入低资源模式,降低 Compose 并发、npm 编译并发和 Next 构建堆内存,并把镜像分步构建,构建会更慢但峰值占用更低。
|
||||||
|
|
||||||
脚本会交互询问:
|
脚本会交互询问:
|
||||||
|
|
||||||
| 问题 | 如何填写 |
|
| 问题 | 如何填写 |
|
||||||
@@ -146,7 +148,20 @@ bash <(curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/script
|
|||||||
也可以通过环境变量覆盖默认行为:
|
也可以通过环境变量覆盖默认行为:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
APP_DIR=/opt/jboard GH_REPO=JetSprow/J-Board BRANCH=main bash <(curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/install-jboard-panel.sh)
|
APP_DIR=/opt/jboard GH_REPO=JetSprow/J-Board BRANCH=lite bash <(curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/lite/scripts/install-jboard-panel.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
构建资源策略也可以手动覆盖:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 自动判断,默认值
|
||||||
|
JBOARD_BUILD_PROFILE=auto ./scripts/upgrade-jboard-panel.sh
|
||||||
|
|
||||||
|
# 强制低资源慢速构建
|
||||||
|
JBOARD_BUILD_PROFILE=low ./scripts/upgrade-jboard-panel.sh
|
||||||
|
|
||||||
|
# 强制常规构建,不额外限制并发或 Node heap
|
||||||
|
JBOARD_BUILD_PROFILE=normal ./scripts/upgrade-jboard-panel.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
脚本完成后会输出:
|
脚本完成后会输出:
|
||||||
@@ -188,6 +203,8 @@ docker compose up -d app
|
|||||||
./scripts/upgrade-jboard-panel.sh
|
./scripts/upgrade-jboard-panel.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
更新脚本同样会自动判断机器配置,并在更新前备份 SQLite 数据库到 `backups/`。
|
||||||
|
|
||||||
常用排障:
|
常用排障:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -384,17 +401,17 @@ Cloudflare 场景建议在 Rules -> Settings -> Managed Transforms 开启 Add vi
|
|||||||
|
|
||||||
## 备份与恢复
|
## 备份与恢复
|
||||||
|
|
||||||
下载 SQL 备份:
|
下载 SQLite 备份:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose exec -T db pg_dump -U jboard jboard > backup_$(date +%Y%m%d_%H%M%S).sql
|
docker compose exec -T app sh -lc 'cd /app/storage && set -- jboard.db; [ -f jboard.db-wal ] && set -- "$@" jboard.db-wal; [ -f jboard.db-shm ] && set -- "$@" jboard.db-shm; tar -czf - "$@"' > backup_$(date +%Y%m%d_%H%M%S).tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
后台也可通过 `/admin/backups` 导出或恢复数据库。恢复前务必先保存当前数据库备份。
|
后台也可通过 `/admin/backups` 导出或恢复数据库。恢复前务必先保存当前数据库备份。
|
||||||
|
|
||||||
建议:
|
建议:
|
||||||
|
|
||||||
- 定期备份 PostgreSQL volume。
|
- 定期备份 SQLite volume 或通过后台导出数据库。
|
||||||
- 将备份加密保存。
|
- 将备份加密保存。
|
||||||
- 备份恢复后立即检查管理员登录、支付配置、节点密码、SMTP、订阅 URL 和 Agent 上报。
|
- 备份恢复后立即检查管理员登录、支付配置、节点密码、SMTP、订阅 URL 和 Agent 上报。
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
GH_REPO="${GH_REPO:-JetSprow/J-Board}"
|
GH_REPO="${GH_REPO:-JetSprow/J-Board}"
|
||||||
BRANCH="${BRANCH:-main}"
|
BRANCH="${BRANCH:-lite}"
|
||||||
APP_DIR="${APP_DIR:-}"
|
APP_DIR="${APP_DIR:-}"
|
||||||
REWRITE_ENV="${REWRITE_ENV:-}"
|
REWRITE_ENV="${REWRITE_ENV:-}"
|
||||||
SKIP_DOCKER_INSTALL="${SKIP_DOCKER_INSTALL:-0}"
|
SKIP_DOCKER_INSTALL="${SKIP_DOCKER_INSTALL:-0}"
|
||||||
@@ -228,6 +228,16 @@ git_in_repo() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
load_resource_helpers() {
|
||||||
|
local helper="$APP_DIR/scripts/lib-resource-profile.sh"
|
||||||
|
if [ -f "$helper" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$helper"
|
||||||
|
else
|
||||||
|
echo "未找到资源检测脚本:$helper,将使用 Docker 默认构建策略。"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
prepare_repo() {
|
prepare_repo() {
|
||||||
section "准备 J-Board 代码"
|
section "准备 J-Board 代码"
|
||||||
|
|
||||||
@@ -345,12 +355,37 @@ configure_env() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
docker_compose() {
|
docker_compose() {
|
||||||
run_as_root docker compose "$@"
|
local env_args=()
|
||||||
|
if [ -n "${COMPOSE_PARALLEL_LIMIT:-}" ]; then
|
||||||
|
env_args+=("COMPOSE_PARALLEL_LIMIT=$COMPOSE_PARALLEL_LIMIT")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
env "${env_args[@]}" docker compose "$@"
|
||||||
|
elif command -v sudo >/dev/null 2>&1; then
|
||||||
|
sudo env "${env_args[@]}" docker compose "$@"
|
||||||
|
else
|
||||||
|
echo "需要 root 权限。请使用 root 用户运行,或先安装 sudo。" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
start_panel() {
|
start_panel() {
|
||||||
section "构建并启动面板"
|
section "构建并启动面板"
|
||||||
|
|
||||||
|
if command -v jboard_prepare_docker_build_env >/dev/null 2>&1; then
|
||||||
|
jboard_prepare_docker_build_env
|
||||||
|
jboard_print_build_profile
|
||||||
|
if jboard_is_low_resource_build; then
|
||||||
|
docker_compose build "${JBOARD_DOCKER_BUILD_ARGS[@]}" init
|
||||||
|
docker_compose build "${JBOARD_DOCKER_BUILD_ARGS[@]}" app
|
||||||
|
else
|
||||||
|
docker_compose build "${JBOARD_DOCKER_BUILD_ARGS[@]}" init app
|
||||||
|
fi
|
||||||
|
else
|
||||||
docker_compose build init app
|
docker_compose build init app
|
||||||
|
fi
|
||||||
|
|
||||||
docker_compose --profile setup run --rm init
|
docker_compose --profile setup run --rm init
|
||||||
docker_compose up -d app
|
docker_compose up -d app
|
||||||
}
|
}
|
||||||
@@ -425,6 +460,7 @@ main() {
|
|||||||
|
|
||||||
install_base_packages
|
install_base_packages
|
||||||
prepare_repo
|
prepare_repo
|
||||||
|
load_resource_helpers
|
||||||
configure_env
|
configure_env
|
||||||
install_docker
|
install_docker
|
||||||
start_panel
|
start_panel
|
||||||
|
|||||||
238
scripts/lib-resource-profile.sh
Normal file
238
scripts/lib-resource-profile.sh
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Shared build profile detection for panel install/upgrade scripts.
|
||||||
|
# Strong machines use Docker's default behavior. Small machines trade time for
|
||||||
|
# lower peak CPU and memory usage.
|
||||||
|
|
||||||
|
JBOARD_BUILD_PROFILE_RESOLVED=""
|
||||||
|
JBOARD_CPU_COUNT=""
|
||||||
|
JBOARD_HOST_MEM_MB=""
|
||||||
|
JBOARD_DOCKER_MEM_MB=""
|
||||||
|
JBOARD_DOCKER_DISK_AVAIL_MB=""
|
||||||
|
JBOARD_EFFECTIVE_MEM_MB=""
|
||||||
|
JBOARD_NODE_HEAP_MB=""
|
||||||
|
JBOARD_DOCKER_BUILD_ARGS=()
|
||||||
|
|
||||||
|
jboard_cpu_count() {
|
||||||
|
local value=""
|
||||||
|
|
||||||
|
if command -v nproc >/dev/null 2>&1; then
|
||||||
|
value="$(nproc 2>/dev/null || true)"
|
||||||
|
elif command -v getconf >/dev/null 2>&1; then
|
||||||
|
value="$(getconf _NPROCESSORS_ONLN 2>/dev/null || true)"
|
||||||
|
elif command -v sysctl >/dev/null 2>&1; then
|
||||||
|
value="$(sysctl -n hw.ncpu 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$value" in
|
||||||
|
''|*[!0-9]*) echo 1 ;;
|
||||||
|
*) echo "$value" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_host_mem_mb() {
|
||||||
|
local value=""
|
||||||
|
|
||||||
|
if [ -r /proc/meminfo ]; then
|
||||||
|
value="$(awk '/^MemTotal:/ {print int($2 / 1024)}' /proc/meminfo 2>/dev/null || true)"
|
||||||
|
elif command -v getconf >/dev/null 2>&1; then
|
||||||
|
local pages page_size
|
||||||
|
pages="$(getconf _PHYS_PAGES 2>/dev/null || true)"
|
||||||
|
page_size="$(getconf PAGE_SIZE 2>/dev/null || true)"
|
||||||
|
if [ -n "$pages" ] && [ -n "$page_size" ]; then
|
||||||
|
value="$((pages * page_size / 1024 / 1024))"
|
||||||
|
fi
|
||||||
|
elif command -v sysctl >/dev/null 2>&1; then
|
||||||
|
local bytes
|
||||||
|
bytes="$(sysctl -n hw.memsize 2>/dev/null || true)"
|
||||||
|
if [ -n "$bytes" ]; then
|
||||||
|
value="$((bytes / 1024 / 1024))"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$value" in
|
||||||
|
''|*[!0-9]*) echo 0 ;;
|
||||||
|
*) echo "$value" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_docker_info() {
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v run_as_root >/dev/null 2>&1; then
|
||||||
|
run_as_root docker info "$@" 2>/dev/null
|
||||||
|
else
|
||||||
|
docker info "$@" 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_docker_mem_mb() {
|
||||||
|
local bytes=""
|
||||||
|
bytes="$(jboard_docker_info --format '{{.MemTotal}}' 2>/dev/null || true)"
|
||||||
|
|
||||||
|
case "$bytes" in
|
||||||
|
''|*[!0-9]*) echo 0 ;;
|
||||||
|
*) echo "$((bytes / 1024 / 1024))" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_path_avail_mb() {
|
||||||
|
local path="$1"
|
||||||
|
local value=""
|
||||||
|
|
||||||
|
if [ -n "$path" ]; then
|
||||||
|
if command -v run_as_root >/dev/null 2>&1; then
|
||||||
|
value="$(run_as_root df -Pm "$path" 2>/dev/null | awk 'NR == 2 {print $4}' || true)"
|
||||||
|
else
|
||||||
|
value="$(df -Pm "$path" 2>/dev/null | awk 'NR == 2 {print $4}' || true)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$value" in
|
||||||
|
''|*[!0-9]*) echo 0 ;;
|
||||||
|
*) echo "$value" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_docker_disk_avail_mb() {
|
||||||
|
local root_dir=""
|
||||||
|
root_dir="$(jboard_docker_info --format '{{.DockerRootDir}}' 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [ -n "$root_dir" ]; then
|
||||||
|
jboard_path_avail_mb "$root_dir"
|
||||||
|
else
|
||||||
|
echo 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_effective_mem_mb() {
|
||||||
|
local host="$1"
|
||||||
|
local docker_mem="$2"
|
||||||
|
|
||||||
|
if [ "$docker_mem" -gt 0 ] && [ "$host" -gt 0 ]; then
|
||||||
|
if [ "$docker_mem" -lt "$host" ]; then
|
||||||
|
echo "$docker_mem"
|
||||||
|
else
|
||||||
|
echo "$host"
|
||||||
|
fi
|
||||||
|
elif [ "$docker_mem" -gt 0 ]; then
|
||||||
|
echo "$docker_mem"
|
||||||
|
else
|
||||||
|
echo "$host"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_low_resource_heap_mb() {
|
||||||
|
local mem_mb="$1"
|
||||||
|
|
||||||
|
if [ -n "${JBOARD_LOW_RESOURCE_NODE_MB:-}" ]; then
|
||||||
|
echo "$JBOARD_LOW_RESOURCE_NODE_MB"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$mem_mb" -gt 0 ] && [ "$mem_mb" -le 1200 ]; then
|
||||||
|
echo 640
|
||||||
|
elif [ "$mem_mb" -gt 0 ] && [ "$mem_mb" -le 1700 ]; then
|
||||||
|
echo 768
|
||||||
|
elif [ "$mem_mb" -gt 0 ] && [ "$mem_mb" -le 2400 ]; then
|
||||||
|
echo 1024
|
||||||
|
else
|
||||||
|
echo 1536
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_resolve_build_profile() {
|
||||||
|
local requested="${JBOARD_BUILD_PROFILE:-auto}"
|
||||||
|
local cpu="$1"
|
||||||
|
local mem_mb="$2"
|
||||||
|
local docker_disk_mb="$3"
|
||||||
|
|
||||||
|
case "$requested" in
|
||||||
|
low|slow|small)
|
||||||
|
echo low
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
normal|fast|strong)
|
||||||
|
echo normal
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
auto|'')
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "未知 JBOARD_BUILD_PROFILE=$requested,回退为 auto。" >&2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$cpu" -le 1 ]; then
|
||||||
|
echo low
|
||||||
|
elif [ "$mem_mb" -gt 0 ] && [ "$mem_mb" -lt 2048 ]; then
|
||||||
|
echo low
|
||||||
|
elif [ "$docker_disk_mb" -gt 0 ] && [ "$docker_disk_mb" -lt 8192 ]; then
|
||||||
|
echo low
|
||||||
|
else
|
||||||
|
echo normal
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_prepare_docker_build_env() {
|
||||||
|
JBOARD_CPU_COUNT="$(jboard_cpu_count)"
|
||||||
|
JBOARD_HOST_MEM_MB="$(jboard_host_mem_mb)"
|
||||||
|
JBOARD_DOCKER_MEM_MB="$(jboard_docker_mem_mb)"
|
||||||
|
JBOARD_DOCKER_DISK_AVAIL_MB="$(jboard_docker_disk_avail_mb)"
|
||||||
|
JBOARD_EFFECTIVE_MEM_MB="$(jboard_effective_mem_mb "$JBOARD_HOST_MEM_MB" "$JBOARD_DOCKER_MEM_MB")"
|
||||||
|
JBOARD_BUILD_PROFILE_RESOLVED="$(jboard_resolve_build_profile "$JBOARD_CPU_COUNT" "$JBOARD_EFFECTIVE_MEM_MB" "$JBOARD_DOCKER_DISK_AVAIL_MB")"
|
||||||
|
JBOARD_DOCKER_BUILD_ARGS=()
|
||||||
|
|
||||||
|
export NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
|
if [ "$JBOARD_BUILD_PROFILE_RESOLVED" = "low" ]; then
|
||||||
|
JBOARD_NODE_HEAP_MB="$(jboard_low_resource_heap_mb "$JBOARD_EFFECTIVE_MEM_MB")"
|
||||||
|
export COMPOSE_PARALLEL_LIMIT="${COMPOSE_PARALLEL_LIMIT:-1}"
|
||||||
|
export NPM_CONFIG_JOBS="${NPM_CONFIG_JOBS:-1}"
|
||||||
|
export npm_config_jobs="${npm_config_jobs:-$NPM_CONFIG_JOBS}"
|
||||||
|
export NEXT_BUILD_NODE_OPTIONS="${NEXT_BUILD_NODE_OPTIONS:---max-old-space-size=${JBOARD_NODE_HEAP_MB}}"
|
||||||
|
else
|
||||||
|
JBOARD_NODE_HEAP_MB=""
|
||||||
|
export NEXT_BUILD_NODE_OPTIONS="${NEXT_BUILD_NODE_OPTIONS:-}"
|
||||||
|
export NPM_CONFIG_JOBS="${NPM_CONFIG_JOBS:-}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${NEXT_BUILD_NODE_OPTIONS:-}" ]; then
|
||||||
|
JBOARD_DOCKER_BUILD_ARGS+=(--build-arg "NEXT_BUILD_NODE_OPTIONS=${NEXT_BUILD_NODE_OPTIONS}")
|
||||||
|
fi
|
||||||
|
if [ -n "${NPM_CONFIG_JOBS:-}" ]; then
|
||||||
|
JBOARD_DOCKER_BUILD_ARGS+=(--build-arg "NPM_CONFIG_JOBS=${NPM_CONFIG_JOBS}")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_is_low_resource_build() {
|
||||||
|
[ "${JBOARD_BUILD_PROFILE_RESOLVED:-}" = "low" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
jboard_print_build_profile() {
|
||||||
|
local docker_mem="${JBOARD_DOCKER_MEM_MB:-0}"
|
||||||
|
local docker_disk="${JBOARD_DOCKER_DISK_AVAIL_MB:-0}"
|
||||||
|
local docker_text="unknown"
|
||||||
|
local disk_text="unknown"
|
||||||
|
|
||||||
|
if [ "$docker_mem" -gt 0 ]; then
|
||||||
|
docker_text="${docker_mem}MB"
|
||||||
|
fi
|
||||||
|
if [ "$docker_disk" -gt 0 ]; then
|
||||||
|
disk_text="${docker_disk}MB"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if jboard_is_low_resource_build; then
|
||||||
|
echo "检测到低资源构建环境:CPU=${JBOARD_CPU_COUNT:-?},内存=${JBOARD_EFFECTIVE_MEM_MB:-0}MB,Docker内存=${docker_text},Docker可用空间=${disk_text}"
|
||||||
|
echo "启用慢速低占用模式:Compose 并发=1,npm jobs=${NPM_CONFIG_JOBS:-1},Node heap=${JBOARD_NODE_HEAP_MB:-?}MB。"
|
||||||
|
else
|
||||||
|
echo "检测到常规构建环境:CPU=${JBOARD_CPU_COUNT:-?},内存=${JBOARD_EFFECTIVE_MEM_MB:-0}MB,Docker内存=${docker_text},Docker可用空间=${disk_text}"
|
||||||
|
echo "使用 Docker 默认构建策略,不额外限制并发或 Node heap。"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$docker_disk" -gt 0 ] && [ "$docker_disk" -lt 8192 ]; then
|
||||||
|
echo "提示:Docker 可用空间低于 8GB,建议扩容 Docker 数据盘或清理未使用镜像/缓存。"
|
||||||
|
fi
|
||||||
|
}
|
||||||
@@ -10,31 +10,86 @@ HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:3000/api/public/app-info}"
|
|||||||
|
|
||||||
cd "$APP_DIR"
|
cd "$APP_DIR"
|
||||||
|
|
||||||
|
load_resource_helpers() {
|
||||||
|
if [ -f "$APP_DIR/scripts/lib-resource-profile.sh" ]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. "$APP_DIR/scripts/lib-resource-profile.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
load_resource_helpers
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
$COMPOSE "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_sqlite_database() {
|
||||||
|
mkdir -p backups
|
||||||
|
|
||||||
|
local backup_path="backups/jboard-sqlite-$(date +%F-%H%M%S).tar.gz"
|
||||||
|
local backed_up="0"
|
||||||
|
local backup_cmd='cd /app/storage 2>/dev/null && if [ -f jboard.db ]; then set -- jboard.db; [ -f jboard.db-wal ] && set -- "$@" jboard.db-wal; [ -f jboard.db-shm ] && set -- "$@" jboard.db-shm; tar -czf - "$@"; fi'
|
||||||
|
|
||||||
|
if compose ps --services --filter status=running 2>/dev/null | grep -qx app; then
|
||||||
|
if compose exec -T app sh -lc "$backup_cmd" > "$backup_path"; then
|
||||||
|
backed_up="1"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$backed_up" != "1" ] || [ ! -s "$backup_path" ]; then
|
||||||
|
if compose --profile setup run --rm -T --entrypoint sh init -lc "$backup_cmd" > "$backup_path"; then
|
||||||
|
backed_up="1"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$backed_up" = "1" ] && [ -s "$backup_path" ]; then
|
||||||
|
echo "SQLite backup saved: $backup_path"
|
||||||
|
else
|
||||||
|
rm -f "$backup_path"
|
||||||
|
echo "No existing SQLite database found; skipping database backup."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_updated_images() {
|
||||||
|
if command -v jboard_prepare_docker_build_env >/dev/null 2>&1; then
|
||||||
|
jboard_prepare_docker_build_env
|
||||||
|
jboard_print_build_profile
|
||||||
|
if jboard_is_low_resource_build; then
|
||||||
|
compose build "${JBOARD_DOCKER_BUILD_ARGS[@]}" init
|
||||||
|
compose build "${JBOARD_DOCKER_BUILD_ARGS[@]}" app
|
||||||
|
else
|
||||||
|
compose build "${JBOARD_DOCKER_BUILD_ARGS[@]}" init app
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
compose build init app
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
echo "[1/7] Pulling latest code..."
|
echo "[1/7] Pulling latest code..."
|
||||||
git pull --ff-only
|
git pull --ff-only
|
||||||
|
load_resource_helpers
|
||||||
|
|
||||||
if [ "$BACKUP" = "1" ]; then
|
if [ "$BACKUP" = "1" ]; then
|
||||||
echo "[2/7] Backing up database..."
|
echo "[2/7] Backing up SQLite database..."
|
||||||
mkdir -p backups
|
backup_sqlite_database
|
||||||
$COMPOSE exec -T db pg_dump -U jboard jboard > "backups/jboard-db-$(date +%F-%H%M%S).sql"
|
|
||||||
else
|
else
|
||||||
echo "[2/7] Skipping database backup..."
|
echo "[2/7] Skipping database backup..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[3/7] Building updated images..."
|
echo "[3/7] Building updated images..."
|
||||||
$COMPOSE build init app
|
build_updated_images
|
||||||
|
|
||||||
echo "[4/7] Syncing Prisma schema inside Docker network..."
|
echo "[4/7] Syncing Prisma schema inside Docker network..."
|
||||||
$COMPOSE --profile setup run --rm init sh -lc 'npm run db:push'
|
compose --profile setup run --rm init sh -lc 'npm run db:push'
|
||||||
|
|
||||||
echo "[5/7] Restarting services..."
|
echo "[5/7] Restarting services..."
|
||||||
$COMPOSE up -d app
|
compose up -d app
|
||||||
|
|
||||||
echo "[6/7] Waiting for app to boot..."
|
echo "[6/7] Waiting for app to boot..."
|
||||||
sleep 8
|
sleep 8
|
||||||
|
|
||||||
echo "[7/7] Checking service status..."
|
echo "[7/7] Checking service status..."
|
||||||
$COMPOSE ps
|
compose ps
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "App health:"
|
echo "App health:"
|
||||||
@@ -42,7 +97,7 @@ curl -fsS "$HEALTH_URL" || true
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Recent app logs:"
|
echo "Recent app logs:"
|
||||||
$COMPOSE logs --tail=80 app || true
|
compose logs --tail=80 app || true
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Upgrade complete."
|
echo "Upgrade complete."
|
||||||
|
|||||||
Reference in New Issue
Block a user