mouhamadoul moustapha fall
Orion

Follow

Orion

Follow
DOCKER, The starter pack

DOCKER, The starter pack

mouhamadoul moustapha fall's photo
mouhamadoul moustapha fall
·Nov 22, 2021·

15 min read

Commençons d’abord par un point que tout développeur trouve très ennuyeux : la mise en place de notre environnement de développement. Maintenant, imaginons que nous avons terminé notre application et que nous devons l’envoyer à une autre personne pour qu’il valide. Sommes-nous prêts à refaire la même mise en place de l’environnement pour que l’application fonctionne sur l’autre poste ? Sommes-nous assurés que nous aurons les mêmes versions ? Serons-nous sur un même OS ? Et tant d’autres questions. Il serait alors temps de s’arrêter et réfléchir à un moyen de s’assurer que notre code va fonctionner quel que soit l’environnement ou nous l’exécutons. C’est dans ce sens que les technologies de virtualisation entrent en jeu.

Dans ce chapitre, nous verrons, c’est quoi un container et ses différences avec une machine virtuelle. Nous verrons par la suite, c’est quoi Docker, son utilité et pourquoi nous en avons besoin. Puis nous allons passer en revue quelques commandes pour bien prendre en main cet outil. Après cela, nous créerons notre première image docker et profiterons de cette occasion pour parler des différents réseaux dans docker ainsi que le stockage dans docker Si vous êtes prêts, prenez votre tasse de café et allons-y.

Container vs Machine virtuelle

Le conteneur est placé au-dessus du serveur physique et de son système d'exploitation hôte (tel que Linux ou Windows). Chaque conteneur partage le noyau du système d'exploitation hôte et partage généralement également des binaires et des bibliothèques. Les composants partagés sont en lecture seule. En conséquence, ces conteneurs sont extrêmement légers: ils ne font que des mégaoctets et ne prennent que quelques secondes pour démarrer, tandis que les machines virtuelles nécessitent des gigaoctets et des minutes. La virtualisation des serveurs présente de nombreux avantages, dont le plus important est la possibilité de consolider les applications en un seul système. Il est révolu le temps d'exécuter une seule application sur un seul serveur. La virtualisation permet d'économiser de l'argent en réduisant l'encombrement, en accélérant la configuration du serveur et en améliorant la reprise après sinistre. Les machines virtuelles et les conteneurs sont différents à plusieurs égards, mais la principale différence est que les conteneurs permettent de virtualiser les systèmes d'exploitation afin que plusieurs charges de travail puissent s'exécuter sur une seule instance de système d'exploitation. À l'aide de machines virtuelles, le matériel peut être virtualisé pour exécuter plusieurs instances de système d'exploitation. La vitesse, l'agilité et la portabilité des conteneurs en font un autre outil de simplification du développement logiciel. L'image ci-dessous illustre l'architecture de base des deux entités:

vmvmc.png

Docker: quoi, pourquoi et comment ?

Docker est une plate-forme ouverte pour le développement, la livraison et l'exécution d'applications. Docker permet de séparer les applications de l'infrastructure afin que les logiciels puissent être livrés rapidement. Avec Docker, vous pouvez gérer votre infrastructure comme vous gérez une application. Docker permet aux applications d'être empaquetées et exécutées dans un environnement à faible isolation appelé un conteneur. Vous pouvez même exécuter des conteneurs Docker dans un hôte qui est en fait une machine virtuelle. Docker fournit des outils et une plates-forme pour gérer le cycle de vie des conteneurs: Utilisez des conteneurs pour développer des applications et leurs composants. Le conteneur deviendra l'unité de livraison et de test de votre application. Lorsque vous êtes prêt, vous pouvez déployer l'application en tant que conteneur ou service de coordination dans un environnement de production. Que votre environnement de production soit un serveur local, un fournisseur de services cloud ou un hybride des deux, le principe de fonctionnement est le même. Pour des informations beaucoup plus poussées sur Docker, voir la documentation

La prise en main de Docker

Il nous faut d’abord installer Docker sur notre machine. Pour ce faire, dépendant de l’OS que vous utilisez, suivez les instructions d’installation proposées sur le site officiel.

maxresdefault.jpeg Après avoir installé docker sur la machine, il nous faut créer un compte pour pouvoir bénéficier pleinement des possibilités de docker. Pour cela se rendre sur docker hub et se créer un compte.

Les commandes de base

Après avoir créé notre compte, testons si Docker fonctionne correctement dans notre environnement. C’est le moment d’introduire notre première commande à savoir “docker version” .

docker version

Cette commande permet de voir la version docker qui est installée.

version.png A présent que nous nous sommes assurés que docker est bien installé, passons en revue quelques commandes qui sont utiles à connaître. Mais tout d’abord, éclaircissons quelques concepts importants avant d’aller plus loin. Une image Docker est un modèle en lecture seule qui contient un ensemble d'instructions pour créer un conteneur pouvant fonctionner sur la plateforme Docker. Elle offre un moyen pratique de regrouper des applications et des environnements de serveur pré configurés, que vous pouvez utiliser pour votre propre usage privé ou partager publiquement avec d'autres utilisateurs de Docker. Nous verrons plus tard comment créer notre propre image docker. Docker repository est l'endroit où vous pouvez stocker une ou plusieurs versions d'une image Docker spécifique. Une image peut avoir une ou plusieurs versions (tags). Il convient également de souligner que le Docker Hub et d'autres services d'hébergement de repository tiers sont appelés «registres». Un registre stocke une collection de repository. Maintenant, nous sommes prêts à y aller.

docker pull "image_name"

Cette commande permet de récupérer une image mise à notre disposition à travers un registre donné. Le registre par défaut que nous allons utiliser et qui est gratuit est le Docker Hub. Nous y trouverons toutes les images dont nous aurons besoin. Supposons que nous ayons besoin d’un serveur Web, au lieu d’installer nginx nous pouvons l’avoir directement avec une image déjà disponible.

docker pull nginx

Cette commande nous a permis de télécharger l’image dans notre host.

docker run "image_name"

Permet de lancer un container à partir de l’image donnée. Avec cette commande nous pouvons lancer une instance de l’application contenue dans l’image. Le processus de lancement est le suivant: docker vérifie d’abord si l’image est présente dans le host. Si oui, il lance la création du container. Sinon, il télécharge d’abord l’image à partir du docker hub(pull) puis effectue le lancement.

docker run nginx

Maintenant si vous voulez spécifier le nom du container qui sera créé, ajoutez l’option name.

docker run --name NOM_CONTAINER nginx

Et si vous voulez exécuter une version spécifique de l’image, il faut spécifier le tag comme suit:

docker run nginx:alpine

Ici alpine représente le tag qui pourrait aussi être une autre version comme: 1, 1.18, 1.18-perl , etc. Si nous ne spécifions pas de version, celle qui sera prise par défaut est la version latest pour dire la dernière version. Par défaut, un container docker n'écoute pas une entrée standard. Il ne peut lire aucun input venant du terminal et fonctionne en mode non interactif. Si vous voulez interagir avec le container en lui envoyant des inputs, vous devez mapper l’entrée standard du host avec celle du container en ajoutant l’option i à la commande.

docker run -i image-name

Pour se connecter au terminal du container, nous devons ajouter l’option t à la commande.

docker run -it image-name

Avec cette commande vous pouvez interagir avec le container en lui envoyant des instructions, lisant ses fichiers, vérifiant les logs, etc. Par défaut, avec la commande docker run, le container exécuté en premier plan et nous ne pouvons plus utiliser le terminal sauf si nous l’arrêtons avec Ctrl + C. Toutefois, il est possible de l'exécuter en arrière-plan avec l’option d.

docker run -d image-name

Pour permettre à d’autres utilisateurs en dehors du host d’accéder à mon container, nous devons mapper un port du host avec un port du container. Pour ce faire, nous devons ajouter l’option p à la commande et en spécifiant les deux ports concernés comme suit:

docker run -p 80:5000 simple-webapp

80 : représente le port du host
5000 : représente le port au niveau du container
simple-webapp : le nom de l’image
Avec ça, vous pouvez lancer plusieurs instances du même container en faisant le mapping à différents ports.

NB: La seule contrainte est que vous ne pouvez pas mapper deux instances du container à un même port du host.

Parfois, nous aurons besoin de mettre en place des variables d’environnement qui seront utilisées par nos containers. Pour mettre cela en place, nous utilisons l’option e.

docker run -e ENV_VARIABLE_NAME=value simple-webapp

Après avoir passé en revue la commande run, passons à une autre très utile.

docker ps

Cette commande permet de lister l’ensemble des containers qui sont en cours d’exécution avec quelques informations basiques à leur propos.

ps.png Pour avoir une liste plus complète de l’ensemble des containers qui sont en cours d'exécution et ceux qui sont arrêtés, on ajoute l’option a à la commande

docker ps -a

docker stop

Cette commande permet d’arrêter un container en cours d’exécution. Nous devons identifier le container grâce à son id ou à son nom.

docker stop ContainerId | ContainerName
Exemple:

docker stop nginx

ou

docker stop eb97

Avec 'eb97' l'identifiant du container. Vous remarquerez que je n'ai écrit tout l'identifiant, juste les les premier elements suffirons.

docker rm

Elle permet de supprimer définitivement un container. Nous devons spécifier l’id ou le nom du container à supprimer.

docker rm simple-webapp

docker images

Liste l’ensemble des images présentes dans le host et affiche aussi la taille de chaque image.

docker images

docker rmi

Permet de supprimer une image du host. Il faudra d’abord s’assurer qu’aucun container est en train d’utiliser cette image. Vous devez alors arrêter et supprimer tous les containers dépendants de cette image. Si ces conditions sont remplies, ajouter le nom de l’image à la commande.

docker rmi nginx

docker exec

Supposons que nous avons exécuté(run) notre container avec l’option d qui lui permet de s’exécuter en arrière plan et que nous voulions interagir avec. Docker exec permet d’exécuter des commandes sur un container en cours d’exécution. Nous devons spécifier l’id ou le nom du container.

docker exec constellation_orion cat /etc/hosts

constellation_orion : nom du container
cat /etc/hosts: la commande à exécuter sur le container

docker inspect

Pour avoir plus de détails par rapport à un container. Cette commande retourne tous les détails dans un format JSON. Nous devons spécifier l’id ou le nom du container.

docker inspect <NAME | ID>

docker logs

Quand un container est exécuté en arrière-plan, nous ne voyons pas ses traces. Pour voir ces informations, nous exécutons cette commande en spécifiant l’id ou le nom du container.

docker logs <NAME | ID>

Nous avons passé en revue ces quelques commandes de base très importantes. Maintenant, passons à l’étape où nous créons notre propre image.

Création d’une image Docker

Dans cette partie, nous créerons une image dans laquelle nous aurons le mini framework de développement web FLASK. Nous devrons suivre ces étapes pour créer l’image:

  • Choix d'une image de base : Ubuntu par exemple
  • Mise à jour du repo
  • Installation des dépendances en utilisant apt
  • Installation des dépendances python avec pip
  • Copie des fichiers sources dans /opt
  • Exécution du serveur web à l’aide de la commande flask

NB:Une image docker doit toujours être créée à partir d'une image de base.

Toutes ces étapes doivent être spécifiées dans un fichier appelé Dockerfile sans extension. Dans ce fichier nous aurons ceci:

1) FROM ubuntu
2) RUN apt-get update
3) RUN apt-get install -y python
4) RUN apt-get install -y pip
5)
6) RUN pip install flask
7) RUN pip install flask-mysql
8) 
9) COPY . /opt/source-code
10) ENTRYPOINT FLASK_APP=/opt/source-code/app.py flask run

Un dockerfile est un fichier écrit dans un format que docker peut comprendre. Ce format est un format INSTRUCTION ARGUMENT. Expliquons le contenu de ce fichier ligne par ligne. A la ligne 1) Nous avons l’OS de base pour le container. Toute image docker doit se baser sur une autre image et tout dockerfile doit commencer par l’instruction FROM Aux lignes 2), 3),4), 6) et 7) nous avons l'instruction RUN qui dit à docker d’exécuter ces commandes sur l’image de base. La ligne 9) indique à docker de copier les fichiers source de l'application depuis le host(machine locale) vers l’image de base. Ici les fichiers à copier sont dans le même dossier que le dockerfile d'où le “.” La ligne 10) permet d’identifier la commande à lancer lorsque l’image est exécutée en tant que container. Quand une image est exécutée, elle est immédiatement stoppée quand il n’y a plus de processus qui tourne dedans. Pour spécifier une instruction à exécuter, l’instruction CMD est utilisée dans le dockerfile. Cette instruction peut se présenter sous plusieurs formes:

CMD commande parametre ou CMD ["commande","parametre"]
Exemple: CMD sleep 5 Une fois que nous avons mis en place le dockerfile, nous devons créer l’image à travers la commande docker build en spécifiant le dockerfile en même temps le tag à donner à l’image.

docker build Your-Dockerfile -t Your-Docker-Id/Your-Image-Name:Tag

Your-Dockerfile: le fichier Dockerfile
Your-Docker-Id/Your-Image-Name:Tag : c'est une convention de nommage où Your-Docker-Id représente l'identifiant de ton compte dans le docker Hub, Your-Image-Name représentant le nom que tu donnes à l'image et Tag représente le tag.
Si le tag n'est pas mentionné, le tag par défaut sera latest

NB: Un dockerfile est un fichier sans extension et avec comme nom Dockerfile.

Après l’exécution de cette commande, une image sera créée localement dans le host. Pour vérifier que l’image est bien créée, il faut utiliser la commande docker images détaillée plus haut. Maintenant que nous avons notre image, nous pouvons la rendre accessible à tous au niveau du docker hub. Pour cela nous utilisons la commande docker push en spécifiant le nom de l’image.

docker push Your-Docker-Id/Your-Image-Name:Tag

Nous avons maintenant notre image disponible pour tous. Vous vous êtes sûrement rendu compte qu’au moment de la création de notre image que le mot layer est affiché plusieurs fois à l’écran. Voyons ce que ça signifie.

Architecture en couche

Docker a une architecture en couche. Chaque ligne dans un dockerfile représente une couche. Pour avoir l’information sur les couches, nous exécutons la commande docker history.

docker history Your-Docker-Id/Your-Image-Name:Tag

L’architecture en couche permet de reprendre l’exécution du build à partir d’une étape précise au cas ou l’exécution s’est pas bien passée ou si nous voulons ajouter d’autres étapes au build. Attaquons maintenant la partie réseau dans docker.

Le réseau dans Docker

Quand nous installons docker, il crée automatiquement trois réseaux. Ces réseaux sont : Bridge, None et Host. Voyons voir à quoi correspondent ces réseaux. Commençons par Bridge:
C’est le réseau par défaut auquel chaque container est attaché. Le réseau Bridge est un réseau privé (172.17.0.0) créé par docker dans la machine host.
Pour le réseau Host:
Le container est rattaché au réseau de la machine host.
Dans le cas du réseau None:
Le container n’est rattaché à aucun réseau. Il est exécuté dans un réseau isolé.
Si vous voulez rattacher un container à un réseau, il faut utiliser l’option network de la commande docker run.

docker run ubuntu --network=host

Nous pouvons aussi créer notre propre réseau et y rattacher nos containers. Pour ce faire, nous utilisons la commande docker network create

docker network create --driver bridge --subnet 182.18.0.0/16 custom-isolated-network

avec 182.18.0.0/16 : le réseau que nous voulons créer, custom-isolated-network: le nom du réseau.
Pour lister tous les réseaux, il faut exécuter la commande suivante:

docker network ls

Tous les containers à l'intérieur du même host peuvent se joindre à travers leurs noms respectifs. Nous avons un serveur DNS (127.0.0.11) embarqué qui fait cette résolution entre adresses IP et noms des containers. Pour voir les détails par rapport à un réseau spécifique, il faut exécuter la commande:

docker network inspect Network-Name

Après avoir vu les réseaux, passons maintenant au stockage.

Le stockage dans Docker

Docker utilise une architecture en couche et ceci a plusieurs avantages:

  • Une fois qu’une couche est créée, docker utilise un cache pour stocker ses informations pour une utilisation future. Permettant ainsi un gain de temps et d’espace mémoire.
  • Une fois qu’une image est créée, ses données ne peuvent être modifiées. Nous avons un accès en lecture seule à la couche de l’image. Etant donné qu’une image peut être utilisée par plusieurs containers en même temps, c’est pour cette raison que ses couches doivent être immuables. Quand nous voulons effectuer des changements sur le code source, une copie est créée sur la couche du container et nous pouvons ainsi modifier le code de la copie. Ce mécanisme est appelé "copy-on-write".Toutes les modifications seront faites au niveau de la couche du container sur la nouvelle version. L’image va rester la même tout le temps jusqu’à ce que vous faisiez un nouveau build avec la commande docker build.
  • Si nous supprimons un container, tous ses fichiers seront supprimés.
  • Si nous voulons garder ces données, les volumes sont utilisés. Ce principe est appelé "volume mounting". Pour ce faire, nous devons créer un volume avec la commande:
    docker volume create VOLUME_NAME
    
    Ceci créera un volume nommé NAME_VOLUME dans un dossier du host(/var/lib/docker/volumes) Puis nous pouvons monter ce volume au container quand nous exécutons la commande:
    docker run -v VOLUME_NAME:/var/lib/mysql mysql
    
    Cette commande permet de sauvegarder les données depuis /var/lib/mysql dans notre host. Si nous exécutons la commande suivante:
    docker run -v VOLUME_NAME_2:/var/lib/mysql mysql
    
    docker va automatiquement créer un volume VOLUME_NAME_2 et y monter le container.
  • Si nous avons des données dans un dossier autre part par exemple /home/mara/data et que nous voulons le connecter à un container. Ce volume n’est pas créé par docker, dans ce cas il faut spécifier le chemin vers ce dossier dans la commande docker run:
    docker run -v /home/mara/data:/var/lib/mysql mysql
    
    Ce principe est appelé "bind mounting" -Il y a un autre moyen de monter des volumes avec la commande suivante:
    docker run --mount type=bind,source=/home/mara/data,target=/var/lib/mysql mysql
    
    source: chemin depuis le host
    target: localisation des données dans le container.
  • Si vous voulez supprimer tous les containers stoppés, tous les réseaux non utlisés, toutes les images présentes au niveau du host et non liées à un container, tout le cache, tapez la commande:
    docker system prune
    
  • Pour supprimer toutes images:
    docker system prune -a
    
  • Par défaut, les volumes ne sont pas supprimés, pour les supprimer, ajouter l'option volumes:
    docker system prune -a --volumes
    
    Arrivé à ce point, nous avons les connaissances de base permettant d’attaquer quelques notions plus poussées sur docker. J’espère que vous avez eu un plaisir à suivre le document tout au long. Dans un prochain chapitre nous aborderons les notions comme docker compose, l’orchestration de container avec docker swarm et kubernetes. A bientôt pour un nouveau document. D’ici là portez vous bien.

Vous ne pouvez pas ordonner la productivité, vous devez fournir les outils pour permettre aux gens de devenir meilleurs. -Steve Jobs

Références:

 
Share this