刘光辉
昨天 bb638871a7fb692d80f1b7a758f991dc0879002c
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# JNPF 全栈 docker-compose 操作入口(详见 docs/docker-compose-guide.md)
.PHONY: help jars jars-microservice flow-engine prepare web-dist check-web-dist pull-infra images preflight up up-no-pull images-offline down restart ps logs smoke
 
# ── 第三方基础设施镜像:SWR 长名 → 本地短名 ──────────────────────────────────
# compose 里写的是短名(cx-redis / cx-onlyoffice / cx-nginx),由下面的 pull-infra retag 而来。
# `docker tag` 只是给同一个 image ID 挂别名,不复制数据(0 字节开销)。
SWR := swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io
 
help: ## 显示本帮助
    @grep -E '^[a-z-]+:.*##' $(MAKEFILE_LIST) | awk -F':.*## ' '{printf "  make %-10s %s\n", $$1, $$2}'
 
jars: ## Maven 打包全部业务 jar(业务镜像构建的前置)
    mvn clean package -DskipTests
 
# 2026-08-11 平台聚合:默认(monolith)产出 jnpf-platform 一个 fat jar,取代原来
# oauth/system/visualdev/flowable/file/message/permission/visualdata/app 九个。
# 九个 *-server 模块的源码**保留未删**,由各自父 pom 的 microservice profile 门控。
# 回滚到微服务形态 = 本目标 + 还原 config/*/discovery.yaml 的九个服务名端口
# + 放回 docker-compose.yml / start-all.sh 里被注释的九段。不需要 git revert。
jars-microservice: ## 回滚用:按微服务形态打包(额外产出九个平台服务 fat jar)
    mvn -P microservice clean package -DskipTests
 
flow-engine: ## 构建自有流程引擎 jar(独立工程,不在父 POM,故单独构建)
    mvn -f jnpf-flow-engine/pom.xml clean package -DskipTests
 
# 业务镜像 COPY 宿主 target/*.jar(非多阶段构建),故 images 前必须先有业务 jar。
# 用哨兵校验避免"干净机器忘了 make jars → docker COPY 阶段晦涩失败":缺失即报错提示。
# 不直接让 images 依赖 jars,是为保留本地"编一次、反复起"的迭代速度(全量 mvn 约 10min)。
check-jars:
    @test -f jnpf-gateway/target/jnpf-gateway-*.jar || { \
      echo "错误:未找到业务 jar(jnpf-gateway/target/*.jar)"; \
      echo "  请先构建全部业务 jar:make jars"; exit 1; }
 
prepare: flow-engine ## 构建并暂存自建流程引擎 jar 到镜像上下文(不入 git)
    ./docker/flow-engine/prepare-context.sh
 
web-dist: ## 构建前端并快照 dist 到镜像上下文(前端仓库路径可 FRONTEND_REPO= 覆盖;只拷不构建 SKIP_BUILD=1)
    ./docker/frontend/sync-dist.sh
 
# 与 check-jars 同理:不让 images 直接依赖 web-dist(前端构建数分钟级),
# 只做存在性哨兵;dist 是否新鲜看 docker/frontend/dist/.build-info
check-web-dist:
    @test -f docker/frontend/dist/index.html || { \
      echo "错误:未找到前端产物(docker/frontend/dist/index.html)"; \
      echo "  请先构建前端:make web-dist"; exit 1; }
 
pull-infra: ## 拉取第三方基础设施镜像并 retag 成短名(cx-redis / cx-onlyoffice / cx-nginx)
    docker pull --platform linux/amd64 $(SWR)/redis:8.4.0-alpine
    docker tag  $(SWR)/redis:8.4.0-alpine  cx-redis:8.4.0-alpine
    # OnlyOffice DS 同样走 SWR(2026-08-19):Hub 直连在国内网络稳定超时。
    # 镜像 ~2GB,首次拉取偏慢;compose 里对应短名 cx-onlyoffice:9.4.0.1。
    docker pull --platform linux/amd64 $(SWR)/onlyoffice/documentserver:9.4.0.1
    docker tag  $(SWR)/onlyoffice/documentserver:9.4.0.1  cx-onlyoffice:9.4.0.1
    # cx-nginx 是 cx-web 的**构建基底**(Dockerfile FROM),不是 compose 的 image 字段——
    # 故它只在 .env 设了 NGINX_BASE_IMAGE=cx-nginx:1.27-alpine 时被消费;未设则走
    # compose 默认的 Docker Hub 多架构 nginx:1.27-alpine(arm64 原生,但需 Hub 可达)。
    docker pull --platform linux/amd64 $(SWR)/nginx:1.27-alpine
    docker tag  $(SWR)/nginx:1.27-alpine  cx-nginx:1.27-alpine
    @echo "基础设施镜像已就绪(短名 → 架构):"
    @for i in cx-redis:8.4.0-alpine cx-onlyoffice:9.4.0.1 cx-nginx:1.27-alpine; do \
      printf '  %-24s %s\n' "$$i" "$$(docker image inspect --format '{{.Architecture}}' $$i 2>/dev/null || echo '缺失')"; \
    done
 
# 取代原先的 `docker compose pull --ignore-buildable`:compose 里没有 build 段的服务
# 恰好就是那三个第三方基础设施服务(redis/namesrv/broker),它们现在用短名,
# 裸 pull 会去 docker.io 找不存在的仓库。pull-infra 覆盖同一批镜像且带 retag。
# --profile localdb 是构建期必须的:cx-postgres 在该 profile 内(默认不启动,见 compose 服务块),
# 不带它 `compose build` 会跳过 PG 镜像,交付/正式环境起栈时才发现没镜像。
# 构建全集 ≠ 启动集合:这里只保证镜像齐,起哪些服务仍由 .env 的 COMPOSE_PROFILES 决定。
images: check-jars check-web-dist prepare pull-infra ## 确保全部镜像就绪:自建的构建(cx/postgres、cx/flow-engine、业务、前端),第三方的拉取+retag
    docker compose --profile localdb build
 
# up/up-no-pull 强制前置 preflight(Backlog C1):空卷/空库/缺 .env 键在 compose up 前拦下,
# 消灭"空库 PG 却 healthy、业务全线连不上"的静默失败;确要跳过 SKIP_PREFLIGHT=1
preflight: ## 部署自举校验:docker/内存/.env 必填键/数据卷/三库 schema/种子数据/共享配置文件/业务角色
    @if [ "$(SKIP_PREFLIGHT)" = "1" ]; then echo "跳过 preflight(SKIP_PREFLIGHT=1)"; \
    else ./docker/preflight.sh; fi
 
up: images preflight ## 镜像就绪后一键启动全栈(冷启动约 5-8 分钟:PG→业务自动排队)
    docker compose up -d
    docker compose ps
 
up-no-pull: preflight ## 跳过构建与拉取,用本地已有镜像起全栈(离线/快速迭代;镜像缺失直接报错)
    docker compose up -d --no-build --pull never
    docker compose ps
 
images-offline: check-jars check-web-dist prepare ## 组装整栈 amd64 离线交付包到 dist/(详见 docs/docker-compose-guide.md §14)
    ./docker/delivery/assemble-offline-package.sh
 
# --profile localdb 不能省:compose 的 down 只覆盖当前启用 profile 内的服务(实测:profile 关闭时
# 该容器会被原样留着跑)。带上它,无论本环境用不用栈内 PG,停栈都是干净的(没起过则是空操作)。
down: ## 全部停止并移除容器(数据安全:pgdata 是 external 卷,永不删除)
    docker compose --profile localdb down
 
restart: ## 重启全栈容器(原地重启,不重建容器/不丢 MQ 无持久化消息)
    docker compose restart
 
ps: ## 查看容器状态与健康
    docker compose ps
 
logs: ## 跟踪某服务日志:make logs s=cx-lims
    docker compose logs -f $(s)
 
smoke: ## 冒烟三段:gateway 登录 + 前端静态 200 + 经 80 反代登录(L017 脚本;与 site.Makefile 同步维护)
    @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 反代登录)"