刘光辉
12 小时以前 34981c30a78e8bbd7791131059a9210f9928b62c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 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 反代登录)"