Docker
- Installation Docker
- Labo 1 - Premiers conteneurs, premières commandes
- Labo 2 - Les IDs et la complétion Bash
- Labo 3 - Préserver les données
- Labo 4 - Les volumes
- Labo 5 - Le réseau, partie 1
- Labo 6 - Détacher, attacher un conteneur
- Labo 7 - Création d'images
- Labo 8 - Le réseau, partie 2
- Labo 9 - Les volumes, partie 2
- Labo 10 - Docker compose
- Labo 11 - Portainer
- Labo 12 - Docker Registry Local - Commit
Installation Docker
L'installation de Docker est très simple, il suffit de lire et d'exécuter ce qui est décrit sur le site officiel de docker à cette adresse.
Si tout est ok, passons à la suite avec le premier labo
Labo 1 - Premiers conteneurs, premières commandes
Voici la première commande :
sudo docker run --rm bash echo Salut
docker -> nom de la commande qui permet de donner des ordres à docker
run -> c'est l'action qu'on demande à docker d'exécuter (ici on lui demande de créer et lancer un conteneur)
--rm -> paramètre optionnel qui indique à docker que quand le conteneur aura terminé de s'exécuter, on veut qu'il soit supprimé - on parle bien du conteneur pas de l'image qui restera en cache sur notre ordinateur prête à être instanciée en un nouveau conteneur dès qu'on en aura besoin
bash -> c'est le nom de l'image
echo Salut -> commande à exécuter dans le conteneur
Commande suivant :
sudo docker images
images -> demande l'affichage des images présentent localement dans le cache de notre serveur
REPOSITORY -> nom du dépôt d'où provient l'image
TAG -> identification d'un version spécifique d'une image
IMAGE ID -> identifiant unique d'une image
CREATED -> date de création de l'image
SIZE -> taille de l'image
Pour vérifier, chercher une version spécifique d'une image, se rendre sur le hub de docker
Commande suivante :
sudo docker run -ti --rm bash
Nous avons accès à un terminal du conteneur avec clavier et écran
Dernière commande :
sudo docker ps
Liste les conteneurs en cours d'exécution avec des informations détaillées
Labo 2 - Les IDs et la complétion Bash
Les IDs des conteneurs permettent de donner des ordres à un conteneur en spécifiant son id
sudo docker images
Je peux donc consulter les différentes couches qui composent mon image bash en tapant juste le début de son id
sudo docker history 39a
On peut utiliser la complétion dans le shell pour afficher les commandes de docker
sudo docker<TAB>
Si la complétion ne fonctionne pas, il faut voir si le paquet bash-completion est bien installé. Si ce n'est pas le cas, l'installer, se déconnecter de la session et se reconnecter.
En tapant la commande suivante voici la liste des différentes commandes possibles de donner à docker :
sudo docker --help
Labo 3 - Préserver les données
Il faut savoir que lorsque qu'un conteneur est supprimé, les modifications faites dans le conteneur disparaissent
Je créé un fichier fic dans mon conteneur, si j'ai mis l'option --rm en le lançant et que je quitte le conteneur, le fichier fic n'existe plus
Si je refais la commande précédente en enlevant le --rm et que je quitte le conteneur, le fichier n'existe plus.
Il faut se rappeler que la commande docker run créé à chaque fois un nouveau conteneur
Par contre si on utilise la commande suivante, on voit la liste des conteneurs créés mais non supprimés si on a pas mis l'option --rm
sudo docker ps -a
Par contre nous pouvons utiliser un conteneur en status Exited (qui est créé mais qui ne tourne pas) :
Mais avant voyons les différentes options de cette commande :
sudo docker start --help
Pour rentrer dans le conteneur et vérifier si le fichier est bien dedans :
sudo docker start -ai <CONTENAIR ID> ou <NAMES>
Si la machine hôte, celle qui contient le docker engine, est redémarrée les conteneurs créés sans l'option --rm seront sauvegardés
Labo 4 - Les volumes
Nous pouvons monter des volumes dans un conteneur pour pouvoir interagir entre le système de fichiers de la machine hôte et celui du conteneur.
Créons un fichier dans la machine hôte
sudo echo OK > fic
Voilà comment monter le volume courant accessible depuis le conteneur :
sudo docker run -ti --rm -v $(pwd):/texte bash
Le paramètre $(pwd) est le chemin courant (là où on se trouve dans la machine hôte)
On retrouve bien le fichier fic
On peut également, à travers du conteneur, écrire dans ce fichier et vérifier dans la machine hôte si on a pu écrire dedans
echo TEST >> /texte/fic
Le paramètre >> permet d'incrémenter le texte du fichier
Il est également possible de donner accès à ce fichier en lecture seule de la manière suivante. En rajoutant une ligne nous aurons un message d'erreur disant que le fichier est en lecture seule (ro = read only) :
On peut également créer un script et voir s'il est compatible dans la version de bash que nous avons
Créons le script :
vi script.sh
echo OK &>> /tmp/test
cat /tmp/test
Le rendre executable
sudo chmod +x script.sh
Maintenant lançon-le dans docker
sudo docker run --rm -v $(pwd)/script.sh:/script.sh bash /script.sh
Attention de ne pas monter de dossier sensibles de la machine hôte sur le conteneur !
Labo 5 - Le réseau, partie 1
Pour voir comment se comporte le réseau entre les conteneurs, la machine hôte et le réseau local, nous allons créer un conteneur avec le serveur web nginx
sudo docker run --rm nginx
On voit que le conteneur est créé et en cours d'exécution. Le port 80 est ouvert mais uniquement sur le conteneur. Il va falloir faire un mappage de port pour accéder au serveur nginx du conteneur à travers le navigateur web
Pour ce faire il faut utiliser la commande précédente et rajouter l'option -p avec le port de l'hôte 80 et celui du conteneur 80
sudo docker run --rm -p 80:80 nginx
Si nous ouvrons un navigateur avec l'adresse ip du conteneur, nous arrivons sur nginx
Attention, il n'est pas possible d'ouvrir le même port hôte pour un autre conteneur
Il est également possible de laisser l'hôte choisir son port
sudo docker run --rm 80 nginx
Puis sur un autre terminal de la machine hôte :
sudo netstat -nate
On voit que le port 32768 est apparu. Nginx sera donc accessible sur votre navigateur via http://votreadresseip:32768
Nous pouvons également trouver le port aléatoire créé par l'hôte avec la commande suivante depuis la machine hôte
sudo docker inspect lenomdevotreconteneur
Nous pouvons voir également quels sont les ports exposés par une image d'un conteneur :
sudo docker inspect nginx
Labo 6 - Détacher, attacher un conteneur
Pour lancer un conteneur en tâche de fond, il faut se détacher de ce dernier avec l'option -d, par exemple pour nginx :
sudo docker run -d -p 80:80 nginx
Mais comment arrêter un conteneur ?
On peut se rattacher au conteneur pour pouvoir l'arrêter avec un ctrl+c
sudo docker attach <idduconteneur ou nomduconteneur>
Pour pouvoir se rattacher et se détacher au conteneur sans l'arrêter, il faut lancer la première commande avec l'option -ti
Puis on peut s'y attacher avec la commande précédente
Et s'en détacher sans l'arrêter avec ctrl+p et ctrl+q
Nous pouvons également arrêter un conteneur
sudo docker stop <idduconteneur ou nomduconteneur>
Pour voir les logs d'un conteneur en cours d'exécution
sudo docker logs <idduconteneur ou nomduconteneur>
Et pour voir les logs qui apparaissent au fur et à mesure, il faut rajouter l'option -f à la commande précédente
sudo docker logs -f <idduconteneur ou nomduconteneur>
Labo 7 - Création d'images
Nous allons voir dans cette exemple comment customiser une image officielle php.
D'abord créons le conteneur et on se retrouve dans la console php du conteneur
sudo docker run -ti php
Nous allons utiliser Soap (qui permet de créer des web services)
new SoapClient();
Nous voyons que le module Soap n'est pas présent sur l'image officielle de php téléchargée précédemment
Pour l'installer, il faut d'abord se connecter au conteneur php en bash depuis un terminal de la machine hôte
sudo docker exec -ti <idduconteneur> bash
Pour trouver comment installer l'extension souhaitée, il faut aller sur le hub de docker dans explore, puis php
Donc dans le terminal bash du conteneur
docker-php-ext-install soap
Visiblement il manque une librairie : libxml-2.0
Pour là trouver de retour dans le terminal bash du conteneur :
apt update && apt-cache search libxml2
Puis faire
apt install -y libxml2-dev
Et maintenant relançons l'installation de soap
docker-php-ext-install soap
Si nous relançons la commande new SoapClient depuis le terminal php cela ne fonctionnera pas puisque php est déjà lancé et il n'a pas l'extension précédemment installée.
Depuis le terminal bash, lançons d'abord php -a (pour se remettre en mode php, puis
new SoapClient('http://webservices.oorsprong.org/webexamples.countryinfo/CountryInfoService.wso?WSDL');
Le webservice a été déplacé... mais cela n'empêche en rien la création de l'image.
La création de l'image passe par un Dockerfile
De retour dans le terminal hôte nous allons éditer un Dockerfile
sudo vi Dockerfile
Puis copier coller le texte dedans en sauvegardant
FROM php:7.0.31-cliRUN apt updateRUN apt install -y libxml2-devRUN docker-php-ext-install soap
Pour construire l'image, il faut
sudo docker build -t php_soap:7.0.31 .
build -> construction de l'image à l'aide du Dockerfile
-t -> permet de donner un tag à notre image
. -> chemin courant où se trouve le Dockerfile (pour un Dockerfile avec un nom personnalisé, il faut rajouter -f MonDockerFile .)
J'ai choisi de personnaliser le nom de mon Dockerfile donc je lance la commande
sudo docker build -t php_soap:7.0.31 -f MonDockerFile .
On vérifie que l'image soit bien dans le cache :
sudo docker images
Testons notre image pour voir si le module soap a bien été installé :
sudo docker run -ti php_soap:7.0.31
L'image customisée avec soap est bien présente !
Maintenant il est également possible de faire évoluer la version de notre image par exemple en 7.2.8
Modifions notre fichier customisé MonDockerFile
sudo vi MonDockerFile
sudo docker build -t php_soap:7.2.8 -f MonDockerFile .
Même chose que plus haut, vérifions
sudo docker run -ti php_soap:7.2.8
Cela a fonctionné. Il ne nous reste plus qu'à arrêter l'ancien conteneur et mettre en marche le nouveau
Labo 8 - Le réseau, partie 2
Il existe 5 types de drivers réseaux que nous pouvons utiliser lors de la création d'un conteneur en ajoutant cet argument
--network <type>
Driver 1 : none
Absence totale de réseau au conteneur
sudo docker run -ti --rm --network none bash
Même en spécifiant un port avec -p il n'y aura pas de communication réseau
Driver 2 : bridge
Iil est le pilote par défaut. Il peut être utilisé pour faire communiquer plusieurs conteneurs entre eux quand c'est spécifié
Nous avons des adresses ip et nous voyons que les conteneurs se voient
Les deux conteneurs peuvent également communiquer avec le réseau de l'hôte qui a par défaut l'adresse ip 172.17.0.1
Maintenant chaque conteneur créé pourra communiquer avec un autre grâce au bridge par défaut.
Il est cependant possible d'isoler les réseaux des conteneurs en créant un clone du bridge
sudo docker network create --driver=bidge mon_bridge
Puis un
sudo docker network ls
Voyons comment créer des conteneurs sur ce nouveau bridge
sudo docker run -ti --rm --network=mon_bridge --name=srv1 bash
Puis
ifconfig
Et pour le deuxième conteneur
sudo docker run -ti --rm --network=mon_bridge --name=srv2 bash
Puis
ifconfig
Le DNS interne géré par Docker ne s'applique uniquement qu'aux réseaux bridges clonés
Maintenant si les conteneurs sont rattachés au bridge par défaut, il est possible de les rattacher dynamiquement à un bridge cloné
sudo docker network connect=mon_bridge srv1
et
sudo docker network connect=mon_bridge srv2
Pour supprimer un bridge cloné, il suffit de faire
sudo docker network rm mon_bridge
Cette opération ne peut se faire si nous n'avons plus aucun conteneur attaché à ce réseau
Driver 3 : host
Il permet à un conteneur de partager la même pile réseau que celle de l'hôte
Par exemple avec nginx nous avions spécifié un port particulier mais si nous faisons simplement
sudo docker run --rm --network=host nginx
On a bien accès au serveur nginx via un navigateur web
L'accès au network host est assez peu courant
Driver 4 : overlay
Il permet de connecter entre eux qui tournent sous des hôtes différents
Driver 5 : Macvlan
Il permet d'attribuer une adresse MAC à l'interface réseau virtuelle de chaque conteneur
Labo 9 - Les volumes, partie 2
Nous allons continuer à voir le mappage des volumes de l'hôte vers le conteneur
Créons un dossier avec un fichier auquel je lui donne tous les droits et du texte dedans
sudo mkdir test && sudo chmod -R 777 test && sudo echo OK > test/fic && sudo cat test/fic
Créons un conteneur en mappant ce dossier :
sudo docker run --rm -ti -v $(pwd)/test:/test bash
Voyons le contenu de notre fichier /sbin (répertoire qui contient des commandes de base pour l'administration du système)
ls -lh /sbin
Sortons du conteneur et créons-en un nouveau en changeant le mappage du volume de cette manière :
sudo docker run --rm -ti -v $(pwd)/test:/sbin bash
Le mappage a totalement éclipsé le contenu de sbin, c'est la particularité du mappage.
Les volumes managés
Nous allons voir un autre type de volumes : les volumes managés. C'est docker qui a la main dessus alors que les volumes mappés sont sur l'hôte lui même.
Pour ce faire, créons un volume
sudo docker volume create mes_donnees && sudo docker volume ls
Essayons de créer un nouveau conteneur avec le volume managé créé ci-dessus
sudo docker run --rm -ti -v mes_donnees:/test bash
On voit bien qu'en créant un fichier dans le conteneur, en sortant du conteneur (= conteneur détruit) et en recréant un nouveau conteneur, le fichier est toujours présent grâce au volume managé
En lançant la commande précédente, il est possible de créer directement le volume managé sans passer par la commande
sudo docker volume create mes_donnees
Voici comment retrouver les volumes managés par docker
sudo docker volume inspect mes_donnees
Allons voir dedans pour voir si le fichier fic est bien présent
sudo ls -lh /var/lib/docker/volumes/mes_donnees/_data
Si on monte sur le volume managé le dossier sbin
sudo docker run --rm -ti -v mes_donnees:/sbin bash
On voit bien le fichier fic présent dans le volume managé sur l'hôte.
Supprimons, depuis l'hôte ce fichier dans le volume managé et relançons le création d'un nouveau conteneur
Le volume managé étant vide, on peut voir maintenant le contenu du dossier /sbin dans le conteneur.
On sort du conteneur, et affichons le contenu du volume partagé
sudo ls -lh /var/lib/docker/volumes/mes_donnees/_data/
On retrouve l'intégralité du dossier /sbin du conteneur bien que ce dernier ait été supprimé
Je peux donc créer, modifier, supprimer des dossiers ou fichiers depuis l'hôte ou depuis le conteneur.
Quand on monte un volume managé VIDE, le contenu du dossier de montage du conteneur est intégralement transféré dans le volume managé. Tout cela est persistent à la suppression du conteneur
Labo 10 - Docker compose
Docker compose est un chef de cuisine qui permet de créer une recette en y mettant dedans tous le conteneurs nécessaires à la fabrication du plat final
Nous allons monter un serveur Wordpress (serveur Web + base de données)
Tout d'abord il faut créer le fichier docker-compose.yml
Pour plus d'infos sur le format .yaml, il suffit d'aller sur le sur leur site https://yaml.org/
La première ligne correspond à la dernière version de docker compose qui est rétro-compatible avec les anciennes versions
sudo vi docker-compose.yml
On peut retrouver plusieurs sections dans ce fichier :
version: "3.8" -> obligatoire (version actuelle de docker-compose)
services: -> obligatoire (les conteneurs dont nous aurons besoin)
volumes: -> dépend de vos besoins
networks: -> dépend de vos besoins
Voici donc le texte à copier-coller dans votre fichier docker-compose.yml
Attention : pensez à respecter les indentations !!!!
version: "3.8"
services: #nom du conteneur
wordpress:
image: wordpress:4.9 #image à téléchager sur le docker hub avec le tag
ports:
- 80:80 #ports à ouvrir entre l'hôte et le conteneur
environment: #variables d'environnements nécessaires pour la création du conteneur prises sur le docker hub www.hub.docker.com
- WORDPRESS_DB_HOST=db #nom du conteneur de la base de données
- WORDPRESS_DB_USER=tata #utilisateur qui aura été créé plus bas
- WORDPRESS_DB_PASSWORD=yoyo #mot de passe de l'utilisateur de la base de données
- WORDPRESS_DB_NAME=wordp #nom de la basse de données
networks:
- galaxie #nom du réseau auquel sera connecté le conteneur
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=tata_yoyo #mot de passe root de la base de données
- MYSQL_DATABASE=wordp #nom de la base de données
- MYSQL_USER=tata #utilisateur de la base de données
- MYSQL_PASSWORD=yoyo #mot de passe de l'utilisateur de la base de données
networks:
- galaxie
#volumes: #à ce stade la section volume sera utilisée plus tard
networks:
galaxie: #création réseau bridgé cloné
Pour lancer la création de mon environnement
docker-compose up
S'il n'y a pas d'erreur, rendez-vous sur votre navigateur web en tapant l'ip de votre host
En suivant les étapes d'installation, on a bien un wordpress fonctionnel
Si nous quittons l'environnement, les conteneurs vont s'arrêter. Pour que les conteneurs soit lancés en tâche de fond
docker-compose up -d
Pour arrêter les conteneurs sans les supprimer
docker-compose stop
Pour les démarrer
docker compose start
Pour supprimer tout un environnement
docker-compose down
Cette commande supprime tout sauf les volumes
Voyons justement comment personnaliser wordpress avec les volumes
Le chemin de base de wordpress se trouve dans /var/www/html
Et celui de mysql dans /var/lib/mysql
Nous allons commencer par la création de volumes mappés
Editons le fichier docker-compose.yml
sudo vi docker-compose.yml
version: "3.8"
services: #nom du conteneur
wordpress:
image: wordpress:4.9 #image à téléchager sur le docker hub avec le tag
ports:
- 80:80 #ports à ouvrir entre l'hôte et le conteneur
environment: #variables d'environnements nécessaires pour la création du conteneur prises sur le docker hub www.hub.docker.com
- WORDPRESS_DB_HOST=db #nom du conteneur de la base de données
- WORDPRESS_DB_USER=tata #utilisateur qui aura été créé plus bas
- WORDPRESS_DB_PASSWORD=yoyo #mot de passe de l'utilisateur de la base de données
- WORDPRESS_DB_NAME=wordp #nom de la basse de données
networks:
- galaxie #nom du réseau auquel sera connecté le conteneur
volumes:
- ./data/wp:/var/www/html #volume pour préserver les données de wordpress
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=tata_yoyo #mot de passe root de la base de données
- MYSQL_DATABASE=wordp #nom de la base de données
- MYSQL_USER=tata #utilisateur de la base de données
- MYSQL_PASSWORD=yoyo #mot de passe de l'utilisateur de la base de données
networks:
- galaxie
volumes:
- ./data/db:/var/lib/mysql
#volumes: #à ce stade la section volume sera utilisée plus tard
networks:
galaxie: #création réseau bridgé cloné
Tapez la commande pour recréer l'environnement et la nouvelle installation de wordpress
docker-compose up -d
Donc en tapant la commande docker-compose down, les conteneurs seront arrêtés et supprimés mais les données conservées dans le volume spécifié (ici le /data)
Voyons maintenant le comportement avec les volumes managés
Editons de nouveau le fichier docker-compose.yml
version: "3.8"
services: #nom du conteneur
wordpress:
image: wordpress:4.9 #image à téléchager sur le docker hub avec le tag
ports:
- 80:80 #ports à ouvrir entre l'hôte et le conteneur
environment: #variables d'environnements nécessaires pour la création du conteneur prises sur le docker hub www.hub.docker.com
- WORDPRESS_DB_HOST=db #nom du conteneur de la base de données
- WORDPRESS_DB_USER=tata #utilisateur qui aura été créé plus bas
- WORDPRESS_DB_PASSWORD=yoyo #mot de passe de l'utilisateur de la base de données
- WORDPRESS_DB_NAME=wordp #nom de la basse de données
networks:
- galaxie #nom du réseau auquel sera connecté le conteneur
volumes:
- wp:/var/www/html #volume pour préserver les données de wordpress
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=tata_yoyo #mot de passe root de la base de données
- MYSQL_DATABASE=wordp #nom de la base de données
- MYSQL_USER=tata #utilisateur de la base de données
- MYSQL_PASSWORD=yoyo #mot de passe de l'utilisateur de la base de données
networks:
- galaxie
volumes:
- db:/var/lib/mysql
volumes: #ici ce sont des volumes managés que vous modifierez plus haut
wp:
db:
networks:
galaxie: #création réseau bridgé cloné
Et nous relançons la commande suivant pour recréer les conteneurs avec les volumes managés
docker-compose up
Pas de surprise tout fonctionne et on repart sur une nouvelle installation de wordpress
Arrêtons le tout et voyons si les volumes ont bien été créés
sudo docker volume ls
En faisant un docker-compose down, les conteneurs seront supprimés mais pas les volumes
Cependant il est possible de forcer la suppression de ces volumes
docker-compose down -v
Cela supprime les volumes managés créés à partir du docker-compose.yml mais pas les autres volumes managés créés avec docker
Pour finir, il est possible de modifier un paramètre dans le fichier docker-compose.yml en cas d'arrêt ou redémarrage de docker.
Il s'agit de restart:
restart: always #permet de redémarrer automatiquement le conteneur quel que soit l'état dans lequel il était avant l'arrêt ou le redémarrage de docker
restart: no #empêche de redémarrer automatiquement le conteneur quel que soit l'état dans lequel il était avant l'arrêt ou le redémarrage de docker
restart: unless-stopped #permet de redémarrer automatiquement le conteneur s'il était démarré avant l'arrêt ou le redémarrage de docker
Labo 11 - Portainer
Portainer est un outil graphique permettant de piloter les conteneurs d'un ou plusieurs hôtes
Installons-le
sudo docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer-ce
Rendez-vous maintenant sur un navigateur avec l'url de votre serveur en précisant le port 9000
Paramétrez un mot de passe de première connexion
Nous pouvons gérer des conteneurs distants mais là nous allons le faire sur notre machine locale
En cliquant sur le bandeau local on peut retrouver nos images, nos volumes, ...
Je ne vais pas détailler toutes les vues de cette interface graphique mais vous pourrez chercher et fouiller !
Labo 12 - Docker Registry Local - Commit
Nous allons voir comment créer un registre local d'images Docker afin de pouvoir les télécharger plus rapidement, créer des images modifiées ou simplement sauvegardé les images existantes
Considérons que votre machine hébergeant le registre local est un machine sous Linux et que docker et docker-compose sont installés.
Nous installerons une version dite insecure qui n'est pas viable en production
Vous pourrez retrouver la documentation complète ici
Tout d'abord, il faut éditer ou créer le fichier docker-compose.yml
sudo vim /opt/docker/docker-compose.yml
version: "3.8"
services:
registry:
container_name: registry
restart: always
image: registry:latest
ports:
- 5000:5000
volumes:
- /opt/docker/registry/data:/var/lib/registry
- /opt/docker/registry/certs:/certs
- /opt/docker/registry/auth:/auth
Ensuite, il faudra éditer ou créer un fichier sur la machine qui hébergera le registre local ainsi que sur celle qui voudra récupérer l'image
sudo vim /etc/docker/daemon.json
{
"insecure-registries" : ["myregistry.local:5000"]
}
Ensuite il faudra modifier le fichier hostname et le fichier hosts de notre machine. A noter qu'il faudra bien déclarer la machine hébergeant le registre local dans le fichier hosts des autres machines voulant récupérer les images
Pour le fichier hostname
sudo nano /etc/hostname
myregistry.local
Et pour le fichier hosts
sudo vim /etc/hosts
127.0.0.1 localhost
192.168.1.226 localhost
127.0.0.1 myregistry.local
192.168.1.226 myregistry.local
Ensuite on redémarre les démons et le service docker
sudo systemctl daemon-reload
sudo systemctl restart docker
Maintenant on peut lancer le conteneur
sudo docker-compose up -d
Le conteneur tourne et est opérationnel
docker push bash
docker tag
sudo firewall-cmd --add-port=5000/tcp --permanent
sudo firewall-cmd --reload
