Guide de déploiement

Installer Apache Airflow sur VPS : Docker Compose et PostgreSQL

Déployer sur un VPS Cloud →

Tutoriel

Installer Apache Airflow sur VPS : Docker Compose et PostgreSQL

Automatisation12 min de lecture9 étapes

Apache Airflow est la référence open source pour orchestrer des pipelines de données, des workflows ETL et des tâches ML en Python. Self-hébergé sur un VPS, il vous affranchit des coûts d'un service managé (Cloud Composer, MWAA) tout en gardant un contrôle total sur vos données et dépendances. Ce guide part de zéro et va jusqu'à une configuration prête pour la production : PostgreSQL comme base de métadonnées (ne jamais utiliser SQLite sur des volumes Docker), CeleryExecutor pour distribuer les tâches, connexions et variables secrètes chiffrées, et les bons réflexes pour déboguer rapidement.

Sommaire· Pourquoi héberger Apache Airflow sur votre propre VPS1/13
  1. 01Pourquoi héberger Apache Airflow sur votre propre VPS
  2. 02Ce qu'Airflow orchestre concrètement
  3. 03Prérequis VPS et stack technique
  4. 04Architecture Docker Compose d'Airflow
  5. 05Déployer Airflow 3.x avec Docker Compose
  6. 06Configurer PostgreSQL comme backend de métadonnées
  7. 07Passer au CeleryExecutor pour plusieurs workers
  8. 08Gérer les connexions et les variables secrètes
  9. 09Créer et tester votre premier DAG Python
  10. 10Sécuriser votre installation Airflow
  11. 11LocalExecutor vs CeleryExecutor vs KubernetesExecutor
  12. 12Mettre à jour Airflow sans coupure
  13. 13Déboguer et lire les logs Airflow

Pourquoi héberger Apache Airflow sur votre propre VPS

Les orchestrateurs cloud comme Cloud Composer (Google) ou MWAA (Amazon) embarquent Airflow en service managé, mais facturent l'environnement à l'heure — indépendamment de votre charge réelle. En self-hébergeant sur un VPS, vous payez uniquement le serveur et vos DAG s'exécutent au plus près de vos sources de données internes, sans transit réseau externe. La liberté va plus loin : vous choisissez la version d'Airflow, les providers Python, les connexions à vos bases, l'exécuteur (Local, Celery, Kubernetes). Pour des pipelines qui tournent sur des données sensibles ou des environnements réglementés, rester on-premise avec un VPS dédié n'est pas une option mais une contrainte. Enfin, le coût : un VPS 4 vCPU / 8 Go RAM revient à une fraction d'un environnement managé pour la même charge de travail quotidienne.

Ce qu'Airflow orchestre concrètement

  • Data pipelines et ETL — extraire depuis des API ou des bases, transformer et charger vers un data warehouse.
  • Workflows ML — entraînement de modèles, évaluation, déploiement automatisé avec des dépendances entre étapes.
  • Tâches planifiées complexes — backfills, catchups, gestion des échecs avec retry configurable par tâche.
  • Intégrations tierces — plus de 80 providers officiels : PostgreSQL, MySQL, S3, BigQuery, dbt, Spark, Kubernetes, HTTP.
  • Pipelines de rapport — génération automatique de rapports périodiques et envoi par e-mail ou Slack.
  • Orchestration de microservices — déclencher des jobs distants via API et attendre leur résultat avant d'enchaîner.

Prérequis VPS et stack technique

Airflow est la stack la plus gourmande en ressources de cette catégorie car elle fait tourner en parallèle plusieurs services. Pour la production : 4 vCPU et 8 Go de RAM minimum — choisissez un VPS Power ou un VPS dédié pour commencer. Pour le développement ou les tests : 2 vCPU et 4 Go de RAM suffisent en LocalExecutor (sans Celery ni Redis). Prévoyez 40 Go de disque SSD pour les logs et les métadonnées. Sur le plan logiciel : Docker 24+ et Docker Compose v2 (vérifiez avec docker compose version, pas l'ancien docker-compose v1 qui ne supporte pas tous les healthchecks), Ubuntu 22.04 LTS ou Debian 12, et un nom de domaine pointant vers votre VPS pour le reverse proxy HTTPS.

Architecture Docker Compose d'Airflow

Le fichier docker-compose.yaml officiel d'Airflow déploie six services qui forment une architecture complète. Le webserver sert l'interface graphique sur le port 8080 : visualisation des DAG, déclenchement manuel, consultation des logs. Le scheduler est le cœur du système : il analyse les DAG, planifie les tâches selon leur schedule et leurs dépendances, et les remet aux workers. Le worker exécute les tâches confiées par le scheduler — vous pouvez en lancer plusieurs pour la parallélisation. Le triggerer gère les tâches deferables (sensors asynchrones Airflow 2.2+) sans bloquer de slots worker. PostgreSQL est la base de métadonnées d'Airflow : état des DAG runs, logs structurés, XComs, variables et connexions — c'est le composant le plus critique. Redis sert de broker de messages entre le scheduler et les workers Celery : chaque tâche prête à l'exécution transite par une queue Redis avant d'être prise en charge par un worker disponible.

Déployer Airflow 3.x avec Docker Compose

  1. Récupérer le docker-compose officiel et créer les répertoires

    Créez le répertoire de travail, descendez le fichier de référence et préparez les dossiers montés en volumes :

    mkdir -p /opt/airflow && cd /opt/airflow
    curl -LfO 'https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml'
    mkdir -p ./dags ./logs ./plugins ./config

    Ces dossiers doivent exister avant de lancer les conteneurs. Si Docker les crée lui-même, il leur attribue le propriétaire root et Airflow ne peut pas y écrire.

  2. Configurer le fichier .env (UID, PostgreSQL, clé secrète)

    Créez /opt/airflow/.env avec les variables essentielles :

    echo "AIRFLOW_UID=$(id -u)" > .env
    echo "AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=postgresql+psycopg2://airflow:airflow@postgres/airflow" >> .env
    echo "AIRFLOW__CORE__FERNET_KEY=$(python3 -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())')" >> .env

    AIRFLOW_UID aligne les permissions des volumes sur votre utilisateur système. AIRFLOW__DATABASE__SQL_ALCHEMY_CONN force PostgreSQL — la valeur par défaut du compose officiel utilise déjà PostgreSQL, mais la rendre explicite dans .env évite toute confusion. FERNET_KEY chiffre les connexions et variables stockées en base — générez-la une seule fois et sauvegardez-la : si vous la perdez, toutes vos connexions secrètes deviennent illisibles.

  3. Initialiser la base de données

    Appliquez les migrations et créez le premier compte administrateur :

    docker compose up airflow-init

    Le conteneur airflow-init se connecte à PostgreSQL, applique toutes les migrations de schéma et crée l'utilisateur airflow (mot de passe airflow). Attendez l'exit code 0 — un code différent indique un problème de connexion à la base (PostgreSQL pas encore healthy) ou une image manquante. Changez le mot de passe dès votre première connexion via l'UI ou la commande docker compose exec airflow-webserver airflow users reset-password.

  4. Démarrer tous les services

    Lancez la stack complète en arrière-plan :

    docker compose up -d
    docker compose ps

    Tous les conteneurs doivent passer à l'état healthy en une à trois minutes. Si un service reste en starting, consultez ses logs :

    docker compose logs airflow-scheduler --tail=50

    Le webserver est accessible sur http://localhost:8080. N'ouvrez pas ce port publiquement — passez par un reverse proxy.

  5. Créer un compte administrateur personnalisé

    Le compte airflow/airflow créé par airflow-init est à usage unique. Créez votre compte permanent :

    docker compose exec airflow-webserver airflow users create \
      --username admin \
      --firstname Prenom \
      --lastname Nom \
      --role Admin \
      --email [email protected] \
      --password VotreMotDePasseSolide

    Supprimez ensuite le compte par défaut via Admin → Users dans l'interface web.

  6. Exposer Airflow derrière un reverse proxy avec SSL

    N'exposez jamais le port 8080 directement — l'UI Airflow affiche des connexions, des variables et des logs sensibles. Avec Caddy (recommandé pour la simplicité du TLS automatique) :

    apt install -y caddy
    cat > /etc/caddy/Caddyfile << 'EOF'
    airflow.votredomaine.com {
        reverse_proxy localhost:8080
    }
    EOF
    systemctl reload caddy
    ufw deny 8080

    Caddy obtient et renouvelle automatiquement le certificat Let's Encrypt. Avec nginx, créez un vhost standard en proxy_pass http://127.0.0.1:8080 et bloquez le port avec ufw deny 8080.

Configurer PostgreSQL comme backend de métadonnées

Ne jamais utiliser SQLite en production avec Airflow sur Docker. SQLite n'est pas conçu pour des accès concurrents multiples : le scheduler, le webserver et les workers accèdent à la base simultanément, et SQLite sur un volume Docker a des limites de verrouillage qui causent des corruptions et des pertes de données — le projet Airflow documente explicitement cet avertissement depuis la version 2.0. Le fichier docker-compose.yaml officiel inclut déjà un service PostgreSQL 13, mais vérifiez que votre .env force bien la connexion :

AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=postgresql+psycopg2://airflow:airflow@postgres/airflow

Pour une production robuste, personnalisez le mot de passe PostgreSQL. Dans docker-compose.yaml, cherchez la section postgres et modifiez POSTGRES_PASSWORD. Mettez à jour AIRFLOW__DATABASE__SQL_ALCHEMY_CONN en conséquence. Sauvegardez la base PostgreSQL régulièrement avec docker compose exec postgres pg_dump -U airflow airflow > backup_$(date +%Y%m%d).sql. Si vous gérez déjà un serveur PostgreSQL externe, supprimez le service postgres du compose et pointez SQL_ALCHEMY_CONN vers votre instance : c'est la configuration recommandée pour les installations multi-VPS.

Passer au CeleryExecutor pour plusieurs workers

Le LocalExecutor (défaut dans certaines configs) exécute les tâches dans des sous-processus du scheduler — simple, mais limité à un seul nœud. Le CeleryExecutor découple l'exécution : le scheduler pousse les tâches dans une queue Redis, et un ou plusieurs workers les consomment indépendamment. Le fichier docker-compose.yaml officiel active CeleryExecutor par défaut. Pour scale-out, dupliquez simplement le service worker :

docker compose up -d --scale airflow-worker=3

Cela démarre trois workers qui consomment la même queue Redis en parallèle. Chaque worker prend en charge parallelism tâches simultanées (configurable via AIRFLOW__CORE__PARALLELISM, défaut 32). Pour distribuer les workers sur plusieurs VPS, pointez-les tous vers le même Redis et le même PostgreSQL — c'est l'architecture Celery standard. Ajoutez AIRFLOW__CELERY__WORKER_CONCURRENCY=8 dans .env pour affiner la concurrence par worker selon les ressources disponibles sur chaque nœud.

Gérer les connexions et les variables secrètes

Airflow chiffre les connexions et variables sensibles en base grâce à la FERNET_KEY configurée dans .env. Via l'UI : Admin → Connections → Add Connection — renseignez l'URI complète ou les champs individuels (host, login, password, port). Ces valeurs sont chiffrées avec Fernet avant écriture en base. Via les variables d'environnement (recommandé pour les CI/CD) : une variable d'env préfixée AIRFLOW_CONN_ surpasse toute connexion enregistrée en base. Exemple dans .env :

AIRFLOW_CONN_MON_POSTGRES=postgresql://user:password@host:5432/dbname

Le nom de la connexion dans vos DAG est alors mon_postgres (le préfixe et les majuscules sont retirés). Secret Backend : pour les environnements Kubernetes ou cloud, configurez AIRFLOW__SECRETS__BACKEND=airflow.providers.amazon.aws.secrets.secrets_manager.SecretsManagerBackend (ou HashiCorp Vault, GCP Secret Manager) — Airflow résoudra les connexions depuis votre coffre-fort plutôt que depuis PostgreSQL. Variables : Admin → Variables dans l'UI, ou via env AIRFLOW_VAR_NOM_DE_LA_VARIABLE. Évitez de stocker des secrets dans les Variables non chiffrées — préférez les Connections ou le Secret Backend.

Créer et tester votre premier DAG Python

  1. Créer le fichier DAG dans le dossier /dags

    Créez /opt/airflow/dags/mon_premier_dag.py :

    from airflow.sdk import DAG, task
    from datetime import datetime
    
    with DAG(
        dag_id='mon_premier_dag',
        schedule='@daily',
        start_date=datetime(2025, 1, 1),
        catchup=False,
        tags=['exemple'],
    ) as dag:
    
        @task
        def extraire():
            return {'lignes': 42}
    
        @task
        def transformer(donnees: dict):
            print(f"Traitement de {donnees['lignes']} lignes")
            return donnees['lignes'] * 2
    
        @task
        def charger(resultat: int):
            print(f"Résultat final : {resultat}")
    
        charger(transformer(extraire()))

    Notez l'utilisation de schedule (et non schedule_interval, supprimé en Airflow 3).

  2. Vérifier que le scheduler parse le DAG sans erreur

    Le scheduler détecte et parse automatiquement les fichiers .py du dossier dags. Vérifiez manuellement :

    docker compose exec airflow-scheduler airflow dags list | grep mon_premier_dag

    Si le DAG n'apparaît pas après 30 secondes, cherchez les erreurs de parsing :

    docker compose logs airflow-scheduler | grep -i 'error\|exception' | tail -20

    Une erreur d'import Python dans le fichier DAG empêche toute la détection — corrigez la syntaxe et le scheduler relancera automatiquement le parsing.

  3. Déclencher une exécution manuelle et inspecter les logs

    Dans l'UI Airflow (https://airflow.votredomaine.com), naviguez vers DAGs, trouvez mon_premier_dag, activez-le (toggle), puis cliquez sur ▶ Trigger DAG. Suivez l'exécution en temps réel dans la vue Graph ou Grid. Cliquez sur une tâche, puis sur Logs pour voir la sortie standard de la fonction. Depuis le terminal :

    docker compose exec airflow-scheduler airflow dags trigger mon_premier_dag
    docker compose exec airflow-scheduler airflow dags state mon_premier_dag $(date +%Y-%m-%dT%H:%M:%S+00:00)

Sécuriser votre installation Airflow

Une installation Airflow expose potentiellement vos connexions de bases de données, vos variables et vos logs d'exécution. Appliquez ces mesures dès le déploiement. Authentification : par défaut, Airflow 3 utilise FAB (Flask-AppBuilder) avec authentification par mot de passe. Pour une organisation, connectez Airflow à votre annuaire via AIRFLOW__WEBSERVER__AUTH_BACKEND=airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager avec LDAP, ou activez OAuth2 (GitHub, Google, Azure AD) en configurant le provider FAB correspondant. Désactiver les DAG d'exemple : ajoutez dans .env :

AIRFLOW__CORE__LOAD_EXAMPLES=False

Ces DAG fictifs encombrent l'UI et peuvent induire en erreur. Pare-feu sur le port 8080 : ufw deny 8080 — seul le reverse proxy doit y accéder depuis localhost. Pas de clé Fernet dans les logs : ne loggez jamais os.environ, qui imprimerait la FERNET_KEY en clair. Rotation des secrets : si vous devez changer la FERNET_KEY, utilisez airflow db rotate-fernet-key pour rechiffrer toutes les connexions stockées avant de mettre à jour la variable.

LocalExecutor vs CeleryExecutor vs KubernetesExecutor

Faites défiler le tableau

CritèreLocalExecutorCeleryExecutorKubernetesExecutor
Ressources nécessaires2 vCPU / 4 Go RAM4 vCPU / 8 Go RAM + RedisCluster Kubernetes requis
ParallélismeLimité au nombre de CPU du schedulerHorizontal — autant de workers que nécessaireUn pod par tâche — parallélisme quasi sans borne
Isolation des tâchesSous-processus partagésWorkers séparés, même imagePod isolé par tâche, image configurable
Complexité opérationnelleSimple — pas de RedisModérée — Redis à maintenirÉlevée — nécessite Kubernetes
Cas d'usage idéalDev, tests, pipelines légersProduction VPS, charge variableCloud-native, isolation forte requise

Mettre à jour Airflow sans coupure

Pour une mise à jour rolling sans interrompre les DAG en cours : commencez par mettre à jour l'image dans docker-compose.yaml (ex. apache/airflow:3.3.1). Arrêtez uniquement le webserver et le scheduler, appliquez les migrations, puis redémarrez service par service. Les workers Celery continuent d'exécuter les tâches déjà démarrées pendant la migration :

docker compose stop airflow-webserver airflow-scheduler
docker compose pull
docker compose up -d airflow-webserver airflow-scheduler
docker compose exec airflow-scheduler airflow db upgrade
docker compose up -d

Toujours consulter le CHANGELOG officiel entre les versions mineures — certaines migrations de schéma sont irréversibles. Gardez une sauvegarde PostgreSQL fraîche avant toute montée de version.

Déboguer et lire les logs Airflow

Airflow génère des logs à plusieurs niveaux et comprendre leur organisation accélère considérablement le débogage. Logs de tâches : chaque tâche écrit dans ./logs/dag_id/run_id/task_id/. Accessibles depuis l'UI (clic sur la tâche → Logs) ou en ligne de commande :

docker compose exec airflow-scheduler airflow tasks logs mon_premier_dag extraire 2025-01-01

Logs du scheduler : le plus important pour diagnostiquer les DAG qui ne se déclenchent pas :

docker compose logs airflow-scheduler --follow --tail=100

Remote logging : pour des installations multi-workers ou des logs à longue rétention, déportez vers S3 ou GCS :

AIRFLOW__LOGGING__REMOTE_LOGGING=True
AIRFLOW__LOGGING__REMOTE_BASE_LOG_FOLDER=s3://mon-bucket/airflow-logs
AIRFLOW__LOGGING__REMOTE_LOG_CONN_ID=mon_aws

log_filename_template : le nom du fichier de log est configurable via AIRFLOW__LOGGING__LOG_FILENAME_TEMPLATE. Le défaut produit des chemins courts mais vous pouvez l'ajuster pour mieux organiser les logs par date. Erreurs silencieuses : si un DAG disparaît de l'UI sans message, cherchez les import errors du scheduler :

docker compose exec airflow-webserver airflow dags list-import-errors

Purge des logs anciens : configurez AIRFLOW__LOG_RETENTION_DAYS=30 pour éviter la saturation du disque — le dossier ./logs peut rapidement atteindre plusieurs gigaoctets sur des pipelines fréquents.

Le VPS Cloud idéal pour Apache Airflow

Airflow 3 en mode Celery réclame de la RAM et plusieurs conteneurs. Le VPS Cloud ServOrbit fournit les ressources, Docker préconfiguré et SSL automatique pour héberger votre ordonnanceur data en self-hosted, à coût maîtrisé.

Besoin d'aide ?

Parcourez notre centre d'aide et notre FAQ, ou contactez notre équipe — rappel, WhatsApp ou e-mail. Support en français, anglais et arabe.

Écrire sur WhatsApps'ouvre dans un nouvel onglet