Files
knowledge-governance/compose.yaml
T
姚章浩 e1c5f6895a
build / build (push) Failing after 21s
chore(deploy): 部署与备份脚本、示例配置与忽略规则
- 新增 scripts/deploy-api-web.sh(API/Web 构建发布)与 scripts/wiki_cleanup_backup.sh(wiki 清理前备份)
- 更新 .env.example、compose.yaml 与 README 说明;忽略 /spool/ingestion 运行期产物
2026-09-30 10:54:07 +08:00

203 lines
7.1 KiB
YAML

name: knowledge-governance-p1
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: governance
POSTGRES_USER: governance
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
secrets:
- postgres_password
volumes:
- governance-pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U governance -d governance"]
interval: 5s
timeout: 3s
retries: 20
restart: unless-stopped
api:
build:
context: .
dockerfile: Dockerfile
command: ["/app/api"]
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
<<: &app-environment
DATABASE_URL: postgres://governance@postgres:5432/governance?sslmode=disable
PGPASSFILE: /run/secrets/pgpass
APP_ADDR: :8080
WORKER_POLL_INTERVAL: 1s
WORKER_LEASE_DURATION: 30s
WORKER_RETRY_DELAY: 5s
TEST_WEKNORA_BASE_URL: "${TEST_WEKNORA_BASE_URL:-}"
DINGTALK_LOGIN_SIDECAR_URL: "http://dingtalk-login:8091"
MINERU_BASE_URL: "${MINERU_BASE_URL:-}"
TEST_INTERNAL_WEKNORA_KB_ID: "${TEST_INTERNAL_WEKNORA_KB_ID:-1b52c140-2e18-4676-afc5-4c7d8d190a8c}"
TEST_EXTERNAL_WEKNORA_KB_ID: "${TEST_EXTERNAL_WEKNORA_KB_ID:-fd7db6aa-763a-46f1-84d2-ecc7c952a5ea}"
# P10 readiness probe reads the routing KB with the same scoped key.
TEST_WEKNORA_API_KEY_FILE: /run/secrets/test_weknora_api_key
TEST_WEKNORA_ALLOW_DOCKER_HTTP: "${TEST_WEKNORA_ALLOW_DOCKER_HTTP:-false}"
WORKER_LIVENESS_STALE_AFTER: "${WORKER_LIVENESS_STALE_AFTER:-2m}"
PRODUCTION_RELEASE_REQUESTS_ENABLED: ${PRODUCTION_RELEASE_REQUESTS_ENABLED:-false}
PRODUCTION_BACKUP_RESTORE_VERIFIED: ${PRODUCTION_BACKUP_RESTORE_VERIFIED:-false}
# Read-only probe of the production WeKnora endpoint; publishing keeps
# reading its target from RELEASE_CONFIG_FILE.
PRODUCTION_WEKNORA_BASE_URL: "${PRODUCTION_WEKNORA_BASE_URL:-}"
PRODUCTION_WEKNORA_API_KEY_FILE: "${PRODUCTION_WEKNORA_API_KEY_FILE:-}"
PRODUCTION_WEKNORA_ALLOW_DOCKER_HTTP: "${PRODUCTION_WEKNORA_ALLOW_DOCKER_HTTP:-false}"
secrets:
- pgpass
- test_weknora_api_key
depends_on:
postgres:
condition: service_healthy
healthcheck:
# P10: liveness only — a third-party outage must never restart the API.
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/livez"]
interval: 5s
timeout: 3s
retries: 20
read_only: true
tmpfs:
- /tmp
networks:
- default
- weknora-local
restart: unless-stopped
worker:
build:
context: .
dockerfile: Dockerfile
command: ["/app/worker"]
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
<<: *app-environment
WORKER_ID: worker-1
PP_SCAN_ENABLED: "${PP_SCAN_ENABLED:-false}"
PP_SCAN_ALLOWED_ROOT: "${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}"
PP_SCAN_LEDGER_PATH: "${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}/public-weknora-sync/state.jsonl"
PP_SCAN_MANIFEST_PATH: "${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}/public-documents/manifest.json"
TEST_WEKNORA_ENABLED: "${TEST_WEKNORA_ENABLED:-false}"
TEST_WEKNORA_ALLOW_DOCKER_HTTP: "${TEST_WEKNORA_ALLOW_DOCKER_HTTP:-false}"
TEST_WEKNORA_KB_ID: "${TEST_WEKNORA_KB_ID:-}"
TEST_WEKNORA_API_KEY_FILE: /run/secrets/test_weknora_api_key
GOVERNANCE_SPOOL_ROOT: /var/lib/governance/spool
INGESTION_SPOOL_ROOT: /var/lib/governance/ingestion
TEST_WEKNORA_HTTP_TIMEOUT: "${TEST_WEKNORA_HTTP_TIMEOUT:-60s}"
TEST_WEKNORA_POLL_INITIAL: "${TEST_WEKNORA_POLL_INITIAL:-10s}"
TEST_WEKNORA_POLL_MAX: "${TEST_WEKNORA_POLL_MAX:-60s}"
TEST_WEKNORA_STALLED_AFTER: "${TEST_WEKNORA_STALLED_AFTER:-30m}"
TEST_WEKNORA_MAX_UPLOAD_BYTES: "${TEST_WEKNORA_MAX_UPLOAD_BYTES:-52428800}"
TEST_ACCEPTANCE_POLICY_VERSION: "${TEST_ACCEPTANCE_POLICY_VERSION:-structural-v1}"
secrets:
- pgpass
- test_weknora_api_key
volumes:
- ./spool:/var/lib/governance/spool:ro
- ./spool/ingestion:/var/lib/governance/ingestion
- "${PP_SCAN_HOST_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}:${PP_SCAN_CONTAINER_DATA_ROOT:-/home/zheromiku/dobot-portal-sync/data}:ro"
- /home/zheromiku/dingtalk_kb_download:/sources/dingtalk:ro
- /home/zheromiku/tmp/alist:/sources/alist:ro
- /home/zheromiku/dobot-portal-sync:/sources/pp:ro
- ./secrets/dingtalk_capture.json:/run/source-secrets/dingtalk_capture.json:ro
- ./secrets/alist_connections.xlsx:/run/source-secrets/alist_connections.xlsx:ro
- ./secrets/alist_api_token:/run/source-secrets/alist_api_token:ro
- ./secrets/pp_credentials.json:/run/source-secrets/pp_credentials.json:ro
networks:
- default
- weknora-local
depends_on:
postgres:
condition: service_healthy
read_only: true
tmpfs:
- /tmp
restart: unless-stopped
release-worker:
build:
context: .
dockerfile: Dockerfile
command: ["/app/release-worker"]
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
<<: *app-environment
WORKER_ID: release-worker-1
RELEASE_WORKER_ENABLED: "false"
RELEASE_CONFIG_FILE: ""
secrets:
- pgpass
depends_on:
postgres:
condition: service_healthy
read_only: true
tmpfs:
- /tmp
restart: unless-stopped
dingtalk-login:
# Chromium profile for DingTalk scan sessions. The bind-mounted secrets
# directory is rw ONLY here; the worker keeps reading the capture read-only.
build:
context: ./services/dingtalk-login
image: knowledge-governance-dingtalk-login:local
user: "${APP_UID:-1000}:${APP_GID:-1000}"
environment:
CAPTURE_FILE: /run/source-secrets/dingtalk_capture.json
DINGTALK_STATE_FILE: /sources/dingtalk/data/dingtalk-internal/inventory-state.json
VERIFY_SPACE: "${DINGTALK_VERIFY_SPACE:-9JOGO6332vlBnm4Q}"
QR_TTL_MS: "300000"
volumes:
- ./secrets:/run/source-secrets
- /home/zheromiku/dingtalk_kb_download:/sources/dingtalk
- dingtalk-chromium-profile:/profile
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:8091/healthz',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"]
interval: 10s
timeout: 5s
retries: 30
start_period: 15s
restart: unless-stopped
web:
build:
context: .
dockerfile: Dockerfile.web
ports:
- "8088:8080"
depends_on:
api:
condition: service_healthy
read_only: true
tmpfs:
- /tmp
- /var/cache/nginx
- /var/run
restart: unless-stopped
secrets:
postgres_password:
file: ./secrets/postgres_password
pgpass:
file: ./secrets/pgpass
test_weknora_api_key:
file: ./secrets/test_weknora_api_key
volumes:
governance-pgdata:
dingtalk-chromium-profile:
networks:
weknora-local:
external: true
name: weknora071full-network