feat: rebuild xiteng.site homelab platform
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
services:
|
||||
metrics:
|
||||
image: python:3-slim@sha256:a7fb1e634c4a578f9e0bd6327f11a3cde11b7a9395f48e24360c0988bcc5c2bc
|
||||
container_name: xiteng-site-metrics
|
||||
restart: unless-stopped
|
||||
command: ["python3", "/app/metrics.py"]
|
||||
environment:
|
||||
- PORT=8092
|
||||
- HOST_PROC=/host/proc
|
||||
- DISK_PATH=/host/disk
|
||||
- CACHE_TTL_SECONDS=2
|
||||
- NVIDIA_VISIBLE_DEVICES=all
|
||||
- NVIDIA_DRIVER_CAPABILITIES=utility
|
||||
volumes:
|
||||
- ./metrics.py:/app/metrics.py:ro
|
||||
- /proc:/host/proc:ro
|
||||
- /etc/hostname:/host/hostname:ro
|
||||
- ./:/host/disk:ro
|
||||
read_only: true
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
healthcheck:
|
||||
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8092/healthz', timeout=2)"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
networks:
|
||||
- homelab_net
|
||||
labels:
|
||||
- "traefik.enable=false"
|
||||
- "xiteng.site.component.host-metrics.enabled=true"
|
||||
- "xiteng.site.component.host-metrics.name=Host Metrics"
|
||||
- "xiteng.site.component.host-metrics.description=采集并公开 CPU、内存、磁盘与 GPU 的实时汇总指标。"
|
||||
- "xiteng.site.component.host-metrics.section=infrastructure"
|
||||
- "xiteng.site.component.host-metrics.category=可观测性"
|
||||
- "xiteng.site.component.host-metrics.access=public"
|
||||
- "xiteng.site.component.host-metrics.access-label=公开只读指标"
|
||||
- "xiteng.site.component.host-metrics.icon=HW"
|
||||
- "xiteng.site.component.host-metrics.accent=green"
|
||||
- "xiteng.site.component.host-metrics.order=590"
|
||||
|
||||
registry:
|
||||
image: node:24-alpine
|
||||
container_name: xiteng-site-registry
|
||||
restart: unless-stopped
|
||||
command: ["node", "/app/registry.mjs"]
|
||||
environment:
|
||||
- PORT=8091
|
||||
- DOCKER_SOCKET=/var/run/docker.sock
|
||||
- DATABASE_PATH=/data/registry.db
|
||||
- DISCOVERY_INTERVAL_MS=5000
|
||||
- MISSING_RETENTION_DAYS=30
|
||||
- RAW_RETENTION_DAYS=30
|
||||
- AGGREGATE_RETENTION_DAYS=365
|
||||
- MONITOR_CONCURRENCY=4
|
||||
volumes:
|
||||
- ./registry.mjs:/app/registry.mjs:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./data:/data
|
||||
read_only: true
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8091/healthz').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
networks:
|
||||
- homelab_net
|
||||
labels:
|
||||
- "traefik.enable=false"
|
||||
- "xiteng.site.component.site-registry.enabled=true"
|
||||
- "xiteng.site.component.site-registry.name=Component Registry"
|
||||
- "xiteng.site.component.site-registry.description=只读发现 Docker Label,并向门户输出白名单组件元数据。"
|
||||
- "xiteng.site.component.site-registry.section=infrastructure"
|
||||
- "xiteng.site.component.site-registry.category=门户"
|
||||
- "xiteng.site.component.site-registry.access=internal"
|
||||
- "xiteng.site.component.site-registry.access-label=仅容器网络"
|
||||
- "xiteng.site.component.site-registry.icon=API"
|
||||
- "xiteng.site.component.site-registry.accent=blue"
|
||||
- "xiteng.site.component.site-registry.order=12"
|
||||
|
||||
xiteng-site:
|
||||
image: node:24-alpine
|
||||
container_name: xiteng-site
|
||||
restart: unless-stopped
|
||||
command: ["node", "/app/server.mjs"]
|
||||
environment:
|
||||
- PORT=8080
|
||||
- REGISTRY_URL=http://xiteng-site-registry:8091/components
|
||||
- REGISTRY_ADMIN_URL=http://xiteng-site-registry:8091/admin
|
||||
- METRICS_URL=http://xiteng-site-metrics:8092/metrics
|
||||
- KEY_VAULT_URL=http://ai-gateway:8093
|
||||
- PROVIDER_TEST_URL=http://xiteng-chat:3000/api/provider-test
|
||||
- KEY_VAULT_TOKEN_FILE=/run/secrets/portal_gateway_hmac
|
||||
- ADMIN_USERNAME=liooil
|
||||
- AUTHENTIK_ISSUER=https://auth.xiteng.site
|
||||
- AUTHENTIK_URL=https://auth.xiteng.site
|
||||
- AUTHENTIK_TOKEN_FILE=/run/authentik-secrets/portal_api_token
|
||||
- IDENTITY_AUDIT_PATH=/data/identity-audit.jsonl
|
||||
volumes:
|
||||
- ./index.html:/app/index.html:ro
|
||||
- ./styles.css:/app/styles.css:ro
|
||||
- ./app.js:/app/app.js:ro
|
||||
- ./sw.js:/app/sw.js:ro
|
||||
- ./manifest.webmanifest:/app/manifest.webmanifest:ro
|
||||
- ./favicon.svg:/app/favicon.svg:ro
|
||||
- ./favicon.ico:/app/favicon.ico:ro
|
||||
- ./icons:/app/icons:ro
|
||||
- ./admin.html:/app/admin.html:ro
|
||||
- ./admin.js:/app/admin.js:ro
|
||||
- ./account.html:/app/account.html:ro
|
||||
- ./account.js:/app/account.js:ro
|
||||
- ./authentik.mjs:/app/authentik.mjs:ro
|
||||
- ./server.mjs:/app/server.mjs:ro
|
||||
- ../ai-gateway/secrets/portal_gateway_hmac:/run/secrets/portal_gateway_hmac:ro
|
||||
- ../authentik/secrets/portal_api_token:/run/authentik-secrets/portal_api_token:ro
|
||||
- ./data:/data
|
||||
read_only: true
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
depends_on:
|
||||
registry:
|
||||
condition: service_healthy
|
||||
metrics:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- homelab_net
|
||||
labels:
|
||||
# Traefik
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.xiteng-site.rule=Host(`xiteng.site`)"
|
||||
- "traefik.http.routers.xiteng-site.entrypoints=websecure"
|
||||
- "traefik.http.routers.xiteng-site.tls=true"
|
||||
- "traefik.http.routers.xiteng-site.tls.certresolver=cfresolver"
|
||||
- "traefik.http.routers.xiteng-site.service=xiteng-site"
|
||||
- "traefik.http.routers.xiteng-site.middlewares=xiteng-site-nocache"
|
||||
- "traefik.http.services.xiteng-site.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.xiteng-site-http.rule=Host(`xiteng.site`)"
|
||||
- "traefik.http.routers.xiteng-site-http.service=xiteng-site"
|
||||
- "traefik.http.routers.xiteng-site-http.entrypoints=web"
|
||||
- "traefik.http.routers.xiteng-site-http.middlewares=xiteng-site-nocache"
|
||||
- "traefik.http.middlewares.xiteng-site-nocache.headers.customresponseheaders.Cache-Control=no-store, no-cache, must-revalidate"
|
||||
- "traefik.http.middlewares.xiteng-site-nocache.headers.customresponseheaders.Pragma=no-cache"
|
||||
- "traefik.http.middlewares.xiteng-site-nocache.headers.customresponseheaders.Expires=0"
|
||||
# Authentik ForwardAuth protects all Portal administration and account routes.
|
||||
- "traefik.http.middlewares.xiteng-admin-scheme.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||
- "traefik.http.middlewares.xiteng-admin-auth.forwardauth.address=http://authentik-outpost:9000/outpost.goauthentik.io/auth/traefik"
|
||||
- "traefik.http.middlewares.xiteng-admin-auth.forwardauth.trustForwardHeader=true"
|
||||
- "traefik.http.middlewares.xiteng-admin-auth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-entitlements,X-authentik-email,X-authentik-name,X-authentik-uid"
|
||||
- "traefik.http.middlewares.xiteng-admin-context.headers.customrequestheaders.X-Portal-Authenticated=1"
|
||||
- "traefik.http.routers.xiteng-site-admin.rule=Host(`xiteng.site`) && (PathPrefix(`/admin`) || PathPrefix(`/account`) || PathPrefix(`/api/admin`) || PathPrefix(`/api/account`))"
|
||||
- "traefik.http.routers.xiteng-site-admin.entrypoints=websecure"
|
||||
- "traefik.http.routers.xiteng-site-admin.tls=true"
|
||||
- "traefik.http.routers.xiteng-site-admin.tls.certresolver=cfresolver"
|
||||
- "traefik.http.routers.xiteng-site-admin.service=xiteng-site"
|
||||
- "traefik.http.routers.xiteng-site-admin.middlewares=xiteng-admin-scheme,xiteng-admin-auth,xiteng-admin-context,xiteng-site-nocache"
|
||||
- "traefik.http.routers.xiteng-site-admin.priority=200"
|
||||
- "traefik.http.routers.xiteng-site-admin-http.rule=Host(`xiteng.site`) && (PathPrefix(`/admin`) || PathPrefix(`/account`) || PathPrefix(`/api/admin`) || PathPrefix(`/api/account`))"
|
||||
- "traefik.http.routers.xiteng-site-admin-http.entrypoints=web"
|
||||
- "traefik.http.routers.xiteng-site-admin-http.service=xiteng-site"
|
||||
- "traefik.http.routers.xiteng-site-admin-http.middlewares=xiteng-admin-scheme,xiteng-admin-auth,xiteng-admin-context,xiteng-site-nocache"
|
||||
- "traefik.http.routers.xiteng-site-admin-http.priority=200"
|
||||
# The native Authentik admin UI is hidden; login, OAuth/OIDC and API endpoints remain available.
|
||||
- "traefik.http.routers.authentik-admin-hidden.rule=Host(`auth.xiteng.site`) && PathPrefix(`/if/admin`)"
|
||||
- "traefik.http.routers.authentik-admin-hidden.entrypoints=websecure"
|
||||
- "traefik.http.routers.authentik-admin-hidden.tls=true"
|
||||
- "traefik.http.routers.authentik-admin-hidden.tls.certresolver=cfresolver"
|
||||
- "traefik.http.routers.authentik-admin-hidden.service=xiteng-site"
|
||||
- "traefik.http.routers.authentik-admin-hidden.priority=5000"
|
||||
- "traefik.http.routers.authentik-admin-hidden-http.rule=Host(`auth.xiteng.site`) && PathPrefix(`/if/admin`)"
|
||||
- "traefik.http.routers.authentik-admin-hidden-http.entrypoints=web"
|
||||
- "traefik.http.routers.authentik-admin-hidden-http.service=xiteng-site"
|
||||
- "traefik.http.routers.authentik-admin-hidden-http.priority=5000"
|
||||
- "xiteng.site.cache.portal-static.enabled=true"
|
||||
- "xiteng.site.cache.portal-static.routers=xiteng-site,xiteng-site-http"
|
||||
- "xiteng.site.cache.portal-static.paths=/icons/"
|
||||
- "xiteng.site.cache.portal-static.edge-ttl=604800"
|
||||
- "xiteng.site.cache.portal-static.stale-while-revalidate=86400"
|
||||
# Dynamic catalog
|
||||
- "xiteng.site.component.portal.enabled=true"
|
||||
- "xiteng.site.component.portal.name=Xiteng Portal"
|
||||
- "xiteng.site.component.portal.description=唯一公开入口、个人主页与 Authentik 保护的 Homelab 管理控制面。"
|
||||
- "xiteng.site.component.portal.section=infrastructure"
|
||||
- "xiteng.site.component.portal.category=门户"
|
||||
- "xiteng.site.component.portal.url=https://xiteng.site"
|
||||
- "xiteng.site.component.portal.access=public"
|
||||
- "xiteng.site.component.portal.access-label=公开目录"
|
||||
- "xiteng.site.component.portal.icon=XT"
|
||||
- "xiteng.site.component.portal.icon-url=https://xiteng.site/favicon.svg"
|
||||
- "xiteng.site.component.portal.accent=red"
|
||||
- "xiteng.site.component.portal.order=10"
|
||||
- "xiteng.site.component.portal.monitor.enabled=true"
|
||||
- "xiteng.site.component.portal.monitor.url=http://xiteng-site:8080/healthz"
|
||||
- "xiteng.site.component.portal.monitor.interval=60"
|
||||
- "xiteng.site.component.portal.monitor.failures=3"
|
||||
- "xiteng.site.component.portal.monitor.timeout=10"
|
||||
- "xiteng.site.component.portal.monitor.accept=200-299"
|
||||
|
||||
networks:
|
||||
homelab_net:
|
||||
external: true
|
||||
Reference in New Issue
Block a user