# JNPF 整栈离线交付包 现场操作入口(本文件随包分发为 Makefile;流程详见 INSTALL.md)
|
# 现场机器不需要源码、不需要外网:镜像全部来自 images/ 目录的离线 tar。
|
.PHONY: help verify load preflight up down restart ps logs wait smoke
|
|
help: ## 显示本帮助
|
@grep -E '^[a-z-]+:.*##' $(MAKEFILE_LIST) | awk -F':.*## ' '{printf " make %-10s %s\n", $$1, $$2}'
|
|
# up 强制前置 preflight:空卷/空库/缺 .env 键在 compose up 前拦下并给修复指引;
|
# 确要跳过(自担风险):SKIP_PREFLIGHT=1 make up
|
preflight: ## 部署自举校验:docker/内存/.env 必填键/数据卷/四库 schema/种子数据/业务角色
|
@if [ "$(SKIP_PREFLIGHT)" = "1" ]; then echo "跳过 preflight(SKIP_PREFLIGHT=1)"; \
|
else ./docker/preflight.sh; fi
|
|
verify: ## 校验交付包完整性(sha256,镜像 tar 较大需数分钟)
|
@command -v sha256sum >/dev/null && sha256sum -c SHA256SUMS || shasum -a 256 -c SHA256SUMS
|
@echo "完整性校验通过 ✓"
|
|
load: ## docker load 全部离线镜像(运行镜像 + 迁移辅助镜像)
|
docker load -i images/cx-images.tar.gz
|
@test -f images/cx-migration-tools.tar.gz && docker load -i images/cx-migration-tools.tar.gz || true
|
|
up: preflight ## 用已 load 的本地镜像起全栈(绝不构建/拉取;冷启动 5-8 分钟后 make wait)
|
docker compose up -d --no-build --pull never
|
docker compose ps
|
|
wait: ## 等待全部带健康检查的容器 healthy(业务 start_period 180s,冷启动约 5-8 分钟)
|
@for i in $$(seq 1 60); do \
|
total=$$(docker compose ps --format '{{.Name}} {{.Health}}' | awk 'NF==2' | wc -l | tr -d ' '); \
|
ok=$$(docker compose ps --format '{{.Name}} {{.Health}}' | awk '$$2=="healthy"' | wc -l | tr -d ' '); \
|
echo "healthy $$ok/$$total"; \
|
[ -n "$$total" ] && [ "$$total" != "0" ] && [ "$$ok" = "$$total" ] && { echo "全部 healthy ✓"; exit 0; }; \
|
sleep 10; \
|
done; echo "超时:仍有容器未 healthy,docker compose ps 查看(L024:先确认内存 ≥12GB)"; exit 1
|
|
# --profile localdb 不能省:compose 的 down 只覆盖当前启用 profile 内的服务,漏带会把栈内 PG
|
# 原样留着跑。带上它,无论本环境用不用栈内 PG,停栈都是干净的(没起过则是空操作)。
|
down: ## 全部停止并移除容器(数据安全:pgdata 是 external 卷,永不删除)
|
docker compose --profile localdb down
|
|
restart: ## 重启全栈容器
|
docker compose restart
|
|
ps: ## 查看容器状态与健康
|
docker compose ps
|
|
logs: ## 跟踪某服务日志:make logs s=cx-lims
|
docker compose logs -f $(s)
|
|
smoke: ## 冒烟三段:gateway 登录 + 前端静态 200 + 经 80 反代登录(依赖 curl/openssl/md5sum 或 md5)
|
@set -o pipefail; \
|
MD5=$$(command -v md5 >/dev/null 2>&1 && echo md5 || echo md5sum); \
|
hash5() { if [ "$$MD5" = md5 ]; then md5; else md5sum | cut -d' ' -f1; fi; }; \
|
KEYHEX=$$(printf '%s' "$$(printf '%s' 'EY8WePvjM5GGwQzn' | hash5)" | xxd -p | tr -d '\n'); \
|
ENC=$$(printf '%s' "$$(printf '%s' '123456' | hash5)" | openssl enc -aes-256-ecb -K "$$KEYHEX" -nosalt | xxd -p | tr -d '\n'); \
|
RESP=$$(curl -fsS -X POST http://127.0.0.1:30000/api/oauth/Login -H 'Content-Type: application/x-www-form-urlencoded' \
|
--data-urlencode account=admin --data-urlencode "password=$$ENC" \
|
--data-urlencode grant_type=password --data-urlencode origin=password); \
|
echo "$$RESP" | head -c 200; echo; \
|
echo "$$RESP" | grep -q '"code":200' || { echo "冒烟失败:登录未返回 code 200(gateway 30000 直连)"; exit 1; }; \
|
curl -fsS -o /dev/null http://127.0.0.1:80/ || { echo "冒烟失败:前端静态入口 http://127.0.0.1:80/ 不通"; exit 1; }; \
|
RESP2=$$(curl -fsS -X POST http://127.0.0.1:80/api/oauth/Login -H 'Content-Type: application/x-www-form-urlencoded' \
|
--data-urlencode account=admin --data-urlencode "password=$$ENC" \
|
--data-urlencode grant_type=password --data-urlencode origin=password); \
|
echo "$$RESP2" | grep -q '"code":200' || { echo "冒烟失败:经前端 80 反代登录未返回 code 200"; exit 1; }; \
|
echo "冒烟通过 ✓(gateway 直连 + 前端静态 + 80 反代登录)"
|