Aller au contenu

docker run décortiqué

200 · Pratiquer ⏱ 55 min docker

À la fin, vous saurez

  • Lire une commande docker run et distinguer les options du moteur de la commande du conteneur
  • Retrouver l'ENTRYPOINT et le CMD d'une image et les remplacer à bon escient
  • Choisir entre les modes -i, -t, -it et -d selon l'usage, y compris en CI
  • Passer la configuration par variables d'environnement et fichiers d'environnement
  • Interpréter les codes de sortie 125, 126, 127 et 128+n
  • Choisir une politique de redémarrage adaptée

Prérequis

Testé avec docker 29.8.1 ubuntu 24.04 , vérifié le 1 octobre 2026

Pourquoi

docker run est la porte d'entrée de Docker, et c'est aussi la commande la plus mal comprise. On la recopie depuis un fichier README avec une dizaine d'options, on ajoute -it « parce que ça marche mieux », et le jour où elle tourne dans une chaîne d'intégration continue, elle échoue avec un message obscur. Ou bien un conteneur s'arrête aussitôt démarré, sans erreur, et on ne comprend pas pourquoi.

Comprendre docker run, c'est comprendre un contrat : l'image propose des valeurs par défaut (la commande à lancer, l'utilisateur, le répertoire de travail, les variables d'environnement), et vous les complétez ou les remplacez au lancement. Cette leçon établit ce contrat, puis passe en revue les options qu'on utilise réellement au quotidien. Les options liées au stockage (-v, --mount), au réseau (-p, --network) et aux ressources (--memory, --cpus) ont chacune leur leçon.

Les concepts

L'anatomie de la commande

docker run [OPTIONS] IMAGE [COMMANDE] [ARGUMENTS...]
           └──┬────┘ └─┬─┘ └──────────┬───────────┘
      pour Docker   quoi lancer   pour le conteneur

Tout ce qui se trouve avant le nom de l'image s'adresse à Docker. Tout ce qui se trouve après est transmis tel quel au conteneur. C'est la règle la plus importante de cette leçon, et la source de l'erreur la plus fréquente : une option placée après l'image n'est pas une option Docker.

ENTRYPOINT et CMD : ce que l'image prévoit

La configuration d'une image (définie par la spécification d'image OCI) contient notamment deux champs qui déterminent le processus lancé :

  • Entrypoint : le programme de base, rarement remplacé ;
  • Cmd : les arguments par défaut, ou la commande complète si Entrypoint est vide.

Le processus lancé est la concaténation Entrypoint + Cmd. Quand vous écrivez une commande après le nom de l'image, elle remplace Cmd ; Entrypoint ne change pas. Pour remplacer Entrypoint, il faut l'option --entrypoint.

Voyons ce que prévoient quatre images courantes :

$ for i in alpine:3.22 python:3.14-slim nginx:1.29 postgres:18; do
    echo "$i -> Entrypoint=$(docker image inspect $i --format '{{json .Config.Entrypoint}}') Cmd=$(docker image inspect $i --format '{{json .Config.Cmd}}')"
  done
alpine:3.22 -> Entrypoint=null Cmd=["/bin/sh"]
python:3.14-slim -> Entrypoint=null Cmd=["python3"]
nginx:1.29 -> Entrypoint=["/docker-entrypoint.sh"] Cmd=["nginx","-g","daemon off;"]
postgres:18 -> Entrypoint=["docker-entrypoint.sh"] Cmd=["postgres"]

Deux familles apparaissent :

  • Alpine et Python n'ont pas d'Entrypoint. La commande par défaut est un shell ou l'interpréteur. Tout ce que vous écrivez après l'image remplace entièrement cette commande : docker run alpine:3.22 ls / lance ls /.
  • nginx et PostgreSQL ont un script d'entrée, docker-entrypoint.sh, qui prépare l'environnement (générer une configuration, initialiser une base de données au premier lancement) puis exécute Cmd. Ce que vous écrivez après l'image remplace Cmd et devient l'argument du script : docker run postgres:18 postgres -c max_connections=200 garde l'initialisation et ajoute une option au serveur.
Vous écrivezEntrypoint de l'imageProcessus lancé
docker run alpine:3.22aucun/bin/sh
docker run alpine:3.22 ls /aucunls /
docker run nginx:1.29/docker-entrypoint.sh/docker-entrypoint.sh nginx -g "daemon off;"
docker run nginx:1.29 nginx -v/docker-entrypoint.sh/docker-entrypoint.sh nginx -v
docker run --entrypoint cat nginx:1.29 /etc/os-releaseremplacécat /etc/os-release

Les états d'un conteneur

Un conteneur passe par des états bien définis :

    stateDiagram-v2
  [*] --> created: docker create
  created --> running: docker start
  running --> paused: docker pause
  paused --> running: docker unpause
  running --> exited: fin du processus, docker stop, docker kill
  exited --> running: docker start, politique de redémarrage
  exited --> [*]: docker rm
  running --> [*]: docker rm -f
  

docker run enchaîne create puis start. Un conteneur vit exactement aussi longtemps que son processus principal : quand ce processus se termine, le conteneur passe à l'état exited, quel que soit l'état de ses éventuels processus enfants. Un conteneur arrêté n'est pas supprimé : il garde sa couche inscriptible, ses journaux et sa configuration, et on peut le relancer avec docker start.

Entrée, terminal et détachement

Trois options gouvernent la relation entre votre terminal et le conteneur :

  • -i (--interactive) garde l'entrée standard du conteneur ouverte et la relie à la vôtre. Sans -i, le conteneur reçoit une entrée vide.
  • -t (--tty) alloue un pseudo-terminal dans le conteneur. Les programmes s'y croient face à un humain : ils affichent une invite, des couleurs, et le terminal convertit les fins de ligne.
  • -d (--detach) lance le conteneur en arrière-plan et rend aussitôt la main, en affichant l'identifiant du conteneur.

-it combine les deux premières : c'est le mode d'une session interactive. -d s'emploie pour les services.

En pratique

Pourquoi mon conteneur s'arrête-t-il aussitôt ?

$ docker run --name essai alpine:3.22
$ docker ps -a --filter name=essai --format 'table {{.Names}}\t{{.Status}}\t{{.Command}}'
NAMES     STATUS                              COMMAND
essai     Exited (0) Less than a second ago   "/bin/sh"
$ docker rm essai

Rien ne s'est mal passé. La commande par défaut d'Alpine est /bin/sh. Sans -i, son entrée standard est vide : le shell lit une fin de fichier, considère qu'il n'a plus rien à faire, et se termine avec le code 0. Le processus principal s'arrête, donc le conteneur aussi. La même logique explique le classique « mon conteneur Ubuntu s'arrête tout de suite » : une image de distribution n'a pas de service à faire tourner.

-i : brancher l'entrée standard

$ echo 'echo "bonjour depuis stdin"; cat /etc/alpine-release' | docker run --rm -i alpine:3.22 sh
bonjour depuis stdin
3.22.6
$ echo 'echo bonjour' | docker run --rm alpine:3.22 sh
$

Avec -i, le script envoyé par le tube arrive dans le sh du conteneur. Sans -i, il est perdu, et sh s'arrête sans rien dire. -i seul est le bon choix pour envoyer des données à un conteneur dans un script : restaurer une sauvegarde avec docker run -i postgres:18 psql ... < sauvegarde.sql, filtrer un flux, etc.

-t : un terminal, avec ses effets de bord

Un pseudo-terminal n'est pas neutre. Comparez les octets produits avec et sans -t :

$ docker run --rm -t alpine:3.22 echo salut | od -c
0000000   s   a   l   u   t  \r  \n
0000007
$ docker run --rm alpine:3.22 echo salut | od -c
0000000   s   a   l   u   t  \n
0000006

Avec -t, la discipline de ligne du terminal a converti le saut de ligne \n en \r\n, comme le fait tout terminal. Sur un écran, c'est invisible. Dans un fichier ou un tube, c'est un \r parasite qui fait échouer une comparaison, un grep ou un traitement CSV. N'utilisez pas -t quand la sortie est destinée à un programme.

Le programme peut d'ailleurs savoir s'il a un terminal :

$ docker run --rm -it alpine:3.22 tty
/dev/pts/0
$ docker run --rm alpine:3.22 tty
not a tty

C'est ce test que font les programmes pour décider d'afficher des couleurs, une barre de progression ou une invite.

-it en CI : l'erreur classique

Dans une chaîne d'intégration continue, il n'y a pas de terminal. Une commande copiée depuis une documentation avec -it échoue alors dès qu'on lui envoie des données :

$ echo x | docker run --rm -it alpine:3.22 cat
cannot attach stdin to a TTY-enabled container because stdin is not a terminal

La correction est simple : en CI et dans les scripts, utilisez -i (si vous envoyez des données) ou rien du tout, jamais -t.

-d, --name, --rm : services et conteneurs jetables

Pour un service, on détache et on nomme :

$ docker run -d --name web -p 127.0.0.1:8080:80 nginx:1.29
edda13a1714176ab89b6e786e9de990aaadf2975cb81af85d93df04af828cb4b
$ docker ps --filter name=web --format 'table {{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}'
CONTAINER ID   IMAGE        STATUS                  PORTS                    NAMES
edda13a17141   nginx:1.29   Up Less than a second   127.0.0.1:8080->80/tcp   web
$ curl -sI http://127.0.0.1:8080 | head -2
HTTP/1.1 200 OK
Server: nginx/1.29.8
  • -d rend la main en affichant l'identifiant complet. Les douze premiers caractères (edda13a17141) suffisent partout où Docker attend un identifiant, et même moins tant qu'il n'y a pas d'ambiguïté.
  • --name web donne un nom stable. Sans lui, Docker invente un nom du type adjectif_scientifique, pratique pour les essais mais inutilisable dans un script.
  • -p 127.0.0.1:8080:80 publie le port 80 du conteneur sur le port 8080 de l'hôte, uniquement sur l'interface locale. La leçon 10 détaille la publication de ports ; retenez dès maintenant qu'on précise l'adresse d'écoute.

Un nom est unique. Relancer la même commande échoue :

$ docker run -d --name web nginx:1.29
docker: Error response from daemon: Conflict. The container name "/web" is already in use by container "edda13a1714176ab89b6e786e9de990aaadf2975cb81af85d93df04af828cb4b". You have to remove (or rename) that container to be able to reuse that name.

Le conteneur existe même arrêté. Il faut le supprimer (docker rm -f web) avant de le recréer. Pour les commandes ponctuelles, l'option --rm évite d'accumuler des conteneurs arrêtés : le conteneur est supprimé dès que son processus se termine. On ne l'utilise pas pour un service dont on veut pouvoir consulter les journaux après un arrêt inattendu.

-e et --env-file : la configuration par l'environnement

Les images bien conçues se configurent par variables d'environnement, selon le principe de l'application twelve-factor : la même image tourne en recette et en production, seule la configuration change.

$ export APP_MODE=recette
$ docker run --rm -e APP_LANG=fr -e APP_MODE alpine:3.22 sh -c 'echo "$APP_LANG $APP_MODE"'
fr recette

-e NOM=valeur fixe une valeur ; -e NOM sans valeur reprend la valeur de la variable sur l'hôte. Cette seconde forme évite d'écrire un secret en clair dans la ligne de commande, et donc dans l'historique du shell.

Quand les variables sont nombreuses, on les regroupe dans un fichier :

$ cat app.env
DB_HOST=postgres
DB_PORT=5432
# commentaire ignoré
DB_NAME="cadastre"
$ docker run --rm --env-file app.env alpine:3.22 sh -c 'env | grep ^DB_ | sort'
DB_HOST=postgres
DB_NAME="cadastre"
DB_PORT=5432

Regardez bien DB_NAME : les guillemets font partie de la valeur. Le format de --env-file n'est pas du shell : une ligne NOM=valeur est prise littéralement, guillemets compris, et il n'y a ni substitution de variables ni continuation de ligne. L'application chercherait la base "cadastre", avec les guillemets, et ne la trouverait pas. Écrivez DB_NAME=cadastre.

Notez que le fichier .env de Docker Compose (leçon 11) a des règles différentes et accepte les guillemets. Ne réutilisez pas l'un pour l'autre sans vérifier.

-u et -w : utilisateur et répertoire de travail

$ docker run --rm -u 1000:1000 -w /tmp alpine:3.22 sh -c 'id; pwd; touch /etc/test'
uid=1000 gid=1000 groups=1000
/tmp
touch: /etc/test: Permission denied

-u UID:GID lance le processus sous un autre utilisateur que celui prévu par l'image. Ici, l'UID 1000 n'existe même pas dans l'image : ce n'est pas un problème, le noyau ne manipule que des nombres. Le processus n'a plus le droit d'écrire dans /etc. -w change le répertoire de travail. Ces deux options sont utiles pour faire tourner un outil avec vos droits sur un répertoire monté (leçon 9).

--entrypoint : passer outre le script d'entrée

Pour examiner une image dont l'Entrypoint lance un service, remplacez-le :

$ docker run --rm --entrypoint cat nginx:1.29 /etc/os-release | head -1
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"

Notez l'ordre : --entrypoint cat est une option, donc avant l'image ; /etc/os-release est l'argument, donc après. On apprend ainsi que l'image nginx officielle est basée sur Debian 13. L'usage le plus courant est --entrypoint sh pour obtenir un shell dans une image dont le script d'entrée échoue au démarrage.

Les codes de sortie

Quand docker run est utilisé au premier plan, son code de sortie est celui du processus du conteneur. Mais Docker se réserve trois codes pour ses propres erreurs, sur le modèle des conventions du shell :

$ docker run --rm --nope alpine:3.22
unknown flag: --nope

Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run 'docker run --help' for more information
$ echo $?
125
$ docker run --rm alpine:3.22 /etc/hostname
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "/etc/hostname": permission denied
$ echo $?
126
$ docker run --rm alpine:3.22 commande-inexistante
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "commande-inexistante": executable file not found in $PATH
$ echo $?
127
$ docker run --rm alpine:3.22 sh -c 'exit 3'
$ echo $?
3
CodeSignification
125Erreur de Docker lui-même : option inconnue, image introuvable, conflit de nom
126La commande existe mais n'a pas pu être exécutée (pas exécutable, droits)
127La commande est introuvable dans le conteneur
128 + nLe processus a été tué par le signal n : 137 = SIGKILL (9), 143 = SIGTERM (15)
autreCode renvoyé par le programme lui-même

Lisez aussi la longue erreur en partant de la fin : elle remonte la chaîne de la leçon 3 (démon, shim, runc, initialisation du conteneur), et la cause réelle est le dernier élément (executable file not found in $PATH).

L'erreur de placement

Voici l'erreur annoncée en début de leçon :

$ docker run alpine:3.22 --rm
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "--rm": executable file not found in $PATH

Placé après l'image, --rm est devenu la commande à exécuter dans le conteneur. Et comme Docker n'a pas vu l'option --rm, le conteneur raté reste là : docker ps -a le montre à l'état Created.

Les politiques de redémarrage

L'option --restart dit à Docker quoi faire quand le processus principal se termine :

PolitiqueRedémarre si le processus s'arrêteAprès un docker stop manuelAu redémarrage du démon
no (défaut)JamaisNonNon
on-failure[:N]Si le code de sortie est non nul, au plus N foisNonNon
alwaysToujoursNon, jusqu'au prochain redémarrage du démonOui, même s'il avait été arrêté à la main
unless-stoppedToujoursNonOui, sauf s'il avait été arrêté à la main
$ docker run -d --name toujours --restart unless-stopped alpine:3.22 sleep 300
$ docker inspect toujours --format '{{json .HostConfig.RestartPolicy}}'
{"Name":"unless-stopped","MaximumRetryCount":0}
$ docker rm -f toujours

Pour un service sur un serveur sans orchestrateur, unless-stopped est généralement le bon choix : le service revient après un redémarrage de la machine, mais un arrêt volontaire est respecté. Entre deux tentatives, Docker attend un délai qui double à chaque échec (en partant de 100 ms) pour éviter de saturer la machine ; ce délai revient à sa valeur initiale dès que le conteneur a tenu au moins dix secondes.

Sous le capot

Que se passe-t-il exactement avec docker run nginx:1.29 nginx -v ? Le processus réellement lancé est /docker-entrypoint.sh nginx -v, et le script d'entrée de l'image décide quoi faire de ses arguments :

$ docker run --rm nginx:1.29 nginx -v
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
...
/docker-entrypoint.sh: Configuration complete; ready for start up
nginx version: nginx/1.29.8

(Sortie abrégée.) Le script a d'abord exécuté ses étapes de configuration, puis lancé nginx -v. Il le fait parce que le premier argument est nginx ; avec docker run nginx:1.29 ls, il aurait sauté la configuration et lancé directement ls. Ce motif est courant dans les images officielles : le script vérifie le premier argument, prépare ce qu'il faut, puis termine par exec "$@". Le exec est essentiel : il remplace le shell par le programme, qui devient ainsi le PID 1 du conteneur et reçoit directement les signaux (leçon 6).

Les autres valeurs par défaut de l'image (User, WorkingDir, Env, ExposedPorts, StopSignal) se lisent de la même façon avec docker image inspect. -u, -w et -e les remplacent ou les complètent ; les variables passées avec -e s'ajoutent à celles de l'image et l'emportent en cas de conflit.

Les états du schéma du début se parcourent à la main avec les commandes élémentaires :

$ docker create --name etats alpine:3.22 sleep 300
7a28acd34876...
$ docker inspect etats --format '{{.State.Status}}'
created
$ docker start etats
etats
$ docker inspect etats --format '{{.State.Status}}'
running
$ docker pause etats
etats
$ docker inspect etats --format '{{.State.Status}}'
paused
$ docker exec etats true
Error response from daemon: Container etats is paused, unpause the container before exec
$ docker unpause etats
etats
$ docker stop -t 2 etats
etats
$ docker inspect etats --format '{{.State.Status}} {{.State.ExitCode}}'
exited 137
$ docker rm etats
etats

docker pause n'envoie aucun signal : il gèle le cgroup du conteneur (fichier cgroup.freeze en cgroups v2). Les processus sont suspendus, sans en être informés, d'où le refus de docker exec. Et le code 137 après docker stop -t 2 ? sleep en PID 1 a ignoré SIGTERM, et Docker a dû envoyer SIGKILL au bout des deux secondes de grâce : c'est le sujet de la leçon suivante.

Pièges courants

Options après l'image. docker run nginx:1.29 -p 8080:80 ne publie aucun port : -p 8080:80 est passé au script d'entrée de nginx. Relisez toujours la commande avec la règle « avant l'image : Docker ; après : le conteneur ».

-it partout. Inutile pour un service (-d suffit), nuisible dans un script (erreur stdin is not a terminal, \r parasites). Réservez-le aux sessions interactives.

Guillemets dans --env-file. Ils font partie de la valeur. Symptôme typique : « mot de passe incorrect » ou « base introuvable » alors que la valeur semble juste.

Le conteneur qui s'arrête aussitôt. Ce n'est pas une panne : le processus principal s'est terminé. Regardez docker ps -a (le code de sortie) et docker logs <nom> (le dernier message). Si le code est 0, la commande a simplement fini son travail.

sleep infinity pour « garder le conteneur en vie ». C'est le signe qu'on utilise le conteneur comme une VM. Si le besoin est d'avoir un shell pour déboguer, docker run --rm -it image sh suffit et ne laisse rien derrière.

Sécurité

  • Les variables d'environnement ne sont pas des coffres-forts. Elles sont visibles par docker inspect pour quiconque a accès au démon, héritées par tous les processus enfants, et souvent écrites dans les journaux d'erreur par les applications. Elles conviennent aux réglages, pas aux secrets de grande valeur. Si vous devez en passer, utilisez au moins -e NOM (valeur reprise de l'environnement) ou --env-file (fichier avec des droits restreints) plutôt que la valeur en clair dans la commande. La gestion propre des secrets est abordée à la leçon 11 et dans le cours dédié.
  • --entrypoint et -u changent le profil de sécurité. Un conteneur prévu pour tourner avec un utilisateur non privilégié peut être lancé en root avec -u 0. Sur un hôte, quiconque peut lancer docker run décide de ces paramètres : c'est un argument de plus pour restreindre l'accès au démon.
  • Publiez sur 127.0.0.1 tant qu'un service n'a pas vocation à être joignable depuis le réseau. -p 8080:80 écoute sur toutes les interfaces de l'hôte.

En production

  • On ne tape pas docker run en production. Une commande de quinze options tapée à la main n'est ni relue, ni versionnée, ni reproductible. Dès qu'un conteneur doit durer, on décrit sa configuration dans un fichier : un compose.yaml (leçon 11) sur un serveur seul, des manifestes Kubernetes sur un cluster. docker run reste l'outil des essais, du diagnostic et des tâches ponctuelles.
  • Les mêmes concepts se retrouvent dans Kubernetes, sous d'autres noms : command remplace l'Entrypoint, args remplace le Cmd, env et envFrom jouent le rôle de -e et --env-file, securityContext.runAsUser celui de -u. Comprendre le contrat image/lancement ici vous évitera la confusion classique entre command et args.
  • Les politiques de redémarrage ne remplacent pas la supervision. Un conteneur qui redémarre toutes les trente secondes est « up » la plupart du temps mais ne rend aucun service. Surveillez le compteur de redémarrages (docker inspect <nom> --format '{{.RestartCount}}') et les vérifications de santé (leçon 6).

Exercices

1. Lire une commande. Dans docker run -d --name api -e LOG_LEVEL=debug -u 1000 registre.exemple.fr/api:2.3 --port 9000 --workers 4, quelles parties sont lues par Docker, et lesquelles par le conteneur ? Si l'image a Entrypoint=["/app/api"] et Cmd=["--port","8000"], quel processus est lancé ?

Solution

Docker lit -d, --name api, -e LOG_LEVEL=debug et -u 1000. Tout ce qui suit l'image (--port 9000 --workers 4) remplace le Cmd. Le processus lancé est /app/api --port 9000 --workers 4, avec l'UID 1000 et la variable LOG_LEVEL=debug ajoutée à l'environnement de l'image.

2. Restaurer par stdin. Démarrez un serveur PostgreSQL de test (docker run -d --name pg -e POSTGRES_PASSWORD=essai postgres:18), attendez quelques secondes, puis envoyez-lui la requête SQL SELECT version(); par l'entrée standard, sans ouvrir de session interactive. Indice : docker exec, présenté en détail à la leçon suivante, lance une commande dans un conteneur en cours et accepte les mêmes options -i et -t. Quelle combinaison d'options faut-il ?

Solution
$ echo 'SELECT version();' | docker exec -i pg psql -U postgres

Il faut -i pour transmettre l'entrée standard, et surtout pas -t, puisque l'entrée vient d'un tube. docker exec (leçon 6) accepte les mêmes options -i et -t que docker run. Nettoyez avec docker rm -f pg.

3. Explorer une image qui refuse de démarrer. L'image postgres:18 lancée sans variable POSTGRES_PASSWORD s'arrête aussitôt. Constatez-le, lisez le message, puis ouvrez un shell dans cette image pour lire son script d'entrée et trouver le passage qui produit le message.

Solution
$ docker run --name pg-ko postgres:18
$ docker logs pg-ko
$ docker rm pg-ko
$ docker run --rm -it --entrypoint bash postgres:18
# grep -n "POSTGRES_PASSWORD" /usr/local/bin/docker-entrypoint.sh

Le script refuse de créer une base sans mot de passe (sauf si l'on choisit explicitement POSTGRES_HOST_AUTH_METHOD=trust, à réserver aux essais). --entrypoint bash contourne le script pour l'examiner.

4. Choisir la politique (niveau 200). Pour chacun de ces conteneurs, choisissez une politique de redémarrage et justifiez : (a) une application web sur un serveur unique ; (b) une tâche de migration de base de données lancée avant chaque déploiement ; (c) un agent de collecte de métriques ; (d) un traitement par lots qui échoue parfois à cause d'un service distant indisponible.

Solution

(a) unless-stopped : le service revient après un redémarrage du serveur, un arrêt volontaire pour maintenance est respecté. (b) no : une migration doit s'exécuter une fois ; la relancer automatiquement après un échec pourrait aggraver les choses, et l'échec doit bloquer le déploiement. (c) unless-stopped ou always : il doit tourner en permanence. (d) on-failure:3 : quelques nouvelles tentatives absorbent une indisponibilité passagère, mais l'échec définitif reste visible.

Récapitulatif

  • Avant l'image : Docker. Après l'image : le conteneur. Les arguments après l'image remplacent le Cmd ; --entrypoint remplace l'Entrypoint.
  • Un conteneur vit aussi longtemps que son processus principal. S'il s'arrête aussitôt, regardez le code de sortie et les journaux.
  • -i branche l'entrée, -t ajoute un terminal (et des \r), -it sert aux sessions interactives, -d aux services. Jamais -t dans un script.
  • -e, --env-file, -u, -w complètent ou remplacent les valeurs par défaut de l'image. Les guillemets d'un --env-file font partie de la valeur.
  • Codes de sortie : 125 Docker, 126 non exécutable, 127 introuvable, 128 + n tué par le signal n.
  • --restart unless-stopped pour un service sur un serveur seul ; mais en production, on décrit les conteneurs dans des fichiers.

Pour aller plus loin

  • La référence complète de docker container run : une centaine d'options, dont beaucoup sont présentées dans les leçons suivantes.
  • La spécification de configuration d'image OCI, pour voir la liste exhaustive des valeurs par défaut qu'une image peut porter.
  • Le chapitre III (Config) de The Twelve-Factor App, qui justifie la configuration par l'environnement.
  • Leçon suivante : faire vivre un conteneur, le diagnostiquer et l'arrêter proprement.

Sources