User Tools

Site Tools


virtualisation:docker-dockerfile

Docker: précisions sur le Dockerfile

Dans cet article, on passera à la loupe le Dockerfile, le fichier de description d’une image et d’un conteneur Docker . Même si le nombre de commandes est réduit, leur subtilité n’apparaît pas à la première utilisation. Le site officiel demeure la meilleure source de documentation. On ne s’attardera que sur les commandes de base – ADD, COPY, CMD et ENTRYPOINT.

Les layers :

Dans le Dockerfile, chaque commande (ADD, COPY, CMD, ENTRYPOINT, …) fait l’objet d’ajout d’une nouvelle couche (COW) à l’image. Et les couches, moins on en a, mieux c’est pour la taille des images. Sachant qu’en plus, le nombre de couches a une limite (42 auparavant et 127 depuis peu). Même si la contrainte du nombre de lignes (ou couches) est quasiment écartée, regrouper les commandes facilite la compréhension du Dockerfile.

Tip : Regrouper les commandes autant que possible

* Example 1. Dockerfile (avec 4 couches)

RUN curl -fsSL http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz
RUN tar xzf apache-maven-$MAVEN_VERSION-bin.tar.gz  - -C /usr/share
RUN mv /usr/share/apache-maven-$MAVEN_VERSION /usr/share/maven
RUN ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
* Example 2. Dockerfile “refactore” en une seule commande

RUN curl -fsSL http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz | tar xzf - -C /usr/share \
  && mv /usr/share/apache-maven-$MAVEN_VERSION /usr/share/maven \
  && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn

On réduit le nombre de couches a une et on a gagne en lisibilité.

Le cache

Toutes les couches d’une image sont mises dans le cache. Quand on lance le build d’une image Docker, il faut d’abord commencer par chercher dans le cache des couches qu’il pourrait réutiliser pour optimiser le temps de construction de l’image en évitant les téléchargements inutiles. De ce fait, en cas de modification, seules les lignes concernées par la modification seront réexecutées.

FROM java:openjdk-8-jdk
MAINTAINER Yakhya DABO
ENV MAVEN_VERSION 3.3.3
ENV M2_HOME /usr/share/maven
ENV PROJECT_DIR /usr/src/app
...

...
8. RUN mkdir -p $PROJECT_DIR
9. COPY config/settings.xml $M2_HOME/conf/
10. RUN curl -fsSL http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz | tar xzf - -C /usr/share \
  && mv /usr/share/apache-maven-$MAVEN_VERSION /usr/share/maven \
  && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
11. VOLUME $PROJECT_DIR
12. WORKDIR $PROJECT_DIR

Si on apporte une modification sur la ligne 9, le cache invalide toutes ses filles, les lignes 10, 11, … qui seront réexecutées. Les lignes 0, 1, … 8 n’étant pas des filles de 9, elles ne seront pas concernées par les modifications, c’est le cache qui sera utilisé.

Deux astuces pour bien profiter du cache :

  • Placer les lignes qui changent souvent le plus bas possible (ajout d’un jar par exemple, COPY).
  • Mettre les opérations coûteuses le plus haut possible dans le Dockerfile afin d’éviter de les réexécuter à chaque modification (téléchargement par exemple, RUN curl).

Les Directives

La directive FROM spécifie une image à partir de laquelle Toute référence d'image valide peut être utilisée.

FROM node:5

La directive WORKDIR définit le répertoire de travail actuel dans le conteneur, ce qui équivaut à exécuter cd dans le conteneur. RUN cd ne changera pas le répertoire de travail en cours.

WORKDIR /usr/src/app

La directive RUN exécute la commande donnée à l'intérieur du conteneur.

RUN npm install cowsay knock-knock-jokes

La directive COPY copie le fichier ou le répertoire spécifié dans le premier argument à partir du contexte de génération (le path transmis au docker build path ) vers l'emplacement du conteneur spécifié par le deuxième argument.

COPY cowsay-knockknock.js .

La directive CMD spécifie une commande à exécuter lorsque l'image est exécutée et qu'aucune commande n'est donnée. Il peut être remplacé en transmettant une commande à docker run .

CMD node cowsay-knockknock.js

Il existe de nombreuses autres instructions et options.

Organisation d'un dockerfile

Exemple simple

# Base image
FROM python:2.7-alpine

# Metadata
MAINTAINER John Doe <johndoe@example.com>

# System-level dependencies
RUN apk add --update \
    ca-certificates \
    && update-ca-certificates \
    && rm -rf /var/cache/apk/*

# App dependencies
COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt

# App codebase
WORKDIR /app
COPY . ./

# Configs
ENV DEBUG true
EXPOSE 5000
CMD ["python", "app.py"]

Classement du contenu

Le dokerfile présenté ci-dessus est organisé de la maière suivante

  • Déclaration d'image de base (FROM)
  • Métadonnées (par exemple MAINTAINER , LABEL )
  • Installation des dépendances du système (RUN: apt-get install , apk add )
  • Copie du fichier de dépendances de l'application (COPY: bower.json , package.json , build.gradle , requirements.txt )
  • Installation de dépendances d'application (RUN: npm install pip install )
  • Copier l'intégralité du code
  • Configuration des configurations d'exécution par défaut (CMD, ENTRYPOINT ,ENV ,EXPOSE )

Ces commandes sont destinées à optimiser le temps de création à l'aide du mécanisme de mise en cache intégré de Docker.

Règle de base: Les parties qui changent souvent (par exemple, la base de code) doivent être placées au bas du fichier Dockerfile et vice-versa. Les parties qui changent rarement (par exemple les dépendances) doivent être placées en haut.

Directives ADD et COPY

Ces deux commandes sont facilement sujet à confusion, de par leur nom mais aussi de par leur syntaxe : elles semblent faire la même chose, sauf que dans la pratique, ce n’est pas tout le temps le cas.

 ADD  src dest
 COPY   src dest
  • src: un répertoire (ou fichier) du host relatif au contextDir.
  • dest: un nom de fichier (/var/opt/fileName), ou un répertoire (/var/opt/) du conteneur
Une petite précision : dans la commande “docker build”, on spécifie le context du Dockerfile.

 $ docker build -f dockerfileDir contextDir

ou

 $ docker build contextDir  // (si contextDir = buildDir)

ADD

ADD peut aussi faire la même chose, mais le src peut être une URL. Dans ce cas, docker se charge du téléchargement et de placer le fichier téléchargé dans dest. Si src est un fichier zippé et dest un répertoire docker dezzipe src (ADD file.zip /var/opt/).

COPY

COPY se contente tout simplement de prendre un fichier (ou répertoire) du host et de le mettre dans le conteneur.

On peut se contenter de COPY pour les opérations simples de copie du host vers le conteneur, et de coupler RUN avec les utilitaires existants tels que tar, unzip, wget, curl, … si on a besoin de zipper ou de télécharger des fichiers.

Directives CMD et ENTRYPOINT

Il existe deux directives Dockerfile pour spécifier quelle commande exécuter par défaut dans les images construites. Si vous spécifiez uniquement CMD alors docker exécutera cette commande en utilisant le ENTRYPOINT par défaut, à savoir /bin/sh -c. On peut remplacer soit le point d’entrée, soit la commande lorsqu'on démarre l’image construite.

Si on spécifie les deux, alors ENTRYPOINT spécifie l'exécutable du processus de conteneur et CMD sera fourni comme paramètre de cet exécutable.

CMD

Par exemple, si Dockerfile contient

FROM ubuntu:16.04
CMD ["/bin/date"]

On utilise la directive ENTRYPOINT par défaut de /bin/sh -c avec /bin/date (par défaut). La commande du processus de conteneur sera /bin/sh -c /bin/date . Lorsqu'on exécutera cette image, elle affichera par défaut la date actuelle

$ docker build -t test .
$ docker run test
Tue Jul 19 10:37:43 UTC 2016

On peut spécifier la commande à passer sur la ligne de commande, auquel cas il exécutera la commande spécifiée.

$ docker run test /bin/hostname
bf0274ec8820

ENTRYPOINT

Lorsqu'on spécifie une directive ENTRYPOINT , Docker utilise cet exécutable et la directive CMD spécifie le ou les paramètres par défaut de la commande. Donc, si votre Dockerfile contient:

FROM ubuntu:16.04
ENTRYPOINT ["/bin/echo"]
CMD ["Hello"]

Alors lord fe l'exécution ça va produire

$ docker build -t test .
$ docker run test
Hello

On peut fournir différents paramètres, mais ils seront tous exécutés dans /bin/echo

$ docker run test Hi
Hi

Pour remplacer le point d'entrée répertorié dans le fichier Docker (par exemple, si on souhaite exécuter une commande différente de echo dans ce conteneur), il faut spécifier le paramètre --entrypoint sur la ligne de commande:

$ docker run --entrypoint=/bin/hostname test
b2c70e74df18

Généralement, on utilise la directive ENTRYPOINT pour pointer vers uns script que l'on vous souhaite exécuter et CMD vers les paramètres par défaut.

Directive EXPOSE

Expose un port dans le fichier Dockerfile

Description

EXPOSE <port> [<port>...]

EXPOSE informe Docker que le conteneur écoute les ports réseau spécifiés au moment de l'exécution. EXPOSE ne rend pas les ports du conteneur accessibles à l'hôte. Pour ce faire, vous devez utiliser l'option -p pour publier une plage de ports ou l'option -P pour publier tous les ports exposés. On peut exposer un numéro de port et le publier en externe sous un autre numéro.

Exemple:

À l'intérieur du fichier Docker:

EXPOSE 8765

Pour accéder à ce port depuis la machine hôte, inclure cet argument dans le commande docker run :

-p 8765:8765

virtualisation/docker-dockerfile.txt · Last modified: 2025/02/19 10:59 by 127.0.0.1