Guide de déploiement
Ce guide couvre le déploiement de Gateo en Docker Compose (environnements simples, VMs) et en Kubernetes (environnements critiques, haute disponibilité). Gateo est une application Python/FastAPI + frontend React packagée en une seule image Docker.
Prérequis
| Outil | Version minimale | Usage |
|---|---|---|
docker | 24+ | Build & run des conteneurs |
docker compose | v2 (plugin) | Orchestration locale |
kubectl | 1.27+ | Déploiement Kubernetes |
| Cluster Kubernetes | 1.27+ | k3s, RKE2, EKS, AKS, GKE… |
| Image Gateo | dernière stable | registry.example.com/gateo:latest |
Image unique. L'image Docker de Gateo contient le backend Python et les assets frontend compilés. Aucun conteneur séparé n'est nécessaire pour le frontend.
Variables d'environnement
Gateo se configure entièrement via des variables d'environnement. Voici la référence complète :
Générales
| Variable | Défaut | Description |
|---|---|---|
APP_HOST | 0.0.0.0 | Interface d'écoute |
APP_PORT | 8080 | Port d'écoute |
LOG_LEVEL | INFO | DEBUG / INFO / WARNING / ERROR |
DATABASE_URL | sqlite:///./gateo.db | URL SQLAlchemy. PostgreSQL : postgresql://user:pass@host/db |
JWT_SECRET | change-me-in-production | À changer impérativement. Clé de signature des tokens JWT et de chiffrement des secrets en base. |
JWT_EXPIRE_HOURS | 8 | Durée de vie des sessions utilisateur (heures) |
ADMIN_USERNAME | admin | Login du compte admin bootstrapé au premier démarrage |
ADMIN_PASSWORD | changeme | À changer impérativement. |
Licence
| Variable | Défaut | Description |
|---|---|---|
LICENSE_FILE_PATH | gateo.lic | Chemin absolu ou relatif au CWD vers le fichier .lic. Sans fichier : période d'essai 14 jours. |
Connecteur ITSM
| Variable | Défaut | Description |
|---|---|---|
CONNECTOR_TYPE | ivanti | ivanti / jira / pagerduty / none |
IVANTI_BASE_URL | requis | URL de base de l'API Ivanti ISM |
IVANTI_AUTH_HEADER | requis | Token d'authentification Ivanti (rest_api_key=XXX) |
IVANTI_ALERTS_ENDPOINT | alerts | Nom de la Business Object collection |
DRY_RUN | false | true : simule les appels ITSM sans écrire |
Comportement alertes
| Variable | Défaut | Description |
|---|---|---|
DEDUP_ENABLED | true | Active la déduplication des alertes |
DEDUP_TTL_SECONDS | 3600 | Fenêtre de déduplication (secondes) |
CORRELATION_WINDOW_SECONDS | 300 | Fenêtre de corrélation des alertes parentes/enfants |
REOPEN_ENABLED | true | Réouvre les tickets fermés si l'alerte re-fire |
REOPEN_WINDOW_SECONDS | 1800 | Fenêtre de réouverture (secondes) |
SMTP (notifications e-mail)
| Variable | Défaut | Description |
|---|---|---|
SMTP_HOST | localhost | Serveur SMTP |
SMTP_PORT | 587 | Port SMTP |
SMTP_FROM | gateo@localhost | Adresse expéditeur |
SMTP_TLS | starttls | none / starttls / ssl |
SMTP_USERNAME | vide | Authentification SMTP (optionnel) |
SMTP_PASSWORD | vide | Authentification SMTP (optionnel) |
SSL / Proxy d'entreprise
| Variable | Défaut | Description |
|---|---|---|
REQUESTS_CA_BUNDLE | vide | Chemin absolu vers un bundle CA personnalisé (Netskope, Zscaler, proxy SSL) |
HTTP_CA_BUNDLE | vide | Alias Gateo (même effet que REQUESTS_CA_BUNDLE) |
SSL_CERT_FILE | vide | Convention Python standard |
Authentification LDAP / OIDC
| Variable | Défaut | Description |
|---|---|---|
LDAP_ENABLED | false | Active l'authentification LDAP/Active Directory |
LDAP_SERVER | vide | Adresse du contrôleur de domaine (dc01.corp.local) |
LDAP_PORT | 389 | Port LDAP (389 ou 636 en SSL) |
LDAP_BASE_DN | vide | Base de recherche : DC=corp,DC=local |
LDAP_BIND_DN | vide | DN du compte de service |
LDAP_BIND_PASSWORD | vide | Mot de passe du compte de service |
LDAP_ROLE_ADMIN | vide | DN du groupe AD → rôle admin |
LDAP_ROLE_OPERATOR | vide | DN du groupe AD → rôle éditeur |
LDAP_ROLE_VIEWER | vide | DN du groupe AD → rôle lecteur |
OIDC_ENABLED | false | Active l'authentification SSO OIDC |
OIDC_ISSUER_URL | vide | URL du provider OIDC (https://sso.corp.local/realms/gateo) |
OIDC_CLIENT_ID | vide | Client ID OIDC |
OIDC_CLIENT_SECRET | vide | Client Secret OIDC |
Docker Compose
Docker Compose est la méthode recommandée pour les déploiements sur une VM ou un serveur bare-metal.
Structure des fichiers
# Structure recommandée
gateo/
├── docker-compose.yml
├── .env # Ne jamais commiter ce fichier
├── data/
│ └── gateo.db # Volume SQLite (créé automatiquement)
└── licence/
└── gateo.lic # Fichier de licence
Déploiement minimal avec SQLite
Adapté aux environnements mono-serveur. La base de données SQLite est stockée dans un volume Docker.
Fichier docker-compose.yml
YAMLservices:
gateo:
image: registry.example.com/gateo:latest
container_name: gateo
restart: unless-stopped
ports:
- "8080:8080"
env_file:
- .env
volumes:
- gateo-data:/app/data
- ./licence/gateo.lic:/app/licence/gateo.lic:ro
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 30s
timeout: 5s
retries: 3
volumes:
gateo-data:
Fichier .env
.ENV# ── Obligatoire ──────────────────────────────────
JWT_SECRET=un-secret-long-et-aleatoire-a-generer
ADMIN_USERNAME=admin
ADMIN_PASSWORD=MotDePasseForte!2025
# ── Base de données ───────────────────────────────
DATABASE_URL=sqlite:////app/data/gateo.db
# ── Licence ───────────────────────────────────────
LICENSE_FILE_PATH=/app/licence/gateo.lic
# ── Connecteur ITSM ───────────────────────────────
CONNECTOR_TYPE=ivanti
IVANTI_BASE_URL=https://itsm.corp.local/api/odata/businessobject
IVANTI_AUTH_HEADER=rest_api_key=VOTRE_CLE_API
# ── Logs ──────────────────────────────────────────
LOG_LEVEL=INFO
Générez un JWT_SECRET robuste avec : openssl rand -hex 32. Ce secret chiffre les mots de passe stockés en base et signe les sessions — ne le changez jamais en production sans migration.
Démarrage
SHELL# Premier démarrage (migration DB automatique au CMD)
docker compose up -d
# Vérifier les logs de démarrage
docker compose logs -f gateo
# Vérifier que l'app est up
curl http://localhost:8080/healthz
Déploiement avec PostgreSQL
Recommandé en production pour la durabilité et les performances.
YAMLservices:
postgres:
image: postgres:16-alpine
container_name: gateo-db
restart: unless-stopped
environment:
POSTGRES_DB: gateo
POSTGRES_USER: gateo
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gateo"]
interval: 10s
timeout: 5s
retries: 5
gateo:
image: registry.example.com/gateo:latest
container_name: gateo
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ports:
- "8080:8080"
env_file:
- .env
volumes:
- ./licence/gateo.lic:/app/licence/gateo.lic:ro
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 30s
timeout: 5s
retries: 3
volumes:
pg-data:
Ajoutez dans .env :
.ENVDB_PASSWORD=MotDePasseBDD_Complexe!
DATABASE_URL=postgresql://gateo:${DB_PASSWORD}@postgres:5432/gateo
La migration Alembic (alembic upgrade head) s'exécute automatiquement au démarrage du conteneur Gateo. Elle est idempotente : relancer le conteneur n'applique que les migrations manquantes.
Reverse proxy (Nginx / Traefik)
En production, placez Gateo derrière un reverse proxy pour gérer le TLS.
Exemple Nginx (nginx.conf)
NGINXserver {
listen 443 ssl http2;
server_name gateo.corp.local;
ssl_certificate /etc/ssl/certs/gateo.crt;
ssl_certificate_key /etc/ssl/private/gateo.key;
location / {
proxy_pass http://gateo:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 120s;
}
}
server {
listen 80;
server_name gateo.corp.local;
return 301 https://$host$request_uri;
}
Exemple Traefik (labels Docker Compose)
YAMLgateo:
labels:
- "traefik.enable=true"
- "traefik.http.routers.gateo.rule=Host(`gateo.corp.local`)"
- "traefik.http.routers.gateo.entrypoints=websecure"
- "traefik.http.routers.gateo.tls=true"
- "traefik.http.services.gateo.loadbalancer.server.port=8080"
Kubernetes
Ce guide suppose un cluster fonctionnel avec kubectl configuré. Les manifestes ci-dessous sont compatibles k3s, RKE2, EKS, AKS et GKE.
1. Namespace et Secrets
SHELL# Créer le namespace
kubectl create namespace gateo
# Secret pour les variables sensibles
kubectl create secret generic gateo-env \
--namespace gateo \
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
--from-literal=ADMIN_PASSWORD="MotDePasseForte!2025" \
--from-literal=IVANTI_AUTH_HEADER="rest_api_key=VOTRE_CLE_API" \
--from-literal=DATABASE_URL="postgresql://gateo:mdp@postgres-svc:5432/gateo"
# Secret pour le fichier de licence
kubectl create secret generic gateo-licence \
--namespace gateo \
--from-file=gateo.lic=./gateo.lic
Sécurité des Secrets K8s. Par défaut les Secrets Kubernetes ne sont pas chiffrés au repos dans etcd. En production, activez Encryption at Rest ou utilisez un gestionnaire de secrets externe (HashiCorp Vault, AWS Secrets Manager, Sealed Secrets).
2. ConfigMap + Deployment
YAML — gateo-deployment.yamlapiVersion: v1
kind: ConfigMap
metadata:
name: gateo-config
namespace: gateo
data:
APP_PORT: "8080"
LOG_LEVEL: "INFO"
CONNECTOR_TYPE: "ivanti"
IVANTI_BASE_URL: "https://itsm.corp.local/api/odata/businessobject"
ADMIN_USERNAME: "admin"
LICENSE_FILE_PATH: "/licence/gateo.lic"
DEDUP_ENABLED: "true"
REOPEN_ENABLED: "true"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateo
namespace: gateo
labels:
app: gateo
spec:
replicas: 1
selector:
matchLabels:
app: gateo
template:
metadata:
labels:
app: gateo
spec:
containers:
- name: gateo
image: registry.example.com/gateo:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: gateo-config
- secretRef:
name: gateo-env
volumeMounts:
- name: licence
mountPath: /licence
readOnly: true
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 30
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: licence
secret:
secretName: gateo-licence
SQLite + replicas > 1. SQLite ne supporte pas les écritures concurrentes multi-pods. Maintenez replicas: 1 avec SQLite, ou passez à PostgreSQL pour scaler horizontalement.
3. Service et Ingress
YAML — gateo-service.yamlapiVersion: v1
kind: Service
metadata:
name: gateo-svc
namespace: gateo
spec:
selector:
app: gateo
ports:
- port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gateo-ingress
namespace: gateo
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- gateo.corp.local
secretName: gateo-tls
rules:
- host: gateo.corp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gateo-svc
port:
number: 80
4. Persistance de la base de données (PVC — SQLite)
Si vous utilisez SQLite en Kubernetes, montez un PersistentVolumeClaim pour que la base survive aux redémarrages du pod.
YAML — gateo-pvc.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gateo-data
namespace: gateo
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 5Gi
# storageClassName: "local-path" # k3s, adapter selon votre cluster
Ajoutez dans le Deployment :
YAML — extrait volumes# Sous spec.template.spec.containers[].volumeMounts
- name: data
mountPath: /app/data
# Sous spec.template.spec.volumes
- name: data
persistentVolumeClaim:
claimName: gateo-data
Et dans le ConfigMap :
YAMLDATABASE_URL: "sqlite:////app/data/gateo.db"
5. Appliquer les manifestes
SHELL# Appliquer dans l'ordre
kubectl apply -f gateo-pvc.yaml
kubectl apply -f gateo-deployment.yaml
kubectl apply -f gateo-service.yaml
# Vérifier le déploiement
kubectl -n gateo rollout status deployment/gateo
# Consulter les logs de migration
kubectl -n gateo logs deployment/gateo --since=5m
# Accéder au pod directement (debug)
kubectl -n gateo exec -it deployment/gateo -- sh
Installer la licence
Sans fichier .lic, Gateo démarre en période d'essai 14 jours avec toutes les fonctionnalités actives (sauf IA). Au-delà, l'application passe en mode lecture seule.
Docker Compose
SHELL# Déposer le fichier de licence
mkdir -p ./licence
cp /chemin/vers/votre.lic ./licence/gateo.lic
# Le volume est déjà déclaré dans docker-compose.yml :
# ./licence/gateo.lic:/app/licence/gateo.lic:ro
# Redémarrer pour que Gateo charge la licence
docker compose restart gateo
# Vérifier dans les logs
docker compose logs gateo | grep -i licen
Kubernetes
SHELL# Mettre à jour le secret avec la nouvelle licence
kubectl create secret generic gateo-licence \
--namespace gateo \
--from-file=gateo.lic=./gateo.lic \
--dry-run=client -o yaml | kubectl apply -f -
# Redémarrer le pod pour recharger le secret monté
kubectl -n gateo rollout restart deployment/gateo
# Vérifier le statut de la licence via l'API
kubectl -n gateo exec -it deployment/gateo -- \
curl -s http://localhost:8080/api/license/status | python3 -m json.tool
SSL & proxy d'entreprise
Dans les environnements avec inspection TLS (Netskope, Zscaler, proxy Squid avec CA interne), les appels sortants vers les ITSM et services de notification échouent avec une erreur de certificat. Injectez le certificat CA de votre entreprise via une variable d'environnement.
Docker Compose
YAMLgateo:
volumes:
- ./licence/gateo.lic:/app/licence/gateo.lic:ro
- /etc/ssl/certs/ca-corp.crt:/etc/ssl/certs/ca-corp.crt:ro
environment:
REQUESTS_CA_BUNDLE: /etc/ssl/certs/ca-corp.crt
Kubernetes
SHELL# Créer un ConfigMap avec le certificat CA
kubectl create configmap gateo-ca-bundle \
--namespace gateo \
--from-file=ca-corp.crt=/chemin/vers/ca-corp.crt
YAML — ajout dans le Deployment# volumeMounts
- name: ca-bundle
mountPath: /etc/ssl/certs/ca-corp.crt
subPath: ca-corp.crt
readOnly: true
# volumes
- name: ca-bundle
configMap:
name: gateo-ca-bundle
# env (dans le container)
- name: REQUESTS_CA_BUNDLE
value: /etc/ssl/certs/ca-corp.crt
Vérification post-déploiement
-
Health check
Vérifie que l'application est démarrée et que la base est accessible.
curl -s http://localhost:8080/healthz # Attendu : {"status":"ok"} -
Statut de la licence
Vérifie que le fichier
.licest bien lu et valide.curl -s http://localhost:8080/api/license/status | python3 -m json.tool # "status": "valid" → licence OK # "status": "grace_period" → aucun fichier .lic, période d'essai -
Connexion à l'interface
Ouvrez
https://gateo.corp.localet connectez-vous avecADMIN_USERNAME/ADMIN_PASSWORD. -
Test du connecteur ITSM
Dans Paramètres → ITSM, cliquez sur Tester la connexion. Un retour vert confirme que Gateo atteint votre ITSM.
-
Envoyer une alerte de test
Envoyez une alerte Alertmanager factice pour valider le flux complet.
curl -X POST http://localhost:8080/alertmanager \ -H "Content-Type: application/json" \ -d '{"alerts":[{"status":"firing","labels":{"alertname":"TestGateo","severity":"warning","instance":"test-01"},"annotations":{"summary":"Test de déploiement"}}]}' # Attendu : {"status":"ok","processed":1}
Mise à jour
Docker Compose
SHELL# Récupérer la nouvelle image
docker compose pull gateo
# Redémarrer (migration automatique au démarrage)
docker compose up -d gateo
# Vérifier les logs de migration
docker compose logs -f gateo --since=2m
Kubernetes
SHELL# Mettre à jour le tag d'image dans le Deployment
kubectl -n gateo set image deployment/gateo gateo=registry.example.com/gateo:v1.5.0
# Ou via un rolling update (si imagePullPolicy: Always et tag :latest)
kubectl -n gateo rollout restart deployment/gateo
# Suivre le rollout
kubectl -n gateo rollout status deployment/gateo
# Rollback si nécessaire
kubectl -n gateo rollout undo deployment/gateo
Migrations automatiques. Le CMD du conteneur exécute alembic upgrade head avant de lancer uvicorn. Les mises à jour qui ajoutent des tables ou colonnes sont donc appliquées sans intervention manuelle.