chore(infra): docker dev-apps stack + apollo-router v1.45 compat

- 新增 docker-compose.dev-apps.yml:7 个应用服务容器化
  (iam/classes/core-edu/content/msg/push-gateway/api-gateway)
  + apollo-router override
- 新增 apollo-router dev-apps-entrypoint.sh / dev-apps-supergraph.yaml
  仅等待 5 个子图(iam/core-edu/content/msg/config-service)
  避免等待未启动的 ai/data-ana
- router.yaml:移除 v1.45 不兼容键
  (require_manifest/manifest_path/max_cost/max_batch_size)
  移除 ELv2 受限特性(persisted_queries/limits.max_depth)
  自托管无 GraphOS license
- docker-compose.yml:config-service 添加 NODE_ENV=production
  修复 pino-pretty devDep 误用
  apollo-router 添加 APOLLO_PERSISTED_QUERIES env
- services/{classes,core-edu,content,config-service}/Dockerfile
  重写为 repo 根 context + shared-ts/shared-proto 工作区依赖
  + --ignore-scripts
  修复 ERR_PNPM_WORKSPACE_PKG_NOT_FOUND 与 ERR_PNPM_IGNORED_BUILDS
- api-gateway healthcheck:wget --spider 改为 wget -O /dev/null
  修复 busybox 对 200+body 误报 exit 8
This commit is contained in:
SpecialX
2026-07-22 11:35:02 +08:00
parent f586a0b19e
commit 682f323bad
10 changed files with 603 additions and 71 deletions

View File

@@ -26,13 +26,14 @@ RUN curl -sSL -o /tmp/rover.tar.gz https://github.com/apollographql/rover/releas
# 预下载 supergraph 插件federation-rs supergraph v2.9.0
# 避免运行时因网络问题(如 GitHub 不可达)导致 rover compose 失败
# 插件会被缓存到 /root/.rover/bin/supergraph-v2.9.0
# tarball 内文件路径为 dist/supergraph需 --strip-components=1 解包
RUN APOLLO_ELV2_LICENSE=accept rover supergraph compose --config /dev/null --output /tmp/test-supergraph.graphql 2>&1 || \
(echo "[build] Pre-downloading supergraph plugin..." && \
curl -sSL -o /tmp/supergraph-plugin.tar.gz \
"https://github.com/apollographql/federation-rs/releases/download/supergraph%40v2.9.0/supergraph-v2.9.0-x86_64-unknown-linux-gnu.tar.gz" && \
mkdir -p /root/.rover/bin && \
tar -xzf /tmp/supergraph-plugin.tar.gz -C /root/.rover/bin/ && \
mv /root/.rover/bin/supergraph /root/.rover/bin/supergraph-v2.9.0 2>/dev/null || true && \
tar -xzf /tmp/supergraph-plugin.tar.gz --strip-components=1 -C /root/.rover/bin/ dist/supergraph && \
mv /root/.rover/bin/supergraph /root/.rover/bin/supergraph-v2.9.0 && \
chmod +x /root/.rover/bin/supergraph-v2.9.0 && \
rm -f /tmp/supergraph-plugin.tar.gz /tmp/test-supergraph.graphql && \
echo "[build] Supergraph plugin pre-installed")

View File

@@ -0,0 +1,92 @@
#!/bin/bash
# Apollo Router 启动脚本dev-apps 模式:仅 5 个 TS 子图)
#
# 与 entrypoint.sh 的差异:
# - SUBGRAPHS 仅包含 iam/core-edu/content/msg/config-service排除 ai/data-ana
# - 依赖 docker compose depends_on 已确保子图健康,等待重试次数减少到 30
#
# 使用:通过 docker-compose.dev-apps.yml 卷挂载覆盖 /dist/entrypoint.sh
set -e
SUBGRAPHS=(
"iam:iam:3002"
"core-edu:core-edu:3004"
"content:content:3005"
"msg:msg:3007"
"config-service:config-service:3011"
)
echo "[apollo-router:dev-apps] Waiting for subgraphs to be ready..."
wait_for_subgraph() {
local name="$1"
local host="$2"
local port="$3"
local max_retries=30
local retry=0
while [ $retry -lt $max_retries ]; do
if curl -sf -o /dev/null "http://${host}:${port}/healthz" 2>/dev/null; then
echo "[apollo-router:dev-apps] ${name} is ready (http://${host}:${port})"
return 0
fi
retry=$((retry + 1))
echo "[apollo-router:dev-apps] Waiting for ${name} at ${host}:${port} (attempt ${retry}/${max_retries})"
sleep 3
done
echo "[apollo-router:dev-apps] WARNING: ${name} not ready after ${max_retries} attempts, continuing anyway..."
return 0
}
for entry in "${SUBGRAPHS[@]}"; do
name="${entry%%:*}"
hostport="${entry#*:}"
host="${hostport%%:*}"
port="${hostport##*:}"
wait_for_subgraph "$name" "$host" "$port"
done
# 组合 supergraph SDL
echo "[apollo-router:dev-apps] Composing supergraph SDL..."
export APOLLO_ELV2_LICENSE=accept
max_compose_retries=5
compose_retry=0
while [ $compose_retry -lt $max_compose_retries ]; do
compose_retry=$((compose_retry + 1))
if rover supergraph compose --config /dist/supergraph.yaml --output /tmp/supergraph.graphql 2>&1; then
echo "[apollo-router:dev-apps] Supergraph composed successfully"
break
fi
echo "[apollo-router:dev-apps] Compose attempt ${compose_retry}/${max_compose_retries} failed, retrying in 5s..."
sleep 5
done
if [ ! -f /tmp/supergraph.graphql ]; then
echo "[apollo-router:dev-apps] ERROR: Failed to compose supergraph after ${max_compose_retries} attempts"
exit 1
fi
# PQ manifest 检查dev 模式 require_manifest=false仅警告
MANIFEST_PATH="/etc/apollo-router/pq-manifest.json"
REQUIRE_MANIFEST="${APOLLO_REQUIRE_PQ_MANIFEST:-false}"
if [ "${REQUIRE_MANIFEST}" = "true" ]; then
if [ ! -f "${MANIFEST_PATH}" ]; then
echo "[apollo-router:dev-apps] ERROR: APOLLO_REQUIRE_PQ_MANIFEST=true but manifest not found at ${MANIFEST_PATH}"
exit 1
fi
echo "[apollo-router:dev-apps] PQ manifest loaded (require_manifest=true): ${MANIFEST_PATH}"
else
if [ ! -f "${MANIFEST_PATH}" ]; then
echo "[apollo-router:dev-apps] WARNING: PQ manifest not found at ${MANIFEST_PATH} (require_manifest=false, continuing)"
else
echo "[apollo-router:dev-apps] PQ manifest loaded (require_manifest=false): ${MANIFEST_PATH}"
fi
fi
# 启动 router
echo "[apollo-router:dev-apps] Starting Apollo Router on port 3000..."
exec /dist/router --config /dist/configuration.yaml --supergraph /tmp/supergraph.graphql --hot-reload

View File

@@ -0,0 +1,36 @@
# Apollo Federation 2 Supergraph 组合配置dev-apps 模式:仅启动 5 个 TS 子图)
#
# 适用场景:本地用 docker compose 启动 iam/classes/core-edu/content/msg/config-service/apollo-router/api-gateway/push-gateway
# 不包含aiPython、data-anaPython— 用户未要求启动
#
# 与 supergraph.yaml 的差异:
# - 删除 ai / data-ana 子图(避免 rover compose 因它们不可达而失败)
# - 所有 routing_url 用容器名iam:3002 等)而非 host.docker.internal
federation_version: =2.9.0
subgraphs:
iam:
routing_url: http://iam:3002/graphql
schema:
subgraph_url: http://iam:3002/graphql
core-edu:
routing_url: http://core-edu:3004/graphql
schema:
subgraph_url: http://core-edu:3004/graphql
content:
routing_url: http://content:3005/graphql
schema:
subgraph_url: http://content:3005/graphql
msg:
routing_url: http://msg:3007/graphql
schema:
subgraph_url: http://msg:3007/graphql
config:
routing_url: http://config-service:3011/graphql
schema:
subgraph_url: http://config-service:3011/graphql

View File

@@ -17,28 +17,23 @@ supergraph:
listen: 0.0.0.0:3000
path: /graphql
# 生产关闭 introspectionAPOLLO_ROUTER_INTROSPECTION=false
# 开发默认 true 便于调试
introspection: ${env.APOLLO_ROUTER_INTROSPECTION::true}
# 开发默认 true 便于调试(由 docker-compose environment 注入)
introspection: ${env.APOLLO_ROUTER_INTROSPECTION}
# 持久化查询v2.1 M3 安全加固)
# 关联portal-shell spec §4.3
# - enabled: 启用 APQ接受 hash-only 请求)
# - require_manifest: 生产设为 true仅接受 manifest 内的 hash
# - manifest_path: manifest 文件路径(由 portal-shell 构建产物挂载)
persisted_queries:
enabled: true
require_manifest: ${env.APOLLO_REQUIRE_PQ_MANIFEST::false}
manifest_path: /etc/apollo-router/pq-manifest.json
# 注意Apollo Router v1.45 的 persisted_queries 是 ELv2 受限特性,
# 需连接 GraphOSAPOLLO_KEY + APOLLO_GRAPH_REF才能启用。
# 自托管开发态禁用此特性;生产环境如需启用,需配置 GraphOS license。
# persisted_queries:
# enabled: false
# 查询限制v2.1 M3 安全加固)
# 关联portal-shell spec §5.1
# - max_depth: 最大嵌套深度 10防止递归攻击
# - max_cost: 最大查询复杂度 1000防止放大攻击
# - max_batch_size: 批量查询上限 5防止 batch 攻击)
limits:
max_depth: 10
max_cost: 1000
max_batch_size: 5
# 注意Apollo Router v1.45 的 limits.max_depth 是 ELv2 受限特性,
# 需连接 GraphOS 才能启用。自托管开发态禁用;
# 生产环境如需深度限制,可使用 rhai script 或 custom plugin 替代。
# limits:
# max_depth: 10
# Sandbox 模式支持开发和调试v1.45 中 sandbox 已合并到 homepage
homepage: