Développeur FullStack & Devops

Notes et mémos techniques

Docker introduction pour débutants

Docker virtualisation grâce à des images et containers

En tant que développeur, il nous arrive de vouloir "essayer" telle ou telle librairie, faire un petit POC rapide ou utiliser l'une des dizaines d'images utilitaire de https://docs.linuxserver.io/ 🥰. Il y a quelques années était possible d'isoler des environnement de travail et de les rendre "temporaires" ou "jetable" grâce à des solutions de virtualisations (plus ou moins lourde ou onéreuses).

Docker est apparue comme une alternative "légère" à la Virtualisation classique car elle repose sur le système d'exploitation hôte (contrairement aux VM qui nécessite une install d'OS).

Attention: on lit souvent que docker permet de déployer "cross plateform", mais il faut noter que les images docker sont dépendantes de l'OS et de l'architecture CPU hôte. Il faudra donc utiliser une méthode nommé multistage build si votre environnement de dév est sous Linux sur un PC (x64) et que vous souhaitez déployer sur des Raspberry Pi (armV7). Voir également Docker Machine (anciennement Boot2docker)

Concepts de base

Docker nous permet de créer un environnement isolé capable de faire tourner des services/serveurs (web, smtp ou autres) ou de lancer des exécutables, sans polluer le système hôte, tous les fichiers/libs nécessaires sont empaquetés dans l'image docker.

Mots clé

Image

Une image docker c'est un package exécutable en lecture seule, qui comprend tout ce qui est nécessaire pour lancer une application (le code, runtime, bibliothèques, var d'environnement et fichiers de conf). Une image Docker peut être une application web complète, un serveur quelconque ou juste un exécutable. Il existe de nombreuses images facilement récupérables depuis un repo Docker, elles nous serviront de base pour construire notre propre image (contenant notre toute dernière SPA par ex).

Container

Un docker container c'est l'instance d'une image, c'est une image qui est "exécutée" et visible avec la commande docker ps

DockerFile

le DockerFile est un fichier de commandes qui va nous permet de créer une image personnalisée en se basant sur des images existantes puis la configuration et installation d'outils divers

Docker Engine

Le docker engine est le moteur de Docker coté serveur, il se compose du process (deamon) dockerd, qui va permettre de gérer les containers et images. Pour interagir avec ce docker engine nous disposons d'une API REST ainsi que d'un SDK.

Le SDK officiel supporte Python et Go mais il existe également de nombreuses bibliothèques non officiels pour différents languages de programmations :

L'API REST se nomme le Docker Engine API, et comme toute API bien concue, elle est versionnée. Sélection la version de l'API selon les versions de Docker daemon et Docker client utilisés.

Docker Hub

Repository d'images dockers pour divers architectures matériels (et spécificquement pour ici Raspberry Pi)

Commandes de base

Gestion

docker images  : liste l'ensemble des images présente en local (machine faisant tourner le deamon docker)

docker ps -a  ou docker container ls -all  : liste l'ensemble des containers (même ceux qui sont exited)

docker diff e319dc35e14e  : affiche la différence entre le container (l'argument est le CONTAINER ID fournie par docker ps ) et l'image à partir de laquelle il a été lancé

docker commit e319dc35e14e debian-perso : enregistre le container ayant l'ID spécifié dans une image nommée debian-perso

docker save debian-perso > ~/debian-perso.tar  : exporte l'image debian-perso sur dans le home de l'utilisateur courant sous forme de fichier tar

docker run --hostname=dockerized --name=toto -ti debian  : lance l'image debian en nommant le container "toto" et en spécifiant le nom d’hôte dokerized, en mode interactif

docker run --hostname=dockerized -v /tmp/local:/tmp/container -ti debian : lance l'image debian en mappant un dossier de la machine hôte sur un dossier du container, cela permet de faire persister les fichiers

Run

La commande docker run est particulièrement riche en options mais voici

# lance le conteneur mais s'arrete
docker run alpine:latest

# lance le conteneur et donne la main puis supprime le conteneur une fois la session terminée (--rm)
docker run -ti --rm debian:latest 

# lance le conteneur en arrière plan et le nomme (--name)
docker run -di -p 8080:80 --name mon_nginx nginx:latest

docker run -di -p 8080:80 -v ./local/folder:/usr/share/nginx/html/ nginx:latest # montage de volume

docker exec -ti mon_alpine sh # reprendre la main sur un conteneur lancé en deamon
docker ps -a # lister tous les conteneurs meme ceux arretés
docker inspect mon_nginx | jq -C | less # liste toutes les infos => good pour Debug

les conteneur disposent d'une adresse IP dynamique sur un réseau docker fourni par docker inspect, dans l'exemple précédent le conteneur mon_nginx nous mets à dispo le service sur :

http://localhost:8080
http://172.17.0.3:80

Gestion par lots

Ces commandes permettent de nettoyer un système, donc attention à ces copier/coller ☠️ :

docker ps -aq    # liste les ID des containers présent
docker stop `docker ps -aq`  # arrête tous le containers
docker rm `docker ps -aq`    # supprime tous le containers
docker rmi `docker images -q`   # supprime toutes les images

Persistance des données

Par défaut un conteneur Docker écrit sur un système de fichier interne (writable container layer). Ces données sont donc physiquement liés au conteneur ce qui présente 3 inconvénients :

  • il est difficile de déplacer/backup la data
  • il est difficile d'y accéder depuis un autre conteneur ou système hote
  • les données ne résisteront pas à la destruction/re-création du conteneur

Pour persister les données utilisés par un conteneur, il faut utiliser l'un des 2 mécanismes dédiés :

Docker has two options for containers to store files on the host machine, so that the files are persisted even after the container stops: volumes, and bind mounts.

Il y a donc les notions de volumes et les bind mounts qui vont permettre de stocker les fichiers sur le système hôte, qui peuvent etre montés grace à l'option -v ou --volume du docker run.

Volumes

Volumes are the preferred way to persist data in Docker containers and services.

Les volumes sont stockés dans un dossier gérer par Docker (/var/lib/docker/volumes/ sur Linux) il sont donc en quelque sorte cachés, ce qui évite les boulettes, mais aussi que d'autres process viennent y toucher.

Il est possible de monter 1 meme volume sur plusieurs conteneur simultanément.

Commandes docker volume

Les commandes de gestion des volumes sont les suivantes :

Usage:  docker volume COMMAND

Commands:
  create      Create a volume
  inspect     Display detailed information on one or more volumes
  ls          List volumes
  prune       Remove all unused local volumes
  rm          Remove one or more volumes

volume drivers

Il existe également la notion de volume drivers qui permet de stocker nos fichiers non plus sur le système hote, mais dans le cloud ou sur des support de stockage distant.

Bind mounts

Les Bind mounts sont le système de persistance historique de docker. Ils permettent simplement lorsqu'on docker run d'attacher un dossier du système hote à un dossier à l'intérieur du conteneur.

docker run -di -p 80:80 -v $(pwd)/toto:/usr/share/nginx/html/

Pour éviter de perdre du tps 😉 il est à noter que les chemins spécifiés doivent être des chemins absolus, faute de quoi docker créera un volume du meme nom, ici le volume toto sera créé (visible via un docker volume ls)

docker run -di -p 80:80 -v toto:/usr/share/nginx/html/

Sécurité des bind mounts

Attention, d'après la doc officielle, les bind mounts permettent d'interagir avec le système de fichier hote via des process tournant à l'intérieur du conteneur 😱

Bind mounts allow access to sensitive files

One side effect of using bind mounts, for better or for worse, is that you can change the host filesystem via processes running in a container, including creating, modifying, or deleting important system files or directories. This is a powerful ability which can have security implications, including impacting non-Docker processes on the host system.

A lire

  1. comprendre ces concepts lire la doc officielle Docker.
  2. ce très bon blog post à propos des Docker volumes vs. bind mounts (logrocket) avec des exemples

exemple avec coloration syntaxique

docker volume ls --format '{{json .}}'|jq

Réseau

Le réseau par défaut utilisé par Docker est le bridge aussi libellé docker0 Les conteneur peuvent communiquer à travers ce réseau (ou un réseau custom) en se référant les uns aux autre par leurs noms de conteneur. Petit piège, les IP sont flottantes, il ne faut donc pas utiliser des adresses IP pour ces communications inter conteneurs.

Tips

Installation

Il existe différentes méthodes d'installation en fonction de l'OS hote:

mais la plus simple est d'exécuter le script d'installation:

curl -fsSL https://get.docker.com -o get-docker.sh

Post-installation

Si vous souhaitez utiliser docker sans sudo à chaque commande, il suffit d'ajouter les logins au group docker (a créer s'il n'existe pas):

  1. Créer le groupe docker.
sudo groupadd docker
  1. Ajouter l’utilisateur courant (ou un autre a spécifier) au groupe système docker.
sudo usermod -aG docker $USER

Tester l'installation locale de docker

Pour vérifier son installation, faire un simple docker -v  puis  tenter de lancer une image (ici Nginx pour Raspberry Pi) en prenant soin de mettre un fichier index.html dans le dossier spécifié en paramètre :

docker run --name testwebsrv -v /dossier/local/contenant/du/html:/usr/share/nginx/html:ro -d -p 8080:80 arm32v7/nginx

❗ si on obtient une erreur : standard_init_linux.go:207: exec user process caused "exec format error" c'est que l'image que l'on souhaite exécuter n'est pas adaptée à l'architecture CPU locale (ex on essaye de lancer une image X64 sur un ARMv7).

Désintallation

Si l'installation a été faite via le script Curl fourni par le site Docke sur une distribution type Debian (ex raspbian), la désinstallation se fait avec dpkg

sudo dpkg -l|grep docker # pour vérifier que le(s) package docker est bien présent
sudo dpkg --remove --force-remove-reinstreq docker-ce
sudo groupdel docker

Liens

devops
docker
linux
raspberry-pi
intro
jq
devops
rédigé le 10/11/17 par Behrouze
A proposCheat SheetsOutilsVidéos