Utiliser docker

Docker logo with transparency

Dans cet article, nous allons utiliser docker et montrer son efficacité pour déployer des environnements rapidement ! Notre objectif sera le suivant : Exposer un serveur web.

Sommaire

Prérequis

Installer docker

Il faut ajouter le dépôt communautaire au gestionnaire de dépendances d’Alpine :

echo http://dl-cdn.alpinelinux.org/alpine/latest-stable/community > /etc/apk/repositories 

Ensuite il faut mettre à jour le gestionnaire de dépendances :

apk update 

Puis on installe docker :

apk add docker 

Démarrer Docker

On va démarrer le service docker :

service docker start 

On ajoute le démarrage du service au boot de la machine :

rc-update add docker boot 

On vérifie si le service est effectif :

service docker status 

Résultat

result-docker-status

Puis on redémarre la machine :

reboot 

Mais docker, a quoi ça sert ?

C’est un outil formidable pour monter des environnements d’exécutions et des environnements préfabriqués. Vous pouvez imaginer ça comme un superviseur de machine virtuelle, mais sans interface graphique ! Voici une illustration pour mieux comprendre :

explication-docker-1

Informations utiles

 

Première image

Les règles de la construction de l’image sont les suivantes :

Création du dossier

On créer un dossier de travail pour l’image docker :

mkdir -p /docker/demo && cd /docker/demo  

Création du script

On initialise un script (helloworld.sh) qui va afficher la chaine de caractères “Hello World” :

nano helloworld.sh 

helloworld.sh

#!bin/ash

echo "HELLO WORLD" 

Création du Dockerfile

Créons le fichier de construction pour docker :

nano Dockerfile 

Structure du dossier /docker/demo :

.
├── Dockerfile
└── helloworld.sh 

Dockerfile

## On récupère une image depuis docker, qui tire une image d'alpine en version 3.7 que docker expose.
FROM alpine:3.7 

## On exécute à l'intérieur de cette image (alpine 3.7) un update des dépendances 
RUN apk update 

## On copie le script qui va nous permettre d'écrire "HELLO WORLD" de la machine (./helloworld.sh, correspond à notre script, / correspond au répertoire de destination à l'intérieur de l'image), donc, on copie le fichier helloworld.sh à la racine de l'image alpine 3.7. 
## SOURCE | ## DESTINATION 
COPY ./helloworld.sh / 

## On rends le fichier sh exécutable (qui a été copié à la racine de l'image alpine). 
RUN chmod +x /helloworld.sh 

## On renseigne que le point d'entrée de l'image, lorsqu'on la lance, est notre script, on verra plus tard à quoi sert cette ligne. 
ENTRYPOINT ["/helloworld.sh"]

Build de l'image

Comme l’image docker est préparée, on va pouvoir la build :

docker build . -t helloworld  

Résultat

Sending build context to Docker daemon 3.072kB
Step 1/5 : FROM alpine:3.7 
 ---> 6d1ef012b567
Step 2/5 : RUN apk update 
 ---> Running in 95b11e5c9184
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
v3.7.3-184-gffd32bfd09 [http://dl-cdn.alpinelinux.org/alpine/v3.7/main]
v3.7.3-194-gcddd1b2302 [http://dl-cdn.alpinelinux.org/alpine/v3.7/community]
OK: 9054 distinct packages available
Removing intermediate container 95b11e5c9184
 ---> 1e018627922f
Step 3/5 : COPY  ./helloworld.sh /
 ---> 41bddbbf579d
Step 4/5 : RUN chmod +x /helloworld.sh
 ---> Running in 207b215d50d2
Removing intermediate container 207b215d50d2
 ---> a8a0f4dbcde1
Step 5/5 : ENTRYPOINT ["/helloworld.sh"]
 ---> Running in 00fa98653d16
Removing intermediate container 00fa98653d16
 ---> 5babeaf05c5e
Successfully built 5babeaf05c5e
Successfully tagged helloworld:latest
 

Vérification de l'image

Notre image est créée avec le tag “helloworld“, listons les images docker pour vérifier :

docker image ls  

Résultat

REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
helloworld   latest    5babeaf05c5e   5 minutes ago     5.43MB
alpine       3.7       6d1ef012b567   2 years ago      4.21MB

Exécuter l'image

Pour exécuter l’image dans l’environnement docker :

docker run helloworld  

Résultat

HELLO WORLD 

Explications

Lors de la commande “docker run“, comme l’ENTRYPOINT qui est configuré dans le Dockerfile est le script helloworld.sh, c’est celui-ci qui a été appelé par notre image et qui a renvoyé la chaine de caractèresHELLO WORLD“. Pour bien comprendre, voici un schéma descriptif :

explication-docker-2

Exposer un serveur web

La demande initiale était d’exposer un serveur web, on va donc construire une nouvelle image :

mkdir -p /demo/docker/exposewebserver && cd /demo/docker/exposewebserver 

Pour cela on créer un nouveau Dockerfile  :

Dockerfile

## On récupère une image alpine version 3.7 depuis Docker 
FROM alpine:3.7 

## On mets à jour les dépendances. 
RUN apk update 

## On ajoute nginx (pour simplifier le montage du serveur) 
RUN apk add nginx 

## On crée le dossier pour éviter que NGINX râle 
RUN mkdir /run/nginx 

## On expose le port 80 de l'image docker instanciée 
EXPOSE 80 

## On quitte l'image sur un signal stop (CTRL+C) ou docker stop
STOPSIGNAL SIGQUIT 

## On lance nginx 
CMD ["nginx", "-g", "daemon off;"] 

Résultat

Sending build context to Docker daemon 2.048kB 
Step 1/7 : FROM alpine:3.7
 ---> 6d1ef012b567 
Step 2/7 : RUN apk update
 ---> Using cache
 ---> 1e018627922f 
Step 3/7 : RUN apk add nginx
 ---> Running in 52ef92245914 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz 
(1/2) Installing pcre (8.41-r1) 
(2/2) Installing nginx (1.12.2-r4) 
Executing nginx-1.12.2-r4.pre-install 
Executing busybox-1.27.2-r11.trigger 
OK: 6 MiB in 15 packages 
Removing intermediate container 52ef92245914
 ---> 0410d2a8d1c8 
Step 4/7 : RUN mkdir /run/nginx
 ---> Running in cd978d869c98 
Removing intermediate container cd978d869c98
 ---> 805dd2bdf6e6 
Step 5/7 : EXPOSE 80
 ---> Running in 0adeebdda85c 
Removing intermediate container 0adeebdda85c
 ---> a9f7695180e5 
Step 6/7 : STOPSIGNAL SIGQUIT
 ---> Running in 04ebe5a0cdd2 
Removing intermediate container 04ebe5a0cdd2
 ---> b1687008888c 
Step 7/7 : CMD ["nginx", "-g", "daemon off;"]
 ---> Running in e32041734a37 
Removing intermediate container e32041734a37
 ---> 486bad5a0d0d 
Successfully built 486bad5a0d0d 
Successfully tagged mynginx:latest 

Vérifions que l’image s’est bien créée :

docker image ls 

Résultat

REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
mynginx      latest    486bad5a0d0d   53 seconds ago   8.02MB
helloworld   latest    5babeaf05c5e   13 hours ago     5.43MB
alpine       3.7       6d1ef012b567   2 years ago      4.21MB 

On lance le serveur web :

docker run mynginx 

Contacter le serveur

Le port exposé par le container est le port 80 (via l’instruction EXPOSE 80), si on tape l’adresse IP de la machine virtuelle dans le navigateur (http://172.19.193.132 dans mon cas), on devrait atterrir sur notre serveur web exposé dans le container docker :

failed-connexion-docker

Ajustements

Pour corriger le problème, on va ajuster la commandedocker run” pour y ajouter certains paramètres :

docker run -p 80:80 mynginx # -p [portMachineHote]:[portContainerDocker] 

Nouvel essai

Ressayons de charger notre page (http://172.19.193.132 dans mon cas ) :

nginx-not-found

Exécuter le container en tâche de fond

La commande “docker run” se lance dans le terminal et le bloque, ce n’est pas très pratique pour continuer à gérer sa machine, on souhaite exécuter notre container docker en tâche de fond :

docker run -d -p 80:80 mynginx  

Résultat

hash-container-public

Lister le container en exécution

Comme on a lancé le container docker en tâche de fond, on doit avoir la possibilité de le lister :

docker ps 

Résultat

docker-ps

Stopper un container

Pour stopper le container, on va se servir de son identifiant :

docker kill b92dac652469 

Un petit problème...

La commande qu’on a lancé précédemment (docker run -d -p 80:80 mynginx) comporte un problème :

A chaque lancement, un nom dynamique sera crée et va polluer le contexte d’exécution de docker.

Solution

On va rajouter des arguments à la commande :

docker run -d -p 80:80 --name="CustomNginx" --restart=always mynginx 

Instancier un deuxième serveur

On souhaite instancier un nouveau serveur web, mais cette fois exposé sur le port 81 de la machine hôte :

docker run -d -p 81:80 --name "CustomNginxPort81" --restart=always mynginx 

Contacter le deuxième serveur

Pour le second serveur, on va taper sur la même adresse que pour le premier en modifiant le port de destination (http://172.19.198.132:81) :

url

adresse-ip-vm-server-2

Résultat

nginx-not-found

Lister les containers

Pour le second serveur, on va taper sur la même adresse que pour le premier en modifiant le port de destination (http://172.19.198.132:81) :

docker ps 

Résultat

docker-ps-2

Conseils

C’est un conseil qu’on donne pour tous vos besoins : essayez de chercher une image docker qui correspond déjà à votre idée sur : https://hub.docker.com/

Informations utiles

Lors de la commande docker run, si on associe un nom d’image, docker essaiera d’abord de télécharger l’image depuis internet (seulement au premier lancement, puisqu’après elle est enregistrée dans l’environnement d’exécution de docker en tant qu’image). Par exemple, essayons d’installer l’image officielle de nginx :

docker run -d -p 80:80 --name=OfficialNginx --restart=always nginx 

Résultat

docker-download-nginx

Administrer avec docker

On va afficher les containers en cours d’exécution :

docker ps 

Résultat

nginx-container-ps

Ensuite on va lister nos images pour voir l’état de notre contexte d’exécution :

docker image ls 

Résultat

docker-image-ls

Commande utiles

docker volume # Permets de créer un volume docker
docker network # Permets de créer un réseau docker
docker container prune # Permets de nettoyer tous les containers docker non utilisés
docker image prune # Permets de nettoyer toutes les images docker non utilisées
docker volume prune # Permets de nettoyer tous les volumes docker non utilisés
docker network prune # Permets de nettoyer tous les réseaux docker non utilisés
 

Images courantes

Ci-dessous une liste d’images qui sont très utilisées dans le monde de docker (la liste est non exhaustive) :

alpine:latest # Serveur alpine pré-configuré
nginx:latest # Serveur web pré-configuré
redis:latest # Serveur de mise en cache pré-configurée
mysql:latest # Serveur avec base de données pré-configurée
debian:latest # Serveur debian pre-configuré
....
 

Utilisation avancée

Pour les plus déterminés d’entre vous, il est possible de faire communiquer des containers docker entre eux et de les mettre dans le même réseau. Les applications modernes qui utilisent docker sont souvent architecturées de cette façon :

  • Base de données/cache (souvent redis) = 1 container.
  • Router les requêtes HTTP/PROXY (souvent nginx) = 1 container.
  • Code de l’application (à la guise des devs) = 1 container.
Pour répondre à ces besoins de configuration commune, une autre commande est née : docker-compose

Laisser un commentaire

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