Virtualisation Docker

🤚 Attention, ce texte date d'une autre époque de l'histoire de Docker (2014/2015) alors que le format des conteneurs n'était pas encore standardisé. Le document se trouve ici pour mémoire en vue d'un meilleur contenu.

1. Virtualisation par container

Le projet Docker est une solution de virtualisation logicielle, légère, dite par isolateur ou par container.

En matière d'isolation logicielle, d'autres solutions sont disponibles telles que :

  • LXC
  • OpenVZ
  • BSD Jails
  • Zones Solaris

Les avantages de ce type de virtualisation tiennent aux performances d'exécution des processus logiciels : démarrage immédiat, surcharge presque nulle, déploiement manuel ou automatique immédiat. Par exemple LXC qui utilise les mêmes capacité du noyau que Docker vise plutôt à créer des machines virtuelles légères au sens fonctionnel (avec un noyau partagé). Cette vue est concurrente à la virtualisation matérielle déjà supportée par des projets comme Xen, KVM ou VirtualBox.

On pourrait illustrer cette technologie avec LXC (libvirt) ou OpenVZ (Proxmox VE) mais Docker connait actuellement un essor qui vise à construire une solution complète, sécurisée et évolutive, soit un véritable écosystème pour la mise à disposition d'applications à partir d'éléments natifs du noyau Linux. L'objectif n'étant pas de fournir des VM au sens propre. On sera donc attentif à distinguer les concepts de machines virtuelles et de container.

D'autre part, les deux types de virtualisation "hardware" et "software" peuvent aussi être complémentaires. Combinée aux technologies de virtualisation matérielle, la virtualisation logicielle Docker complète les infrastructures de l'informatique en nuage (cloud) en répondant à ses besoins notamment en élasticité, en gain de performances, en facilité de gestion, etc.

1.1. Docker présentation

  • Projet open source écrit en GOlang
  • Automatiser le déploiement d’applications à l’intérieur de containers logiciels.
  • La technologie est portée par la virtualisation des espaces nommés du noyau Linux.
  • Très forte croissance de développement communautaire depuis sa reprise en 2014.
  • Docker-engine est le projet qui permet de créer des containers.

1.2. Container

"A container is a self contained execution environment that shares the kernel of the host system and which is (optionally) isolated from other containers in the system." (https://github.com/docker/libcontainer)

Un container est un environnement d'exécution complet :

  • qui partage le noyau du système hôte
  • et qui est éventuellement isolé des autres processus du système.

1.3. Docker objectifs

Les objectifs de docker se résument dans son slogan :

Build, Ship and Run

Any App, Anywhere

Soit :

  • Construire et partager efficacement des images de logiciels et d’applications.
  • La mise en production de ces logiciels est exécutée sous forme de containers (environnement virtuel, VE) totalement ou partiellement isolés selon les besoins.
  • Sur n’importe quelle plateforme, n’importe où.

1.4. Modèles traditionnels, hyperviseur et container

Docker se positionne dans un de ces trois modèles de virtualisation :

  • Modèle traditionnel : 1 PM = HW/OS + bin/libs/app
  • Modèle hyperviseur (Hardware) : 1 VM = OS guest + bin/libs/app
  • Modèle container (Software) : 1 VE = bin/libs/app
Modèles de virtualisation
Figure 18 : Modèles de virtualisation

1.5. Isolation logicielle

Contrairement à la virtualisation hyperviseur type 2 qui supporte les applications des machines virtuelles avec leur OS et leurs librairies, docker fournit un niveau supplémentaire d’abstraction et d’automation dans le cadre de la virtualisation légère OS. Des containers indépendants fonctionnent comme une seule instance Linux, évitant ainsi la surcharge de démarrage et d’utilisation une machine virtuelle.

Les propriétés d’isolation du noyau sont assurées par :

  • Les namespaces (espaces nommés) du noyau Linux isolent complètement une application du point de son environnement d’exécution : processus, réseau, ID des utilisateurs et montage de système de fichiers.
  • Les cgroups fournissent le support à l’isolation des ressources CPU, mémoire, stockage (block I/O) et réseau. C'est aussi via les cgroups que l'on attribue les ressources RAM/CPU aux containers.
  • Docker inclut la librairie libcontainer comme référence d’implémentation des containers (structure/fonctionnement). Il est construit autour de libvirt, LXC et systemd-nspawn.

1.6. Virtualisation type 1 et containerisation

On peut combiner les deux modèles en profitant des avantages de gestion, de performance et d'évolutivité liés à chacun :

  • un ou des containers enveloppés dans une VM
  • une VM enveloppée dans un container

Source : https://mainframedebate.com/2015/03/20/virtualization-vs-containerization/

Un ou des containers dans une machine virtuelle (VM).

On retrouve ici plusieurs couches :

  • Une couche Applications (Containers, services)
  • Une couche Machines (Machines virtuelles, OS, noyau)
  • Une couche Matériels (Hyperviseur, Ressources de calcul, de stockage et réseau)
Un ou des containers dans une machine virtuelle (VM)
Figure 19 : Un ou des containers dans une machine virtuelle (VM)

Deux exemples d'intégrations :

Une machine virtuelle dans un container

Ce modèle se propose d'exécuter une instance VM dans un container.

Libvirtd dans un container :

1.7. Ecosystème Docker

  • Registry : dépôt d'images.
  • Compose : outil de composition.
  • Swarm : cluster.
  • Shipyard : web UI/API.
  • Docker Machine : outil multi-os pour déployer des containers localement, chez des fournisseurs de services.

2. Concepts internes Docker

  • Images : contenu statique de l’application (FS RO)
  • Containers : image exécutée (FS RW)
  • Links : permet la communication entre containers
  • Volumes : permet de séparer l’application elle-même (éphémère, volatile) des données (persistantes, locale, distantes, partagées ou non).
  • Index : contient les données utilisateurs, mots de passe, tags
  • Registry : sert les images en faisant référence à un index
  • Repository : endroit de stockage des images
  • Dockerfile : déclaration des actions pour créer (build) une image

2.1. Virtualisation par container

Virtualisation par container
Figure 20 : Virtualisation par container

Container = Exécution RW d’une image dans un espace isolé du noyau.

2.2. Build Ship Run

Build Ship Run
Figure 21 : Build Ship Run

Image = modèle RO, contenu statique d’une application (fichiers)

2.3. Images

Image Docker
Figure 22 : Image Docker

Une image est un modèle statique d’un système de fichiers en mode Read-Only (RO). Il peut s’agir du rootfs Debian ou de n’importe quelle distribution. On travaille en général à partir d’une image de base.

2.4. Images en couches UFS

Images en couches
Figure 23 : Images en couches

Les modifications sur les images sont enregistrées en couches de FS qui peuvent fusionner. Le système utilisé est Union File System. Il crée une relation de parenté entre les images

2.5. Opérations de création les images

Opérations sur les images
Figure 24 : Opérations sur les images
  • Images (distributions) de base déjà prêtes
  • Récupération d’images
  • Construction d’images
  • Diffusion d’images

2.6. Images et containers

Images et containers
Figure 25 : Images et containers

Les containers sont les exécutions en mode RW de ces images en tant qu’environnements virtuels.

2.7. Containers

Un container est un espace utilisateur du noyau isolé par des namespaces :

  • pid namespace: isolation du processus (PID: Process ID)
  • net namespace: gestion des interfaces réseau (NET: Networking)
  • ipc namespace: gestion des ressources IPC (IPC: InterProcess Communication)
  • mnt namespace: gestion des points de montage (MNT: Mount)
  • uts namespace: isolation du noyau et des identifiants de version (UTS: Unix Timesharing System)
  • user namespace : UUID * Les paramètres cgroups permettent notamment de définir des profils de limites de partages de ressources.

2.8. Gestion des applications

Le processus de conception des images permet de créer, distribuer et gérer des applications de manière aisée, rapide, évolutive, sur n’importe quelle plateforme.

La technologie épargne le redémarrage d’un OS invité qui supporte l’application. On évite de la sorte des pertes en surcharge et on obtient des gains en performance.

Toutefois, l’absence d’OS invité implique aussi que les containers soient éphémères et jetables. Pour garder les données utilisateurs, il faut utiliser des Volumes qui permettent au container d’écrire sur un FS natif du système.

2.9. Résumé processus de déploiement

  1. Conception d'images (Dockerfile)
  2. Construction des images (Build)
  3. Mise à disposition sur un server d'images (Push vers Registry)
  4. Déploiement des images sur les machines Docker (Pull vers Docker Hosts)
  5. Configuration des containers (calcul, stockage et réseau)
  6. Exécution des images (démarrage des containers)

Ce processus peut être réalisé manuellement ou de manière entièrement automatisée.

3. Installation

3.1. Dépendances

  • Une plateforme physique ARM ou Intel/AMD
  • Un accès à l’Internet
  • Des projets et de la créativité

Logiciels pré-requis :

  • Version du noyau 3.8
  • Architecture 64 bits
  • Du stockage pour les images et les containers
  • De la swap quand la RAM est faible

Docker est un exécutable contrôlé par un unit systemd

3.2. Installation et configuration

Pour Centos 7 : https://docs.docker.com/engine/installation/linux/centos/

~~ Fedora/Centos, Debian/Ubuntu/Linux Mint, Gentoo :

wget -qO- https://get.docker.com/ | sh

~~

Arch Linux :

pacman -S docker

~~Pour éviter d'être déçu, il est conseillé de déployer la dernière version du logiciel : wget https://get.docker.com/builds/Linux/x86_64/docker-latest -O /usr/bin/docker . ~~

Sous Centos/Fedora/RHEL, chaque démarrage de Firewalld vide la configuration iptables de Docker. Il faut donc redémarrer Docker après celui de Firewalld. Une alternative consiste à ne pas utiliser Firewalld pour gérer le pare-feu.

Le logiciel arrive avec un démon et un client. Par défaut, le service Docker (OPTIONS='-H tcp://0.0.0.0:2375') n’est pas exposé en public; il est conseillé d’activer SSL dans le cas contraire. Sous Centos 7, on peut configurer Docker dans les fichiers suivants :

  • /etc/sysconfig/docker
  • /etc/sysconfig/docker-network
  • /etc/sysconfig/docker-storage
systemctl enable docker
systemctl start docker

Pour la suite, on peut se référer au tutoriel ou à la documentation officielle de Docker.

3.3. Architecture

docker version

Client version: 1.6.0
Client API version: 1.18
Go version (client): go1.4.2
Git commit (client): 4749651
OS/Arch (client): linux/amd64
Server version: 1.6.0
Server API version: 1.18
Go version (server): go1.4.2
Git commit (server): 4749651
OS/Arch (server): linux/amd64
# uname -r

3.16.0-4-amd64
docker info

4. Opérations de base

4.1. Recherche d'images

docker search --help

DockerHub

4.2. Récupération d’images

Récupération d’images :

docker pull [OPTIONS] NAME[:TAG]
docker pull ubuntu

En pratique pour récupérer plusieurs images de base :

for dist in centos fedora ubuntu debian tianon/gentoo-stage3 base/archlinux; do docker pull $dist; done

4.3. Inventaire des images

Liste des images :

docker images

REPOSITORY             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
centos                 latest              8efe422e6104        3 days ago          224 MB
centos                 7                   8efe422e6104        3 days ago          224 MB
centos                 centos7             8efe422e6104        3 days ago          224 MB
debian                 wheezy              479215127fa7        7 days ago          85.1 MB
debian                 7                   479215127fa7        7 days ago          85.1 MB
debian                 7.7                 479215127fa7        7 days ago          85.1 MB
debian                 latest              479215127fa7        7 days ago          85.1 MB
ubuntu                 14.04.1             8eaa4ff06b53        7 days ago          192.7 MB
ubuntu                 latest              8eaa4ff06b53        7 days ago          192.7 MB
ubuntu                 trusty              8eaa4ff06b53        7 days ago          192.7 MB
ubuntu                 14.04               8eaa4ff06b53        7 days ago          192.7 MB
fedora                 21                  834629358fe2        7 days ago          250.2 MB
fedora                 latest              834629358fe2        7 days ago          250.2 MB
<none>                 <none>              acc1b23376ec        7 days ago          224 MB
base/archlinux         latest              dce0559daa1b        5 months ago        282.9 MB
tianon/gentoo-stage3   latest              b5f45754f671        6 months ago        526.4 MB
markc/openwrt          latest              c234df31e584        10 months ago       8.274 MB

4.4. Lancer un container

La commande docker run permet lancer un container à partir d'une image. Elle est suivie :

  • d'une ou plusieurs options
  • du nom d'une image
  • d'une commande
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Si l'image invoquée n'est pas présente au moment de la création du container, elle sera téléchargée à partir de DockerHub.

Pour lancer un container en mode détaché (lancé en arrière-plan) avec un support console :

docker run -tid ubuntu bash
0508427ce94e0e08b3e09385625fa76ff0555aa84c86bf3884d1a455345c68bf
# docker ps
CONTAINER ID 0508427ce94e
IMAGE ubuntu:14.04
COMMAND "bash"
CREATED 12 seconds ago
STATUS Up 9 seconds
PORTS
NAMES clever_morse

On peut aussi lancer un container éphémère qui se contente d'exécuter une commande :

docker run centos echo "Hello World"

Dans ce cas, le container ne dure que le temps de l'exécution de la commande dans un environnement isolé. En conséquence, elle disparaît de la sortie de la commande docker ps. Pour voir, tous les containers exécutés et en cours d'exécution, il faut utiliser la commande :

docker ps -a

4.5. Attacher un container

On peut entrer dans la console d’un container :

docker attach CONTAINER

Un container dispose d'une console accessible si un shell est exécuté dans celui-ci :

# docker attach clever_morse
root@0508427ce94e:/#

Sortir d’un container :

CTRL p CTRL q

Sortir d’un container et le terminer :

CTRL c, CTRL d, exit

4.6. Informations sur un container

docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE…]
docker inspect clever_morse | grep "IPAddress"
        "IPAddress": "172.17.0.2",

4.7. Manipuler les containers

Manipuler les containers :

docker start CONTAINER
docker stop CONTAINER
docker restart CONTAINER

4.8. Gestion des containers

Visualiser les logs du container :

docker logs CONTAINER

Tue un container en lui envoyant un SIGKILL :

docker kill CONTAINER
  • Efface un container du disque :
docker rm CONTAINER
  • Met tous les processus d'un container en pause d'exécution :
docker pause CONTAINER
docker unpause CONTAINER
  • Crée un nouveau container sans l'exécuter :
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
  • Pour copier des fichiers d'un container vers l'hôte Docker :
docker cp CONTAINER:PATH HOSTPATH

Par exemple, pour copier le fichier d'un container sur l'hôte :

docker cp clever_morse:/etc/passwd .
  • Il peut être utile d'exécuter une commande dans un container en cours d'exécution, pour exécuter un shell par exemple :
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

Si on dispose déjà d'une console sur l'hôte Docker, il peut sembler inutile d'ajouter un service SSH dans un container.

  • Supprimer tous les containers stoppés :
docker rm $(docker ps -a -q)

5. Administration de containers et d'images

5.1. Création d’une image à partir d'un container existant

Cet exemple illustre la création d'un serveur Web Apache comme container.

  • Lancement d'un container de base dev1 en y installant le logiciel :
docker run --name dev1 centos yum install httpd -y
  • Conversion du container dev1en image moi/httpd:
docker commit -a "moi" -m "http service" dev1 moi/httpd

On recommande la construction d'une image avec un minimum de couches.

5.2. Suppression d'une image

  • Suppression d’une image
docker rmi ubuntu

5.3. Ports TCP/IP exposés

Pour lancer apache dans un container avec l'image créée plus haut et pour rendre le service disponible sur l'hôte Docker sur le port TCP 8080, on peut tenter la procédure suivante dans le but de comprendre le fonctionnement d'un container. Cette approche n'est jamais recommandée.

Lancer un container qui expose 8080:80

docker run -ti --name dev2 -p 8080:80 moi/httpd bash

Créer un fichier /start.sh à la racine du container

cat  << EOF > /start.sh
#!/bin/bash
rm -rf /run/httpd/* /tmp/httpd
/usr/sbin/apachectl -D FOREGROUND
EOF
chmod +x start.sh

Sortie de la console

CTRL-p CTRL-q

A titre d'illustration, on peut entrer à nouveau dans le container :

docker attach dev2

Exécuter le script de démarrage

docker exec -d dev2 /start.sh

Vérifications

docker ps

Apache rend le service sur le port TCP 80 qui est devient accessible sur TCP 8080 du docker-engine. On "expose" le port d'un container sur un port de l'hôte.

On peut examiner la page par défaut httpd sur l'hôte (docker-engine) TCP8080 :

curl http://127.0.0.1:8080/

Arrêter le container et en faire une nouvelle image

docker stop dev2
docker commit -a "moi" -m "http service" dev2 moi/httpd

Tester la nouvelle image sur un container

docker run -d --name dev3 -p 8080:80 moi/httpd /start.sh
docker ps
curl http://127.0.0.1:8080/

5.4. Réseau

# docker network ls
NETWORK ID          NAME                DRIVER
d71611ff46d6        none                null
cb8b4e72ee3c        host                host
ffea9fae78ff        bridge              bridge
# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "ffea9fae78ff16e1b4f64edaeab8311cfc0f740c5a9117b6fb5a732a275293df",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.0.0/16"
                }
            ]
        },
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        }
    }
]

5.5. Volumes (data volumes)

Un volume (data volume) est un répertoire spécial au sein d'un ou plusieurs containers qui outre-passe UFS (Union File System).

  • Un volume est initialisé au démarrage d'un container. Si le container sert de modèle à une image, les données du volume sont copiées dans l'image.
  • Un volume peut être partagé et réutilisé par plusieurs containers.
  • Les changements dans un volume sont réalisés directement.
  • Les données d'un volume persistent même si le container est effacé.

Monter un volume

  • Monter un volume sur /var/ww/html
# docker run -it --name dev4 -p 8080:80 -v /var/www/html moi/httpd /start.sh &
  • Vérifier l'emplacement du montage
# docker inspect dev4 | grep Source
            "Source": "/var/lib/docker/volumes/91c7e31a3b762d6264ce1a1f5dd1dc2a4207f1902dd9a4325e75f6ae66b73f78/_data",
  • Modification du fichier /var/ww/html/index.hml dans le container
# echo "test http dev4" > /var/lib/docker/volumes/91c7e31a3b762d6264ce1a1f5dd1dc2a4207f1902dd9a4325e75f6ae66b73f78/_data/index.html
  • Redémarrer le container et vérifier le fichier servi
# docker start dev4
# curl 127.0.0.1:8080
test http dev4

Monter un répertoire de l'hôte dans un ou plusieurs containers

  • Création du répertoire source et du fichier
# mkdir -p /opt/dev5/html
# echo "test http dev5" > /opt/dev5/html/index.html
  • Démarrage du container et vérification
#docker run -it --name dev5 -p 8080:80 -v /opt/dev5/html:/var/www/html moi/httpd /start.sh &
#curl 127.0.0.1:8080
test http dev5
#echo "test http dev5 v2" > /opt/dev5/html/index.html
# curl 127.0.0.1:8080
test http dev5 v2
 #docker run -it --name dev5bis -p 8081:80 -v /opt/dev5/html:/var/www/html moi/httpd /start.sh
# curl 127.0.0.1:8081
test http dev5 v2
  • Partage de volume à partir d'un containe avec --volumes-from
# docker run -it --volumes-from dev5 --name dev5ter -p 8082:80 moi/httpd /start.sh &
# curl 127.0.0.1:8082
test http dev5 v2

https://docs.docker.com/userguide/dockervolumes/

drivers

  • local
  • nfs
  • lvm
  • iscsi

Exercice à réaliser : https://access.redhat.com/documentation/en/red-hat-enterprise-linux-atomic-host/version-7/getting-started-guide/#install_and_deploy_an_apache_web_server_container

Gestion CPU/RAM

Réseau nsenter

6. Construction d'une image à partir d'un Dockerfile

Dossier avec un fichier Dockerfile ainsi que tous les fichiers à copier dans le container (scripts, paquets, etc.).

Lancer la commande docker build

Quelques images à construire soi-même :

  1. https://github.com/CentOS/CentOS-Dockerfiles
  2. Stack Lamp : https://github.com/tutumcloud/tutum-docker-lamp
  3. Wordpress : https://github.com/tutumcloud/tutum-docker-wordpress
  4. HAProxy : https://github.com/tutumcloud/tutum-docker-clusterproxy
  5. shipyard : https://github.com/shipyard/shipyard
  6. https://github.com/jfrazelle/dockerfiles

7. Divers

push

backup

restore

Ecosystème Docker

Docker registry

Docker Compose

Docker Swarm

Docker Machine

Builds

Docker MySQL

https://mysqlrelease.com/2015/05/mysql-in-dockerland/

KVM dans un container Docker

https://github.com/dhiltgen/machine/commit/e5d159c17fc9ef497a1933c83b69d2b8d1e6f168

cf. point "1.5. Virtualisation type 1 et containerisation"

Docker quick start

Quelques références LXC

Deux images à prendre directement

Tips