|
Ce document a été traduit automatiquement depuis l’anglais par Claude AI. Les termes du domaine WMO/météorologique doivent être vérifiés par un locuteur natif avant toute utilisation en production. Consultez le lien:../en/[document original en anglais] pour la version faisant autorité. |
1. Déploiement
1.1. Prérequis
-
Docker 20.10+
-
Docker Compose 2.0+
-
4 Go de RAM minimum (8 Go recommandés pour la production)
-
Accès réseau au courtier global WIS2 (port 443)
1.2. Installation
git clone https://github.com/World-Meteorological-Organization/wis2downloader
cd wis2downloader
cp default.env .env
Modifiez .env pour configurer votre déploiement, puis démarrez :
docker-compose up -d
1.3. Configuration de sécurité
Avant de déployer en production, vous devez configurer ces paramètres de sécurité dans votre fichier .env :
|
-
REDIS_PASSWORD- Définissez un mot de passe fort et unique (obligatoire) -
FLASK_SECRET_KEY- Définissez une clé secrète cryptographiquement aléatoire (obligatoire) -
FLASK_DEBUG- Définissez àfalseen production -
Mot de passe Grafana - Changez le mot de passe par défaut
admin/adminaprès la première connexion
Le fichier .env contient des identifiants sensibles. Assurez-vous qu’il est :
-
Non versionné (ajoutez-le à
.gitignore) -
Lisible uniquement par l’utilisateur de déploiement (
chmod 600 .env) -
Sauvegardé de manière sécurisée
1.3.1. Contrôle d’accès
| WIS2 Downloader n’implémente pas d’authentification ni d’autorisation sur l’interface web ou l’API REST du gestionnaire d’abonnements. Toute personne ayant accès au réseau sur l’interface (port 8080) ou l’API (port 5002) peut consulter, créer, modifier et supprimer des abonnements. |
Dans un environnement partagé ou accessible depuis Internet, vous devez restreindre l’accès au niveau réseau. Approches recommandées :
-
Proxy inverse avec authentification — Placez nginx ou Caddy devant les ports de l’interface et de l’API, en imposant une authentification HTTP Basic ou OAuth avant de transmettre les requêtes. Une configuration nginx minimale :
location / { auth_basic "WIS2 Downloader"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://localhost:8080; } -
Règles de pare-feu — Restreignez les ports 8080 et 5002 aux plages d’adresses IP de confiance à l’aide de
iptables,ufwou de groupes de sécurité cloud. -
VPN / réseau privé — Déployez derrière un VPN afin que seuls les utilisateurs VPN authentifiés puissent atteindre les services.
Si le système s’exécute sur un serveur plutôt que sur localhost, assurez-vous que les ports 8080 et 5002 ne sont pas accessibles publiquement avant d’ajouter l’un des contrôles d’accès ci-dessus.
1.4. Permissions de volumes
Les conteneurs de l’application s’exécutent en tant qu’utilisateur non-root (wis2) pour des raisons de sécurité. Pour permettre aux conteneurs d’écrire les fichiers téléchargés sur le système de fichiers hôte, vous devez configurer les permissions appropriées sur le répertoire downloads/.
1.4.1. Détails de l’utilisateur du conteneur
| Propriété | Valeur |
|---|---|
Nom d’utilisateur |
|
Identifiant utilisateur (UID) |
|
Nom du groupe |
|
Identifiant de groupe (GID) |
|
Le worker Celery écrit les fichiers dans /data à l’intérieur du conteneur, ce qui correspond à ./downloads/ sur l’hôte.
1.4.2. Option 1 : Créer un utilisateur/groupe correspondant (Recommandé)
Créez un utilisateur et un groupe sur le système hôte correspondant aux UID/GID du conteneur :
# Créer le groupe wis2 avec GID 988
sudo groupadd -g 988 wis2
# Créer l'utilisateur wis2 avec UID 10001
sudo useradd -u 10001 -g wis2 -M -s /usr/sbin/nologin wis2
# Définir les droits sur le répertoire de téléchargements
sudo mkdir -p downloads
sudo chown -R wis2:wis2 downloads
1.4.3. Option 2 : Utiliser les ACL (Flexible)
Si vous ne pouvez pas créer un utilisateur/groupe correspondant, utilisez les listes de contrôle d’accès POSIX pour accorder au UID du conteneur un accès en écriture :
# Vérifier que le support ACL est installé
sudo apt-get install acl # Debian/Ubuntu
sudo yum install acl # RHEL/CentOS
# Créer le répertoire de téléchargements
mkdir -p downloads
# Accorder un accès complet à UID 10001
sudo setfacl -R -m u:10001:rwx downloads
sudo setfacl -R -d -m u:10001:rwx downloads # Default ACL for new files
1.4.4. Option 3 : Répertoire permissif
| Cette approche est moins sécurisée et n’est pas recommandée pour la production. |
mkdir -p downloads
chmod 777 downloads
1.4.5. Vérification des permissions
Testez que le conteneur peut écrire dans le volume :
# Démarrer le conteneur celery
docker-compose up -d celery
# Tester l'accès en écriture depuis l'intérieur du conteneur
docker exec celery touch /data/test-write && echo "Write OK" || echo "Write FAILED"
# Nettoyer
docker exec celery rm -f /data/test-write
Si le test échoue avec "Permission denied", vérifiez la propriété et les permissions du répertoire downloads/ sur l’hôte.
1.4.6. Accès partagé avec les utilisateurs hôtes
Si vous avez besoin que des utilisateurs hôtes puissent lire les fichiers téléchargés, ajoutez-les au groupe wis2 :
# Ajouter votre utilisateur au groupe wis2
sudo usermod -aG wis2 $USER
# Se déconnecter et se reconnecter pour activer l'appartenance au groupe
# Puis vérifier
groups # Should include 'wis2'
Vous pouvez également utiliser les ACL pour accorder un accès en lecture à des utilisateurs spécifiques :
# Accorder un accès en lecture à un utilisateur spécifique
sudo setfacl -R -m u:youruser:rx downloads
sudo setfacl -R -d -m u:youruser:rx downloads
1.5. Vérification du déploiement
Les exemples ci-dessous utilisent localhost. Si le système est déployé sur un serveur distant, remplacez localhost par le nom d’hôte ou l’adresse IP du serveur. Les ports (5002 pour l’API, 8080 pour l’interface) peuvent être modifiés dans docker-compose.yaml si nécessaire.
|
# Vérifier que tous les services sont en cours d'exécution
docker-compose ps
# Vérifier le point de terminaison de santé (gestionnaire d'abonnements)
curl http://localhost:5002/health
# Vérifier que l'interface web est opérationnelle
curl -o /dev/null -s -w "%{http_code}" http://localhost:8080
# Afficher les journaux
docker-compose logs -f subscriber
2. Configuration
2.1. Variables d’environnement
2.1.1. Paramètres de l’application
| Variable | Type | Valeur par défaut | Description |
|---|---|---|---|
|
string |
|
Niveau de journalisation : DEBUG, INFO, WARNING, ERROR |
|
path |
|
Répertoire de base pour les fichiers téléchargés |
|
string |
obligatoire |
Clé secrète de session Flask (l’application échoue si non définie) |
|
boolean |
|
Activer le mode debug Flask (définir à |
|
string |
|
Adresse d’écoute de l’API |
|
integer |
|
Port d’écoute de l’API (interne) |
2.1.2. Paramètres du courtier MQTT
| Variable | Type | Valeur par défaut | Description |
|---|---|---|---|
|
string |
obligatoire |
Nom d’hôte du courtier global WIS2 (ex. : |
|
integer |
|
Port du courtier |
|
string |
|
Nom d’utilisateur MQTT |
|
string |
|
Mot de passe MQTT |
|
string |
|
Protocole de transport : |
|
string |
généré automatiquement |
Identifiant de session persistant pour la reprise après redémarrage |
2.1.3. Paramètres Redis
| Variable | Type | Valeur par défaut | Description |
|---|---|---|---|
|
string |
|
Nom d’hôte du serveur Redis |
|
integer |
|
Port du serveur Redis |
|
integer |
|
Numéro de la base de données Redis |
|
string |
obligatoire |
Mot de passe d’authentification Redis (l’application échoue si non défini) |
|
integer |
|
TTL pour les clés de déduplication |
|
integer |
|
Expiration du verrou pour la prévention des téléchargements simultanés |
2.1.4. Paramètres Celery
| Variable | Type | Valeur par défaut | Description |
|---|---|---|---|
|
string |
|
Chaîne de connexion au courtier Celery (noter le format du mot de passe) |
|
string |
|
Chaîne de connexion au backend de résultats (noter le format du mot de passe) |
2.1.5. Filtrage des téléchargements
| Variable | Type | Valeur par défaut | Description |
|---|---|---|---|
|
string |
vide |
Liste séparée par des virgules des noms d’hôtes de cache global à exclure |
2.1.6. Paramètres de l’interface web
| Variable | Type | Valeur par défaut | Description |
|---|---|---|---|
|
string |
URL interne utilisée par l’interface pour atteindre l’API du gestionnaire d’abonnements |
|
|
string |
URL utilisée pour intégrer les panneaux Grafana dans la vue Tableau de bord |
|
|
string |
|
Clé secrète de stockage de session NiceGUI — définissez une valeur unique en production |
|
integer |
|
Secondes de mise en cache des données du catalogue GDC dans Redis (6 heures par défaut) ; définissez à |
2.2. Structure des fichiers
wis2downloader/
├── config/
│ ├── grafana/provisioning/ # Grafana datasource config
│ ├── loki/ # Loki configuration
│ └── prometheus/ # Prometheus scrape config
├── containers/ # Dockerfiles
├── downloads/ # Downloaded data (mounted volume)
├── modules/ # Python modules
│ ├── shared/ # Shared utilities
│ ├── subscriber/ # MQTT subscriber
│ ├── subscription_manager/ # REST API
│ ├── task_manager/ # Celery tasks
│ └── ui/ # NiceGUI web interface
├── docker-compose.yaml
├── default.env
└── README.adoc
3. Mise à l’échelle
3.1. Redis
Le système utilise une seule instance Redis pour :
-
La messagerie pub/sub entre les services
-
Le stockage de l’état des abonnements
-
Le suivi de la déduplication
-
La file d’attente des tâches Celery et les résultats
Le système utilise une seule instance Redis et ne fournit pas de haute disponibilité. Quelle que soit l’échelle, assurez-vous que les données Redis sont durables :
-
Activez la persistance Redis (AOF + RDB)
-
Mettez en place des sauvegardes régulières du dump Redis
3.2. Mise à l’échelle des workers
Augmentez la concurrence du worker Celery pour un débit plus élevé :
# docker-compose.yaml
celery:
command: ["... --concurrency=16 ..."]
Ou exécutez plusieurs conteneurs workers :
docker-compose up -d --scale celery=3
3.3. Ajout de courtiers globaux
Chaque service abonné se connecte à un seul courtier global WIS2. Pour recevoir des données de plusieurs courtiers, ajoutez des services abonnés supplémentaires dans docker-compose.yaml :
subscriber-france:
container_name: subscriber-france
restart: always
build:
context: .
dockerfile: ./containers/subscriber/Dockerfile
env_file: *default-env
environment:
GLOBAL_BROKER_HOST: globalbroker.meteo.fr
GLOBAL_BROKER_PORT: 443
GLOBAL_BROKER_USERNAME: everyone
GLOBAL_BROKER_PASSWORD: everyone
MQTT_PROTOCOL: websockets
depends_on:
- redis
networks:
- redis-net
logging: *default-logging
subscriber-china:
container_name: subscriber-china
restart: always
build:
context: .
dockerfile: ./containers/subscriber/Dockerfile
env_file: *default-env
environment:
GLOBAL_BROKER_HOST: gb.wis.cma.cn
GLOBAL_BROKER_PORT: 443
GLOBAL_BROKER_USERNAME: everyone
GLOBAL_BROKER_PASSWORD: everyone
MQTT_PROTOCOL: websockets
depends_on:
- redis
networks:
- redis-net
logging: *default-logging
Chaque abonné doit avoir un container_name unique.
|
Tous les abonnés partagent le même backend Redis, de sorte que les abonnements créés via l’API sont reçus par toutes les instances d’abonnés. Les téléchargements sont dédupliqués, donc le même fichier ne sera pas téléchargé deux fois même si des notifications arrivent de plusieurs courtiers.
4. Surveillance
4.1. Métriques Prometheus
Point de terminaison des métriques : http://localhost:5002/metrics
Les métriques sont stockées de manière atomique dans Redis via HINCRBYFLOAT et exposées au point de terminaison /metrics au format texte Prometheus. Cette approche est sûre pour plusieurs conteneurs de workers Celery sans nécessiter de système de fichiers partagé ni le répertoire multiprocessus de prometheus_client.
|
4.1.1. Métriques disponibles
| Métrique | Type | Description |
|---|---|---|
|
Counter |
Messages MQTT reçus avant la mise en file d’attente (étiquettes : broker) ; à comparer avec |
|
Counter |
Total des notifications traitées par Celery (étiquettes : status) |
|
Counter |
Fichiers téléchargés avec succès (étiquettes : cache, media_type) |
|
Counter |
Total des octets téléchargés (étiquettes : cache, media_type) |
|
Counter |
Notifications ignorées par raison (étiquettes : reason) |
|
Counter |
Téléchargements échoués (étiquettes : cache, reason) |
|
Counter |
Échecs de mise en file d’attente d’une tâche Celery depuis l’abonné (étiquettes : broker) |
|
Gauge |
Nombre actuel de tâches dans la file d’attente Celery |
|
Gauge |
Capacité totale du disque du volume de téléchargement |
|
Gauge |
Espace disque utilisé sur le volume de téléchargement |
|
Gauge |
Espace disque disponible sur le volume de téléchargement |
|
Gauge |
Octets utilisés par les fichiers téléchargés (suivi incrémentiel) |
4.1.2. Exemples de requêtes
# Taux de téléchargement par minute
sum(rate(wis2downloader_downloads_total[1m]))
# Téléchargements par cache
sum by (cache) (rate(wis2downloader_downloads_total[5m]))
# Téléchargements échoués par raison
sum by (reason) (wis2downloader_failed_total)
# Octets téléchargés dans la dernière heure
sum(increase(wis2downloader_downloads_bytes_total[1h]))
# Profondeur de la file d'attente
wis2downloader_celery_queue_length
4.2. Grafana
Accédez à Grafana sur http://localhost:3000 (identifiants par défaut : admin/admin)
Changez le mot de passe Grafana par défaut après la première connexion ou configurez-le via la variable d’environnement GF_SECURITY_ADMIN_PASSWORD pour les déploiements en production.
|
Sources de données préconfigurées :
-
Prometheus -
http://prometheus:9090 -
Loki -
http://loki:3100
4.3. Journalisation
Tous les services journalisent vers stdout avec des horodatages UTC :
2026-01-28T10:15:30.123Z subscriber INFO Connected successfully
Consultez les journaux via Docker :
# Tous les services
docker-compose logs -f
# Service spécifique
docker-compose logs -f celery
# Avec les horodatages
docker-compose logs -f -t subscriber
Les journaux sont également collectés par Loki et interrogeables dans Grafana.
5. Maintenance
5.1. Sauvegarde
5.1.1. Données Redis
# Déclencher un instantané RDB
docker exec redis redis-cli -a $REDIS_PASSWORD BGSAVE
# Copier l'instantané
docker cp redis:/data/dump.rdb ./backup/
5.1.2. Fichiers téléchargés
# Sauvegarder le répertoire de téléchargements
tar -czf wis2-downloads-$(date +%Y%m%d).tar.gz downloads/
5.2. Suppression des données
| Ces opérations sont destructives. |
# Effacer tous les abonnements
docker exec redis redis-cli -a $REDIS_PASSWORD DEL global:subscriptions
# Effacer le cache de déduplication (permet de re-télécharger toutes les données)
docker exec redis redis-cli -a $REDIS_PASSWORD KEYS "wis2:notifications:*" | xargs -r docker exec -i redis redis-cli -a $REDIS_PASSWORD DEL
# Effacer les fichiers téléchargés
rm -rf downloads/*
5.3. Redémarrage des services
# Redémarrer un service unique
docker-compose restart subscriber
# Redémarrer tous les services
docker-compose restart
# Reconstruction complète (après des modifications du code)
docker-compose build && docker-compose up -d
6. Dépannage
6.1. Le service ne démarre pas
# Vérifier les journaux
docker-compose logs <service-name>
# Vérifier le statut du conteneur
docker-compose ps
# Vérifier l'environnement
docker-compose config
6.2. Aucun téléchargement
-
Vérifiez que l’abonné est connecté :
docker-compose logs subscriber | grep -i connect -
Vérifiez que l’abonnement existe :
curl http://localhost:5002/subscriptions -
Vérifiez que le worker Celery traite :
docker-compose logs celery | tail -50 -
Vérifiez la profondeur de la file d’attente :
curl -s http://localhost:5002/metrics | grep queue_length
6.3. Erreurs de connexion Redis
-
Vérifiez que Redis est en cours d’exécution :
docker exec redis redis-cli -a $REDIS_PASSWORD PING -
Vérifiez la connectivité réseau :
docker network inspect wis2downloader_redis-net
6.4. Utilisation élevée de la mémoire
-
Augmentez
max-tasks-per-childpour recycler les workers plus fréquemment -
Réduisez la concurrence des workers
-
Vérifiez si des fichiers volumineux surchargent les workers
6.5. Les métriques ne se mettent pas à jour
-
L’intervalle de scraping Prometheus est de 15 secondes par défaut
-
Vérifiez les cibles Prometheus via Grafana : Connections → Data sources → Prometheus → Save & test
-
Vérifiez le point de terminaison des métriques :
curl http://localhost:5002/metrics
6.6. Interface web : données du catalogue non chargées
Si les vues Catalogue ou Arborescence affichent « Catalogue data not loaded » :
-
Vérifiez si le conteneur de l’interface a démarré avec succès :
docker-compose logs wis2downloader-ui | tail -30 -
Confirmez que les clés de cache GDC existent dans Redis :
docker exec redis redis-cli -a $REDIS_PASSWORD KEYS "gdc:cache:*"Si aucune clé n’est présente, la récupération initiale a échoué ou est toujours en cours. Attendez un moment et rechargez la page.
-
Forcez une récupération fraîche depuis la vue Paramètres (
http://localhost:8080) en cliquant sur Actualiser les données GDC, ou en redémarrant le conteneur de l’interface :docker-compose restart wis2downloader-ui -
Si la récupération GDC échoue systématiquement, vérifiez la connectivité réseau depuis le conteneur de l’interface vers les points de terminaison GDC publics :
docker exec wis2downloader-ui curl -s -o /dev/null -w "%{http_code}" \ https://wis2-gdc.weather.gc.ca/collections/wis2-discovery-metadata/items?limit=1