Docker - Creation d'une image
Création d’une image personnalisée
La création d’image s’appelle un build. Il s’effectue à l’aide de la commande docker build
.
Il faut passer en paramètre à cette commande un dossier contenant :
- au moins un Dockerfile.
- les autres fichiers éventuellement nécessaires au Dockerfile.
Ce dossier peut être directement à la racine d’un repo git, ou via un tar du dossier dans l’entrée standard (avec le Dockerfile à la racine). Le client docker va alors transférer l’intégralité de ce dossier au serveur docker, qui va effectuer toutes les étapes du build. L’option “-t
de docker build
permet de mettre un tag à l’image qui sera créée. Il est aussi possible de faire ça manuellement ensuite avec docker tag
. Une fois l’image créée, il est préférable de la pousser sur un registry à l’aide de docker push
pour pouvoir plus facilement la versionner et réutiliser.
Qu’est-ce qu’un fichier DockerFile
L’élément le plus important d’un build est le fichier Dockerfile, c’est lui qui définit toutes les étapes de création d’une image.
Il s’agit d’une suite de ligne de type :
INSTRUCTION arguments
Les instructions disponibles sont :
- FROM
- RUN
- ENV
- LABEL
- ADD
- COPY
- ENTRYPOINT
- CMD
- HEALTHCHECK
- EXPOSE
- WORKDIR
- VOLUME
- USER
- ONBUILD
- STOPSIGNAL
- SHELL
FROM
L’instruction FROM doit être la première du Dockerfile. Elle définit à partir de quelle image existante on construit notre image.
FROM debian:latest
ENV
ENV permet de définir une variable d’environnement. Ces variables sont visibles :
- Dans les étapes suivantes du Dockerfile.
- Dans les images construites à partir de cette image,
Lors du lancement d’un container à partir de cette image
ENV var1 a ENV var1=a var2=b var3="c d"
LABEL
Les labels fonctionnent comme ENV pour la déclaration et propagation, mais ne servent qu’à donner des indications sur l’image.
LABEL version 1
LABEL author=FredGrnd email=fredgr@pm.me
RUN
RUN permet d’exécuter une commande pour créer une nouvelle image à partir de l’image précédente sur laquelle on exécute cette commande. Chaque instruction RUN ajoute une nouvelle couche à l’image finale, il faut donc essayer de limiter leur nombre.
FROM debian:latest
RUN apt-get update
RUN apt-get install -y apache
Ici on aura 3 couches :
- Debian
- le cache apt
- le package apache téléchargé dans le cache apt + apache installé
On pourrait tenter de réduire la taille en faisant un apt-get clean :
FROM debian:latest
RUN apt-get update
RUN apt-get install -y apache
RUN apt-get clean
On a maintenant 4 couches :
- Debian
- le cache apt
- le package apache téléchargé dans le cache apt + apache installé
- l’indication de purger le cache apt dont le package .deb téléchargé (une couche qui masque des fichiers de l’image précédente)
La bonne façon de faire ça et de grouper les commandes dans un seul RUN :
FROM debian:latest
RUN apt-get update \
&& apt-get install -y apache \
&& apt-get clean
Il ne reste que deux couches avec juste le minimum nécessaire :
- Debian
- le package apache installé
Les couches étant réutilisables, il ne faut pas chercher non plus à tout mettre dans la même : ajouter un git clone
de la dernière version d’une application dans le même RUN va forcer la réinstallation d’apache à chaque fois, et faire une multitude d’images apache+application alors qu’il aurait pu n’y avoir que plein de petites couches pour les versions de l’application.
ADD
ADD permet d’ajouter des fichiers dans l’image. Avec ADD, la source de la copie peut aussi être une URL ou une archive tar qui sera décompresser.
ADD /entrypoint.sh /entrypoint.sh
COPY
COPY permet d’ajouter des fichiers comme ADD, mais uniquement à partir du dossier du Dockerfile
ENTRYPOINT et CMD
ENTRYPOINT définit la commande qui sera lancée par défaut lors d’un run de l’image. CMD définit ce qui sera immédiatement après.
Dans un docker run, ce qui est après le nom de l’image remplace uniquement le CMD
ENTRYPOINT /etc/init.d/apache
CMD start
Ici par défaut le docker run va lancer /etc/init.d/apache start
Si on lance le container ainsi :
docker run mon_container configtest
Alors la commande lancée sera :
/etc/init.d/apache configtest
Attention
La commande lancée via ENTRYPOINT et CMD ne doit pas lancer un process en arrière plan et rendre la main : si ce premier process meurt, le container est stoppé. Il faut donc toujours lancer la commande en foreground (souvent grace aux options foreground ou debug des outils). Si jamais il est nécessaire d’avoir plusieurs outils dans le même container, il faut utiliser un wrapper comme runit
ou supervisord
pour jouer le rôle que joue habituellement init sur un système classique.
HEALTHCHECK
HEALTHCHECK permet de définir une commande qui permet de valider qu’un container est fonctionnel. Par exemple une requête HTTP sur l’application pour vérifier qu’elle est correctement démarrée.
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
Ce test sera effectué par docker avec l’intervalle indiqué pour vérifier que le service est fonctionnel, lors du démarrage du container, et pour détecter qu’il ne marche plus et le redémarrer quand le run a été fait avec –restart always.
EXPOSE
EXPOSE indique à Docker sur quels ports écoute un container. Docker ne fera pas de bind automatique des ports exposés, sauf si le docker run est fait avec l’option “-P” qui va binder pour chaque port exposé du container un port haut aléatoire de l’hôte.
EXPOSE 80 443
VOLUME
VOLUME indique qu’un dossier de l’image est un point de montage. Lors du docker run de l’image, pour chaque volume un dossier de stockage éphémère sera créé, et le contenu de ce dossier dans l’image sera copié dans le dossier éphémère. Il est conseillé de monter des volumes persistants dans ces dossiers avec docker run -v
pour faire persister ces données.
Remarque Si un build est fait à partir d’une image qui a des volumes, le contenu éventuellement modifié dans ces volumes sera perdu.
USER
USER permet de spécifier un nom d’utilisateur ou un uid
qui sera utilisé pour toutes les :
- RUN suivants du Dockerfile
ENTRYPOINT et CMD au démarrage des containers utilisant cette image
USER www-data
Le username est converti en UID via le /etc/passwd
de l’image et non de l’hôte.
[Atelier] Création d’un conteneur personnalisé apache
Créer une image docker avec :
- OS : Fedora
- Installation d’un serveur web apache
- Mettre une page statique dans le site
- Déclarer le dossier du site comme étant un montage
- Lancement du serveur web au run de l’image
- Ajout d’un healthcheck qui test le site
Création de l’arborescence.
mkdir -p docker_fedora_httpd/volumes/html
mkdir -p docker_fedora_httpd/files
echo "Hello Word (volume)" > docker_fedora_httpd/volumes/html/index.html
echo "Hello Word" > docker_fedora_httpd/files/index.html
Création du Dockerfile
FROM fedora:latest
LABEL Version 1
RUN yum -y update && yum -y install httpd && yum clean all
ADD /files/index.html /var/www/html/index.html
VOLUME /var/www/html
ENTRYPOINT /usr/sbin/httpd -X
EXPOSE 80 443
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1%
Construire une image a partir du Dockerfile
docker build -t docker_fedora_httpd .
Vérifier que l’image est bien présente dans le repository local
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker_fedora_httpd latest e365a8fa7e86 2 minutes ago 387MB
Démarrer l’image sans le point de montage
docker run -d --name docker_fedora_httpd -p 8080:80 docker_fedora_httpd
Tester le site.
curl -i localhost:8080/index.html
HTTP/1.1 200 OK
Date: Wed, 29 Nov 2017 08:22:12 GMT
Server: Apache/2.4.29 (Fedora)
Last-Modified: Thu, 16 Nov 2017 06:10:29 GMT
ETag: "86-55e137a12df40"
Accept-Ranges: bytes
Content-Length: 134
Content-Type: text/html; charset=UTF-8
Hello World
Modifier la page d’accueil du site directement dans le conteneur
docker exec -it docker_fedora_httpd bash
[root@65a18fefa034 /]# vim
# vi /var/www/html/index.html
Tester de nouveau le site.
curl -i http://localhost:8080
HTTP/1.1 200 OK
Date: Wed, 29 Nov 2017 08:26:32 GMT
Server: Apache/2.4.29 (Fedora)
Last-Modified: Wed, 29 Nov 2017 08:26:04 GMT
ETag: "17-55f1ae2ee2b18"
Accept-Ranges: bytes
Content-Length: 23
Content-Type: text/html; charset=UTF-8
Hello World (Modified)
Stopper, supprimer et relancer le conteneur.
docker stop docker_fedora_httpd
docker rm docker_fedora_httpd
docker run -d -p 8080:80 docker_fedora_httpd
Tester le site.
curl -i localhost:8080/index.html
HTTP/1.1 200 OK
Date: Wed, 29 Nov 2017 08:22:12 GMT
Server: Apache/2.4.29 (Fedora)
Last-Modified: Thu, 16 Nov 2017 06:10:29 GMT
ETag: "86-55e137a12df40"
Accept-Ranges: bytes
Content-Length: 134
Content-Type: text/html; charset=UTF-8
Hello World
Le site est revenu à l’initial, les données modifiées ne sont pas persistantes.
Stopper et nettoyer le conteneur
docker stop docker_fedora_httpd
docker rm docker_fedora_httpd
Lancer le conteneur en montant le répertoire volumes/html/
docker run -d --name docker_fedora_httpd -p 8080:80 -v ~/docker_fedora_httpd/volumes/html:/var/www/html docker_fedora_httpd
Test de nouveau le site
curl -i http://localhost:8080
HTTP/1.1 200 OK
Date: Wed, 29 Nov 2017 09:16:03 GMT
Server: Apache/2.4.29 (Fedora)
Last-Modified: Wed, 29 Nov 2017 09:15:49 GMT
ETag: "15-55f1b94d07b40"
Accept-Ranges: bytes
Content-Length: 21
Content-Type: text/html; charset=UTF-8
Hello World (volume)
Stopper et nettoyer le conteneur
docker stop docker_fedora_httpd
docker rm docker_fedora_httpd