# 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 反代登录)"