Passer

Comment installer containerd localement  et construire de jolies images multi-plateformes ?

Pourquoi ?

J’ai rédigé un petit article intitulé « Comment installer Podman localement avec Vagrant » pour remplacer l’installation de Docker Desktop. Dans cet article, j’ai indiqué que j’allais effectuer le même test, mais avec Containerd. Ainsi, nous allons suivre les mêmes étapes que dans l’article précédent, mais avec Containerd en adaptant légèrement le processus pour découvrir de nouvelles choses. Au programme : Vagrant, Ansible, Containerd et une petite image Docker pour les architectures amd64 et arm64 ?.

La stack technologique

Je ne vais pas réexpliquer les technologies présentées dans l’article précédent : VirtualBox, Vagrant et Ansible, qui sont utilisées de la même manière.

Containerd est un outil permettant d’exécuter des conteneurs compatibles OCI. Nous allons donc avoir une machine virtuelle sous VirtualBox avec Containerd installé dessus, ainsi qu’une commande à distance qui nous permettra de gérer Containerd depuis notre machine cliente. Tout cela sera construit grâce à Vagrant et Ansible ?.

Les prérequis sont identiques à ceux mentionnés dans l’article précédent, donc rien à faire de plus (ou suivre les mêmes étapes !).

L’infrastructure containerd


tdesa ~\Repositories\thibault.desaules@devoteam.com
❯ Set-Location -Path « C:\Users\tdesa\Repositories\thibault.desaules@devoteam.com »

tdesa ~\Repositories\thibault.desaules@devoteam.com
❯ git clone https://gitlab.com/thibault.desaules/dear-vagrant-please-build-my-containerd-local-environment.git

Cloning into ‘dear-vagrant-please-build-my-containerd-local-environment’…
[…]

tdesa ~\Repositories\thibault.desaules@devoteam.com
❯ Set-Location -Path « .\dear-vagrant-please-build-my-containerd-local-environment »

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ vagrant up
Bringing machine ‘containerd’ up with ‘virtualbox’ provider…
[…]

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ vagrant status
Current machine states:

containerd                running (virtualbox)
[…]

Ensuite, nous allons nous connecter à la machine créée avec Vagrant pour vérifier que Containerd et Nerdctl sont correctement installés, et pour lancer un petit conteneur de test.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ vagrant ssh

vagrant@containerd:~$ systemctl status containerd
● containerd.service - Containerd Container Service
     Loaded: loaded (/etc/systemd/system/containerd.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2023-04-28 18:50:55 CEST; 34s ago
       Docs: https://containerd.io
   Main PID: 706 (containerd)
      Tasks: 9
     Memory: 57.2M
        CPU: 1.132s
     CGroup: /system.slice/containerd.service
             └─706 /usr/local/bin/containerd

vagrant@containerd:~$ nerdctl --version
nerdctl version 1.3.0

vagrant@containerd:~$ sudo nerdctl run hello-world
docker.io/library/hello-world:latest:
[...]                                             
Hello from Docker!

Note 1

Si vous voulez voir les étapes d’installation de Containerd, de Nerdctl (la CLI pour administrer Containerd), de Buildkit et de Binfmt (émulateur d’architecture pour Docker), ils sont dans le playbook utilisé, vous pouvez le consulter. Cela vous permettra de posséder tous les outils nécessaires pour générer des images Docker multi-architecture.

Nerdctl

Première mauvaise nouvelle… nerdctl n’a pas la capacité de gérer containerd à distance. Nous allons essayer de le tromper ? pour voir comment cela se passe. Pour cela, il est possible d’utiliser SSH pour lancer des commandes à distance et PowerShell pour masquer cela. 

Nous allons récupérer notre fichier de profil PowerShell pour y ajouter la fonction avec la commande et l’alias souhaité.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ $profile
C:\Users\tdesa\OneDrive\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ Add-Content -Path "C:\Users\tdesa\OneDrive\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" -Value @'

function Invoke-NerdCtl {
  $repository_location = ("$(Get-Location)").Replace("$Home","").Replace("\","/")
  $params = [system.String]::Join(" ", $args)
  ssh -i "C:\Users\tdesa\Repositories\tdesaules@outlook.com\vagrant-infra\containerd\ansible\containerd\files\containerd" vagrant@10.10.0.10 -t "cd ~$repository_location && sudo nerdctl $params"
}
New-Alias -Name "nerdctl" -Value "Invoke-NerdCtl"
'@

Nous pouvons maintenant effectuer un petit test en utilisant notre alias précédemment créé.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl --version
The authenticity of host '10.10.0.10 (10.10.0.10)' can't be established.
ED25519 key fingerprint is SHA256:pnHxd1efaWyTkYAKLRaGO02YMUpPSwHl7IL/7AaFaL8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.0.10' (ED25519) to the list of known hosts.
nerdctl version 1.3.0
Connection to 10.10.0.10 closed.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.
[...]

Cela fonctionne assez bien pour une utilisation classique ?

Note 1

La fonction « nerdctl » créée en PowerShell est assez basique : elle va récupérer notre chemin actuel, le transformer pour correspondre au répertoire monté via Vagrant qui contient nos dépôts locaux (vous pouvez consulter le fichier Vagrantfile avec l’entrée « containerd.vm.synced_folder »). Par conséquent, petite limitation, la commande ne fonctionnera que dans le répertoire racine et les sous-répertoires de nos dépôts (mais c’est tout ce dont j’ai besoin pour accéder aux sources de mes applications). Ensuite, nous invoquons SSH avec la clé privée définie dans Vagrant via Ansible, nous nous positionnons sur le chemin défini précédemment, et nous pouvons lancer nerdctl via SSH en lui passant tous les paramètres donnés à distance.

Construire une image

Essayons de construire une image Docker ultra-simple (voir le Dockerfile).

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl build -t my-hello-world .
[+] Building 22.1s (5/5) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                                        [...]
unpacking docker.io/library/my-hello-world:latest (sha256:31458ebaff922e8cf1d4df620887c499372cc5fcca9f29f80cc373b4642db118)...
Loaded image: docker.io/library/my-hello-world:latest
Connection to 10.10.0.10 closed.

Et elle fonctionne plutôt bien, il faut le reconnaître ?? L’informatique, c’est vraiment cool !

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl images --format=json | ConvertFrom-Json | Select-Object ID,Name,Platform
Connection to 10.10.0.10 closed.

ID           Name                                     Platform
--           ----                                     --------
4e83453afed1 docker.io/library/hello-world:latest     linux/amd64
[...]

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run my-hello-world
Hello Devoteam :)
Connection to 10.10.0.10 closed.

Nous pouvons vérifier qu’il est possible d’exécuter un conteneur Linux amd64 et d’émuler de l’arm64 sans aucun problème.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run --privileged --rm tonistiigi/binfmt --install all
installing: s390x OK
installing: riscv64 OK
installing: mips64le OK
installing: arm64 OK
installing: arm OK
installing: ppc64le OK
installing: mips64 OK
{
  "supported": [
    "linux/amd64",
    "linux/arm64",
    "linux/riscv64",
    "linux/ppc64le",
    "linux/s390x",
    "linux/386",
    "linux/mips64le",
    "linux/mips64",
    "linux/arm/v7",
    "linux/arm/v6"
  ],
  "emulators": [
    "qemu-aarch64",
    "qemu-arm",
    "qemu-mips64",
    "qemu-mips64el",
    "qemu-ppc64le",
    "qemu-riscv64",
    "qemu-s390x"
  ]
}

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl pull --platform="arm64,amd64" ubuntu:22.04
docker.io/library/ubuntu:22.04:                                                   
[...]
Connection to 10.10.0.10 closed.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl images --format=json | ConvertFrom-Json | Select-Object ID,Name,Platform
Connection to 10.10.0.10 closed.

ID           Name                                     Platform
--           ----                                     --------
[...]
67211c14fa74 docker.io/library/ubuntu:22.04           linux/amd64
67211c14fa74 docker.io/library/ubuntu:22.04           linux/arm64/v8
67211c14fa74 docker.io/library/ubuntu:latest          linux/amd64
67211c14fa74 docker.io/library/ubuntu:latest          linux/arm64/v8
66e11bea77a5 docker.io/tonistiigi/binfmt:latest       linux/amd64
[...]

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run --rm --platform=amd64 ubuntu uname -a
Linux 23a5156693c0 5.15.0-71-generic #78-Ubuntu SMP Tue Apr 18 09:00:29 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Connection to 10.10.0.10 closed.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run --rm --platform="arm64" ubuntu uname -a
Linux 0adc8e038d46 5.15.0-71-generic #78-Ubuntu SMP Tue Apr 18 09:00:29 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux
Connection to 10.10.0.10 closed.

Allons un peu plus loin et essayons de construire cette même image mais avec une architecture multiple, amd64 et arm64.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl build --platform="amd64,arm64" -t my-hello-world2 .
[+] Building 17.0s (7/7) FINISHED
[...]
Loaded image: docker.io/library/my-hello-world2:latest
Connection to 10.10.0.10 closed.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl images --format=json | ConvertFrom-Json | Select-Object ID,Name,Platform
Connection to 10.10.0.10 closed.

ID           Name                                     Platform
--           ----                                     --------
[...]
7665c2ab4ab2 docker.io/library/my-hello-world2:latest linux/amd64
7665c2ab4ab2 docker.io/library/my-hello-world2:latest linux/arm64
[...]

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run --rm --platform=arm64 my-hello-world2
Hello Devoteam :)
Connection to 10.10.0.10 closed.

Là, on touche un petit quelque chose, non ? ?? Ou est-ce juste mon côté geek ?

Note 1

Dans le monde professionnel, compte tenu des adaptations à apporter pour faire tourner « nativement » Containerd sur un poste Windows 10 (avec une vision « dev »), j’aurais tendance à orienter mon équipe vers des solutions telles que Docker Desktop, Podman Desktop ou encore Rancher Desktop. En natif Linux, pourquoi pas, cela fonctionne bien.

Nerdctl compose

Il est temps de construire une petite application. 

Pour cela, nous allons utiliser une API et une interface Web mises à disposition par HashiCorp dans le cadre d’une démo d’un service mesh utilisant Consul (https://github.com/hashicorp/demo-consul-101/). Nous utiliserons uniquement l’application de base avec une API qui compte les appels effectués et les affiche via un tableau de bord. 

J’ai choisi cette application car les packages des deux services sont compilés en amd64 et en arm64 et sont disponibles sur Git ?. 

Nous allons commencer par créer les images associées à nos deux services (vous pouvez voir ce qui est fait dans les Dockerfiles, nous utiliserons un « builder » pour télécharger l’application pour la bonne architecture et la copier dans notre image finale).

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl build --platform="amd64,arm64" -t my-hello-world2 .
[...]

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run --privileged --rm tonistiigi/binfmt --install all
[...]

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl build --platform="amd64,arm64" -t my-counting counting
[...]

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl build --platform="amd64,arm64" -t my-dashboard dashboard
[...] 

Nous devrions maintenant avoir nos images pour les deux architectures ciblées. 

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl images --format=json | ConvertFrom-Json | Select-Object ID,Name,Platform
Connection to 10.10.0.10 closed.

ID           Name                                     Platform
--           ----                                     --------
[...]
4ff53dd91f72 docker.io/library/my-counting:latest     linux/amd64
4ff53dd91f72 docker.io/library/my-counting:latest     linux/arm64
8e8b9b7a5cf1 docker.io/library/my-dashboard:latest    linux/amd64
8e8b9b7a5cf1 docker.io/library/my-dashboard:latest    linux/arm64
[...]  

Nous pourrions lancer ces deux images comme nous l’avons fait pour les images précédentes avec ces commandes dans deux terminaux.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run --rm --platform=arm64 -p 1081:1081 my-counting
Serving at http://localhost:1081
(Pass as PORT environment variable)

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl run --rm --platform=arm64 -p 1080:1080 my-dashboard
Starting server on http://0.0.0.0:1080
(Pass as PORT environment variable)
Using counting service at http://10.10.0.10:1081
(Pass as COUNTING_SERVICE_URL environment variable)
Starting websocket server... 

Cependant, je vous encourage à regarder le fichier « docker-compose.yml » et à tester la commande « compose » fournie avec Nerdctl.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl compose up
INFO[0000] Ensuring image my-counting
INFO[0000] Ensuring image my-dashboard
INFO[0000] Re-creating container my-counting
INFO[0001] Re-creating container my-dashboard
INFO[0002] Attaching to logs
my-dashboard |Starting server on http://0.0.0.0:1080
my-dashboard |(Pass as PORT environment variable)
my-dashboard |Using counting service at http://10.10.0.10:1081
my-dashboard |(Pass as COUNTING_SERVICE_URL environment variable)
my-dashboard |Starting websocket server...
my-counting  |Serving at http://localhost:1081
my-counting  |(Pass as PORT environment variable)

Il ne reste plus qu’à tester l’API et l’interface utilisateur Web et à effectuer plusieurs appels à celles-ci.

tdesa dear-vagrant-please-build-my-containerd-local-environment on main
❯ nerdctl compose up
INFO[0000] Ensuring image my-counting
INFO[0000] Ensuring image my-dashboard
INFO[0000] Re-creating container my-counting
INFO[0001] Re-creating container my-dashboard
INFO[0002] Attaching to logs
my-dashboard |Starting server on http://0.0.0.0:1080
my-dashboard |(Pass as PORT environment variable)
my-dashboard |Using counting service at http://10.10.0.10:1081
my-dashboard |(Pass as COUNTING_SERVICE_URL environment variable)
my-dashboard |Starting websocket server...
my-counting  |Serving at http://localhost:1081
my-counting  |(Pass as PORT environment variable)
my-dashboard |New client connected
my-dashboard |Fetched count 2
my-dashboard |Fetched count 1
my-dashboard |New client connected
[...]
my-dashboard |Fetched count 36
my-dashboard |Fetched count 37

Voilà ?.

En conclusion

Nous arrivons à la fin de cet article. 

Des informations supplémentaires sont disponibles dans les fichiers du dépôt, en particulier pour la partie vagrant, ansible ainsi que les fichiers Dockerfile et docker-compose.yml.

Nous avons vu comment utiliser containerd et sa ligne de commande nerdctl pour exécuter des conteneurs, construire des images pour amd64 et arm64 et lancer plusieurs conteneurs via nerdctl compose. 

Cool ?

Ressources

Containerd

Containerd Website : https://containerd.io/

Containerd Github : https://github.com/containerd/containerd

Nerdctl Github : https://github.com/containerd/nerdctl

Nerdctl Commands Refs : https://github.com/containerd/nerdctl/blob/main/docs/command-reference.md

Nerdctl Multi-Platform : https://github.com/containerd/nerdctl/blob/main/docs/multi-platform.md

Hashicorp demo-consul-101

Github : https://github.com/hashicorp/demo-consul-101

Docker Building Multi-Platform

Docs : https://docs.docker.com/build/building/multi-platform/

GitLab

Repo : https://gitlab.com/thibault.desaules/dear-vagrant-please-build-my-containerd-local-environment