feat(infra): prêt au déploiement GitOps Portainer + Telegram optionnel (v0.32.0)
Compose de prod docker-compose.prod.yml (GitOps, sans env_file, réseau proxy réel, certresolver letsencrypt) + runbook docs/deploy.md (Phase 1, users chlova restreints Portainer/n8n). Surface Telegram rendue optionnelle pour un déploiement UI-only ; garde assertHasSurface fail-closed. Typecheck + 78 tests verts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016w5jRe87MGdd6AMvXQcHNi
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
# CHLOVA — compose de PRODUCTION (déploiement GitOps via Portainer).
|
||||
#
|
||||
# Différences avec ../infra/docker-compose.yml (dev local) :
|
||||
# • Aucun `env_file` : le clone git ne contient PAS de .env. TOUS les secrets
|
||||
# et réglages arrivent par les VARIABLES DE STACK Portainer (interpolation
|
||||
# ${VAR}). L'agent ne voit jamais de secret en clair (CLAUDE.md).
|
||||
# • Réseau Traefik réel du homelab = `proxy` (external), pas `traefik-public`.
|
||||
# • certresolver réel = `letsencrypt` (cf. stack proxy), pas `le`.
|
||||
# • Le backend rejoint `proxy` pour joindre n8n en interne (http://n8n:5678).
|
||||
#
|
||||
# Cible : environnement Portainer `vps-pogoo-002` (endpoint 11).
|
||||
# Build : Portainer clone ce dépôt et build l'image sur le VPS (GitOps).
|
||||
# → chemin compose = infra/docker-compose.prod.yml ; contexte build = racine.
|
||||
#
|
||||
# Phase 1 (lecture seule) : CHLOVA_PHASE=1, PORTAINER_READ_ONLY=true.
|
||||
# Voir docs/deploy.md pour la procédure complète + variables de stack à fournir.
|
||||
|
||||
name: chlova
|
||||
|
||||
services:
|
||||
# ── Ollama : proxy authentifié vers les modèles cloud (ollama.com) ──────
|
||||
ollama:
|
||||
image: ollama/ollama:0.6.8
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
OLLAMA_API_KEY: ${OLLAMA_API_KEY:?OLLAMA_API_KEY requis}
|
||||
OLLAMA_HOST: 0.0.0.0:11434
|
||||
volumes:
|
||||
- ollama-data:/root/.ollama
|
||||
networks:
|
||||
- chlova-internal
|
||||
- chlova-egress
|
||||
# AUCUN port publié : Ollama n'a pas d'auth native, jamais exposé.
|
||||
|
||||
# ── socket-proxy : accès Docker filtré, LECTURE SEULE (Phase 1) ─────────
|
||||
socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy:0.3.0
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
CONTAINERS: 1
|
||||
IMAGES: 1
|
||||
NETWORKS: 1
|
||||
VOLUMES: 1
|
||||
SERVICES: 1
|
||||
TASKS: 1
|
||||
NODES: 1
|
||||
INFO: 1
|
||||
VERSION: 1
|
||||
POST: 0
|
||||
EXEC: 0
|
||||
AUTH: 0
|
||||
SECRETS: 0
|
||||
CONFIGS: 0
|
||||
BUILD: 0
|
||||
COMMIT: 0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
networks:
|
||||
- chlova-internal
|
||||
# AUCUN port publié.
|
||||
|
||||
# ── MCP Portainer (portainer/portainer-mcp) — read-only en Phase 1 ──────
|
||||
mcp-portainer:
|
||||
image: portainer/portainer-mcp:0.6.0
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORTAINER_URL: ${PORTAINER_URL:?PORTAINER_URL requis} # URL PUBLIQUE Portainer (serveur sur autre hôte — cf. deploy.md)
|
||||
PORTAINER_MCP_AUTH_TOKEN: ${PORTAINER_MCP_AUTH_TOKEN:?requis} # token user chlova restreint
|
||||
PORTAINER_READ_ONLY: ${PORTAINER_READ_ONLY:-true} # P1 : NE PAS passer à false
|
||||
DOCKER_HOST: tcp://socket-proxy:2375
|
||||
depends_on:
|
||||
- socket-proxy
|
||||
networks:
|
||||
- chlova-internal
|
||||
# AUCUN port publié.
|
||||
|
||||
# ── Backend CHLOVA : SEULE surface, cerveau (boucle agent) ──────────────
|
||||
backend:
|
||||
build:
|
||||
context: .. # racine du dépôt (image = API + SPA web)
|
||||
dockerfile: orchestrator/Dockerfile
|
||||
image: chlova/backend:0.2.0
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# — Runtime / phase —
|
||||
CHLOVA_ENV: ${CHLOVA_ENV:-production}
|
||||
CHLOVA_LOG_LEVEL: ${CHLOVA_LOG_LEVEL:-info}
|
||||
CHLOVA_PHASE: ${CHLOVA_PHASE:-1} # 1 = lecture seule
|
||||
CHLOVA_DB_PATH: ${CHLOVA_DB_PATH:-/app/data/chlova.db}
|
||||
# — Ollama (cloud proxy) —
|
||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||
OLLAMA_API_KEY: ${OLLAMA_API_KEY:?requis}
|
||||
OLLAMA_MODEL: ${OLLAMA_MODEL:-qwen3:cloud}
|
||||
# — MCP n8n (natif, interne via réseau proxy) —
|
||||
MCP_N8N_URL: ${MCP_N8N_URL:-http://n8n:5678/mcp-server/http}
|
||||
MCP_N8N_AUTH_TOKEN: ${MCP_N8N_AUTH_TOKEN:?requis}
|
||||
# — MCP Portainer (sidecar) —
|
||||
MCP_PORTAINER_URL: ${MCP_PORTAINER_URL:-http://mcp-portainer:3000}
|
||||
PORTAINER_MCP_AUTH_TOKEN: ${PORTAINER_MCP_AUTH_TOKEN:?requis}
|
||||
PORTAINER_READ_ONLY: ${PORTAINER_READ_ONLY:-true}
|
||||
# — Alertes (Phase 3) : vide = log-only —
|
||||
ALERT_WEBHOOK_URL: ${ALERT_WEBHOOK_URL:-}
|
||||
# — API/UI (surface exposée) : login fort —
|
||||
CHLOVA_ADMIN_USER: ${CHLOVA_ADMIN_USER:?requis}
|
||||
CHLOVA_ADMIN_PASSWORD_HASH: ${CHLOVA_ADMIN_PASSWORD_HASH:?requis}
|
||||
CHLOVA_TOTP_SECRET: ${CHLOVA_TOTP_SECRET:?requis}
|
||||
CHLOVA_JWT_SECRET: ${CHLOVA_JWT_SECRET:?requis}
|
||||
# — Auto-extension (Phase 5) : off par défaut —
|
||||
CHLOVA_AUTOEXT_ENABLED: ${CHLOVA_AUTOEXT_ENABLED:-false}
|
||||
CHLOVA_REPO_ROOT: ${CHLOVA_REPO_ROOT:-/app/repo}
|
||||
volumes:
|
||||
- chlova-data:/app/data # SQLite (table assets, P2+)
|
||||
depends_on:
|
||||
- ollama
|
||||
- mcp-portainer
|
||||
networks:
|
||||
- chlova-internal
|
||||
- proxy # joint Traefik + n8n (réseau homelab)
|
||||
labels:
|
||||
traefik.enable: "true"
|
||||
traefik.docker.network: proxy
|
||||
traefik.http.routers.chlova.rule: Host(`${CHLOVA_DOMAIN:-chlova.pogoo.app}`)
|
||||
traefik.http.routers.chlova.entrypoints: websecure
|
||||
traefik.http.routers.chlova.tls: "true"
|
||||
traefik.http.routers.chlova.tls.certresolver: letsencrypt
|
||||
traefik.http.services.chlova.loadbalancer.server.port: "8080"
|
||||
|
||||
networks:
|
||||
chlova-internal:
|
||||
internal: true # aucune route vers l'extérieur
|
||||
chlova-egress:
|
||||
driver: bridge # sortie contrôlée (Ollama → ollama.com)
|
||||
proxy:
|
||||
name: proxy
|
||||
external: true # réseau Traefik existant du homelab (cf. stacks proxy/n8n)
|
||||
|
||||
volumes:
|
||||
ollama-data:
|
||||
chlova-data:
|
||||
Reference in New Issue
Block a user