Conteneurs avec les namespaces sous Linux

Ce TD est à réaliser dans une machine virtuelle Ubuntu avec le démon Docker installé et activé. Avec les machines vagrant :

$ vagrant up ubuntu
$ vagrant ssh ubuntu

Objectifs

  • Découvrir le principe des conteneurs à l’aide de Docker

Introduction aux conteneurs avec Docker

Vérifiez que le démon Docker est bien démarré :

$ sudo systemctl status docker

Lancement d’un conteneur interactif

Pour récupérer directement du registre de conteneurs public proposé par Docker (DockerHub) l’image officielle de conteneur Ubuntu, utilisez :

$ sudo docker pull ubuntu

Vérifiez qu’elle a bien été importée avec la commande :

$ sudo docker images

Par défaut, la dernière version publiée de l’image est téléchargée. Lancez un shell interactif dans un conteneur en utilisant cette image :

$ sudo docker run -it ubuntu bash

Essayez les commandes suivantes : ps aux, id, findmnt, lsns et comparez le résultat obtenu à l’intérieur et à l’extérieur du conteneur.

Quitter le conteneur avant de passer à la suite.

Construction d’un conteneur

Nous allons créer un conteneur qui contiendra un serveur HTTP hébergeant un site Web statique.

Pour commencer, voici un programme en Go qui mets à disposition sur le réseau le contenu du dossier www en HTTP sur le port 8000 :

app.go (télécharger) :

package main

import (
	"log"
	"net/http"
)

func main() {
	fs := http.FileServer(http.Dir("www"))
	http.Handle("/", fs)

	log.Println("Listening...")
	http.ListenAndServe(":8000", nil)
}

Créez un site Web minimal :

$ mkdir www
$ echo "Hello world" > www/index.html

Compilez et testez le bon fonctionnement du programme avec les commandes :

$ go build -o app app.go
$ ./app

Testez votre application avec curl (ou avec un navigateur web) :

$ curl http://localhost:8000

Maintenant que notre application est prête, nous pouvons la mettre dans un conteneur. Pour que notre application puisse fonctionner, nous allons lister les bibliothèques dont elle a besoin pour les inclure ensuite dans le conteneur:

$ ldd app
    linux-vdso.so.1 (0x00007ffea02a0000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f4f9e080000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f4f9e275000)

La librairie linux-vdso.so.1 “n’hexiste pas” car elle est fournie directement par le noyau aux processus (voir vdso(7)). Nous récupérons les autres dépendances:

$ cp /<chemin-complet-bilbiothèques> .

Pour décrire le contenu d’une image de conteneur avec Docker, nous allons utiliser un Dockerfile. Voici un Dockerfile qui crée un conteneur avec notre application et le site web :

Dockerfile (télécharger) :

# Partir d'une image vide
FROM scratch

# Copier les bibliothèques et le binaire de notre application
COPY ld-linux-x86-64.so.2 /<chemin-complet-bibliothèque>
COPY libc.so.6 /<chemin-complet-bibliothèque>
COPY app app

# Copier le répertoire www avec la page web
COPY www www

# L'application utilise le port 8000
EXPOSE 8000

# La commande à lancer pour démarrer ce conteneur
CMD ["./app"]

Créer ensuite l’image du conteneur à partir du Dockerfile :

$ sudo docker build --tag app .

Lancez le conteneur :

$ sudo docker run -ti app

Pour vérifier que nous avons bien accés à notre application, listez tous les conteneurs en cours d’exécution :

$ sudo docker ps
CONTAINER ID  IMAGE  COMMAND  ...  PORTS     NAMES
79c533003fe8  app    "./app"  ...  8000/tcp  loving_goldwasser

Récupérez l’adresse IP du conteneur qui nous intéresse à l’aide de son container id :

$ sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container id>
172.17.0.2

Récupérez la page Web avec curl (ou un navigateur web) :

$ curl 172.17.0.2:8000

Références