Comme je m’intéresse à PostgreSql (“The World’s Most Advanced Open Source Relational Database”) et Docker, j’ai décidé d’installer Docker et l’image PostgreSql afin d’en cerner les avantages et inconvénients par rapport à la virtualisation classique.

Préparation

Comme d’habitude, il convient de mettre à jour Debian (ici en version 11) avant d’installer des paquets:

1
sudo apt-get update && sudo apt-get upgrade

Ensuite, il faut installer les paquets suivants (j’ai juste eu besoin de apt-transport-https, le reste est déjà installé sur ma version):

1
sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release

Installation de Docker

Ajout du repository

On commence par installer la clé PGP de Docker avec ces commandes:

1
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Puis on ajoute le repository Docker:

1
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Installation des paquets Docker

On fait une nouvelle mise à jour Debian afin de prendre en compte le repository puis on installe les paquets Docker:

1
2
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

Stockage des images et données

Avant d’aller plus loin, il faut savoir que les images Docker peuvent vite remplir le disque. Pour éviter que mon disque système déborde, j’ai choisi de déplacer les images dans ma partition /opt.

Pour cela, il faut d’ajouter ajouter le dossier /opt/docker_images puis il faut éditer le fichier /etc/docker/daemon.json et ajouter les lignes suivantes:

1
2
3
{
"data-root": "/opt/docker_images"
}

Contrôle de l’installation

Une fois l’installation terminée, on peut vérifier que Docker est prêt grâce aux commandes suivantes (réponses en bleu):

1
2
sudo systemctl is-enabled docker
enabled
1
2
sudo systemctl is-enabled containerd
enabled
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
systemctl status docker containerd
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2021-12-25 16:51:16 CET; 3min 48s ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 28277 (dockerd)
      Tasks: 13
     Memory: 36.0M
        CPU: 275ms
     CGroup: /system.slice/docker.service
             └─28277 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Dec 25 16:51:15 station.gtg dockerd[28277]: time="2021-12-25T16:51:15.913595169+01:00" level=info msg="scheme \"unix\" not registered, fallback to default scheme" module=grpc
Dec 25 16:51:15 station.gtg dockerd[28277]: time="2021-12-25T16:51:15.913612836+01:00" level=info msg="ccResolverWrapper: sending update to cc: {[{unix:///run/containerd/containerd.sock  <nil> 0 <nil>}] <ni>
Dec 25 16:51:15 station.gtg dockerd[28277]: time="2021-12-25T16:51:15.913624402+01:00" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc
Dec 25 16:51:16 station.gtg dockerd[28277]: time="2021-12-25T16:51:16.016000291+01:00" level=info msg="Loading containers: start."
Dec 25 16:51:16 station.gtg dockerd[28277]: time="2021-12-25T16:51:16.207380620+01:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used >
Dec 25 16:51:16 station.gtg dockerd[28277]: time="2021-12-25T16:51:16.279475675+01:00" level=info msg="Loading containers: done."
Dec 25 16:51:16 station.gtg dockerd[28277]: time="2021-12-25T16:51:16.301485806+01:00" level=info msg="Docker daemon" commit=459d0df graphdriver(s)=overlay2 version=20.10.12
Dec 25 16:51:16 station.gtg dockerd[28277]: time="2021-12-25T16:51:16.301591296+01:00" level=info msg="Daemon has completed initialization"
Dec 25 16:51:16 station.gtg systemd[1]: Started Docker Application Container Engine.
Dec 25 16:51:16 station.gtg dockerd[28277]: time="2021-12-25T16:51:16.351774256+01:00" level=info msg="API listen on /run/docker.sock"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
sudo systemctl status containerd
● containerd.service - containerd container runtime
     Loaded: loaded (/lib/systemd/system/containerd.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2021-12-25 16:51:14 CET; 6min ago
       Docs: https://containerd.io
   Main PID: 28192 (containerd)
      Tasks: 13
     Memory: 21.8M
        CPU: 252ms
     CGroup: /system.slice/containerd.service
             └─28192 /usr/bin/containerd

Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.783865144+01:00" level=info msg="loading plugin \"io.containerd.grpc.v1.namespaces\"..." type=io.containerd.grpc.v1
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.783876315+01:00" level=info msg="loading plugin \"io.containerd.internal.v1.opt\"..." type=io.containerd.internal.v1
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.784109298+01:00" level=info msg="loading plugin \"io.containerd.grpc.v1.snapshots\"..." type=io.containerd.grpc.v1
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.784128313+01:00" level=info msg="loading plugin \"io.containerd.grpc.v1.tasks\"..." type=io.containerd.grpc.v1
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.784142614+01:00" level=info msg="loading plugin \"io.containerd.grpc.v1.version\"..." type=io.containerd.grpc.v1
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.784155687+01:00" level=info msg="loading plugin \"io.containerd.grpc.v1.introspection\"..." type=io.containerd.grpc.v1
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.784347206+01:00" level=info msg=serving... address=/run/containerd/containerd.sock.ttrpc
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.784384609+01:00" level=info msg=serving... address=/run/containerd/containerd.sock
Dec 25 16:51:14 station.gtg containerd[28192]: time="2021-12-25T16:51:14.784422458+01:00" level=info msg="containerd successfully booted in 0.047712s"
Dec 25 16:51:14 station.gtg systemd[1]: Started containerd container runtime.

Ajout des droits utilisateurs

Par défaut, seul le root peut lancer Docker. Pour une question de facilité (démarrage à la demande) et de sécurité (on travaille le moins possible avec le compte root), il vaut mieux autoriser son compte (ou un autre) à lancer Docker. Cela se fait simplement avec la commande:

1
sudo usermod -aG docker <login>

Ensuite, en voulant tester Docker avec la commande docker run hello-world, j’ai reçu le message suivant:

1
got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/create?name=redis: dial unix /var/run/docker.sock: connect: permission denied

Pour corriger cela, il faut autoriser son compte (ou le même qu’à l’étape précédente) à écrire le fichier de lock avec la commande:

1
sudo setfacl --modify user:<login>:rw /var/run/docker.sock

A ce stade, Docker est prêt!

Création de l’image PostgreSql

Récupération de l’image

Il existe une image PostgreSql officielle pour Docker et il faut lancer la préparation avec la commande docker pull postgres.La réponse est la suivante:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Using default tag: latest
latest: Pulling from library/postgres
a2abf6c4d29d: Pull complete 
e1769f49f910: Pull complete 
33a59cfee47c: Pull complete 
461b2090c345: Pull complete 
8ed8ab6290ac: Pull complete 
495e42c822a0: Pull complete 
18e858c71c58: Pull complete 
594792c80d5f: Pull complete 
794976979956: Pull complete 
eb5e1a73c3ca: Pull complete 
6d6360292cba: Pull complete 
131e916e1a28: Pull complete 
757a73507e2e: Pull complete 
Digest: sha256:f329d076a8806c0ce014ce5e554ca70f4ae9407a16bb03baa7fef287ee6371f1
Status: Downloaded newer image for postgres:latest
docker.io/library/postgres:latest

Création d’un volume de stockage

Par défaut, Docker ne persiste pas le contenu des images et c’est un peu gênant pour une base de données de voir son contenu réinitialisé à chaque démarrage. Pour activer le stockage, il faut d’abord créer un volume dédié avec la commande suivante:

1
docker volume create pgdata

On peut vérifier que le volume est créé et quel dossier contient les fichiers qui vont être sauvés grâce à la commande:

1
docker volume inspect pgdata

On obtient une réponse au format JSON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[
    {
        "CreatedAt": "2022-01-22T16:58:42+01:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/opt/docker_images/volumes/pgdata/_data",
        "Name": "pgdata",
        "Options": {},
        "Scope": "local"
    }
]

En rouge, il s’agit du dossier qu’on a définit dans le fichier /etc/docker/daemon.json. En bleu, il s’agit du nom du volume.

Démarrage de l’image

Pour démarrer notre image PostgreSql, il suffit simplement d’exécuter la commande:

1
docker run -d --name=pgsql -p 5432:5432 --mount source=pgdata,target=/var/lib/postgresql/data -e POSTGRES_PASSWORD=<mot de passe> postgres

On trouve beaucoup (tous en fait) de tutoriels qui indiquent d’utiliser le paramètre “-v” pour désigner le volume à prendre en compte. Cela fonctionne uniquement si le container est en mode interactif. Dans mon cas, le container est lancé en daemon (paramètre “-d”) et il faut alors utiliser le paramètre “--mount” pour lier le volume au container.

Connexion au serveur PostgreSql

J’ai ajouté une connexion dans dBeaver (un des meilleurs clients SQL Open source) comme ceci:

PostgreSql: connexion avec dBeaver

PostgreSql: connexion avec dBeaver

Pour vérifier que Docker ne perd pas les modifications, je vais ajouter une table à la base avec cette requête:

1
2
3
CREATE TABLE public.test (
	id varchar(36) NULL
);

Contrôler la persistance du volume

Pour vérifier que le volume a bien enregistré les fichiers de PostgreSql, on va arrêter le container puis le relancer. Normalement on doit retrouver la table de test créée à l’étape précédente. On commence par trouver l’identifiant du container:

1
2
3
docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED          STATUS          PORTS                                       NAMES
a81ad52651f8   postgres   "docker-entrypoint.s…"   17 minutes ago   Up 17 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   pgsql

Puis on arrête le container avec la commande suivante:

1
docker container stop a81ad52651f8 && docker container rm a81ad52651f8

Et maintenant on relance notre image avec la même commande qu’au lancement initial:

1
docker run -d --name=pgsql -p 5432:5432 --mount source=pgdata,target=/var/lib/postgresql/data -e POSTGRES_PASSWORD=<mot de passe> postgres

Puis on se connecte au serveur PostgreSql avec dBeaver et magie! La table de test est présente.

Docker: la table est toujours présente

Docker: la table est toujours présente

Conclusion

L’installation de Docker ne pose aucune difficulté, l’ajout d’image est très simple. La gestion des images et containers est plutôt aisée. Le point fort de ce type de virtualisation est de ne pas avoir à installer un OS à chaque fois.