1- docker run
La commande de base docker run prend la forme suivante :
$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
Lorsque vous démarrez un conteneur Docker, vous devez d'abord décider si vous souhaitez exécuter le conteneur en arrière-plan dans un mode "detached", ou dans le mode avant-plan ("foreground") par défaut :
1.1 Mode détaché (detached)
Pour démarrer un conteneur en mode détaché, vous utilisez l'option -d=true ou simplement -d. Par conception, les conteneurs démarrés en mode détaché se terminent lorsque le processus racine utilisé pour exécuter le conteneur se termine, sauf si vous spécifiez également l'option --rm. Si vous utilisez -d avec --rm, le conteneur est supprimé lorsqu'il se termine ou lorsque le démon se termine, selon ce qui se produit en premier.
# Mode détaché : Exécute le conteneur en arrière-plan, et renvoie le nouvel identifiant du conteneur. $ docker run -d=true my_image
Ne pas passer une commande de démarrage "service x start" à un conteneur détaché. Par exemple, la commande suivante tente de démarrer le service nginx :
$ docker run -d -p 80:80 mon_image service nginx start
Cette commande réussit à démarrer le service nginx à l'intérieur du conteneur. Cependant, le paradigme du conteneur détaché n'est pas bien utilisé, en ce sens que le processus racine (service nginx start) effectue un "return" et le conteneur détaché s'arrête comme prévu. Par conséquent, le service nginx est démarré mais ne peut pas être utilisé, le conteneur étant arrêté. Au lieu de cela, pour démarrer un processus tel que le serveur web nginx, faites ce qui suit :
$ docker run -d -p 80:80 my_image nginx -g 'daemon off;'
Pour effectuer des entrées/sorties avec un conteneur détaché, utilisez des connexions réseau ou des volumes partagés. Ceux-ci sont nécessaires car le conteneur n'écoute plus la ligne de commande où docker run a été exécuté.
Pour se rattacher à un conteneur détaché, utilisez la commande docker attach.
1.2 Mode avant-plan (foreground)
En mode avant-plan (le mode par défaut lorsque -d n'est pas spécifié), docker run peut démarrer le processus dans le conteneur et attacher la console à l'entrée, la sortie et l'erreur standard du processus. Il peut même se faire passer pour un TTY (c'est ce que la plupart des exécutables en ligne de commande attendent) et transmettre des signaux. Tout cela est configurable :
-a=[] : Attacher à `STDIN`, `STDOUT` et/ou `STDERR` -t : Allouer un pseudo-tty --sig-proxy=true : Proxyer tous les signaux reçus vers le processus (mode non-TTY uniquement) -i : Garder STDIN ouvert même si non attaché
Si vous ne spécifiez pas -a, Docker attachera à la fois stdout et stderr. Vous pouvez spécifier auquel des trois flux standard (STDIN, STDOUT, STDERR) vous souhaitez vous connecter à la place, comme dans :
$ docker run -a stdin -a stdout -i -t ubuntu /bin/bash
Pour les processus interactifs (comme un shell), vous devez utiliser -i -t ensemble afin d'allouer un tty pour le processus du conteneur. -i -t est souvent écrit -it. La spécification de -t est interdite lorsque le client reçoit son entrée standard à partir d'un pipe, comme dans :
$ echo test | docker run -i busybox cat
Remarque : Un processus s'exécutant sous le PID 1 à l'intérieur d'un conteneur est traité de manière spéciale par Linux : il ignore tout signal avec l'action par défaut. Par conséquent, le processus ne se terminera pas sur SIGINT ou SIGTERM, sauf s'il est codé pour le faire.
1.3 cmd
Rappelle la COMMAND facultative dans la ligne de commande de Docker :
$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
Cette commande est facultative car la personne qui a créé l'image peut avoir déjà fourni une COMMAND par défaut à l'aide de l'instruction CMD du Dockerfile. En tant qu'opérateur (la personne qui exécute un conteneur à partir de l'image), vous pouvez remplacer cette instruction CMD en spécifiant simplement une nouvelle COMMAND.
Si l'image spécifie également un ENTRYPOINT, les instructions CMD ou COMMAND sont ajoutées comme arguments à l'ENTRYPOINT.
1.4 entrypoint
--entrypoint="" : Ecrase le point d'entrée par défaut défini par l'image
L'ENTRYPOINT d'une image est similaire à une COMMAND car il spécifie l'exécutable à lancer au démarrage du conteneur, mais il est (volontairement) plus difficile à remplacer. L'ENTRYPOINT donne au conteneur sa nature ou son comportement par défaut, de sorte que lorsque vous définissez un ENTRYPOINT, vous pouvez exécuter le conteneur comme s'il s'agissait de ce binaire, avec les options par défaut, et vous pouvez passer d'autres options via la COMMAND. Mais, parfois, un opérateur peut vouloir exécuter quelque chose d'autre à l'intérieur du conteneur, alors vous pouvez remplacer le ENTRYPOINT par défaut au moment de l'exécution en utilisant une chaîne pour spécifier le nouveau ENTRYPOINT. Voici un exemple de la façon d'exécuter un shell dans un conteneur qui a été configuré pour exécuter automatiquement autre chose (comme /usr/bin/redis-server) :
$ docker run -it --entrypoint /bin/bash example/redis
ou deux exemples de comment passer plus de paramètres à cet ENTRYPOINT :
$ docker run -it --entrypoint /bin/bash example/redis -c ls -l $ docker run -it --entrypoint /usr/bin/redis-cli exemple/redis --help
Vous pouvez réinitialiser le point d'entrée d'un conteneur en passant une chaîne vide, par exemple :
$ docker run -it --entrypoint="" mysql bash
Remarque : Passer --entrypoint effacera tout jeu de commandes par défaut sur l'image (c'est-à-dire toute instruction CMD dans le Dockerfile utilisé pour la construire).
2- docker exec
La commande docker exec prend la forme suivante :
$ docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
La commande docker exec exécute une nouvelle commande dans un conteneur en cours d'exécution.
La commande lancée à l'aide de docker exec ne s'exécute que lorsque le processus principal du conteneur (PID 1) est en cours d'exécution, et elle n'est pas relancée si le conteneur est redémarré.
COMMAND s'exécutera dans le répertoire par défaut du conteneur. Si l'image sous-jacente possède un répertoire personnalisé spécifié avec la directive WORKDIR dans son Dockerfile, celui-ci sera utilisé à la place.
COMMAND doit être un exécutable, une commande chaînée ou entre quotes ne fonctionnera pas. Exemple : docker exec -ti my_container "echo a && echo b" ne fonctionnera pas, il faudra utilise à la place docker exec -ti my_container sh -c "echo a && echo b".
2.1 Options disponibles
--detach , -d Mode détaché : exécution de la commande en arrière-plan --detach-keys Remplace la séquence de clés pour détacher un conteneur. --env , -e Définit les variables d'environnement (API 1.25+) --env-file Lire dans un fichier de variables d'environnement (API 1.25+) --interactive , -i Garde STDIN ouvert même s'il n'est pas attaché. --privileged Donne des privilèges étendus à la commande --tty , -t Allouer un pseudo-TTY --user , -u Nom d'utilisateur ou UID (format : <name|uid>[:<group|gid>]) --workdir , -w Répertoire de travail à l'intérieur du conteneur (API 1.25+)
2.2 Exemples
Tout d'abord, démarrez un conteneur.
$ docker run --name ubuntu_bash --rm -i -t ubuntu bash
Cela va créer un conteneur nommé ubuntu_bash et démarrer une session Bash.
Ensuite, exécutez une commande sur le conteneur.
$ docker exec -d ubuntu_bash touch /tmp/execWorks
Cela créera un nouveau fichier /tmp/execWorks à l'intérieur du conteneur en cours d'exécution ubuntu_bash, en arrière-plan.
Ensuite, exécutez un shell bash interactif sur le conteneur.
$ docker exec -it ubuntu_bash bash
Cela va créer une nouvelle session Bash dans le conteneur ubuntu_bash.
Ensuite, définissez une variable d'environnement dans la session bash actuelle.
$ docker exec -it -e VAR=1 ubuntu_bash bash
Cela créera une nouvelle session Bash dans le conteneur ubuntu_bash avec la variable d'environnement $VAR définie à "1". Notez que cette variable d'environnement ne sera valide que dans la session Bash actuelle.
Par défaut, la commande docker exec s'exécute dans le même répertoire de travail que celui défini lors de la création du conteneur.
$ docker exec -it ubuntu_bash pwd /
Vous pouvez sélectionner le répertoire de travail dans lequel la commande doit s'exécuter
$ docker exec -it -w /root ubuntu_bash pwd /root
3- docker inspect
La commande docker inspect est utile pour voir le détail d'une image, elle permet par exemple de déterminer quels ENTRYPOINT ou CMD ont été utilisés dans cette image :
# Syntaxe générale
docker inspect <image id>
# Exemple
$ docker inspect debian:buster-20210408
[
{
"Id": "sha256:0d587dfbc4f4800bfe9ab08662e8396ffc37060c493f8ef24b2823fef3320df6",
"RepoTags": [
"debian:buster-20210408"
],
"RepoDigests": [
"debian@sha256:ba4a437377a0c450ac9bb634c3754a17b1f814ce6fa3157c0dc9eef431b29d1f"
],
"Parent": "",
"Comment": "",
"Created": "2021-04-10T01:20:09.405921432Z",
"Container": "500e3636c803c0bfe9d45d920334767971ac9340b6b5056e19c0d0a5c55f0bc2",
"ContainerConfig": {
"Hostname": "500e3636c803",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"bash\"]"
],
"Image": "sha256:41ff4ab0523a7943deca7834d2b38985062aeb867b8282c9e71a807e873658bd",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
.....
4- Dockerfile
Un fichier Dockerfile permet de construire une image Docker, il est appelé par la commande docker build.
4.1 docker build
La commande docker build prend la forme suivante :
docker build [OPTIONS] PATH | URL | -
Elle permet de construire des images Docker à partir d'un fichier Dockerfile et d'un "contexte". Le contexte d'un build est l'ensemble des fichiers situés dans le PATH ou l'URL spécifiée. Le processus de construction peut faire référence à n'importe quel fichier du contexte. Par exemple, votre build peut utiliser une instruction COPY pour référencer un fichier dans le contexte.
Le paramètre URL peut faire référence à trois types de ressources : Les dépôts Git, les contextes de tarball pré-packagés et les fichiers en texte brut.
Voici un exemple d'utilisation classique :
# Création d'un répertoire pour le "contexte" $ mkdir ~/my_dir # Aller dans le répertoire de "contexte" et créer un fichier "Dockerfile" $ cd ~/my_dir $ vi Dockerfile # Lancement du build # option "--tag , -t" : donner un nom et un numéro de tag éventuel à l'image que l'on va construire en respectant le format 'name:tag' # À noter : il n'est pas possible de nommer et tagger l'image directement dans le Dockerfile $ docker build -t my_image:1.0 .
4.2 Instructions du Dockerfile
Les instructions ne sont pas sensibles à la casse. Cependant, la convention veut qu'elles soient en MAJUSCULES pour les distinguer plus facilement des arguments.
4.2.1 FROM
L'instruction FROM initialise une nouvelle étape de construction et définit l'image de base pour les instructions suivantes. Ainsi, un Dockerfile valide doit toujours commencer par une instruction FROM. L'image peut être n'importe quelle image valide ; il est particulièrement simple de commencer en réalisant un pull d'une image des dépôts publics.
4.2.2 LABEL
LABEL <key>=<value> <key>=<value> <key>=<value> ...
L'instruction LABEL ajoute des métadonnées à une image. Un LABEL est une paire clé-valeur. Pour inclure des espaces dans une valeur LABEL, utilisez des guillemets et des barres obliques inversées comme vous le feriez pour l'analyse syntaxique en ligne de commande. Quelques exemples d'utilisation :
LABEL "com.example.vendor"="ACME Incorporated" LABEL com.example.label-with-value="foo" LABEL version="1.0" LABEL description="Ce texte illustre le fait \ que les valeurs d'étiquette peuvent s'étendre sur plusieurs lignes."
Une image peut avoir plus d'une étiquette. Vous pouvez spécifier plusieurs étiquettes sur une seule ligne. Avant la version 1.10 de Docker, cela réduisait la taille de l'image finale, mais ce n'est plus le cas. Vous pouvez toujours choisir de spécifier plusieurs étiquettes dans une seule instruction, de l'une des deux manières suivantes :
LABEL multi.label1="valeur1" multi.label2="valeur2" other="valeur3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
4.2.3 EXPOSE
EXPOSE <port> [<port>/<protocole>...]
L'instruction EXPOSE informe Docker que le conteneur écoute sur les ports réseau spécifiés au moment de l'exécution. Vous pouvez spécifier si le port écoute sur TCP ou UDP, et la valeur par défaut est TCP si le protocole n'est pas spécifié.
L'instruction EXPOSE ne publie pas réellement le port. Elle fonctionne comme un type de documentation entre la personne qui construit l'image et la personne qui exécute le conteneur, sur les ports qui sont destinés à être publiés. Pour publier réellement le port lors de l'exécution du conteneur, utilisez l'indicateur -p sur docker run pour publier et mapper un ou plusieurs ports, ou l'indicateur -P pour publier tous les ports exposés et les mapper sur des ports d'ordre supérieur.
Par défaut, EXPOSE suppose TCP. Vous pouvez également spécifier UDP :
EXPOSE 80/udp
Pour exposer à la fois sur TCP et UDP, incluez deux lignes :
EXPOSE 80/tcp EXPOSE 80/udp
4.2.4 ENV
L'instruction ENV définit la variable d'environnement <key> à la valeur <value>. Cette valeur sera dans l'environnement pour toutes les instructions suivantes de l'étape de construction et peut être remplacée en ligne dans de nombreuses autres. La valeur sera interprétée pour d'autres variables d'environnement, donc les caractères de citation seront supprimés s'ils ne sont pas échappés. Comme pour l'analyse syntaxique des lignes de commande, les guillemets et les barres obliques inversées peuvent être utilisés pour inclure des espaces dans les valeurs.
Exemple :
ENV MY_NAME="John Doe" ENV MY_DOG=Rex\ The\ Dog ENV MY_CAT=fluffy
L'instruction ENV permet de définir plusieurs variables <key>=<value> ... en même temps, et l'exemple ci-dessous donnera les mêmes résultats nets dans l'image finale :
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
Les variables d'environnement définies à l'aide de ENV persisteront lorsqu'un conteneur sera exécuté à partir de l'image résultante. Vous pouvez afficher les valeurs à l'aide de la commande docker inspect, et les modifier en utilisant la commande docker run --env <key>=<value>.
La persistance des variables d'environnement peut entraîner des effets secondaires inattendus. Par exemple, la définition de ENV DEBIAN_FRONTEND=noninteractive modifie le comportement d'apt-get et peut perturber les utilisateurs de votre image.
Si une variable d'environnement n'est nécessaire que pendant la construction, et non dans l'image finale, envisagez plutôt de définir une valeur pour une seule commande :
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
Ou en utilisant l'instruction ARG, qui n'est pas conservée dans l'image finale :
ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y ...
4.2.5 WORKDIR
WORKDIR /path/to/workdir
L'instruction WORKDIR définit le répertoire de travail pour toutes les instructions RUN, CMD, ENTRYPOINT, COPY et ADD qui la suivent dans le Dockerfile. Si le répertoire WORKDIR n'existe pas, il sera créé même s'il n'est pas utilisé dans une instruction Dockerfile ultérieure.
L'instruction WORKDIR peut être utilisée plusieurs fois dans un Dockerfile. Si un chemin relatif est fourni, il sera relatif au chemin de l'instruction WORKDIR précédente. Par exemple :
WORKDIR /a WORKDIR b WORKDIR c RUN pwd
Le résultat de la dernière commande pwd de ce Dockerfile serait /a/b/c.
L'instruction WORKDIR peut résoudre les variables d'environnement précédemment définies à l'aide de ENV. Vous ne pouvez utiliser que les variables d'environnement explicitement définies dans le Dockerfile. Par exemple :
ENV DIRPATH=/path WORKDIR $DIRPATH/$DIRNAME RUN pwd
La sortie de la dernière commande pwd de ce fichier Docker serait /path/$DIRNAME.
4.2.6 CMD
L'instruction CMD a trois formes :
CMD ["executable", "param1", "param2"] (forme exec, c'est la forme préférée)
CMD ["param1", "param2"] (comme paramètres par défaut de ENTRYPOINT)
CMD command param1 param2 (forme shell)
Il ne peut y avoir qu'une seule instruction CMD dans un Dockerfile. Si vous listez plus d'une CMD, seule la dernière prendra effet.
L'objectif principal d'un CMD est de fournir des valeurs par défaut pour un conteneur en cours d'exécution. Ces valeurs par défaut peuvent inclure un exécutable, ou omettre l'exécutable, auquel cas vous devez également spécifier une instruction ENTRYPOINT.
Si la CMD est utilisée pour fournir des arguments par défaut pour l'instruction ENTRYPOINT, les instructions CMD et ENTRYPOINT doivent être spécifiées avec le format de tableau JSON.
Note : La forme exec est analysée comme un tableau JSON, ce qui signifie que vous devez utiliser des guillemets doubles (") autour des mots et non des guillemets simples (').
Contrairement à la forme shell, la forme exec n'invoque pas une commande shell. Cela signifie que le traitement normal du shell ne se produit pas. Par exemple, CMD [ "echo", "$HOME" ] ne fera pas de substitution de variable sur $HOME. Si vous voulez un traitement de l'interpréteur de commandes, utilisez la forme shell ou exécutez directement un interpréteur de commandes, par exemple : CMD [ "sh", "-c", "echo $HOME" ]. Lorsque vous utilisez la forme exec et que vous exécutez directement un interpréteur de commandes, comme dans le cas de la forme shell, c'est l'interpréteur de commandes qui effectue l'expansion des variables d'environnement, et non docker.
Lorsqu'elle est utilisée dans les formes shell ou exec, l'instruction CMD définit la commande à exécuter lors de l'exécution de l'image.
Si vous utilisez la forme shell de l'instruction CMD, alors la <commande> sera exécutée dans /bin/sh -c :
FROM ubuntu CMD echo "Ceci est un test." | wc -
Si vous voulez exécuter votre <commande> sans shell, alors vous devez exprimer la commande sous forme de tableau JSON et donner le chemin complet de l'exécutable. Cette forme de tableau est le format préféré de CMD. Tous les paramètres supplémentaires doivent être exprimés individuellement sous forme de chaînes de caractères dans le tableau :
FROM ubuntu CMD ["/usr/bin/wc", "--help"]
Si vous souhaitez que votre conteneur exécute le même exécutable à chaque fois, vous devez envisager d'utiliser ENTRYPOINT en combinaison avec CMD.
Si l'utilisateur spécifie des arguments à docker run, ils remplaceront les arguments par défaut spécifiés dans CMD.
Remarque : Ne confondez pas RUN et CMD. RUN exécute réellement une commande et committe le résultat ; CMD n'exécute rien au moment de la construction, mais spécifie la commande prévue pour l'image.
4.2.7 ENTRYPOINT
ENTRYPOINT a deux formes :
- La forme
exec, qui est la forme préférée :
ENTRYPOINT ["executable", "param1", "param2"]
- La forme
shell:
ENTRYPOINT command param1 param2
Un ENTRYPOINT vous permet de configurer un conteneur qui sera exécuté comme un exécutable.
Par exemple, la commande suivante démarre nginx avec son contenu par défaut, en écoutant sur le port 80 :
$ docker run -i -t --rm -p 80:80 nginx.
Les arguments de ligne de commande de docker run <image> seront ajoutés après tous les éléments d'une forme exec ENTRYPOINT, et remplaceront tous les éléments spécifiés à l'aide de CMD. Cela permet de passer des arguments au point d'entrée, c'est-à-dire que docker run <image> -d passera l'argument -d au point d'entrée. Vous pouvez remplacer l'instruction ENTRYPOINT en utilisant le flag docker run --entrypoint.
La forme shell empêche l'utilisation de tout argument de ligne de commande CMD ou run, mais présente l'inconvénient que votre ENTRYPOINT sera lancé en tant que sous-commande de /bin/sh -c, qui ne passe pas de signaux. Cela signifie que l'exécutable ne sera pas le PID 1 du conteneur - et ne recevra pas de signaux Unix - donc votre exécutable ne recevra pas de SIGTERM de docker stop <container>.
Seule la dernière instruction ENTRYPOINT du Dockerfile aura un effet.
4.2.7.1 Exemple de la forme exec de ENTRYPOINT
Vous pouvez utiliser la forme exec de ENTRYPOINT pour définir des commandes et des arguments par défaut assez stables, puis utiliser l'une ou l'autre forme de CMD pour définir des valeurs par défaut supplémentaires qui sont plus susceptibles d'être modifiées.
FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"]
Lorsque vous exécutez le conteneur, vous pouvez constater que top est le seul processus :
Pour examiner le résultat plus en détail, vous pouvez utiliser docker exec :
Et vous pouvez demander à top de s'arrêter en douceur en utilisant docker stop test.
Le fichier Dockerfile suivant montre l'utilisation de l'ENTRYPOINT pour exécuter Apache en avant-plan (c'est-à-dire en tant que PID 1) :
FROM debian:stable RUN apt-get update && apt-get install -y apache2 EXPOSE 80 443 VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"] ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
Si vous devez écrire un script de démarrage pour un seul exécutable, vous pouvez vous assurer que l'exécutable final reçoit les signaux Unix en utilisant les commandes exec et gosu :
#!/usr/bin/env bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@"
Enfin, si vous avez besoin de faire un peu de nettoyage supplémentaire (ou de communiquer avec d'autres conteneurs) à l'arrêt, ou si vous coordonnez plus d'un exécutable, vous pouvez avoir besoin de vous assurer que le script ENTRYPOINT reçoit les signaux Unix, les transmet, et fait ensuite un peu plus de travail :
#!/bin/sh # Note: I've written this using sh so it works in the busybox container too # USE the trap if you need to also do manual cleanup after the service is stopped, # or need to start multiple services in the one container trap "echo TRAPed signal" HUP INT QUIT TERM # start service in background here /usr/sbin/apachectl start echo "[hit enter key to exit] or run 'docker stop <container>'" read # stop service and clean up here echo "stopping apache" /usr/sbin/apachectl stop echo "exited $0"
Si vous exécutez cette image avec docker run -it --rm -p 80:80 --name test apache, vous pouvez ensuite examiner les processus du conteneur avec docker exec, ou docker top, puis demander au script d'arrêter Apache :
Note : Vous pouvez remplacer le paramètre ENTRYPOINT en utilisant --entrypoint, mais cela ne peut que définir le binaire sur exec (aucun sh -c ne sera utilisé).
Note : La forme exec est analysé comme un tableau JSON, ce qui signifie que vous devez utiliser des guillemets doubles (") autour des mots et non des guillemets simples (').
Contrairement à la forme shell, la forme exec n'invoque pas un shell de commande. Cela signifie que le traitement normal du shell ne se produit pas. Par exemple, ENTRYPOINT [ "echo", "$HOME" ] ne fera pas de substitution de variable sur $HOME. Si vous voulez un traitement de l'interpréteur de commandes, utilisez la forme shell ou exécutez directement un interpréteur de commandes, par exemple : ENTRYPOINT [ "sh", "-c", "echo $HOME" ]. Lorsque vous utilisez la forme exec et exécutez directement un shell, comme dans le cas de la forme shell, c'est le shell qui effectue l'expansion de la variable d'environnement, et non docker.
4.2.7.2- Exemple de forme Shell ENTRYPOINT
Vous pouvez spécifier une chaîne simple pour le ENTRYPOINT et il s'exécutera dans /bin/sh -c. Cette forme utilisera le traitement de l'interpréteur de commandes pour substituer les variables d'environnement de l'interpréteur de commandes, et ignorera tout argument de ligne de commande CMD ou docker run. Pour s'assurer que docker stop signalera correctement tout exécutable ENTRYPOINT en cours d'exécution depuis longtemps, vous devez vous souvenir de le démarrer avec exec :
FROM ubuntu ENTRYPOINT exec top -b
Lorsque vous exécutez cette image, vous verrez le seul processus PID 1 :
Qui se termine proprement sur docker stop :
Si vous oubliez d'ajouter exec au début de votre ENTRYPOINT :
FROM ubuntu ENTRYPOINT top -b CMD --ignored-param1
Vous pouvez ensuite l'exécuter (en lui donnant un nom pour l'étape suivante) :
Vous pouvez voir dans la sortie de top que le ENTRYPOINT spécifié n'est pas PID 1.
Si vous exécutez ensuite docker stop test, le conteneur ne sortira pas proprement - la commande stop sera forcée d'envoyer un SIGKILL après le délai d'attente :
4.2.8- Comprendre l'interaction entre CMD et ENTRYPOINT
Les instructions CMD et ENTRYPOINT définissent la commande à exécuter lors de l'exécution d'un conteneur. Il existe quelques règles qui décrivent leur coopération.
- Le Dockerfile doit spécifier au moins une des commandes
CMDouENTRYPOINT. ENTRYPOINTdoit être défini lorsque le conteneur est utilisé comme un exécutable.CMDdoit être utilisé pour définir des arguments par défaut pour une commandeENTRYPOINTou pour exécuter une commande ad hoc dans un conteneur.CMDsera remplacé lors de l'exécution du conteneur avec des arguments alternatifs.
Le tableau ci-dessous montre quelle commande est exécutée pour différentes combinaisons ENTRYPOINT / CMD :
Remarque : Si CMD est défini à partir de l'image de base, le réglage de ENTRYPOINT réinitialisera CMD à une valeur vide. Dans ce cas, CMD doit être défini dans l'image courante pour avoir une valeur.
4.2.9- VOLUME
VOLUME ["/data"]
L'instruction VOLUME crée un point de montage avec le nom spécifié et le marque comme contenant des volumes montés en externe depuis l'hôte natif ou d'autres conteneurs. La valeur peut être un tableau JSON, VOLUME ["/var/log/"], ou une chaîne simple avec plusieurs arguments, comme VOLUME /var/log ou VOLUME /var/log /var/db.
La commande docker run initialise le volume nouvellement créé avec toutes les données qui existent à l'emplacement spécifié dans l'image de base. Par exemple, considérez l'extrait de Dockerfile suivant :
FROM ubuntu RUN mkdir /myvol RUN echo "hello world" > /myvol/greeting VOLUME /myvol
Ce fichier Dockerfile génère une image qui demande à docker run de créer un nouveau point de montage sur /myvol et de copier le fichier d'accueil dans le volume nouvellement créé.
4.2.9.1- Remarques sur la spécification des volumes
Gardez à l'esprit les éléments suivants concernant les volumes dans le Dockerfile.
- Volumes sur les conteneurs basés sur Windows : Lorsque vous utilisez des conteneurs basés sur Windows, la destination d'un volume à l'intérieur du conteneur doit être l'une des suivantes :
- un répertoire inexistant ou vide
- un lecteur autre que C :
- Modification du volume à partir du fichier
Dockerfile: Si une étape de construction modifie les données à l'intérieur du volume après qu'il ait été déclaré, ces modifications seront écartées. - Formatage
JSON: La liste est analysée comme un tableauJSON. Vous devez entourer les mots de guillemets doubles (") plutôt que de guillemets simples ('). - Le répertoire hôte est déclaré au moment de l'exécution du conteneur : Le répertoire hôte (le point de montage) est, par nature, dépendant de l'hôte. Cela permet de préserver la portabilité de l'image, car on ne peut pas garantir qu'un répertoire hôte donné sera disponible sur tous les hôtes. Pour cette raison, vous ne pouvez pas monter un répertoire hôte à partir du
Dockerfile. L'instructionVOLUMEne prend pas en charge la spécification d'un paramètrehost-dir. Vous devez spécifier le point de montage lorsque vous créez ou exécutez le conteneur.
4.2.10- ARG
ARG <name>[=<default value>]
L'instruction ARG définit une variable que les utilisateurs peuvent transmettre au moment de la construction au constructeur avec la commande docker build en utilisant le flag --build-arg <varname>=<value>. Si un utilisateur spécifie un argument de construction qui n'a pas été défini dans le Dockerfile, le constructeur émet un avertissement.
[Warning] One or more build-args [foo] were not consumed.
Un Dockerfile peut inclure une ou plusieurs instructions ARG. Par exemple, le texte suivant est un fichier Dockerfile valide :
FROM busybox ARG utilisateur1 ARG buildno # ...
Avertissement : Il n'est pas recommandé d'utiliser les variables build-time pour transmettre des secrets comme les clés github, les informations d'identification des utilisateurs, etc. Les valeurs des variables de build-time sont visibles par tout utilisateur de l'image avec la commande docker history.
4.2.10.1- Valeurs par défaut
Une instruction ARG peut éventuellement inclure une valeur par défaut :
FROM busybox ARG user1=someuser ARG buildno=1 # ...
Si une instruction ARG a une valeur par défaut et si aucune valeur n'est passée au moment de la construction, le constructeur utilise la valeur par défaut.
4.2.10.2- Portée
La définition d'une variable ARG prend effet à partir de la ligne sur laquelle elle est définie dans le Dockerfile et non à partir de l'utilisation de l'argument sur la ligne de commande ou ailleurs. Par exemple, considérez ce Dockerfile :
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
# ...
Un utilisateur construit ce fichier en appelant :
docker build --build-arg user=what_user .
L'USER de la ligne 2 est évalué à some_user car la variable user est définie à la ligne 3 suivante. Le USER de la ligne 4 est évalué à what_user car la variable user est définie et la valeur what_user a été passée sur la ligne de commande. Avant sa définition par une instruction ARG, toute utilisation d'une variable résulte en une chaîne vide.
Une instruction ARG sort de sa portée à la fin de l'étape de construction où elle a été définie. Pour utiliser un arg dans plusieurs étapes, chaque étape doit inclure l'instruction ARG.
FROM busybox ARG SETTINGS RUN ./run/setup $SETTINGS FROM busybox ARG SETTINGS RUN ./run/other $SETTINGS
4.2.10.3- Utilisation des variables ARG
Vous pouvez utiliser une instruction ARG ou ENV pour spécifier des variables qui sont disponibles pour l'instruction RUN. Les variables d'environnement définies à l'aide de l'instruction ENV remplacent toujours une instruction ARG du même nom. Considérez ce Dockerfile avec une instruction ENV et ARG.
FROM ubuntu ARG CONT_IMG_VER ENV CONT_IMG_VER=v1.0.0 RUN echo $CONT_IMG_VER
Ensuite, supposons que cette image soit construite avec cette commande :
docker build --build-arg CONT_IMG_VER=v2.0.1 .
Dans ce cas, l'instruction RUN utilise v1.0.0 au lieu du paramètre ARG transmis par l'utilisateur : v2.0.1 Ce comportement est similaire à celui d'un script shell où une variable à portée locale remplace les variables, transmises en tant qu'arguments, ou héritées de l'environnement, à partir de son point de définition.
En utilisant l'exemple ci-dessus mais une spécification ENV différente, vous pouvez créer des interactions plus utiles entre les instructions ARG et ENV :
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER
Contrairement à une instruction ARG, les valeurs ENV sont toujours conservées dans l'image construite. Considérons une construction docker sans le flag --build-arg :
docker build .
En utilisant cet exemple de Dockerfile, CONT_IMG_VER est toujours conservé dans l'image, mais sa valeur serait v1.0.0, car il s'agit de la valeur par défaut définie à la ligne 3 par l'instruction ENV.
La technique d'expansion de variable dans cet exemple vous permet de passer des arguments depuis la ligne de commande et de les faire persister dans l'image finale en exploitant l'instruction ENV. L'expansion de variable n'est prise en charge que pour un ensemble limité d'instructions Dockerfile.
4.2.10.4- ARG prédéfinis
Docker dispose d'un ensemble de variables ARG prédéfinies que vous pouvez utiliser sans instruction ARG correspondante dans le Dockerfile.
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
Pour les utiliser, passez-les sur la ligne de commande en utilisant le flag --build-arg, par exemple :
docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .
Par défaut, ces variables prédéfinies sont exclues de la sortie de docker history. Le fait de les exclure réduit le risque de fuite accidentelle d'informations d'authentification sensibles dans une variable HTTP_PROXY.
Par exemple, considérez la construction du fichier Dockerfile suivant en utilisant --build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com
FROM ubuntu RUN echo "Hello World"
Dans ce cas, la valeur de la variable HTTP_PROXY n'est pas disponible dans docker history et n'est pas mise en cache. Si vous changez d'emplacement et que votre serveur proxy passe à http://user:pass@proxy.sfo.example.com, une construction ultérieure n'entraînera pas d'erreur de cache.
Si vous avez besoin de remplacer ce comportement, vous pouvez le faire en ajoutant une déclaration ARG dans le Dockerfile comme suit :
FROM ubuntu ARG HTTP_PROXY RUN echo "Hello World"
Lors de la construction de ce Dockerfile, le HTTP_PROXY est conservé dans docker history, et la modification de sa valeur invalide le cache de construction.
4.2.11- ADD
ADD a deux formes :
ADD [--chown=<user>:<group>] <src>.... <dest> ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
La dernière forme est requise pour les chemins contenant des espaces.
Remarque : La fonctionnalité --chown est uniquement prise en charge sur les Dockerfiles utilisés pour construire des conteneurs Linux, et ne fonctionnera pas sur les conteneurs Windows. Étant donné que les concepts de propriété des utilisateurs et des groupes ne se traduisent pas entre Linux et Windows, l'utilisation de /etc/passwd et /etc/group pour traduire les noms d'utilisateurs et de groupes en identifiants limite cette fonctionnalité à être viable uniquement pour les conteneurs basés sur le système d'exploitation Linux.
L'instruction ADD copie de nouveaux fichiers, répertoires ou URL de fichiers distants depuis <src> et les ajoute au système de fichiers de l'image au chemin <dest>.
Plusieurs ressources <src> peuvent être spécifiées mais s'il s'agit de fichiers ou de répertoires, leurs chemins sont interprétés comme relatifs à la source du contexte de la construction.
Chaque <src> peut contenir des caractères génériques et la correspondance sera effectuée en utilisant les règles filepath.Match de Go. Par exemple :
Pour ajouter tous les fichiers commençant par "hom" :
ADD hom* /mydir/
Dans l'exemple ci-dessous, ? est remplacé par n'importe quel caractère unique, par exemple, "home.txt".
ADD hom ?.txt /mydir/
Le <dest> est un chemin absolu, ou un chemin relatif à WORKDIR, dans lequel la source sera copiée, à l'intérieur du conteneur de destination.
L'exemple ci-dessous utilise un chemin relatif, et ajoute "test.txt" à <WORKDIR>/relativeDir/ :
ADD test.txt relativeDir/
Alors que cet exemple utilise un chemin absolu, et ajoute "test.txt" à /absoluteDir/ :
ADD test.txt /absoluteDir/
Lorsque vous ajoutez des fichiers ou des répertoires qui contiennent des caractères spéciaux (tels que [ et ]), vous devez échapper ces chemins en suivant les règles de Golang pour éviter qu'ils ne soient traités comme un motif de correspondance. Par exemple, pour ajouter un fichier nommé arr[0].txt, utilisez ce qui suit :
ADD arr[[]0].txt /mydir/
Tous les nouveaux fichiers et répertoires sont créés avec un UID et un GID de 0, à moins que l'option --chown ne spécifie un nom d'utilisateur, un nom de groupe ou une combinaison UID/GID pour demander la propriété spécifique du contenu ajouté. Le format de l'option --chown permet de spécifier soit des chaînes de nom d'utilisateur et de nom de groupe, soit des nombres entiers directs UID et GID dans n'importe quelle combinaison. Fournir un nom d'utilisateur sans nom de groupe ou un UID sans GID utilisera le même UID numérique que le GID. Si un nom d'utilisateur ou un nom de groupe est fourni, les fichiers /etc/passwd et /etc/group du système de fichiers racine du conteneur seront utilisés pour effectuer la conversion du nom en UID ou GID entier respectivement. Les exemples suivants montrent des définitions valides pour le flag --chown :
ADD --chown=55:mygroup files* /somedir/ ADD --chown=bin files* /somedir/ ADD --chown=1 files* /somedir/ ADD --chown=10:11 files* /somedir/
Si le système de fichiers racine du conteneur ne contient pas les fichiers /etc/passwd ou /etc/group et que des noms d'utilisateurs ou de groupes sont utilisés dans le flag --chown, la compilation échouera lors de l'opération ADD. L'utilisation d'identifiants numériques ne nécessite aucune recherche et ne dépendra pas du contenu du système de fichiers racine du conteneur.
Dans le cas où <src> est une URL de fichier distant, la destination aura des permissions de 600. Si le fichier distant récupéré possède un en-tête HTTP Last-Modified, l'horodatage de cet en-tête sera utilisé pour définir le mtime du fichier de destination. Cependant, comme tout autre fichier traité au cours d'un ADD, le mtime ne sera pas pris en compte pour déterminer si le fichier a été modifié ou non et si le cache doit être mis à jour.
Remarque : Si vous construisez en passant un Dockerfile par STDIN (docker build - < somefile), il n'y a pas de contexte de construction, donc le Dockerfile peut seulement contenir une instruction ADD basée sur une URL. Vous pouvez également transmettre une archive compressée via STDIN : (docker build - < archive.tar.gz), le Dockerfile à la racine de l'archive et le reste de l'archive seront utilisés comme contexte de construction.
Si vos fichiers URL sont protégés par une authentification, vous devez utiliser RUN wget, RUN curl ou un autre outil à partir du conteneur, car l'instruction ADD ne prend pas en charge l'authentification.
Remarque : La première instruction ADD rencontrée invalidera le cache pour toutes les instructions suivantes du Dockerfile si le contenu de <src> a changé. Cela inclut l'invalidation du cache pour les instructions RUN.
ADD obéit aux règles suivantes :
- Le chemin
<src>doit se trouver à l'intérieur du contexte de la construction ; vous ne pouvez pas écrireADD ../something /something, car la première étape d'undocker buildconsiste à envoyer le répertoire de contexte (et les sous-répertoires) audémon docker. - Si
<src>est uneURLet que<dest>ne se termine pas par une barre oblique, alors un fichier est téléchargé depuis l'URLet copié sur<dest>. - Si
<src>est uneURLet que <dest> se termine par une barre oblique, le nom du fichier est déduit de l'URLet le fichier est téléchargé dans<dest>/<filename>. Par exemple,ADD http://example.com/foobar /créerait le fichier/foobar. L'URLdoit avoir un chemin non trivial pour qu'un nom de fichier approprié puisse être découvert dans ce cas (http://example.comne fonctionnera pas). - Si
<src>est un répertoire, tout le contenu du répertoire est copié, y compris les métadonnées du système de fichiers.
Remarque : Le répertoire lui-même n'est pas copié, seulement son contenu.
- Si
<src>est une archive tar locale dans un format de compression reconnu (identity,gzip,bzip2ouxz), elle est décompressée comme un répertoire. Les ressources provenant d'URLs distantesne sont pas décompressées. Quand un répertoire est copié ou décompressé, il a le même comportement quetar -x, le résultat est l'union de :- Ce qui existait sur le chemin de destination et
- Le contenu de l'arbre source, les conflits étant résolus en faveur de "2." sur une base fichier par fichier.
Remarque : L'identification d'un fichier comme un format de compression reconnu ou non se fait uniquement sur la base du contenu du fichier, et non de son nom. Par exemple, si un fichier vide se termine par .tar.gz, il ne sera pas reconnu comme un fichier compressé et ne générera pas de message d'erreur de décompression, mais le fichier sera simplement copié vers la destination.
- Si
<src>est un autre type de fichier, il est copié individuellement avec ses métadonnées. Dans ce cas, si<dest>se termine par une barre oblique, il sera considéré comme un répertoire et le contenu de<src>sera écrit à<dest>/base(<src>). - Si plusieurs ressources
<src>sont spécifiées, soit directement, soit en raison de l'utilisation d'un caractère générique, alors<dest>doit être un répertoire, et il doit se terminerpar une barre oblique. - Si
<dest>ne se termine pas par une barre oblique, il sera considéré comme un fichier régulier et le contenu de<src>sera écrit à<dest>. - Si
<dest>n'existe pas, il est créé avec tous les répertoires manquants dans son chemin.
4.2.12- COPY
COPY a deux formes :
COPY [--chown=<user>:<group>] <src>... <dest> COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
Cette dernière forme est requise pour les chemins contenant des espaces.
Remarque : La fonctionnalité --chown est uniquement prise en charge sur les Dockerfiles utilisés pour construire des conteneurs Linux, et ne fonctionnera pas sur les conteneurs Windows. Étant donné que les concepts de propriété des utilisateurs et des groupes ne se traduisent pas entre Linux et Windows, l'utilisation de /etc/passwd et /etc/group pour traduire les noms d'utilisateurs et de groupes en identifiants limite cette fonctionnalité aux conteneurs basés sur le système d'exploitation Linux.
L'instruction COPY copie de nouveaux fichiers ou répertoires depuis <src> et les ajoute au système de fichiers du conteneur au chemin <dest>.
Plusieurs ressources <src> peuvent être spécifiées mais les chemins des fichiers et des répertoires seront interprétés comme relatifs à la source du contexte de la construction.
Chaque <src> peut contenir des caractères génériques et la correspondance sera effectuée en utilisant les règles filepath.Match de Go. Par exemple :
Pour ajouter tous les fichiers commençant par "hom" :
COPY hom* /mydir/
Dans l'exemple ci-dessous, ? est remplacé par n'importe quel caractère unique, par exemple, "home.txt".
COPY hom ?.txt /mydir/
Le <dest> est un chemin absolu, ou un chemin relatif à WORKDIR, dans lequel la source sera copiée à l'intérieur du conteneur de destination.
L'exemple ci-dessous utilise un chemin relatif, et ajoute "test.txt" à <WORKDIR>/relativeDir/ :
COPY test.txt relativeDir/
Alors que cet exemple utilise un chemin absolu, et ajoute "test.txt" à /absoluteDir/
COPY test.txt /absoluteDir/
Lorsque vous copiez des fichiers ou des répertoires qui contiennent des caractères spéciaux (tels que [ et ]), vous devez échapper ces chemins en suivant les règles de Golang pour éviter qu'ils ne soient traités comme un motif de correspondance. Par exemple, pour copier un fichier nommé arr[0].txt, utilisez ce qui suit :
COPY arr[[]0].txt /mydir/
Tous les nouveaux fichiers et répertoires sont créés avec un UID et un GID de 0, à moins que l'option --chown ne spécifie un nom d'utilisateur, un nom de groupe ou une combinaison UID/GID pour demander la propriété spécifique du contenu copié. Le format de l'option --chown permet de spécifier soit des chaînes de nom d'utilisateur et de nom de groupe, soit des nombres entiers directs UID et GID dans n'importe quelle combinaison. Fournir un nom d'utilisateur sans nom de groupe ou un UID sans GID utilisera le même UID numérique que le GID. Si un nom d'utilisateur ou un nom de groupe est fourni, les fichiers /etc/passwd et /etc/group du système de fichiers racine du conteneur seront utilisés pour effectuer la conversion du nom en UID ou GID entier respectivement. Les exemples suivants montrent des définitions valides pour le flag --chown :
COPY --chown=55:mygroup files* /somedir/ COPY --chown=bin fichiers* /somedir/ COPY --chown=1 fichiers* /somedir/ COPY --chown=10:11 fichiers* /somedir/
Si le système de fichiers racine du conteneur ne contient pas les fichiers /etc/passwd ou /etc/group et que des noms d'utilisateurs ou de groupes sont utilisés dans le flag --chown, la compilation échouera lors de l'opération COPY. L'utilisation d'identifiants numériques ne nécessite aucune recherche et ne dépend pas du contenu du système de fichiers racine du conteneur.
Remarque : Si vous construisez en utilisant STDIN (docker build - < somefile), il n'y a pas de contexte de construction, donc COPY ne peut pas être utilisé.
Optionnellement, COPY accepte un flag --from=<name> qui peut être utilisé pour définir l'emplacement source à une étape de construction précédente (créée avec FROM .. AS <name>) qui sera utilisée à la place d'un contexte de construction envoyé par l'utilisateur. Dans le cas où une étape de construction avec un nom spécifié ne peut pas être trouvée, une image avec le même nom est tentée pour être utilisée à la place.
COPY obéit aux règles suivantes :
- Le chemin
<src>doit être à l'intérieur du contexte de la construction ; vous ne pouvez pas écrireCOPY ../something /something, car la première étape d'undocker buildconsiste à envoyer le répertoire de contexte (et les sous-répertoires) audémon docker. - Si
<src>est un répertoire, tout le contenu du répertoire est copié, y compris les métadonnées du système de fichiers.
Remarque : Le répertoire lui-même n'est pas copié, seulement son contenu.
- Si
<src>est tout autre type de fichier, il est copié individuellement avec ses métadonnées. Dans ce cas, si<dest>se termine par un slash de fin/, il sera considéré comme un répertoire et le contenu de<src>sera écrit à<dest>/base(<src>). - Si plusieurs ressources
<src>sont spécifiées, soit directement, soit en raison de l'utilisation d'un caractère générique, alors<dest>doit être un répertoire, et il doit se terminer par un slash/. - Si
<dest>ne se termine pas par un slash de fin, il sera considéré comme un fichier régulier et le contenu de<src>sera écrit à<dest>. - Si
<dest>n'existe pas, il est créé avec tous les répertoires manquants dans son chemin.
Remarque : La première instruction COPY rencontrée invalidera le cache pour toutes les instructions suivantes du Dockerfile si le contenu de <src> a changé. Cela inclut l'invalidation du cache pour les instructions RUN.
4.2.13- ADD vs COPY
Parfois, vous voyez COPY ou ADD être utilisés dans un fichier Dockerfile, mais dans 99 % des cas, vous devriez utiliser COPY, voici pourquoi.
COPYetADDsont deux instructions deDockerfilequi ont des objectifs similaires. Elles vous permettent de copier des fichiers d'un emplacement spécifique dans uneimage Docker.COPYprend en compte unesourceet unedestination. Elle vous permet uniquement de copier unfichierou unrépertoirelocal de votre hôte (la machine qui crée l'image Docker) dans l'image Dockerelle-même.ADDvous permet également de faire cela, mais il prend également en chargedeux autres sources.- Premièrement, vous pouvez utiliser une
URLau lieu d'un fichier/répertoire local. - Deuxièmement, vous pouvez extraire un
fichier tarde la source directement dans la destination.
- Premièrement, vous pouvez utiliser une
- Dans la plupart des cas, si vous utilisez une
URL, vous téléchargez unfichier zipet vous utilisez ensuite la commandeRUNpour l'extraire. Cependant, vous pouvez tout aussi bien utiliserRUN avec curlau lieu deADDici, afin de tout enchaîner enune seule commande RUNpour obtenir uneimage Dockerplus petite. - Un cas d'utilisation valide pour
ADDest lorsque vous voulez extraire unfichier tar localdans un répertoire spécifique de votreimage Docker. C'est exactement ce que fait l'image AlpineavecADD rootfs.tar.gz /. - Si vous copiez des
fichiers locauxdans votreimage Docker, utilisez toujoursCOPYcar c'est plus explicite.