v1.x Self-hosted

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

OutilVersion minimaleUsage
docker24+Build & run des conteneurs
docker composev2 (plugin)Orchestration locale
kubectl1.27+Déploiement Kubernetes
Cluster Kubernetes1.27+k3s, RKE2, EKS, AKS, GKE…
Image Gateodernière stableregistry.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

VariableDéfautDescription
APP_HOST0.0.0.0Interface d'écoute
APP_PORT8080Port d'écoute
LOG_LEVELINFODEBUG / INFO / WARNING / ERROR
DATABASE_URLsqlite:///./gateo.dbURL SQLAlchemy. PostgreSQL : postgresql://user:pass@host/db
JWT_SECRETchange-me-in-productionÀ changer impérativement. Clé de signature des tokens JWT et de chiffrement des secrets en base.
JWT_EXPIRE_HOURS8Durée de vie des sessions utilisateur (heures)
ADMIN_USERNAMEadminLogin du compte admin bootstrapé au premier démarrage
ADMIN_PASSWORDchangemeÀ changer impérativement.

Licence

VariableDéfautDescription
LICENSE_FILE_PATHgateo.licChemin absolu ou relatif au CWD vers le fichier .lic. Sans fichier : période d'essai 14 jours.

Connecteur ITSM

VariableDéfautDescription
CONNECTOR_TYPEivantiivanti / jira / pagerduty / none
IVANTI_BASE_URLrequisURL de base de l'API Ivanti ISM
IVANTI_AUTH_HEADERrequisToken d'authentification Ivanti (rest_api_key=XXX)
IVANTI_ALERTS_ENDPOINTalertsNom de la Business Object collection
DRY_RUNfalsetrue : simule les appels ITSM sans écrire

Comportement alertes

VariableDéfautDescription
DEDUP_ENABLEDtrueActive la déduplication des alertes
DEDUP_TTL_SECONDS3600Fenêtre de déduplication (secondes)
CORRELATION_WINDOW_SECONDS300Fenêtre de corrélation des alertes parentes/enfants
REOPEN_ENABLEDtrueRéouvre les tickets fermés si l'alerte re-fire
REOPEN_WINDOW_SECONDS1800Fenêtre de réouverture (secondes)

SMTP (notifications e-mail)

VariableDéfautDescription
SMTP_HOSTlocalhostServeur SMTP
SMTP_PORT587Port SMTP
SMTP_FROMgateo@localhostAdresse expéditeur
SMTP_TLSstarttlsnone / starttls / ssl
SMTP_USERNAMEvideAuthentification SMTP (optionnel)
SMTP_PASSWORDvideAuthentification SMTP (optionnel)

SSL / Proxy d'entreprise

VariableDéfautDescription
REQUESTS_CA_BUNDLEvideChemin absolu vers un bundle CA personnalisé (Netskope, Zscaler, proxy SSL)
HTTP_CA_BUNDLEvideAlias Gateo (même effet que REQUESTS_CA_BUNDLE)
SSL_CERT_FILEvideConvention Python standard

Authentification LDAP / OIDC

VariableDéfautDescription
LDAP_ENABLEDfalseActive l'authentification LDAP/Active Directory
LDAP_SERVERvideAdresse du contrôleur de domaine (dc01.corp.local)
LDAP_PORT389Port LDAP (389 ou 636 en SSL)
LDAP_BASE_DNvideBase de recherche : DC=corp,DC=local
LDAP_BIND_DNvideDN du compte de service
LDAP_BIND_PASSWORDvideMot de passe du compte de service
LDAP_ROLE_ADMINvideDN du groupe AD → rôle admin
LDAP_ROLE_OPERATORvideDN du groupe AD → rôle éditeur
LDAP_ROLE_VIEWERvideDN du groupe AD → rôle lecteur
OIDC_ENABLEDfalseActive l'authentification SSO OIDC
OIDC_ISSUER_URLvideURL du provider OIDC (https://sso.corp.local/realms/gateo)
OIDC_CLIENT_IDvideClient ID OIDC
OIDC_CLIENT_SECRETvideClient 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

  1. 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"}
  2. Statut de la licence

    Vérifie que le fichier .lic est 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
  3. Connexion à l'interface

    Ouvrez https://gateo.corp.local et connectez-vous avec ADMIN_USERNAME / ADMIN_PASSWORD.

  4. Test du connecteur ITSM

    Dans Paramètres → ITSM, cliquez sur Tester la connexion. Un retour vert confirme que Gateo atteint votre ITSM.

  5. 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.