DockerVoici le premier volet d’un petit atelier pratique que j’aime bien faire avec mes étudiants ou mes stagiaires dans le cadre de mes cours sur Docker. Il s’agit en gros de compiler le code source de l’économiseur d’écran CMatrix sous Alpine Linux, une distribution ultra-légère spécialement conçue pour servir de base aux conteneurs Docker.

Pour commencer, récupérez la dernière image d’Alpine Linux :

$ docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
43c4264eed91: Pull complete 
Digest: sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest

Sur mon système, l’image pèse moins de 8 Mo. C’est un excellent point de départ pour construire une image Docker légère :

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
alpine       latest    91ef0af61f39   5 weeks ago   7.8MB

La prochaine étape consiste à créer un Dockerfile. C’est en quelque sorte la recette de cuisine de notre image Docker : un fichier texte qui contient toutes les instructions nécessaires pour construire l’image.

$ mkdir -v cmatrix
mkdir: created directory 'cmatrix'
$ cd cmatrix/
$ vim Dockerfile

L’instruction FROM nous indique l’image de base à utiliser pour les instructions subséquentes :

FROM alpine

Pour les métadonnées de l’image, la bonne pratique consiste à utiliser l’instruction LABEL en conformité avec les standards décrits ici. Commencez par renseigner l’auteur de l’image :

LABEL org.opencontainers.image.authors="Nicolas Kovacs"

Ajoutez une description succincte :

LABEL org.opencontainers.image.description="Container image for CMatrix"

Pour l’instant notre image ne fait pas grand-chose, mais rien ne nous empêche de construire un premier jet pour autant :

$ docker build -t kikinovak/cmatrix .

Nos deux images sont de la même taille. C’est normal, puisque nous avons uniquement ajouté les métadonnées pour l’instant.

$ docker images
REPOSITORY          TAG       IMAGE ID       CREATED       SIZE
alpine              latest    91ef0af61f39   5 weeks ago   7.8MB
kikinovak/cmatrix   latest    355beea785e4   5 weeks ago   7.8MB

À présent nous allons démarrer un conteneur basé sur cette image. Dans un premier temps, notre démarche consistera à essayer de compiler CMatrix directement dans le shell du conteneur, en avançant pas à pas dans une approche de tentative et échec.

AstuceAlpine Linux est plus exigeant qu’une base Ubuntu ou Debian. Au départ nous ne disposons même pas d’un shell Bash, et la plupart des outils que nous pouvons avoir l’habitude d’utiliser sont également absents :

$ docker run --rm -it kikinovak/cmatrix sh
/ #

Nous avons besoin du code source de CMatrix. Essayons de le récupérer :

# git clone https://github.com/abishekvashok/cmatrix
sh: git: not found

Alpine Linux utilise le gestionnaire de paquets APK (Alpine Package Keeper) pour installer et gérer les paquets logiciels. Nous allons donc l’utiliser pour récupérer Git :

# apk update
# apk add git

Récupérez le code source de CMatrix :

# git clone https://github.com/abishekvashok/cmatrix
Cloning into 'cmatrix'...

Notez dans un coin de votre tête qu’à ce stade nous avons effectué trois étapes dans la construction de notre image :

  • la mise à jour des métadonnées des paquets
  • l’installation du paquet git
  • la récupération du code source de CMatrix

Continuons allègrement et jetons un œil au code source :

# cd cmatrix/
# ls -l
total 176
-rw-r--r-- 1 root root 65 Oct 18 08:00 AUTHORS
-rw-r--r-- 1 root root 3141 Oct 18 08:00 CMakeLists.txt
-rw-r--r-- 1 root root 3220 Oct 18 08:00 CODE_OF_CONDUCT.md
-rw-r--r-- 1 root root 4235 Oct 18 08:00 CONTRIBUTING.md
-rw-r--r-- 1 root root 35149 Oct 18 08:00 COPYING
-rw-r--r-- 1 root root 65 Oct 18 08:00 ChangeLog
-rw-r--r-- 1 root root 7831 Oct 18 08:00 INSTALL
...

AstuceLorsque vous construisez une image Docker, c’est tout à fait normal d’avancer à tâtons et de rencontrer une succession d’obstacles. Je ne vais pas forcément rentrer dans les détails de tous les obstacles que j’ai pu rencontrer lors de la compilation de CMatrix.

Pour compiler le code source de CMatrix, commençons par invoquer autoreconf -i :

# autoreconf -i
sh: autoreconf: not found

La commande n’est pas disponible non plus. Je vais donc l’installer :

# apk add autoconf
(1/7) Installing m4 (1.4.19-r3)
(2/7) Installing libbz2 (1.0.8-r6)
(3/7) Installing perl (5.38.2-r0)
(4/7) Installing autoconf (2.72-r0)
(5/7) Installing perl-error (0.17029-r2)
(6/7) Installing perl-git (2.45.2-r0)
(7/7) Installing git-perl (2.45.2-r0)
Executing busybox-1.36.1-r29.trigger
OK: 63 MiB in 34 packages

AstuceNotez la taille de tous ces paquets dans un autre coin de votre tête. Tous ces outils contribuent à agrandir considérablement notre image de conteneur.

Et voici le prochain obstacle :

# autoreconf -i
Can't exec "aclocal": No such file or directory at 
/usr/share/autoconf/Autom4te/FileUtils.pm line 299.
autoreconf: error: aclocal failed with exit status: 2

Ici il nous faut installer le paquet automake :

# apk add automake

Et c’est reparti pour un tour :

# autoreconf -i
configure.ac:5: warning: 'AM_CONFIG_HEADER': this macro is obsolete.
configure.ac:5: You should use the 'AC_CONFIG_HEADERS' macro instead.
./lib/autoconf/general.m4:2434: AC_DIAGNOSE is expanded from...
aclocal.m4:745: AM_CONFIG_HEADER is expanded from...
configure.ac:5: the top level
configure.ac:27: warning: The macro 'AC_HEADER_STDC' is obsolete.
configure.ac:27: You should run autoupdate.
./lib/autoconf/headers.m4:663: AC_HEADER_STDC is expanded from...
configure.ac:27: the top level
configure.ac:31: warning: The macro 'AC_TYPE_SIGNAL' is obsolete.
configure.ac:31: You should run autoupdate.
./lib/autoconf/types.m4:805: AC_TYPE_SIGNAL is expanded from...
configure.ac:31: the top level
configure.ac:172: warning: AC_OUTPUT should be used without arguments.
configure.ac:172: You should run autoupdate.
configure.ac:18: installing './compile'
configure.ac:8: installing './config.guess'
configure.ac:8: installing './config.sub'
configure.ac:6: installing './install-sh'
configure.ac:6: installing './missing'
Makefile.am: installing './depcomp'

AstuceSi vous n’avez pas trop l’habitude de compiler du code source, ce gloubi-boulga vous semblera probablement inquiétant. Or, les choses se passent plutôt bien. Pour en avoir le cœur net, affichez le code retour de la dernière commande :

# echo $?
0

Le code retour 0 nous indique ici que la commande précédente s’est correctement effectuée.

La prochaine étape consiste à lancer ./configure, une procédure classique dans la compilation d’applications en C. Notez tout de même que je souhaite construire un binaire statique qui contient toutes les dépendances nécessaires à son exécution :

# ./configure LDFLAGS="-static"
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... no
checking whether make supports nested variables... no
checking build system type... x86_64-pc-linux-musl
checking host system type... x86_64-pc-linux-musl
checking for gcc... no
checking for cc... no
checking for cl.exe... no
checking for clang... no
configure: error: in '/cmatrix':
configure: error: no acceptable C compiler found in $PATH
See 'config.log' for more details

Cette étape échoue également pour la simple raison que notre système réduit ne dispose pas de compilateur pour l’instant :

checking for gcc... no
checking for cc... no

Sous Alpine Linux, les compilateurs de base sont fournis par le méta-paquet alpine-sdk. Là encore, notez la taille relativement importante des paquets installés par rapport au système de base initial :

# apk add alpine-sdk
...
OK: 282 MiB in 68 packages

On retente le coup :

# ./configure LDFLAGS="-static"
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /bin/mkdir -p
...
configure: WARNING:
*** No termcap lib available, consider getting the official ncurses
*** distribution from ftp://ftp.gnu.org/pub/gnu/ncurses if you get
*** errors compiling cmatrix.
...
configure: WARNING:

*** You do not appear to have a consolefonts directory in a standard location
*** (/usr/lib/kbd or /usr/share), even though you appear to have the
*** consolechars and/or setfont command.  The matrix font for the console
*** will not be installed.  This means you will not be able to use the
*** matrix console font (and the -l command line switch) unless the font
*** is located in your current directory when you run CMatrix.
...
config.status: creating Makefile
config.status: creating cmatrix.spec
config.status: creating config.h
config.status: executing depfiles commands

C’est déjà pas mal, à deux détails près :

  • Il nous manque deux répertoires sur le système.
  • Il manque également une dépendance NCurses.

Créez les deux répertoires pour les polices d’affichage :

# mkdir -pv /usr/lib/kbd/consolefonts
created directory: '/usr/lib/kbd/'
created directory: '/usr/lib/kbd/consolefonts'
# mkdir -pv /usr/share/consolefonts
created directory: '/usr/share/consolefonts'

Installez les dépendances NCurses :

# apk add ncurses-dev ncurses-static
(1/8) Installing ncurses-terminfo-base (6.4_p20240420-r1)
(2/8) Installing libncursesw (6.4_p20240420-r1)
(3/8) Installing libformw (6.4_p20240420-r1)
(4/8) Installing libmenuw (6.4_p20240420-r1)
(5/8) Installing libpanelw (6.4_p20240420-r1)
(6/8) Installing libncurses++ (6.4_p20240420-r1)
(7/8) Installing ncurses-dev (6.4_p20240420-r1)
(8/8) Installing ncurses-static (6.4_p20240420-r1)
Executing busybox-1.36.1-r29.trigger
OK: 290 MiB in 76 packages

AstuceNotez au passage que le paquet ncurses-terminfo-base est également installé. Ce paquet va constituer une dépendance d’exécution de notre application. Nous aurons l’occasion d’en reparler en temps et en heure.

On relance la commande ./configure :

# ./configure LDFLAGS="-static"
...
"Using ncurses as the termcap library"
checking for use_default_colors in -lncurses... yes
checking for resizeterm in -lncurses... yes
checking for wresize in -lncurses... yes
checking for consolechars... no
checking for setfont... /usr/sbin/setfont
checking for /usr/lib/kbd/consolefonts... yes
checking for /usr/share/consolefonts... yes
checking for mkfontdir... no
checking for /usr/share/fonts/misc... no
checking for /usr/share/X11/fonts/misc... no
checking for /usr/X11R6/lib/X11/fonts/misc... no
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating cmatrix.spec
config.status: creating config.h
config.status: executing depfiles commands

Tout a l’air parfait. On passe à la compilation :

# make
...
gcc  -g -O2  -static -o cmatrix cmatrix.o  -lncurses  -lncurses
make[1]: Leaving directory '/cmatrix'

Là aussi, tout a l’air parfait. La compilation n’a retourné aucune erreur, et nous disposons à présent d’un binaire cmatrix dans le répertoire de travail :

# ls -lh ./cmatrix
-rwxr-xr-x    1 root     root      777.9K Oct 18 13:39 ./cmatrix

Nous pouvons l’exécuter pour avoir une première idée de ce que ça donne :

# ./cmatrix

CMatrix

Nous avons réussi à compiler CMatrix avec succès. Pour retrouver la procédure de construction du binaire depuis le code source, il nous suffit d’afficher l’historique du shell :

# history
   0 git clone https://github.com/abishekvashok/cmatrix
   1 apk update
   2 apk add git
   3 git clone https://github.com/abishekvashok/cmatrix
   4 cd cmatrix/
   5 ls -l
   6 autoreconf -i
   7 apk add autoconf
   8 autoreconf -i
   9 apk add automake
  10 autoreconf -i
  11 echo $?
  12 ./configure LDFLAGS="-static"
  13 apk add alpine-sdk
  14 ./configure LDFLAGS="-static"
  15 mkdir -pv /usr/lib/kbd/consolefonts
  16 mkdir -pv /usr/share/consolefonts
  17 apk add ncurses-dev ncurses-static
  18 ./configure LDFLAGS="-static"
  19 make
  20 ls -lh ./cmatrix
  21 ./cmatrix
  22 history

Copiez l’intégralité de cet historique dans le presse-papier de votre environnement graphique et quittez le conteneur.

ImportantN’oubliez pas que le conteneur a été créé avec l’option --rm. À partir du moment où nous le quittons (exit), l’arrêt provoque également la suppression. Tout ce que nous avons fait jusqu’ici est donc parti au paradis des octets… ou presque.

Collez le contenu de l’historique tel quel dans le Dockerfile, à la suite des trois premières instructions :

FROM alpine

LABEL org.opencontainers.image.authors="Nicolas Kovacs"
LABEL org.opencontainers.image.description="Container image for CMatrix"

   0 git clone https://github.com/abishekvashok/cmatrix
   1 apk update
   2 apk add git
   3 git clone https://github.com/abishekvashok/cmatrix
   4 cd cmatrix/
   5 ls -l
   6 autoreconf -i
   7 apk add autoconf
   8 autoreconf -i
   9 apk add automake
  10 autoreconf -i
  11 echo $?
  12 ./configure LDFLAGS="-static"
  13 apk add alpine-sdk
  14 ./configure LDFLAGS="-static"
  15 mkdir -pv /usr/lib/kbd/consolefonts
  16 mkdir -pv /usr/share/consolefonts
  17 apk add ncurses-dev ncurses-static
  18 ./configure LDFLAGS="-static"
  19 make
  20 ls -lh ./cmatrix
  21 ./cmatrix
  22 history

La suite au prochain numéro, où nous allons voir en détail la rédaction d’un Dockerfile propre et efficace depuis notre historique du shell.

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.

 

Catégories : Formation

0 commentaire

Laisser un commentaire

Emplacement de l’avatar

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *