Docker dans la pratique
Nous avons vu dans l’article précédent la théorie sur les conteneurs, nous allons maintenant passer à la pratique. L’apprentissage de Docker est relativement simple, mais vous devez le compléter avec Docker Compose pour faire des infrastructures complètes entre les conteneurs.
Docker
Installation
L’installation de Docker va permettre d’avoir les outils nécessaires pour l’utilisation de Docker en local. Vous devez vous inscrire sur le Docker Hub et suivre la procédure d’installation à la fin de l’inscription.
Étape facultative : Installation de Docker avec le WSL2 sur Windows 10 version 2004
La nouvelle version de Windows 10, sortie le 27 Mai 2020 nous permet d’utiliser Docker sur un Linux « natif » sur Windows 10. Attention, il n’est pas activé nativement, vous allez devoir forcer l’utilisation de la version 2 et installer le dernier noyau Linux pour Windows 10!
Pour faire simple, vous devez :
- Valider que vous avez un Windows 10 version 2004
- Activer le WSL depuis un PowerShell en administrateur:
- Installer la mise à jour du noyau Linux WSL 2
- Installer un linux depuis le Microsoft Store : Debian par exemple.
- Définir le Linux par défaut sur le WSL2:
- Installer Docker Desktop for Windows « normalement »
Vous avez maintenant un Docker Linux sur Windows, l’avantage est considérable : Nous n’utilisons plus Hyper-V et le démarrage du Linux sur Windows est très rapide.
Plus d’information sur les étapes d’installation sur la documentation Docker et sur la documentation Microsoft pour l’utilisation du WSL2.
Interface Docker sur Windows
Depuis peu, Docker nous offre la possibilité d’utiliser une version graphique avec beaucoup de simplicité ! Vous pouvez voir la configuration, la charge, les logs, lancer les conteneurs et ouvrir un terminal simplement.
Exemple simple
Nous allons maintenant faire un test avec la création d’un conteneur Nginx qui n’est autre qu’un serveur Web simple permettant d’héberger des sites.
Dans un terminal, nous allons taper :
Ce qui nous donne :
Vous pouvez regarder le résultat sur http://localhost:8080.
Les arguments seront détaillés plus bas dans l’article. A présent nous allons voir les commandes de Docker.
Les commandes de Docker
Docker pull
La commande docker pull
permet de récupérer une image depuis un conteneur d’image Docker, comme le DockerHub.
Attention : les images Docker ne sont pas effacées automatiquement et sont gardées sur votre disque dur.
Tag et sécurité
Vous pouvez demander une version spécifique d’une image Docker sur le hub de docker comme par exemple pour Ngnix :
On peut voir sur la capture ci-dessus, que l’image Docker Nginx propose des versions spécifiques que nous pouvons récupérer avec la commande docker pull ImageDocker:Tag
:
La capture ci-dessus ne montre pas l’existence du tag « alpine », mais en cherchant bien sur les tags de l’image Docker nous pouvons la trouver.
Alpine Linux ?
Je vous recommande de prendre les versions d’Alpine Linux. Ce sont des images légères et performantes, qui n’embarquent pas de fioriture, un gage de sécurité. Nous pouvons voir que l’image de Nginx basée sur Alpine fait 8Mb, ce qui est vraiment léger comparé à la version basée sur Debian (50MB). Cependant, les images Docker ne sont pas basées sur Alpine Linux par défaut, mais sur une Debian, vous devez donc bien les chercher.
Par défaut, la commande docker pull
prend le tag latest sur le téléchargement des images. Il est toutefois préférable de prendre une version précise car un changement de configuration ou de paramètre de l’image peut casser votre application !
Docker run
Permet de lancer une image Docker.
Syntaxe :
Plus d’information sur les options de
docker run
sur la documentation officielle
Les Arguments
Port
Option -p
pour port.
Nous avons simplement demandé à Docker de lancer l’image nginx
(qui est un serveur web) avec une option : -p
pour le mot port
.
C’est une option indispensable dans Docker. Pour rappel, un conteneur Docker est étanche, nous devons donc définir un port pour communiquer avec.
Le -p
de -p 8080:80
signifie -p NotreMachine:ImageDocker
.
Nous devons retenir :
- Une Image Docker peut exposer un ou plusieurs ports, il suffit juste d’ajouter une autre option
-p
suivi des ports. Vous devez regarder la documentation de votre image pour connaitre quel(s) port(s) elle expose. - Nous trouvons souvent des images Docker avec par exemple
-p 9000:9000
, il n’est pas possible d’utiliser des ports déjà utilisés sur notre machine, faites attention ! - Il est obligatoire d’avoir un port sur une application Web. Mais il n’est pas obligatoire de définir un port pour une base de données.
Volume
Le -v
permet de faire un ancrage physique entre notre machine et l’image Docker de notre conteneur, il permet de faire de la persistance d’information :
- Le cas le plus simple est
-v /var/run/docker.sock:/var/run/docker.sock
qui utilise un dossier (ou fichier) physique de notre machine. La notion reste identique sur Docker,-v VotreMachine/Dossier:ImageDocker/Dossier
- Pour la persistance, nous recommandons de faire
-v sonarqube_data:/opt/sonarqube/data
, mais la création d’un volume dans Docker est nécessaire :Docker volume create sonarqube_data
par exemple. - Il n’y a aucune limite dans le nombre d’utilisation de
-v
Exemple :
Le
:ro
(readonly
) à la fin de l’argument du-v
permet de définir les droits d’accès en lecture seule sur le dossier (ou fichier) de votre machine.
Plus d’information sur la documentation officielle
Environnement
Le -e
permet de donner des informations d’environnement pour l’image Docker, ce qui permet de définir des paramètres. Voici un exemple : -e MSSQL_SA_PASSWORD='<YourStrong!Passw0rd>'
.
C’est la seule façon de paramétrer simplement et proprement une application dans une image Docker sans ajouter en dur les informations de configuration. Ce qui permet d’utiliser notre image Docker partout sans contrainte. Nous allons voir un cas d’usage plus bas avec le cas d’une connexion à une base de données.
Les Indispensables
Detach
Le -d
(–detach) est une option qui permet de lancer l’image Docker en tâche de fond.
Bien entendu, inutile quand on crée une image Docker, car nous ne pouvons pas voir les retours sur le terminal si une erreur se produit. Donc c’est plus dans un usage avancé lors de la mise en production par exemple.
Nommer un conteneur
L’argument --name
permet de nommer simplement un conteneur pour avoir une administration plus simple avec les commandes du CLI. Dans le cas contraire, un nom aléatoire est donné ce qui n’est pas vraiment bien, surtout si vous avez deux images docker identique de lancé.
Voici un exemple :
Comme vous pouvez le voir sur cette image, si nous ne définissons pas de nom, il va nous en créer un aléatoirement.
Docker build
Vous pouvez tester votre image avec la commande suivante :
Il est important d’exécuter cette commande lors de la création d’une image. Docker enregistre des parties en cache pour accélérer le build. Si vous êtes en création d’image pour un projet, il est donc obligatoire de le faire.
le MAN de docker
Vous pouvez obtenir les informations des commandes via l’option --help
dans le terminal :
Aide-mémoire
Voici une liste d’actions possibles sur Docker :
Commande | Description |
---|---|
attach | Attach local standard input, output, and error streams to a running container |
build | Build an image from a Dockerfile |
commit | Create a new image from a container’s changes |
cp | Copy files/folders between a container and the local filesystem |
create | Create a new container |
diff | Inspect changes to files or directories on a container’s filesystem |
events | Get real time events from the server |
exec | Run a command in a running container |
export | Export a container’s filesystem as a tar archive |
history | Show the history of an image |
images | List images |
import | Import the contents from a tarball to create a filesystem image |
info | Display system-wide information |
inspect | Return low-level information on Docker objects |
kill | Kill one or more running containers |
load | Load an image from a tar archive or STDIN |
login | Log in to a Docker registry |
logout | Log out from a Docker registry |
logs | Fetch the logs of a container |
pause | Pause all processes within one or more containers |
port | List port mappings or a specific mapping for the container |
ps | List containers |
pull | Pull an image or a repository from a registry |
push | Push an image or a repository to a registry |
rename | Rename a container |
restart | Restart one or more containers |
rm | Remove one or more containers |
rmi | Remove one or more images |
run | Run a command in a new container |
save | Save one or more images to a tar archive (streamed to STDOUT by default) |
search | Search the Docker Hub for images |
start | Start one or more stopped containers |
stats | Display a live stream of container(s) resource usage statistics |
stop | Stop one or more running containers |
tag | Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE |
top | Display the running processes of a container |
unpause | Unpause all processes within one or more containers |
update | Update configuration of one or more containers |
version | Show the Docker version information |
wait | Block until one or more containers stop, then print their exit codes |
Docker Compose
Docker Compose est un orchestrateur de conteneur Docker. Il permet de faire des recettes avec des images et de simplifier l’utilisation de Docker. C’est une solution intéressante qui permet de faire une architecture complexe entre divers services en un seul fichier. C’est l’un des outils requis pour utiliser Docker dans un projet.
Mise à niveau (optionnelle)
Le programme d’installation de Docker sur Windows inclut Docker Compose mais pas toujours avec la dernière version, ce qui peut être bloquant si vous souhaitez utiliser ses nouveautés sur votre machine. La team Docker ne propose pas souvent des mises à jour des outils, voici donc une solution pour garder Docker Compose à jour.
Nous pouvons utiliser la dernière version de Docker Compose en téléchargeant la version Windows sur le projet Github Docker Compose : Release.
Remplacez dans le dossier C:\Program Files\Docker\Docker\resources\bin
le fichier docker-compose.exe
par celui téléchargé.
Docker-compose.yml
Le docker-compose.yml
est notre fichier qui permet de faire la configuration et les interactions entre les images du conteneur.
Pour vous montrer les possibilités, nous allons prendre une image Docker qui demande une base de données. Nous allons faire en sorte que les deux images communiquent pour que l’application fonctionne. Voici un exemple avec SonarQube, une application forte utile en entreprise :
Docker-compose up
Pour créer et lancer les images, nous avons besoin de nous trouver dans le même niveau que le fichier docker-compose.yml
.
La commande est la suivante :
Si nous souhaitons exécuter la commande en tâche de fond, nous pouvons ajouter l’option -d
Docker-compose ps
La commande suivante permet de lister les images en cours, la configuration et le statut du conteneur de notre docker-compose.yml
.
C’est un bon début pour voir si nous avons un problème de lancement !
Nous pouvons aussi retrouver les informations avec la commande
docker ps
mais cela listera toutes les instances et non celui du fichierdocker-compose.yml
!
Docker-compose stop
La commande permet de fermer proprement le conteneur de notre docker-compose.yml
.
Docker-compose down
Pour toute future modification du docker-compose.yml
, vous devez préalablement faire un docker-compose down
si les modifications sont trop importantes. Vous pouvez ensuite faire un docker-compose up -d
.
Cette commande permet de fermer et de supprimer le conteneur, le réseau, les images utilisées et les volumes !
Docker-compose logs et events
Nous avons deux possibilités pour diagnostiquer un conteneur :
Et
Aide mémoire
Commande | Description |
---|---|
build | Build or rebuild services |
bundle | Generate a Docker bundle from the Compose file |
config | Validate and view the Compose file |
create | Create services |
down | Stop and remove containers, networks, images, and volumes |
events | Receive real time events from containers |
exec | Execute a command in a running container |
help | Get help on a command |
images | List images |
kill | Kill containers |
logs | View output from containers |
pause | Pause services |
port | Print the public port for a port binding |
ps | List containers |
pull | Pull service images |
push | Push service images |
restart | Restart services |
rm | Remove stopped containers |
run | Run a one-off command |
scale | Set number of containers for a service |
start | Start services |
stop | Stop services |
top | Display the running processes |
unpause | Unpause services |
up | Create and start containers |
version | Show the Docker-Compose version information |
Docker en développement
Création de projet sous Visual Studio 2019
Lors de la création d’un projet avec Visual Studio 2019, vous pouvez ajouter par défaut la prise en charge de Docker sur votre projet :
Les SPA Angular et React.js ne proposent pas par défaut d’activer Docker. Nous pouvons ajouter Docker dans le projet simplement en ajoutant l’orchestrateur Docker Compose :
Nous allons parler de la modification de l’image Docker pour utiliser Node.js et NPM plus bas dans l’article.
Pour rappel, l’ajout de Docker Compose va créer un projet que Visual Studio pourra lancer. C’est la solution la plus simple pour travailler en équipe, car si vous ajoutez simplement le support de Docker, vous serez le seul à pouvoir le lancer sur votre PC. Les autres développeurs n’auront que IIS Express en proposition car la modification n’est pas enregistrée sur un fichier et donc pas de commit possible.
Concernant l’option de support de Docker, je recommande toujours de prendre Linux pour les projets en .NET Core et le futur .NET 5, qui sortira en cette fin d’année. Cela vous fera économiser un coût de licence non négligeable. Pour les projets Legacy sur .NET Framework, vous n’avez pas le choix, c’est du Windows Container.
Extension Docker pour Visual Studio 2019
Il existe une extension officielle Visual Studio Container Tools Extensions développée par Microsoft pour Visual Studio 2019 qui simplifie le management de Docker.
Vous pouvez avoir accès aux conteneurs en cours de lancement et de les arrêter (de force, car parfois Docker en local ne fonctionne pas correctement) ou relancer simplement. Vous avez aussi la possibilité de lister les images Docker en local depuis cet outil, ouvrir un terminal et voir les fichiers rapidement.
Machine arrière ! Certificats SSL droit devant !
La meilleure façon d’apprendre et de retenir c’est en faisant des erreurs ! Vous allez avoir des erreurs sur votre production si vous continuez. Vous avez sans doute laissé activer le SSL sur votre projet lors de la création, mais saviez-vous que toutes les images Docker du Hub ne le sont pas ?
La raison est simple, nous utilisons généralement un outil externe comme Traefik pour la gestion du Proxy et qui permet d’ajouter la gestion dynamique des certificats. Dans le cas contraire, vous allez devoir intégrer un certificat SSL dans l’image Docker que vous avez créé, ce qui n’est pas pratique du tout.
Pourquoi ça fonctionne en local ?
La raison est simple : Il y a un fichier qui surcharge le docker-compose.yml et qui ajoute les certificats locaux dans l’image.
Dans cet exemple, pour que votre application fonctionne, vous allez devoir installer .NET Core et générer des certificats sur le serveur qui exécute les images Docker. Nous allons donc devoir retirer le SSL du projet.
Ne pas utiliser le SSL :
La méthode la plus simple, en début de projet est de simplement désactiver le SSL lors de la création du projet depuis Visual Studio :
Mais il y a des cas où l’option HTTPS est forcée, comme quand vous activez l’option d’authentification par exemple :
Nous allons prendre pour exemple ce cas et désactiver le SSL, car nous allons utiliser cette démo dans cet article pour vous parler de Docker plus en détail. Attention, nous pouvons simplifier l’étape en ajoutant la prise en charge de Docker Compose après la suppression du SSL du projet. Dans cet exemple je ne vais naturellement pas le faire pour vous montrer toutes les modifications à faire si c’est votre cas.
Nous allons modifier 3 fichiers :
Pour information ce fichier permet à Visual Studio Code et Visual Studio 2017/2019 de lancer le(s) projet(s).
Nous allons supprimer la copie du certificat SSL et de l’utilisation du port dans Docker Compose depuis Visual Studio :
Pour finir, nous allons supprimer l’ouverture du port SSL 443 de l’image Docker :
Voici une petite vidéo de cette manipulation et des résultats :
Création et utilisation de variables d’environnement de Docker dans un projet
Vous avez vu au début de cet article l’utilisation des -e
(environnement) pour personnaliser une image Docker. Mais comment faire pour en ajouter nous-même dans notre programme ? Aussi incroyable que cela puisse paraître, cette partie n’est pas détaillée ni même abordée dans la documentation MSDN, mais nous allons en parler ici. En parallèle Docker nous fournit un exemple que vous ne devez absolument pas utiliser (car cela ne vous permet pas de changer la configuration sans refaire une image) sur cette page : Quickstart: Compose and ASP.NET Core with SQL Server
Pour cet exemple, nous allons créer un projet en .Net Core 3.1 MVC avec l’Authentification en local, car nous allons ajouter dynamiquement la configuration de la base de données depuis Docker.
Pour information, le mode HTTPS est activé par défaut, reportez-vous sur la section « Ne pas utiliser le SSL » pour la supprimer.
Nous allons créer un fichier dans le projet du site web qui s’appelle settings.env
avec comme contenu suivant :
Nous devons par la suite référencer le fichier settings.env
dans le .csproj
du site web :
Maintenant, nous allons ajouter la configuration de Docker Compose, nos variables d’environnement et désactiver le SSL du projet. Vous devez ajouter donc l’orchestrateur Docker Compose (que nous avons vu plus haut, attention de bien vérifier que le SSL est retiré dans le fichier docker-compose.override.yml
).
Nous allons ajouter la configuration pour la connexion de la base de données dans le fichier docker-compose.yml
avec l’ajout d’une image de Microsoft SQL Server :
Il nous manque plus qu’à ajouter une vérification sur le lancement du site pour vérifier de la présence des variables. Pour faire simple dans cette démo, nous allons ajouter dans le fichier Program.cs
une vérification simple :
Pour finir, il nous reste juste à utiliser les variables dans le Startup.cs
pour la chaîne de connexion SQL du projet avec Entity Framework :
Voici la vidéo qui montre le résultat :
Nous pouvons noter qu’il y a une demande de migration Entity Framework pour créer les tables en base, vous pouvez automatiser cette étape avec la commande suivante :
N’oubliez pas de supprimer le container Docker si vous avez utilisé la persistance de données sur l’image de la base SQL !
Création d’une image Docker
Nous avons vu la création de projet .NET Core avec Docker, cependant nous n’avons pas encore vu la personnalisation des dépendances des images Docker. L’objectif est de comprendre que la personnalisation est importante et simple. Pour ce faire, nous allons utiliser la génération d’un projet de base par Visual Studio : .NET Core SPA Angular
Dockerfile
Le Dockerfile est un fichier qui décrit comment construire l’image de notre projet. Cette image va contenir notre application et l’ensemble des runtimes pour son fonctionnement.
Voici un exemple de construction d’image Docker. Je vais prendre l’image de base de .NET Core runtime et installer Node.js et NPM pour que mon projet .NET Core SPA Angular démarre. Je vais prendre un projet un peu plus complexe avec plusieurs projets pour comprendre quelle est la syntaxe et la logique :
Comme vous pouvez le voir ci-dessus, il y a plusieurs étapes et utilisation d’image Docker pour créer une image Docker personnalisée. Ici j’ai fait le choix de générer mon application dans une image Docker avec les SDK de .Net Core pour ne pas le faire depuis mon ordinateur. C’est le choix le plus intéressant, car nous pouvons le faire de n’importe où maintenant et surtout nous pouvons l’automatiser simplement sur des outils de déploiement continu.
.dockerignore
Extrêmement important, il permet d’ignorer les dossiers et fichiers inutiles. Le processus de création d’une image vu ci-dessus est le suivant :
- Nous allons copier le répertoire du projet dans l’image Docker (avec les SDK) pour construire notre application.
- Pour finir nous allons copier la génération de notre application dans une image Docker (avec les runtimes) pour ensuite l’utiliser normalement.
Il est donc inutile d’ajouter des fichiers non-nécessaire au fonctionnement ou sensible dans une image Docker.
Globalement, nous devons retrouver les mêmes règles que le fichier .gitignore mais avec en plus, tout ce qui est strictement inutile à la compilation de votre application :
Plus d’information sur la documentation officielle
1 commentaire
Très intéressant, pour l’installation de Docker ainsi que sa mise en pratique.