Voici la deuxième partie du TP Docker dans le cadre de la formation Docker. Dans mon précédent article, nous avons compilé l’économiseur d’écran CMatrix sous Alpine Linux. Aujourd’hui nous allons utiliser l’historique de cette procédure pour rédiger un Dockerfile
.
Dans un premier temps, notre approche sera inefficace, pour ne pas dire pataude. Notre façon de procéder va même générer une série d’erreurs, mais c’est tout à fait intentionnel. Petit à petit, nous allons corriger ces erreurs et optimiser notre Dockerfile
de façon itérative jusqu’à ce que nous ayons un conteneur léger et rapide.
Ouvrez le Dockerfile
du précédent article avec un éditeur de texte et commencez par supprimer les numéros de ligne de l’historique. Ne vous en faites pas si vous n’avez pas exactement le même résultat que moi :
FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" LABEL org.opencontainers.image.description="Container image for CMatrix" git clone https://github.com/abishekvashok/cmatrix apk update apk add git git clone https://github.com/abishekvashok/cmatrix cd cmatrix/ ls -l autoreconf -i apk add autoconf autoreconf -i apk add automake autoreconf -i echo $? ./configure LDFLAGS="-static" apk add alpine-sdk ./configure LDFLAGS="-static" mkdir -pv /usr/lib/kbd/consolefonts mkdir -pv /usr/share/consolefonts apk add ncurses-dev ncurses-static ./configure LDFLAGS="-static" make ls -lh ./cmatrix ./cmatrix history
Identifiez toutes les étapes où nous avons avancé à tâtons pour expérimenter et/ou qui se sont soldées par un échec et commentez-les :
FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" LABEL org.opencontainers.image.description="Container image for CMatrix" # git clone https://github.com/abishekvashok/cmatrix apk update apk add git git clone https://github.com/abishekvashok/cmatrix cd cmatrix/ # ls -l # autoreconf -i apk add autoconf # autoreconf -i apk add automake autoreconf -i # echo $? # ./configure LDFLAGS="-static" apk add alpine-sdk # ./configure LDFLAGS="-static" mkdir -pv /usr/lib/kbd/consolefonts mkdir -pv /usr/share/consolefonts apk add ncurses-dev ncurses-static ./configure LDFLAGS="-static" make # ls -lh ./cmatrix ./cmatrix # history
Nous voilà avec un bon premier jet de la procédure nécessaire pour compiler un binaire cmatrix
depuis le code source.
- Nous allons ajouter l’instruction
RUN
à chacune de ces étapes, ce qui exécutera chaque commande en ajoutant à chaque fois un layer à notre image. - L’instruction
CMD
servira à exécuter le binaire résultantcmatrix
.
FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" LABEL org.opencontainers.image.description="Container image for CMatrix" # git clone https://github.com/abishekvashok/cmatrix RUN apk update RUN apk add git RUN git clone https://github.com/abishekvashok/cmatrix RUN cd cmatrix/ # ls -l # autoreconf -i RUN apk add autoconf # autoreconf -i RUN apk add automake RUN autoreconf -i # echo $? # ./configure LDFLAGS="-static" RUN apk add alpine-sdk # ./configure LDFLAGS="-static" RUN mkdir -pv /usr/lib/kbd/consolefonts RUN mkdir -pv /usr/share/consolefonts RUN apk add ncurses-dev ncurses-static RUN ./configure LDFLAGS="-static" RUN make # ls -lh ./cmatrix CMD ["./cmatrix"] # history
Faisons un premier test pour voir ce que ça donne :
$ docker build -t kikinovak/cmatrix . ... => ERROR [ 8/14] RUN autoreconf -i 1.2s
La construction de l’image a échoué à la huitième étape. Jetons un œil sur le Dockerfile
:
RUN cd cmatrix/
Ici, nous avons utilisé la commande cd
pour nous placer dans le répertoire cmatrix
. Or, ce changement de répertoire n’est pas persistant pour les instructions RUN
subséquentes.
Nous allons utiliser l’instruction WORKDIR
qui définit le répertoire de travail pour toutes les instructions RUN
, COPY
, ADD
, CMD
et ENTRYPOINT
subséquentes. Si le répertoire en question n’existe pas, l’instruction WORKDIR
se chargera de le créer :
FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" LABEL org.opencontainers.image.description="Container image for CMatrix" WORKDIR /cmatrix # git clone https://github.com/abishekvashok/cmatrix RUN apk update RUN apk add git RUN git clone https://github.com/abishekvashok/cmatrix . # ls -l # autoreconf -i RUN apk add autoconf # autoreconf -i RUN apk add automake RUN autoreconf -i # echo $? # ./configure LDFLAGS="-static" RUN apk add alpine-sdk # ./configure LDFLAGS="-static" RUN mkdir -pv /usr/lib/kbd/consolefonts RUN mkdir -pv /usr/share/consolefonts RUN apk add ncurses-dev ncurses-static RUN ./configure LDFLAGS="-static" RUN make # ls -lh ./cmatrix CMD ["./cmatrix"] # history
Notez que nous ajoutons un .
en argument à notre git clone
de manière à ce que le code source de CMatrix soit récupéré dans le répertoire courant.
À partir de là, la construction de l’image devrait se terminer avec succès :
$ docker build -t kikinovak/cmatrix . [+] Building 42.7s (18/18) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 805B 0.0s => [internal] load metadata for docker.io/library/alpine:latest 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => CACHED [ 1/14] FROM docker.io/library/alpine:latest 0.0s => [ 2/14] WORKDIR /cmatrix 0.0s => [ 3/14] RUN apk update 1.9s => [ 4/14] RUN apk add git 4.0s => [ 5/14] RUN git clone https://github.com/abishekvashok/cmatrix . 1.6s => [ 6/14] RUN apk add autoconf 4.0s => [ 7/14] RUN apk add automake 1.1s => [ 8/14] RUN autoreconf -i 2.4s => [ 9/14] RUN apk add alpine-sdk 21.5s => [10/14] RUN mkdir -pv /usr/lib/kbd/consolefonts 0.3s => [11/14] RUN mkdir -pv /usr/share/consolefonts 0.2s => [12/14] RUN apk add ncurses-dev ncurses-static 2.5s => [13/14] RUN ./configure LDFLAGS="-static" 1.5s => [14/14] RUN make 0.5s => exporting to image 1.0s => => exporting layers 1.0s => => writing image sha256:518e202f0446ae04bb20a147eea94dc2d80f1... 0.0s => => naming to docker.io/kikinovak/cmatrix 0.0s
Jetons un œil sur l’image résultante :
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kikinovak/cmatrix latest 518e202f0446 4 minutes ago 298MB
alpine latest 91ef0af61f39 6 weeks ago 7.8MB
Qu’est-ce qui se passe si nous lançons un conteneur depuis l’image ? Essayons :
$ docker run --rm -it kikinovak/cmatrix
Parfait ! Apparemment tout se passe comme prévu. Mais pour l’instant c’est loin d’être parfait. Notre conteneur a un embonpoint conséquent (298 Mo) pour un simple binaire cmatrix
.
Jusqu’ici nous n’avons appliqué aucune des bonnes pratiques conseillées pour la rédaction d’un Dockerfile
, et nous disposons de bien trop de layers.
Commençons déjà par nous débarrasser de toutes les sections commentées :
FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" LABEL org.opencontainers.image.description="Container image for CMatrix" WORKDIR /cmatrix RUN apk update RUN apk add git RUN git clone https://github.com/abishekvashok/cmatrix . RUN apk add autoconf RUN apk add automake RUN autoreconf -i RUN apk add alpine-sdk RUN mkdir -pv /usr/lib/kbd/consolefonts RUN mkdir -pv /usr/share/consolefonts RUN apk add ncurses-dev ncurses-static RUN ./configure LDFLAGS="-static" RUN make CMD ["./cmatrix"]
La commande apk add
est invoquée plusieurs fois de suite à tire larigot. Nous pouvons combiner toutes ces commandes en une seule :
FROM alpine
LABEL org.opencontainers.image.authors="Nicolas Kovacs"
LABEL org.opencontainers.image.description="Container image for CMatrix"
WORKDIR /cmatrix
RUN apk update
RUN apk add git autoconf automake alpine-sdk ncurses-dev ncurses-static
RUN git clone https://github.com/abishekvashok/cmatrix .
RUN autoreconf -i
RUN mkdir -pv /usr/lib/kbd/consolefonts
RUN mkdir -pv /usr/share/consolefonts
RUN ./configure LDFLAGS="-static"
RUN make
CMD ["./cmatrix"]
Si nous relançons la construction de l’image, nous voyons que nous n’avons plus qu’une dizaine de layers :
=> [10/10] RUN make 0.6s => exporting to image 1.3s
La prochaine étape dans notre recherche d’optimisation consiste à combiner les instructions. La barre oblique inversée \
nous permet d’obtenir des instructions multi-lignes :
LABEL org.opencontainers.image.authors="Nicolas Kovacs" \
org.opencontainers.image.description="Container image for CMatrix"
Nous pouvons faire de même avec l’instruction RUN
en combinant les commandes à l’aide de l’opérateur &&
qui effectue une commande lorsque la commande précédente s’est terminée avec succès :
FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" \ org.opencontainers.image.description="Container image for CMatrix" WORKDIR /cmatrix RUN apk update && \ apk add git autoconf automake alpine-sdk ncurses-dev ncurses-static && \ git clone https://github.com/abishekvashok/cmatrix . && \ autoreconf -i && \ mkdir -pv /usr/lib/kbd/consolefonts && \ mkdir -pv /usr/share/consolefonts && \ ./configure LDFLAGS="-static" && \ make CMD ["./cmatrix"]
Si nous relançons la construction de l’image, nous voyons que nous en sommes à trois layers, avec un conteneur qui s’exécute toujours correctement.
Le souci, c’est que l’image est toujours énorme, étant donné qu’elle contient toutes les briques logicielles nécessaires à la compilation du code.
Comment est-ce qu’on pourrait réduire tout ça ? Est-ce qu’il n’y aurait pas moyen de compiler le code source pour ensuite extraire juste le résultat de cette opération ? La réponse est oui, et nous allons nous servir d’un multi-stage build (construction en plusieurs étapes) pour ce faire.
Notre Dockerfile
sera organisé en deux sections distinctes :
# Build Container Image FROM alpine AS cmatrixbuilder WORKDIR /cmatrix RUN apk update && \ apk add git autoconf automake alpine-sdk ncurses-dev ncurses-static && \ git clone https://github.com/abishekvashok/cmatrix . && \ autoreconf -i && \ mkdir -pv /usr/lib/kbd/consolefonts && \ mkdir -pv /usr/share/consolefonts && \ ./configure LDFLAGS="-static" && \ make # CMatrix Container Image FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" \ org.opencontainers.image.description="Container image for CMatrix" COPY --from=cmatrixbuilder /cmatrix/cmatrix /cmatrix CMD ["./cmatrix"]
Relançons la construction de l’image et voyons le résultat :
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kikinovak/cmatrix latest a0bc0930a33f 37 seconds ago 8.59MB
alpine latest 91ef0af61f39 6 weeks ago 7.8MB
La réduction en termes de taille est assez spectaculaire. Mais ne nous réjouissons pas trop tôt. Voici ce que nous obtenons lorsque nous lançons un conteneur :
$ docker run --rm -it kikinovak/cmatrix Error opening terminal: xterm.
Nous en avons parlé dans le précédent article : CMatrix a besoin de NCurses, et plus précisément du paquet ncurses-terminfo-base
comme dépendance d’exécution. Il va donc falloir ajouter ce paquet à notre image :
# Build Container Image FROM alpine AS cmatrixbuilder WORKDIR /cmatrix RUN apk update --no-cache && \ apk add git autoconf automake alpine-sdk ncurses-dev ncurses-static && \ git clone https://github.com/abishekvashok/cmatrix . && \ autoreconf -i && \ mkdir -pv /usr/lib/kbd/consolefonts && \ mkdir -pv /usr/share/consolefonts && \ ./configure LDFLAGS="-static" && \ make # CMatrix Container Image FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" \ org.opencontainers.image.description="Container image for CMatrix" RUN apk update --no-cache && apk add ncurses-terminfo-base COPY --from=cmatrixbuilder /cmatrix/cmatrix /cmatrix CMD ["./cmatrix"]
Notez en passant que j’ai ajouté l’option --no-cache
à la commande apk update
. Comme son nom le suggère, cette option permet de ne pas garder les méta-informations dans le cache et de réduire encore plus la taille de l’image résultante.
On relance la construction. L’image a augmenté un tout petit peu en taille :
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kikinovak/cmatrix latest 77530482fd12 18 seconds ago 11MB
alpine latest 91ef0af61f39 6 weeks ago 7.8MB
En revanche, elle fonctionne parfaitement :
$ docker run --rm -it kikinovak/cmatrix
La prochaine étape dans le perfectionnement de notre image concerne l’utilisateur. Pour l’instant notre conteneur s’exécute en tant que root
:
$ docker run --rm -it kikinovak/cmatrix whoami root
Nous allons ajouter un utilisateur « commun mortel » pour exécuter notre application :
# Build Container Image FROM alpine AS cmatrixbuilder WORKDIR /cmatrix RUN apk update --no-cache && \ apk add git autoconf automake alpine-sdk ncurses-dev ncurses-static && \ git clone https://github.com/abishekvashok/cmatrix . && \ autoreconf -i && \ mkdir -pv /usr/lib/kbd/consolefonts && \ mkdir -pv /usr/share/consolefonts && \ ./configure LDFLAGS="-static" && \ make # CMatrix Container Image FROM alpine LABEL org.opencontainers.image.authors="Nicolas Kovacs" \ org.opencontainers.image.description="Container image for CMatrix" RUN apk update --no-cache && \ apk add ncurses-terminfo-base && \ adduser -g "Thomas Anderson" -s /usr/sbin/nologin -D -H thomas RUN apk update --no-cache && apk add ncurses-terminfo-base COPY --from=cmatrixbuilder /cmatrix/cmatrix /cmatrix USER thomas CMD ["./cmatrix"]
-g
pour le nom complet de l’utilisateur-s
pour le shell de l’utilisateur-D
pour désactiver le mot de passe-H
pour éviter la création d’un répertoire utilisateur
Je reconstruis l’image et je vérifie :
$ docker run --rm -it kikinovak/cmatrix whoami thomas
Il nous reste un dernier point de détail à régler. C’est que l’application cmatrix
est susceptible d’être lancée avec toute une série d’options. Voyez par vous-même :
$ docker run --rm -it kikinovak/cmatrix sh / $ ./cmatrix --help Usage: cmatrix -[abBcfhlsmVxk] [-u delay] [-C color] [-t tty] [-M message] -a: Asynchronous scroll -b: Bold characters on -B: All bold characters (overrides -b) -c: Use Japanese characters as seen in the original matrix. Requires appropriate fonts -f: Force the linux $TERM type to be on -l: Linux mode (uses matrix console font) -L: Lock mode (can be closed from another terminal) -o: Use old-style scrolling -h: Print usage and exit -n: No bold characters (overrides -b and -B, default) -s: "Screensaver" mode, exits on first keystroke -x: X window mode, use if your xterm is using mtx.pcf -V: Print version information and exit -M [message]: Prints your message in the center of the screen. Overrides -L's default message. -u delay (0 - 10, default 4): Screen update delay -C [color]: Use this color for matrix (default green) -r: rainbow mode -m: lambda mode -k: Characters change while scrolling. (Works without -o opt.) -t [tty]: Set tty to use
Affichez des caractères gras :
$ ./cmatrix -b
Les caractères peuvent changer pendant le défilement :
$ ./cmatrix -k
Combinez ces options avec -r
comme rainbow (arc-en-ciel) :
$ ./cmatrix -k -b -r
Pour l’instant notre image Docker permet la seule exécution de cmatrix
sans options. Nous allons donc modifier notre approche. CMD
fournit un paramètre par défaut pour exécuter un paramètre, mais nous pouvons très bien le remplacer par ENTRYPOINT
. Dans ce cas, CMD
fournira la ou les options par défaut à utiliser :
ENTRYPOINT ["./cmatrix"] CMD ["-b"]
À partir de là, les arguments que nous fournirons à l’exécution du conteneur constitueront autant de paramètres pour ENTRYPOINT
avec le mode -b
(bold pour les caractères gras) activé par défaut :
$ docker run --rm -it kikinovak/cmatrix
Testez le défilement asynchrone :
$ docker run --rm -it kikinovak/cmatrix -a
Combinez le défilement asynchrone avec les caractères gras :
$ docker run --rm -it kikinovak/cmatrix -ab
Accélérez le défilement :
$ docker run --rm -it kikinovak/cmatrix -ab -u 2
Modifiez la couleur de l’affichage :
$ docker run --rm -it kikinovak/cmatrix -ab -u 2 -C magenta
La suite au prochain numéro, où nous allons voir en détail la construction de notre image dans le but de l’utiliser sur différentes architectures : processeurs Intel & AMD, processeurs Mac Silicon, Raspberry Pi, etc.
Remerciements
Cet atelier pratique s’inspire d’une série de cours de James Spurin, un formateur Linux & Open Source assez exceptionnel. Je tiens à le remercier ici.
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.
0 commentaire