Comment utiliser la commande docker compose run pour exécuter des tâches ponctuelles

DockerDockerBeginner
Pratiquer maintenant

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce lab, vous apprendrez à utiliser efficacement la commande docker compose run pour exécuter des tâches ponctuelles (one-off tasks) au sein de vos services Docker Compose. Il s'agit d'une technique puissante pour exécuter des commandes administratives, déboguer ou effectuer des opérations spécifiques sans démarrer l'ensemble de la pile de services.

Nous explorerons divers scénarios, notamment :

  • Le remplacement de la commande par défaut d'un service
  • L'activation des ports de service pour l'interaction
  • Le mappage manuel des ports
  • L'exécution de commandes sans démarrer les services liés
  • La suppression automatique du conteneur après exécution

À la fin de ce lab, vous maîtriserez l'utilisation de docker compose run pour diverses tâches ponctuelles.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ImageOperationsGroup(["Image Operations"]) docker(("Docker")) -.-> docker/NetworkOperationsGroup(["Network Operations"]) docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ContainerOperationsGroup -.-> docker/ps("List Running Containers") docker/ContainerOperationsGroup -.-> docker/stop("Stop Container") docker/ContainerOperationsGroup -.-> docker/rm("Remove Container") docker/ImageOperationsGroup -.-> docker/pull("Pull Image from Repository") docker/NetworkOperationsGroup -.-> docker/network("Manage Networks") subgraph Lab Skills docker/run -.-> lab-555091{{"Comment utiliser la commande docker compose run pour exécuter des tâches ponctuelles"}} docker/ps -.-> lab-555091{{"Comment utiliser la commande docker compose run pour exécuter des tâches ponctuelles"}} docker/stop -.-> lab-555091{{"Comment utiliser la commande docker compose run pour exécuter des tâches ponctuelles"}} docker/rm -.-> lab-555091{{"Comment utiliser la commande docker compose run pour exécuter des tâches ponctuelles"}} docker/pull -.-> lab-555091{{"Comment utiliser la commande docker compose run pour exécuter des tâches ponctuelles"}} docker/network -.-> lab-555091{{"Comment utiliser la commande docker compose run pour exécuter des tâches ponctuelles"}} end

Exécuter une commande ponctuelle en remplaçant la commande du service

Dans cette étape, nous allons apprendre à exécuter une commande ponctuelle dans un conteneur Docker, en remplaçant la commande par défaut spécifiée dans l'image Docker ou le Dockerfile. Cette technique est utile pour exécuter des tâches administratives, déboguer ou lancer un script spécifique dans l'environnement du conteneur sans démarrer le service principal.

Commençons par télécharger une image Docker simple que nous utiliserons pour cette démonstration. Nous utiliserons l'image ubuntu.

docker pull ubuntu:latest

Vous devriez voir une sortie indiquant que l'image est en cours de téléchargement.

Using default tag: latest
latest: Pulling from library/ubuntu
...
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

Maintenant, exécutons une commande ponctuelle dans un conteneur basé sur l'image ubuntu. Nous utiliserons la commande docker run avec le nom de l'image et la commande à exécuter. Par exemple, exécutons la commande ls -l / pour lister le contenu du répertoire racine dans le conteneur.

docker run ubuntu ls -l /

Cette commande créera un nouveau conteneur à partir de l'image ubuntu, exécutera la commande ls -l / à l'intérieur, puis se terminera. Vous devriez voir une sortie similaire à ceci, montrant le contenu du répertoire racine :

total 68
drwxr-xr-x   2 root root  4096 Oct 26 00:00 bin
drwxr-xr-x   2 root root  4096 Oct 26 00:00 boot
drwxr-xr-x   5 root root   360 Nov  1 00:00 dev
drwxr-xr-x  19 root root  4096 Nov  1 00:00 etc
drwxr-xr-x   2 root root  4096 Oct 26 00:00 home
drwxr-xr-x   7 root root  4096 Oct 26 00:00 lib
drwxr-xr-x   2 root root  4096 Oct 26 00:00 lib64
drwxr-xr-x   2 root root  4096 Oct 26 00:00 media
drwxr-xr-x   2 root root  4096 Oct 26 00:00 mnt
drwxr-xr-x   2 root root  4096 Oct 26 00:00 opt
drwxr-xr-x   2 root root  4096 Oct 04 14:00 proc
drwx------   2 root root  4096 Oct 26 00:00 root
drwxr-xr-x   2 root root  4096 Oct 26 00:00 run
drwxr-xr-x   2 root root  4096 Oct 26 00:00 sbin
drwxr-xr-x   2 root root  4096 Oct 26 00:00 srv
drwxr-xr-x   2 root root  4096 Oct 26 00:00 sys
drwxrwxrwt   2 root root  4096 Oct 26 00:00 tmp
drwxr-xr-x  11 root root  4096 Oct 26 00:00 usr
drwxr-xr-x  12 root root  4096 Oct 26 00:00 var

Dans ce cas, la commande par défaut de l'image ubuntu est généralement un shell comme /bin/bash. En fournissant ls -l / après le nom de l'image, nous indiquons à Docker d'exécuter cette commande spécifique au lieu de la commande par défaut.

Essayons une autre commande, par exemple pwd pour afficher le répertoire de travail courant dans le conteneur.

docker run ubuntu pwd

La sortie devrait être /, indiquant que le répertoire racine est le répertoire de travail par défaut.

/

Cela démontre comment vous pouvez facilement exécuter des commandes arbitraires dans un conteneur sans avoir besoin d'y entrer de manière interactive ou de modifier la commande par défaut de l'image.

Exécuter une commande avec les ports du service activés

Dans cette étape, nous allons explorer comment exécuter une commande dans un conteneur Docker tout en activant les ports que le service à l'intérieur du conteneur est configuré pour exposer. Ceci est utile lorsque vous avez besoin d'exécuter une commande temporaire pour du débogage ou de l'administration, tout en souhaitant que le service principal reste accessible depuis l'extérieur du conteneur.

Pour cette démonstration, nous utiliserons une image simple de serveur web. Téléchargeons l'image nginx, un serveur web populaire.

docker pull nginx:latest

Vous devriez voir une sortie indiquant que l'image est en cours de téléchargement.

Using default tag: latest
latest: Pulling from library/nginx
...
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

L'image nginx par défaut est configurée pour écouter sur le port 80 à l'intérieur du conteneur. Pour rendre ce port accessible depuis notre machine hôte, nous devons mapper un port hôte vers le port du conteneur en utilisant l'option -p avec la commande docker run. Mappons le port 8080 de l'hôte vers le port 80 du conteneur.

Maintenant, au lieu d'exécuter le service Nginx par défaut, exécutons une commande simple comme echo "Hello from the container" tout en conservant le mappage de ports.

docker run -p 8080:80 nginx echo "Hello from the container"

Vous pourriez vous attendre à ce que cela démarre le serveur Nginx puis affiche "Hello from the container". Cependant, lorsque vous fournissez une commande après le nom de l'image dans docker run, cette commande remplace la commande par défaut. Donc dans ce cas, le conteneur exécutera la commande echo puis s'arrêtera. Le serveur Nginx ne sera pas démarré, même si nous avons spécifié le mappage de ports.

La sortie sera simplement :

Hello from the container

Et si vous essayez d'accéder à http://localhost:8080 dans votre navigateur web ou en utilisant curl, vous constaterez que la connexion est refusée car le serveur Nginx ne fonctionne pas.

curl http://localhost:8080

La sortie sera probablement :

curl: (7) Failed to connect to localhost port 8080 after ... connection refused

Ceci illustre un point important : lorsque vous remplacez la commande par défaut avec docker run <image> <command>, le conteneur n'exécutera que la commande fournie et ne démarrera pas le service que l'image est conçue pour exécuter. Par conséquent, le mappage de ports, bien que configuré, ne sera pas actif car le service écoutant sur ce port ne fonctionne pas.

Pour exécuter une commande pendant que le service fonctionne et que ses ports sont activés, vous devriez généralement démarrer le service en arrière-plan puis exécuter votre commande. Cependant, la commande docker run est conçue pour exécuter une seule commande puis s'arrêter. Pour obtenir l'effet d'exécuter une commande parallèlement à un service en cours d'exécution, vous utiliseriez généralement docker exec sur un conteneur exécutant déjà le service. Nous explorerons docker exec dans une étape ultérieure.

Pour cette étape, l'essentiel à retenir est que fournir une commande à docker run remplace le point d'entrée/commande par défaut, et donc le service configuré pour s'exécuter par défaut ne démarrera pas, même si des mappages de ports sont spécifiés.

Exécuter une commande avec mappage manuel de ports

Dans cette étape, nous allons continuer à explorer le mappage de ports avec docker run, en nous concentrant sur la manière de spécifier explicitement les ports hôte et conteneur. Alors que l'étape précédente a montré que le remplacement de la commande par défaut empêche le service de s'exécuter, comprendre le mappage manuel de ports est crucial lorsque vous souhaitez que le service soit accessible.

Nous continuerons à utiliser l'image nginx. Pour rappel, l'image nginx expose le port 80 à l'intérieur du conteneur. Pour le rendre accessible depuis notre machine hôte, nous utilisons l'option -p suivie de port_hôte:port_conteneur.

Lançons le conteneur nginx et mappons le port 8081 de l'hôte vers le port 80 du conteneur. Cette fois, nous ne fournirons pas de commande de remplacement, donc le service Nginx par défaut démarrera. Nous l'exécuterons également en mode détaché (-d) pour qu'il fonctionne en arrière-plan.

docker run -d -p 8081:80 nginx

Vous devriez voir une longue chaîne de caractères, qui est l'ID du conteneur, indiquant que le conteneur a démarré en mode détaché.

<container_id>

Maintenant que le conteneur est en cours d'exécution et que le port est mappé, vous pouvez accéder à la page d'accueil Nginx depuis votre machine hôte en utilisant curl ou un navigateur web.

curl http://localhost:8081

Vous devriez voir le contenu HTML de la page d'accueil Nginx par défaut. Ceci confirme que le serveur Nginx fonctionne dans le conteneur et est accessible depuis votre machine hôte via le port 8081.

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</body>
</html>

Ceci démontre comment le mappage manuel de ports vous permet de contrôler quel port hôte est utilisé pour accéder à un service fonctionnant sur un port spécifique à l'intérieur d'un conteneur. Ceci est essentiel pour éviter les conflits de ports sur votre machine hôte et pour rendre les services conteneurisés accessibles.

Pour arrêter le conteneur en cours d'exécution, vous pouvez utiliser la commande docker stop suivie de l'ID ou du nom du conteneur. Vous pouvez trouver l'ID du conteneur en exécutant docker ps.

docker ps

Cela affichera une liste des conteneurs en cours d'exécution. Trouvez l'ID du conteneur nginx que vous venez de démarrer.

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                  NAMES
<container_id>   nginx     "nginx -g 'daemon off"   About a minute ago   Up About a minute   0.0.0.0:8081->80/tcp   <container_name>

Maintenant, arrêtez le conteneur en utilisant son ID. Remplacez <container_id> par l'ID réel de votre sortie.

docker stop <container_id>

L'ID du conteneur sera à nouveau affiché, confirmant que le conteneur a été arrêté.

<container_id>

Si vous essayez d'accéder à http://localhost:8081 après avoir arrêté le conteneur, la connexion sera refusée.

Exécuter une commande sans démarrer les services liés

Dans cette étape, nous allons apprendre comment exécuter une commande dans un conteneur Docker faisant partie d'une application multi-conteneurs, sans démarrer les autres services liés. Ceci est particulièrement utile pour exécuter des migrations de base de données, des scripts de configuration ou des commandes de débogage dans un service sans avoir à démarrer toute la pile d'applications.

Bien que Docker Compose soit l'outil standard pour gérer des applications multi-conteneurs et dispose de fonctionnalités pour exécuter des commandes ponctuelles sur des services spécifiques, nous allons démontrer ici les concepts sous-jacents de Docker. Comme Docker Compose n'est pas préinstallé dans cet environnement, nous nous concentrerons sur l'utilisation de la commande docker run avec le réseau.

Simulons un scénario simple avec deux conteneurs : une application web et une base de données. Nous utiliserons une image générique ubuntu pour représenter notre application web et une image postgres pour la base de données.

Tout d'abord, téléchargeons l'image postgres :

docker pull postgres:latest

Vous devriez voir une sortie indiquant que l'image est en cours de téléchargement.

Using default tag: latest
latest: Pulling from library/postgres
...
Status: Downloaded newer image for postgres:latest
docker.io/library/postgres:latest

Maintenant, créons un réseau Docker pour que nos conteneurs puissent communiquer entre eux par nom.

docker network create my-app-network

Vous devriez voir l'ID du réseau affiché.

<network_id>

Ensuite, lançons le conteneur postgres et connectons-le à notre réseau. Nous définirons également un mot de passe pour l'utilisateur PostgreSQL.

docker run -d --network my-app-network --name my-database -e POSTGRES_PASSWORD=mypassword postgres

Vous devriez voir l'ID du conteneur affiché, indiquant que le conteneur de base de données s'exécute en arrière-plan.

<container_id>

Imaginons maintenant que notre conteneur "application web" doive exécuter une commande interagissant avec la base de données, comme un script de migration. Normalement, si nous utilisions Docker Compose, nous pourrions exécuter une commande sur le service web et Docker Compose gérerait la configuration réseau et les liens.

En utilisant simplement docker run, si nous lançons le conteneur d'application web et qu'il tente de se connecter à my-database, il devra généralement être sur le même réseau.

Exécutons une commande dans un conteneur ubuntu connecté au même réseau, simulant une commande qui pourrait interagir avec la base de données. Nous allons simplement essayer de pinger le conteneur de base de données par son nom (my-database).

docker run --network my-app-network ubuntu ping -c 4 my-database

Cette commande va :

  1. Créer un nouveau conteneur à partir de l'image ubuntu
  2. Le connecter au réseau my-app-network
  3. Exécuter la commande ping -c 4 my-database dans le conteneur

Comme le conteneur ubuntu est sur le même réseau que le conteneur my-database, il peut résoudre le nom my-database en l'adresse IP du conteneur de base de données et le pinger.

Vous devriez voir une sortie montrant les requêtes ping et les réponses :

PING my-database (172.18.0.2) 56(84) bytes of data.
64 bytes from my-database.my-app-network (172.18.0.2): icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from my-database.my-app-network (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from my-database.my-app-network (172.18.0.2): icmp_seq=3 ttl=64 time=0.054 ms
64 bytes from my-database.my-app-network (172.18.0.2): icmp_seq=4 ttl=64 time=0.054 ms

--- my-database ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3060ms
rtt min/avg/max/mdev = 0.050/0.053/0.054/0.001 ms

Ceci démontre que vous pouvez exécuter une commande ponctuelle dans un conteneur et lui faire interagir avec d'autres conteneurs sur le même réseau, sans avoir à démarrer le service par défaut du conteneur exécutant la commande (dans ce cas, le conteneur ubuntu n'a pas de "service" typique). La clé est de connecter le conteneur exécutant la commande au même réseau que les services avec lesquels il doit interagir.

Enfin, nettoyons le conteneur de base de données en cours d'exécution et le réseau.

docker stop my-database
my-database
docker rm my-database
my-database
docker network rm my-app-network
my-app-network

Exécuter une commande et supprimer automatiquement le conteneur

Dans cette étape, nous allons apprendre comment exécuter une commande dans un conteneur Docker et supprimer automatiquement le conteneur une fois la commande terminée. Ceci est particulièrement utile pour des tâches ponctuelles, des scripts ou des jobs où vous n'avez pas besoin que le conteneur persiste après son exécution. La suppression automatique des conteneurs permet de garder votre système propre et d'éviter l'accumulation de conteneurs arrêtés.

Nous utiliserons à nouveau l'image ubuntu pour cette démonstration. Nous allons exécuter une commande simple, comme afficher un message puis quitter. Pour supprimer automatiquement le conteneur après l'exécution de la commande, nous utilisons l'option --rm avec la commande docker run.

Lançons un conteneur avec l'option --rm et exécutons la commande echo "Ce conteneur sera supprimé automatiquement".

docker run --rm ubuntu echo "Ce conteneur sera supprimé automatiquement"

Cette commande va :

  1. Créer un nouveau conteneur à partir de l'image ubuntu
  2. Exécuter la commande echo "Ce conteneur sera supprimé automatiquement" dans le conteneur
  3. Une fois la commande echo terminée, le conteneur sera automatiquement supprimé

Vous devriez voir la sortie de la commande echo :

Ce conteneur sera supprimé automatiquement

Après l'exécution de la commande, le conteneur est arrêté et supprimé. Pour vérifier que le conteneur a bien été supprimé, vous pouvez utiliser la commande docker ps -a qui liste tous les conteneurs, y compris ceux arrêtés.

docker ps -a

Vous ne devriez pas voir le conteneur qui vient de s'exécuter dans la liste. Si vous aviez exécuté la commande sans l'option --rm, le conteneur apparaîtrait toujours dans la sortie avec un statut "Exited".

Essayons un autre exemple. Nous allons exécuter une commande qui fait une pause de quelques secondes avec sleep puis quitte, toujours avec l'option --rm.

docker run --rm ubuntu sh -c "echo 'Début de la pause...'; sleep 5; echo 'Pause terminée.'"

Cette commande utilise sh -c pour exécuter un script simple qui affiche des messages avant et après une pause de 5 secondes.

Vous verrez immédiatement le premier message :

Début de la pause...

Puis, après environ 5 secondes, vous verrez le second message :

Pause terminée.

Une fois le script terminé, le conteneur sera automatiquement supprimé. Vous pouvez à nouveau le vérifier avec docker ps -a.

docker ps -a

Le conteneur qui a exécuté la commande sleep ne devrait pas apparaître dans la liste des conteneurs.

L'utilisation de l'option --rm est une bonne pratique pour les conteneurs conçus pour exécuter une tâche spécifique puis quitter, car cela permet de gérer l'espace disque et de garder votre liste de conteneurs propre.

Résumé

Dans ce lab, nous avons appris à utiliser la commande docker compose run pour exécuter des tâches ponctuelles au sein d'un service Docker Compose. Nous avons commencé par comprendre comment remplacer la commande par défaut définie dans la configuration d'un service, ce qui nous permet d'exécuter des commandes arbitraires à des fins d'administration ou de débogage.

Nous avons ensuite exploré comment gérer la connectivité réseau pour ces tâches ponctuelles, notamment en activant les ports des services et en mappant manuellement les ports. Enfin, nous avons appris à contrôler les dépendances en exécutant une commande sans démarrer les services liés, ainsi qu'à supprimer automatiquement le conteneur après l'exécution de la commande, garantissant ainsi un environnement propre.