Dans cet article, nous allons déployer une application Airflow dans un environnement Conda, sécuriser l’application à l’aide de Nginx et demander un certificat SSL à Let’s Encrypt.
Flux d’air est un outil populaire que nous pouvons utiliser pour définir, planifier et surveiller nos flux de travail complexes. Nous pouvons créer des graphiques acycliques dirigés (DAG) pour automatiser les tâches sur nos plates-formes de travail, et étant open source, Airflow dispose d’une communauté pour fournir une assistance et s’améliorer continuellement.
Il s’agit d’un article sponsorisé par Vultr. Vultr est la plus grande plateforme de cloud computing privée au monde. Un favori des développeurs, Vultr a servi plus de 1,5 million de clients dans 185 pays avec des solutions mondiales flexibles et évolutives de Cloud Compute, Cloud GPU, Bare Metal et Cloud Storage. En savoir plus sur Vultr.
Déployer un serveur sur Vultr
Commençons par déployer un serveur Vultr avec l’application Marketplace Anaconda.
Inscrivez-vous et connectez-vous au Portail client Vultr.
Accédez à la page Produits.
Sélectionner Calculer dans le menu latéral.
Cliquez sur Déployer le serveur.
Sélectionner Calcul en nuage comme type de serveur.
Choisis un Emplacement.
Sélectionner Anaconda parmi les applications du marché.
Choisis un Plan.
Sélectionnez les fonctionnalités supplémentaires nécessaires dans la section « Fonctionnalités supplémentaires ».
Clique le Déployer maintenant bouton.
Création d’une base de données gérée Vultr
Après avoir déployé un serveur Vultr, nous allons ensuite déployer une base de données PostgreSQL gérée par Vultr. Nous créerons également deux nouvelles bases de données dans notre instance de base de données qui seront utilisées pour se connecter à notre application Airflow plus tard dans le blog.
Ouvrez le Portail client Vultr.
Clique le Des produits groupe de menus et accédez à Bases de données pour créer une base de données gérée PostgreSQL.
Cliquez sur Ajouter des bases de données gérées.
Sélectionner PostgreSQL avec la dernière version comme moteur de base de données.
Sélectionner Configuration du serveur et Emplacement du serveur.
Écrire un Étiquette pour le service.
Cliquez sur Déployer maintenant.
Une fois la base de données déployée, sélectionnez Utilisateurs et bases de données.
Cliquez sur Ajouter une nouvelle base de données.
Tapez un nom, cliquez sur Ajouter une base de données et nomme-le airflow-pgsql
.
Répétez les étapes 9 et 10 pour ajouter une autre base de données dans la même base de données gérée et nommez-la airflow-celery
.
Premiers pas avec Conda et Airflow
Maintenant que nous avons créé une instance PostgreSQL gérée par Vultr, nous allons utiliser le serveur Vultr pour créer un environnement Conda et installer les dépendances requises.
Vérifiez la version de Conda :
Créez un environnement Conda :
$ conda create -n airflow python=3.8
Activez l’environnement :
Installez le serveur Redis :
(airflow) $ apt install -y redis-server
Activez le serveur Redis :
(airflow) $ sudo systemctl enable redis-server
Vérifiez l’état :
(airflow) $ sudo systemctl status redis-server
Installez le gestionnaire de packages Python :
(airflow) $ conda install pip
Installez les dépendances requises :
(airflow) $ pip install psycopg2-binary virtualenv redis
Installez Airflow dans l’environnement Conda :
(airflow) $ pip install "apache-airflow[celery]==2.8.1" --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-2.8.1/constraints-3.8.txt"
Connexion d’Airflow à la base de données gérée Vultr
Après avoir préparé l’environnement, connectons maintenant notre application Airflow aux deux bases de données que nous avons créées précédemment dans notre instance de base de données et apportons les modifications nécessaires à la configuration Airflow pour rendre notre application prête pour la production.
Définir la variable d’environnement pour la connexion à la base de données :
(airflow) $ export AIRFLOW__DATABASE__SQL_ALCHEMY_CONN="postgresql://user:password@hostname:port/db_name"
Assurez-vous de remplacer le user
, password
, hostname
et port
avec les valeurs réelles dans la section des détails de connexion en sélectionnant le airflow-pgsql
base de données. Remplace le db_name
avec airflow-pgsql
.
Initialisez la base de données de métadonnées.
Nous devons initialiser une base de données de métadonnées pour Airflow afin de créer les tables et le schéma nécessaires qui stockent les informations telles que les DAG et les informations liées à nos flux de travail :
(airflow) $ airflow db init
Ouvrez le fichier de configuration Airflow :
(airflow) $ sudo nano ~/airflow/airflow.cfg
Faites défiler vers le bas et modifiez le executor
:
executor = CeleryExecutor
Liez la base de données PostgreSQL gérée par Vultr et modifiez la valeur de sql_alchemy_conn
:
sql_alchemy_conn = "postgresql://user:password@hostname:port/db_name"
Assurez-vous de remplacer le user
, password
, hostname
et le port avec les valeurs réelles dans la section des détails de connexion en sélectionnant le airflow-pgsql
base de données. Remplace le db_name
avec airflow-pgsql
.
Faites défiler vers le bas et modifiez les ports du journal de travail et de déclenchement :
worker_log_server_port = 8794
trigger_log_server_port = 8795
Changer la broker_url
:
broker_url = redis://localhost:6379/0
Retirer le #
et changer le result_backend
:
result_backend = db+postgresql://user:password@hostname:port/db_name
Assurez-vous de remplacer le user
, password
, hostname
et port
avec les valeurs réelles dans la section des détails de connexion en sélectionnant le airflow-celery
base de données. Remplace le db_name
avec airflow-celery
.
Enregistrez et quittez le fichier.
Créez un utilisateur Airflow :
(airflow) $ airflow users create \n --username admin \n --firstname Peter \n --lastname Parker \n --role Admin \n --email spiderman@superhero.org
Assurez-vous de remplacer toutes les valeurs des variables par les valeurs réelles.
Entrez un mot de passe lorsque vous êtes invité à le définir pour l’utilisateur lors de l’accès au tableau de bord.
Démoniser l’application Airflow
Démonisons maintenant notre application Airflow afin qu’elle s’exécute en arrière-plan et continue de s’exécuter indépendamment même lorsque nous fermons le terminal et nous déconnectons.
Ces étapes nous aideront également à créer un service persistant pour le serveur Web Airflow, le planificateur et les travailleurs de céleri.
Voir la airflow
chemin:
(airflow) $ which airflow
Copiez et collez le chemin dans le presse-papiers.
Créez un fichier de service de serveur Web Airflow :
(airflow) $ sudo nano /etc/systemd/system/airflow-webserver.service
Collez les configurations de service dans le fichier.
airflow webserver
est chargé de fournir une interface utilisateur Web qui nous permettra d’interagir et de gérer nos flux de travail. Ces configurations créeront un service exécuté en arrière-plan pour notre serveur Web Airflow :
[Unit]
Description="Airflow Webserver"
After=network.target
[Service]
User=example_user
Group=example_user
ExecStart=/home/example_user/.local/bin/airflow webserver
[Install]
WantedBy=multi-user.target
Assurez-vous de remplacer User
et Group
avec les détails réels de votre compte utilisateur sudo non root, et remplacez le ExecStart
path avec le chemin Airflow réel, y compris le binaire exécutable que nous avons copié plus tôt dans le presse-papiers.
Enregistrez et fermez le fichier.
Activer le airflow-webserver
service, afin que le serveur Web démarre automatiquement pendant le processus de démarrage du système :
(airflow) $ systemctl enable airflow-webserver
Démarrez le service :
(airflow) $ sudo systemctl start airflow-webserver
Assurez-vous que le service est opérationnel :
(airflow) $ sudo systemctl status airflow-webserver
Notre sortie devrait ressembler à celle illustrée ci-dessous.
Créez un fichier de service Airflow Celery :
(airflow) $ sudo nano /etc/systemd/system/airflow-celery.service
Collez les configurations de service dans le fichier.
airflow celery worker
démarre un ouvrier du céleri. Celery est une file d’attente de tâches distribuée qui nous permettra de distribuer et d’exécuter des tâches sur plusieurs travailleurs. Les travailleurs se connectent à notre serveur Redis pour recevoir et exécuter des tâches :
[Unit]
Description="Airflow Celery"
After=network.target
[Service]
User=example_user
Group=example_user
ExecStart=/home/example_user/.local/bin/airflow celery worker
[Install]
WantedBy=multi-user.target
Assurez-vous de remplacer User
et Group
avec les détails réels de votre compte utilisateur sudo non root, et remplacez le ExecStart
path avec le chemin Airflow réel, y compris le binaire exécutable que nous avons copié plus tôt dans le presse-papiers.
Enregistrez et fermez le fichier.
Activer le airflow-celery
service:
(airflow) $ sudo systemctl enable airflow-celery
Démarrez le service :
(airflow) $ sudo systemctl start airflow-celery
Assurez-vous que le service est opérationnel :
(airflow) $ sudo systemctl status airflow-celery
Créez un fichier de service du planificateur Airflow :
(airflow) $ sudo nano /etc/systemd/system/airflow-scheduler.service
Collez les configurations de service dans le fichier.
airflow scheduler
est responsable de la planification et du déclenchement des DAG et des tâches qui y sont définies. Il vérifie également périodiquement l’état des DAG et des tâches :
[Unit]
Description="Airflow Scheduler"
After=network.target
[Service]
User=example_user
Group=example_user
ExecStart=/home/example_user/.local/bin/airflow scheduler
[Install]
WantedBy=multi-user.target
Assurez-vous de remplacer User
et Group
avec les détails réels de votre compte utilisateur sudo non root, et remplacez le ExecStart
path avec le chemin Airflow réel, y compris le binaire exécutable que nous avons copié plus tôt dans le presse-papiers.
Enregistrez et fermez le fichier.
Activer le airflow-scheduler
service:
(airflow) $ sudo systemctl enable airflow-scheduler
Démarrez le service :
(airflow) $ sudo systemctl start airflow-scheduler
Assurez-vous que le service est opérationnel :
(airflow) $ sudo systemctl status airflow-scheduler
Notre sortie devrait ressembler à celle illustrée ci-dessous.
Configuration de Nginx en tant que proxy inverse
Nous avons créé des services persistants pour l’application Airflow, nous allons donc maintenant configurer Nginx en tant que proxy inverse pour améliorer la sécurité et l’évolutivité de notre application en suivant les étapes décrites ci-dessous.
Connectez-vous au Portail client Vultr.
Accédez au Des produits page.
Dans le menu latéral, développez le Réseau faites défiler vers le bas et sélectionnez DNS.
Clique le Ajouter un domaine bouton au centre.
Suivez la procédure de configuration pour ajouter votre nom de domaine en sélectionnant l’adresse IP de votre serveur.
Définissez les noms d’hôte suivants comme serveurs de noms principal et secondaire de votre domaine auprès de votre registraire de domaine :
- ns1.vultr.com
- ns2.vultr.com
Installez Nginx :
(airflow) $ apt install nginx
Assurez-vous de vérifier si le serveur Nginx est opérationnel :
(airflow) $ sudo systemctl status nginx
Créez un nouveau fichier de configuration d’hôte virtuel Nginx dans le sites-available
annuaire:
(airflow) $ sudo nano /etc/nginx/sites-available/airflow.conf
Ajoutez les configurations au fichier.
Ces configurations dirigeront le trafic sur notre application du domaine réel vers le serveur backend à l’adresse http://127.0.0.1:8080
en utilisant un passe proxy :
server {
listen 80;
listen [::]:80;
server_name airflow.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
Assurez-vous de remplacer airflow.example.com
avec le domaine réel que nous avons ajouté dans le tableau de bord Vultr.
Enregistrez et fermez le fichier.
Liez le fichier de configuration au sites-enabled
répertoire pour activer le fichier de configuration :
(airflow) $ sudo ln -s /etc/nginx/sites-available/airflow.conf /etc/nginx/sites-enabled/
Assurez-vous de vérifier la configuration pour les erreurs :
(airflow) $ sudo nginx -t
Notre sortie devrait ressembler à celle illustrée ci-dessous.
Redémarrez Nginx pour appliquer les modifications :
(airflow) $ sudo systemctl reload nginx
Autoriser le port HTTP 80
via le pare-feu pour toutes les connexions entrantes :
(airflow) $ sudo ufw allow 80/tcp
Autoriser le port HTTPS 443
via le pare-feu pour toutes les connexions entrantes :
(airflow) $ sudo ufw allow 443/tcp
Rechargez les règles de pare-feu pour enregistrer les modifications :
(airflow) $ sudo ufw reload
Application des certificats SSL Let’s Encrypt à l’application Airflow
La dernière étape consiste à appliquer un Chiffrons Certificat SSL à notre application Airflow afin qu’elle devienne beaucoup plus sécurisée et sauve notre application des attaques indésirables.
À l’aide de Snap, installez le client Certbot Let’s Encrypt :
(airflow) $ snap install --classic certbot
Obtenez un nouveau certificat SSL pour notre domaine :
(airflow) $ certbot --nginx -d airflow.example.com
Assurez-vous de remplacer airflow.example.com
avec notre nom de domaine actuel.
Et lorsque vous y êtes invité, entrez une adresse e-mail et appuyez sur Oui d’accepter les conditions de Let’s Encrypt.
Testez que le certificat SSL se renouvelle automatiquement à l’expiration.
Le renouvellement automatique garantit que nos certificats SSL sont à jour, réduisant ainsi le risque d’expiration des certificats et préservant la sécurité de notre application :
(airflow) $ certbot renew --dry-run
Utilisez un navigateur Web pour ouvrir notre application Airflow : https://airflow.example.com
.
Lorsque vous y êtes invité, entrez le nom d’utilisateur et le mot de passe que nous avons créés précédemment.
En accédant au tableau de bord, tous les DAG fournis par défaut seront visibles.
Conclusion
Dans cet article, nous avons montré comment créer des environnements Conda, déployer une application Airflow prête pour la production et améliorer les performances et la sécurité d’une application.
mai 15, 2024
Comment déployer Apache Airflow sur Vultr à l’aide d’Anaconda —
Dans cet article, nous allons déployer une application Airflow dans un environnement Conda, sécuriser l’application à l’aide de Nginx et demander un certificat SSL à Let’s Encrypt.
Flux d’air est un outil populaire que nous pouvons utiliser pour définir, planifier et surveiller nos flux de travail complexes. Nous pouvons créer des graphiques acycliques dirigés (DAG) pour automatiser les tâches sur nos plates-formes de travail, et étant open source, Airflow dispose d’une communauté pour fournir une assistance et s’améliorer continuellement.
Il s’agit d’un article sponsorisé par Vultr. Vultr est la plus grande plateforme de cloud computing privée au monde. Un favori des développeurs, Vultr a servi plus de 1,5 million de clients dans 185 pays avec des solutions mondiales flexibles et évolutives de Cloud Compute, Cloud GPU, Bare Metal et Cloud Storage. En savoir plus sur Vultr.
Déployer un serveur sur Vultr
Commençons par déployer un serveur Vultr avec l’application Marketplace Anaconda.
Inscrivez-vous et connectez-vous au Portail client Vultr.
Accédez à la page Produits.
Sélectionner Calculer dans le menu latéral.
Cliquez sur Déployer le serveur.
Sélectionner Calcul en nuage comme type de serveur.
Choisis un Emplacement.
Sélectionner Anaconda parmi les applications du marché.
Choisis un Plan.
Sélectionnez les fonctionnalités supplémentaires nécessaires dans la section « Fonctionnalités supplémentaires ».
Clique le Déployer maintenant bouton.
Création d’une base de données gérée Vultr
Après avoir déployé un serveur Vultr, nous allons ensuite déployer une base de données PostgreSQL gérée par Vultr. Nous créerons également deux nouvelles bases de données dans notre instance de base de données qui seront utilisées pour se connecter à notre application Airflow plus tard dans le blog.
Ouvrez le Portail client Vultr.
Clique le Des produits groupe de menus et accédez à Bases de données pour créer une base de données gérée PostgreSQL.
Cliquez sur Ajouter des bases de données gérées.
Sélectionner PostgreSQL avec la dernière version comme moteur de base de données.
Sélectionner Configuration du serveur et Emplacement du serveur.
Écrire un Étiquette pour le service.
Cliquez sur Déployer maintenant.
Une fois la base de données déployée, sélectionnez Utilisateurs et bases de données.
Cliquez sur Ajouter une nouvelle base de données.
Tapez un nom, cliquez sur Ajouter une base de données et nomme-le
airflow-pgsql
.Répétez les étapes 9 et 10 pour ajouter une autre base de données dans la même base de données gérée et nommez-la
airflow-celery
.Premiers pas avec Conda et Airflow
Maintenant que nous avons créé une instance PostgreSQL gérée par Vultr, nous allons utiliser le serveur Vultr pour créer un environnement Conda et installer les dépendances requises.
Vérifiez la version de Conda :
Créez un environnement Conda :
Activez l’environnement :
Installez le serveur Redis :
Activez le serveur Redis :
Vérifiez l’état :
Installez le gestionnaire de packages Python :
Installez les dépendances requises :
Installez Airflow dans l’environnement Conda :
Connexion d’Airflow à la base de données gérée Vultr
Après avoir préparé l’environnement, connectons maintenant notre application Airflow aux deux bases de données que nous avons créées précédemment dans notre instance de base de données et apportons les modifications nécessaires à la configuration Airflow pour rendre notre application prête pour la production.
Définir la variable d’environnement pour la connexion à la base de données :
Assurez-vous de remplacer le
user
,password
,hostname
etport
avec les valeurs réelles dans la section des détails de connexion en sélectionnant leairflow-pgsql
base de données. Remplace ledb_name
avecairflow-pgsql
.Initialisez la base de données de métadonnées.
Nous devons initialiser une base de données de métadonnées pour Airflow afin de créer les tables et le schéma nécessaires qui stockent les informations telles que les DAG et les informations liées à nos flux de travail :
Ouvrez le fichier de configuration Airflow :
Faites défiler vers le bas et modifiez le
executor
:Liez la base de données PostgreSQL gérée par Vultr et modifiez la valeur de
sql_alchemy_conn
:Assurez-vous de remplacer le
user
,password
,hostname
et le port avec les valeurs réelles dans la section des détails de connexion en sélectionnant leairflow-pgsql
base de données. Remplace ledb_name
avecairflow-pgsql
.Faites défiler vers le bas et modifiez les ports du journal de travail et de déclenchement :
Changer la
broker_url
:Retirer le
#
et changer leresult_backend
:Assurez-vous de remplacer le
user
,password
,hostname
etport
avec les valeurs réelles dans la section des détails de connexion en sélectionnant leairflow-celery
base de données. Remplace ledb_name
avecairflow-celery
.Enregistrez et quittez le fichier.
Créez un utilisateur Airflow :
Assurez-vous de remplacer toutes les valeurs des variables par les valeurs réelles.
Entrez un mot de passe lorsque vous êtes invité à le définir pour l’utilisateur lors de l’accès au tableau de bord.
Démoniser l’application Airflow
Démonisons maintenant notre application Airflow afin qu’elle s’exécute en arrière-plan et continue de s’exécuter indépendamment même lorsque nous fermons le terminal et nous déconnectons.
Ces étapes nous aideront également à créer un service persistant pour le serveur Web Airflow, le planificateur et les travailleurs de céleri.
Voir la
airflow
chemin:Copiez et collez le chemin dans le presse-papiers.
Créez un fichier de service de serveur Web Airflow :
Collez les configurations de service dans le fichier.
airflow webserver
est chargé de fournir une interface utilisateur Web qui nous permettra d’interagir et de gérer nos flux de travail. Ces configurations créeront un service exécuté en arrière-plan pour notre serveur Web Airflow :Assurez-vous de remplacer
User
etGroup
avec les détails réels de votre compte utilisateur sudo non root, et remplacez leExecStart
path avec le chemin Airflow réel, y compris le binaire exécutable que nous avons copié plus tôt dans le presse-papiers.Enregistrez et fermez le fichier.
Activer le
airflow-webserver
service, afin que le serveur Web démarre automatiquement pendant le processus de démarrage du système :Démarrez le service :
Assurez-vous que le service est opérationnel :
Notre sortie devrait ressembler à celle illustrée ci-dessous.
Créez un fichier de service Airflow Celery :
Collez les configurations de service dans le fichier.
airflow celery worker
démarre un ouvrier du céleri. Celery est une file d’attente de tâches distribuée qui nous permettra de distribuer et d’exécuter des tâches sur plusieurs travailleurs. Les travailleurs se connectent à notre serveur Redis pour recevoir et exécuter des tâches :Assurez-vous de remplacer
User
etGroup
avec les détails réels de votre compte utilisateur sudo non root, et remplacez leExecStart
path avec le chemin Airflow réel, y compris le binaire exécutable que nous avons copié plus tôt dans le presse-papiers.Enregistrez et fermez le fichier.
Activer le
airflow-celery
service:Démarrez le service :
Assurez-vous que le service est opérationnel :
Créez un fichier de service du planificateur Airflow :
Collez les configurations de service dans le fichier.
airflow scheduler
est responsable de la planification et du déclenchement des DAG et des tâches qui y sont définies. Il vérifie également périodiquement l’état des DAG et des tâches :Assurez-vous de remplacer
User
etGroup
avec les détails réels de votre compte utilisateur sudo non root, et remplacez leExecStart
path avec le chemin Airflow réel, y compris le binaire exécutable que nous avons copié plus tôt dans le presse-papiers.Enregistrez et fermez le fichier.
Activer le
airflow-scheduler
service:Démarrez le service :
Assurez-vous que le service est opérationnel :
Notre sortie devrait ressembler à celle illustrée ci-dessous.
Configuration de Nginx en tant que proxy inverse
Nous avons créé des services persistants pour l’application Airflow, nous allons donc maintenant configurer Nginx en tant que proxy inverse pour améliorer la sécurité et l’évolutivité de notre application en suivant les étapes décrites ci-dessous.
Connectez-vous au Portail client Vultr.
Accédez au Des produits page.
Dans le menu latéral, développez le Réseau faites défiler vers le bas et sélectionnez DNS.
Clique le Ajouter un domaine bouton au centre.
Suivez la procédure de configuration pour ajouter votre nom de domaine en sélectionnant l’adresse IP de votre serveur.
Définissez les noms d’hôte suivants comme serveurs de noms principal et secondaire de votre domaine auprès de votre registraire de domaine :
Installez Nginx :
Assurez-vous de vérifier si le serveur Nginx est opérationnel :
Créez un nouveau fichier de configuration d’hôte virtuel Nginx dans le
sites-available
annuaire:Ajoutez les configurations au fichier.
Ces configurations dirigeront le trafic sur notre application du domaine réel vers le serveur backend à l’adresse
http://127.0.0.1:8080
en utilisant un passe proxy :Assurez-vous de remplacer
airflow.example.com
avec le domaine réel que nous avons ajouté dans le tableau de bord Vultr.Enregistrez et fermez le fichier.
Liez le fichier de configuration au
sites-enabled
répertoire pour activer le fichier de configuration :Assurez-vous de vérifier la configuration pour les erreurs :
Notre sortie devrait ressembler à celle illustrée ci-dessous.
Redémarrez Nginx pour appliquer les modifications :
Autoriser le port HTTP
80
via le pare-feu pour toutes les connexions entrantes :Autoriser le port HTTPS
443
via le pare-feu pour toutes les connexions entrantes :Rechargez les règles de pare-feu pour enregistrer les modifications :
Application des certificats SSL Let’s Encrypt à l’application Airflow
La dernière étape consiste à appliquer un Chiffrons Certificat SSL à notre application Airflow afin qu’elle devienne beaucoup plus sécurisée et sauve notre application des attaques indésirables.
À l’aide de Snap, installez le client Certbot Let’s Encrypt :
Obtenez un nouveau certificat SSL pour notre domaine :
Assurez-vous de remplacer
airflow.example.com
avec notre nom de domaine actuel.Et lorsque vous y êtes invité, entrez une adresse e-mail et appuyez sur Oui d’accepter les conditions de Let’s Encrypt.
Testez que le certificat SSL se renouvelle automatiquement à l’expiration.
Le renouvellement automatique garantit que nos certificats SSL sont à jour, réduisant ainsi le risque d’expiration des certificats et préservant la sécurité de notre application :
Utilisez un navigateur Web pour ouvrir notre application Airflow :
https://airflow.example.com
.Lorsque vous y êtes invité, entrez le nom d’utilisateur et le mot de passe que nous avons créés précédemment.
En accédant au tableau de bord, tous les DAG fournis par défaut seront visibles.
Conclusion
Dans cet article, nous avons montré comment créer des environnements Conda, déployer une application Airflow prête pour la production et améliorer les performances et la sécurité d’une application.
Source link
Partager :
Articles similaires