Aller au contenu
Conteneurs & Orchestration medium

nerdctl : CLI compatible Docker pour containerd

23 min de lecture

Logo nerdctl

nerdctl est une CLI pour containerd qui offre une compatibilité complète avec les commandes Docker. Vous pouvez exécuter des conteneurs, construire des images et utiliser Compose sans Docker, tout en bénéficiant de fonctionnalités avancées comme le lazy pulling, le chiffrement d'images et les checkpoints.

Ce guide couvre l'installation de nerdctl v2.2, les commandes essentielles testées, la gestion des réseaux et volumes, ainsi que les fonctionnalités avancées v2.x. Prérequis : containerd installé et fonctionnel.

  • Installer nerdctl sur Linux (binaire ou bundle complet)
  • Utiliser les commandes de base : run, ps, logs, exec, inspect
  • Gérer réseaux et volumes personnalisés
  • Utiliser Compose pour les applications multi-conteneurs
  • Exploiter les fonctionnalités v2.x : checkpoint, manifest, stats

Le tableau compare les deux CLI sur ce qui les sépare réellement. La différence de fond n'est pas la syntaxe, elle est identique, mais l'architecture : nerdctl dialogue directement avec containerd sans passer par le démon dockerd, et expose des capacités que containerd possède depuis longtemps sans que Docker les ait jamais rendues accessibles.

CritèreDockernerdctl
Daemondockerd obligatoirecontainerd uniquement
LicenceDocker Desktop payant (entreprises)100% open source (Apache 2.0)
Lazy pullingNon natifStargz, Nydus, OverlayBD, SOCI
Images chiffréesNonocicrypt intégré
Distribution P2PNonIPFS natif
CheckpointsExpérimentalSupport CRIU stable
Mode rootlessComplexebypass4netns optimisé

nerdctl n'est pas un fork de Docker, c'est un outil natif pour containerd qui reprend la syntaxe Docker pour faciliter l'adoption.

nerdctl propose deux méthodes d'installation : le binaire seul (si containerd est déjà installé) ou le bundle complet (containerd + BuildKit + CNI plugins inclus).

Cette méthode suppose que containerd est déjà installé et fonctionnel.

  1. Télécharger la dernière version

    Fenêtre de terminal
    VERSION="2.2.1"
    wget https://github.com/containerd/nerdctl/releases/download/v${VERSION}/nerdctl-${VERSION}-linux-amd64.tar.gz
  2. Installer le binaire

    Fenêtre de terminal
    sudo tar -xvf nerdctl-${VERSION}-linux-amd64.tar.gz -C /usr/local/bin
    sudo chmod +x /usr/local/bin/nerdctl
  3. Vérifier l'installation

    Fenêtre de terminal
    nerdctl --version

    Résultat attendu :

    nerdctl version 2.2.1

Après l'installation, vérifiez que nerdctl communique correctement avec containerd :

Fenêtre de terminal
sudo nerdctl info

Résultat attendu :

Client:
Namespace: default
Debug Mode: false
Server:
Server Version: v2.2.1
Storage Driver: overlayfs
Cgroup Driver: systemd
Cgroup Version: 2
Kernel Version: 6.8.0-100-generic
Operating System: Ubuntu 24.04.2 LTS
CPUs: 16
Total Memory: 46.83GiB

nerdctl reprend la syntaxe Docker. Voici les commandes de base testées avec sorties réelles.

L'option --rm détruit le conteneur dès qu'il se termine. Sans elle, chaque exécution laisse derrière elle un conteneur arrêté que nerdctl ps -a finira par afficher par dizaines.

Fenêtre de terminal
# Conteneur éphémère (--rm)
sudo nerdctl run --rm alpine:3.19 cat /etc/os-release

Résultat :

NAME="Alpine Linux"
VERSION_ID=3.19.9
PRETTY_NAME="Alpine Linux v3.19"
HOME_URL="https://alpinelinux.org/"

L'option -d détache le conteneur du terminal, et -p 8080:80 publie le port 80 du conteneur sur le port 8080 de l'hôte. La commande renvoie l'identifiant complet du conteneur.

Fenêtre de terminal
# Nginx sur le port 8080
sudo nerdctl run -d --name mon-nginx -p 8080:80 nginx:alpine

Résultat :

234f3562467bd41fe58d0ece451bb2ff479d25fb9c4e740e513a38a58cd2c3e2

La colonne PORTS confirme la publication du port sur l'hôte : c'est le premier endroit à regarder quand une application ne répond pas depuis l'extérieur du conteneur.

Fenêtre de terminal
sudo nerdctl ps

Résultat :

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
234f3562467b docker.io/library/nginx:alpine "/docker-entrypoint.…" 5 minutes ago Up 0.0.0.0:8080->80/tcp mon-nginx

Ajoutez -a pour voir aussi les conteneurs arrêtés.

nerdctl restitue ce que containerd a capturé sur la sortie standard et la sortie d'erreur du processus principal. Une application qui écrit dans un fichier interne au conteneur n'apparaîtra donc pas ici.

Fenêtre de terminal
sudo nerdctl logs mon-nginx | tail -5

Résultat :

2026/02/13 07:10:47 [notice] 1#1: nginx/1.29.5
2026/02/13 07:10:47 [notice] 1#1: built by gcc 15.2.0 (Alpine 15.2.0)
2026/02/13 07:10:47 [notice] 1#1: OS: Linux 6.8.0-100-generic
2026/02/13 07:10:47 [notice] 1#1: start worker processes
/docker-entrypoint.sh: Configuration complete; ready for start up

exec lance un processus supplémentaire dans un conteneur déjà démarré. Ajoutez -it pour obtenir un shell interactif au lieu d'une commande unique.

Fenêtre de terminal
sudo nerdctl exec mon-nginx cat /etc/nginx/nginx.conf | head -10

Résultat :

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
worker_connections 1024;
}

L'option --format accepte un gabarit Go et extrait un champ précis, ce qui évite de parcourir les quelques centaines de lignes de JSON renvoyées par défaut.

Fenêtre de terminal
sudo nerdctl inspect mon-nginx --format '{{.State.Status}} - {{.NetworkSettings.IPAddress}}'

Résultat :

running - 10.4.0.3

stop envoie d'abord un signal SIGTERM au processus principal, puis un SIGKILL si celui-ci ne rend pas la main. rm ne s'applique qu'à un conteneur déjà arrêté, sauf à forcer avec -f.

Fenêtre de terminal
sudo nerdctl stop mon-nginx
sudo nerdctl rm mon-nginx

L'option --no-stream affiche un relevé unique puis rend la main, au lieu de rafraîchir l'écran en continu comme le fait stats employé seul. C'est la forme utilisable dans un script.

Fenêtre de terminal
sudo nerdctl stats --no-stream

Résultat :

CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
234f3562467b mon-nginx 0.00% 12.85MiB / 46.83GiB 0.03% 1.45kB / 822B 0B / 20.5kB 17

top liste les processus du conteneur tels que l'hôte les voit. Les PID affichés sont donc ceux de l'espace de noms de l'hôte, pas ceux observés depuis l'intérieur du conteneur, où le processus principal porte le PID 1.

Fenêtre de terminal
sudo nerdctl top mon-nginx

Résultat :

UID PID PPID CMD
root 3777377 3777339 nginx: master process nginx -g daemon off;
message+ 3777625 3777377 nginx: worker process

nerdctl manipule les images stockées par containerd dans le namespace default. Ce détail surprend souvent : les images tirées par Kubernetes vivent dans le namespace k8s.io et n'apparaissent pas dans nerdctl images sans l'option --namespace k8s.io. Chercher une image « disparue » commence donc toujours par vérifier le namespace interrogé.

Quand aucun registre n'est précisé, nerdctl complète le nom en docker.io/library/alpine:3.19, comme le montre la colonne IMAGE de nerdctl ps.

Fenêtre de terminal
sudo nerdctl pull alpine:3.19

Deux colonnes de taille apparaissent, contrairement à Docker. BLOB SIZE correspond au volume compressé réellement téléchargé depuis le registre, alors que SIZE donne la taille décompressée occupée sur le disque.

Fenêtre de terminal
sudo nerdctl images

Résultat :

REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE
alpine 3.19 6baf43584bcb 2 weeks ago linux/amd64 8.081MB 3.421MB
nginx alpine b76de378d572 2 weeks ago linux/amd64 47.01MB 18.08MB

La suppression échoue tant qu'un conteneur, même arrêté, référence encore l'image : supprimez le conteneur d'abord.

Fenêtre de terminal
sudo nerdctl rmi alpine:3.19

nerdctl build ne construit rien lui-même, il délègue le travail à BuildKit. Le dernier argument est le contexte de build, c'est-à-dire le répertoire envoyé au constructeur et dans lequel il cherche le Dockerfile.

Fenêtre de terminal
# Créer un Dockerfile simple
cat > /tmp/Dockerfile << 'EOF'
FROM alpine:3.19@sha256:6baf43584bcb78f2e5847d1de515f23499913ac9f12bdf834811a3145eb11ca1
RUN apk add --no-cache curl
CMD ["echo", "Hello from nerdctl!"]
EOF
# Construire l'image
sudo nerdctl build -t mon-image:v1 /tmp

nerdctl ne possède pas de moteur réseau intégré : il s'appuie sur les plugins CNI (Container Network Interface) installés sur l'hôte. Chaque réseau créé se matérialise par un fichier de configuration dans /etc/cni/net.d/, ce qui rend l'état inspectable directement sur le disque, sans passer par la CLI.

Sans --subnet, nerdctl choisit lui-même une plage d'adresses libre. L'imposer évite les collisions avec un VPN ou un plan d'adressage d'entreprise déjà en place.

Fenêtre de terminal
sudo nerdctl network create mon-reseau --subnet 172.28.0.0/24

Résultat :

b047bfb73f50a1a7ff26f4264e82dd94d43096fa70c48a1bdf5b67cf4188ab52

Les entrées host et none n'ont pas de fichier dans la colonne FILE : ce sont des modes intégrés au runtime, pas des réseaux CNI. host partage la pile réseau de la machine, none prive le conteneur de toute interface.

Fenêtre de terminal
sudo nerdctl network ls

Résultat :

NETWORK ID NAME FILE
containerd-net /etc/cni/net.d/10-containerd-net.conflist
b047bfb73f50 mon-reseau /etc/cni/net.d/default/nerdctl-mon-reseau.conflist
17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist
host
none

Le conteneur reçoit une adresse dans le sous-réseau déclaré à la création. nerdctl inspect app la confirme dans la section NetworkSettings.

Fenêtre de terminal
sudo nerdctl run -d --name app --network mon-reseau nginx:alpine

Supprimez d'abord les conteneurs qui y sont attachés : un réseau encore utilisé laisse des configurations CNI incohérentes derrière lui.

Fenêtre de terminal
sudo nerdctl network rm mon-reseau

Un volume est un répertoire géré par nerdctl en dehors du système de fichiers du conteneur. Son contenu survit à la suppression du conteneur qui l'utilisait, ce qui en fait le mécanisme à retenir pour les bases de données et pour tout état que vous ne voulez pas perdre au premier nerdctl rm.

La commande prépare un répertoire dédié sous /var/lib/nerdctl/, propre au namespace containerd courant.

Fenêtre de terminal
sudo nerdctl volume create mes-donnees

La colonne DIRECTORY donne le chemin réel sur l'hôte. C'est là qu'il faut se rendre pour sauvegarder les données ou vérifier un contenu sans avoir à démarrer un conteneur.

Fenêtre de terminal
sudo nerdctl volume ls

Résultat :

VOLUME NAME DIRECTORY
mes-donnees /var/lib/nerdctl/1935db59/volumes/default/mes-donnees/_data

La syntaxe -v nom:/chemin monte le volume au point de montage indiqué. Les données que Redis écrit dans /data survivront donc à la suppression du conteneur db.

Fenêtre de terminal
sudo nerdctl run -d --name db -v mes-donnees:/data redis:alpine

Cette opération est irréversible : le répertoire et son contenu disparaissent, sans corbeille ni sauvegarde intermédiaire.

Fenêtre de terminal
sudo nerdctl volume rm mes-donnees

nerdctl intègre une compatibilité native avec Docker Compose. Pas besoin d'installer docker-compose.

Le fichier suit la spécification Compose standard, sans mot-clé propriétaire. Un fichier écrit pour Docker Compose fonctionne tel quel.

compose.yaml
services:
web:
image: nginx:1.31.3-alpine@sha256:4a73073bd557c65b759505da037898b61f1be6cbcc3c2c3aeac22d2a470c1752
ports:
- "8889:80"
redis:
image: redis:8.8.0-alpine@sha256:9d317178eceac8454a2284a9e6df2466b93c745529947f0cd42a0fa9609d7005

up -d crée le réseau du projet, télécharge les images manquantes puis démarre les services en arrière-plan. Le nom de projet est déduit du répertoire courant, d'où le préfixe myapp- visible dans les traces.

Fenêtre de terminal
sudo nerdctl compose up -d

Résultat :

INFO[0000] Creating network myapp_default
INFO[0000] Ensuring image redis:alpine
INFO[0005] Ensuring image nginx:alpine
INFO[0005] Creating container myapp-redis-1
INFO[0005] Creating container myapp-web-1

compose ps se limite aux conteneurs du projet courant, là où nerdctl ps liste tout ce qui tourne sur l'hôte.

Fenêtre de terminal
sudo nerdctl compose ps

Résultat :

NAME IMAGE COMMAND SERVICE STATUS PORTS
myapp-web-1 docker.io/library/nginx:alpine "/docker-entrypoint.…" web running 0.0.0.0:8889->80/tcp
myapp-redis-1 docker.io/library/redis:alpine "docker-entrypoint.s…" redis running

down supprime les conteneurs et le réseau du projet mais conserve les volumes. L'option -v les détruit également, ce qui efface définitivement les données persistées : ne l'utilisez que sur un environnement jetable.

Fenêtre de terminal
# Arrêter les services
sudo nerdctl compose down
# Avec suppression des volumes
sudo nerdctl compose down -v

Les fonctionnalités qui suivent n'ont pas d'équivalent stable dans la CLI Docker. Elles exposent des capacités présentes dans containerd depuis longtemps mais qu'on n'atteignait pas sans écrire du code : geler un processus sur disque, publier une image sans registre central, ou démarrer un conteneur avant la fin du téléchargement de son image.

Les checkpoints permettent de sauvegarder l'état d'un conteneur en cours d'exécution pour le restaurer plus tard. Utile pour la migration ou le debugging.

Fenêtre de terminal
# Créer un checkpoint
sudo nerdctl checkpoint create mon-conteneur checkpoint-1
# Lister les checkpoints
sudo nerdctl checkpoint ls mon-conteneur
# Supprimer un checkpoint
sudo nerdctl checkpoint rm mon-conteneur checkpoint-1

Créez et gérez des images multi-architecture :

Fenêtre de terminal
# Créer un manifest
sudo nerdctl manifest create mon-image:latest \
mon-image:amd64 \
mon-image:arm64
# Inspecter un manifest
sudo nerdctl manifest inspect mon-image:latest
# Pousser vers un registre
sudo nerdctl manifest push mon-image:latest
# Supprimer un manifest local
sudo nerdctl manifest rm mon-image:latest

container export produit une archive du système de fichiers du conteneur, sans son historique de couches ni ses métadonnées. L'image réimportée repart donc d'une couche unique et perd la commande de démarrage d'origine, qu'il faut redéfinir au lancement.

Fenêtre de terminal
# Exporter un conteneur vers une archive
sudo nerdctl container export mon-conteneur > conteneur.tar
# Importer comme image
sudo nerdctl image import conteneur.tar mon-image:imported

Exécutez des conteneurs sans privilèges root pour une sécurité renforcée.

  1. Installer les prérequis

    Fenêtre de terminal
    sudo apt install uidmap rootlesskit
  2. Configurer containerd en mode rootless

    Fenêtre de terminal
    containerd-rootless-setuptool.sh install
  3. Utiliser nerdctl sans sudo

    Fenêtre de terminal
    nerdctl run --rm alpine:3.19 echo "Hello rootless!"

Le lazy pulling permet de démarrer un conteneur avant que l'image soit entièrement téléchargée. Idéal pour les images volumineuses.

Snaphotters supportés :

  • Stargz : format eStargz optimisé
  • Nydus : accélérateur d'images cloud-native
  • OverlayBD : couche block-device
  • SOCI : Seekable OCI (Amazon)
Fenêtre de terminal
# Utiliser le snapshotter stargz
sudo nerdctl --snapshotter stargz run ghcr.io/stargz-containers/nginx:1.23-esgz

Partagez des images en peer-to-peer sans registre central :

Fenêtre de terminal
# Pousser une image vers IPFS
sudo nerdctl push ipfs://mon-image:latest
# Exécuter depuis IPFS
sudo nerdctl run ipfs://<CID>

Signez et vérifiez vos images pour garantir leur intégrité :

Fenêtre de terminal
# Signer lors du push
sudo nerdctl push --sign=cosign mon-registre/mon-image:latest
# Vérifier lors du pull
sudo nerdctl pull --verify=cosign mon-registre/mon-image:latest

Voir le guide Cosign pour la configuration complète.

Les erreurs listées ici couvrent l'essentiel des blocages rencontrés au démarrage. Deux causes reviennent en boucle : l'absence de droits sur le socket de containerd, qui se traduit par un permission denied sur n'importe quelle commande, et un service BuildKit non démarré qui fait échouer toutes les constructions d'images.

ProblèmeCause probableSolution
permission deniedPas les droits rootUtiliser sudo ou configurer rootless
failed to ping buildkitdBuildKit non démarrésudo systemctl start buildkit
network not foundRéseau supprimé ou inexistantnerdctl network ls puis recréer
image not foundImage non présente localementnerdctl pull image:tag
container already existsNom de conteneur déjà utilisénerdctl rm nom ou choisir un autre nom
cgroup driver mismatchcontainerd/kubelet mal configurésAligner les drivers cgroup

Ces quatre commandes suffisent à situer un problème : l'état du service, ses journaux, la configuration vue par le client, puis le nettoyage. Attention à la dernière, system prune -a supprime toutes les images inutilisées et pas seulement les couches orphelines.

Fenêtre de terminal
# Vérifier l'état de containerd
sudo systemctl status containerd
# Voir les logs containerd
sudo journalctl -u containerd -f
# Vérifier la configuration nerdctl
sudo nerdctl info
# Nettoyer les ressources inutilisées
sudo nerdctl system prune -a

Les recommandations regroupées ici évitent les incidents les plus fréquents en exploitation : un conteneur privilégié sans nécessité, un nom généré aléatoirement qu'on ne retrouve plus le lendemain, ou un tag latest dont le contenu change entre deux déploiements.

Le mode rootless et la réduction des capabilities (les privilèges Linux accordés finement à un processus) sont les deux gestes qui réduisent le plus la surface d'attaque, avant même la question de la signature d'images.

  • Privilégiez le mode rootless pour les environnements de développement
  • Signez vos images avec Cosign avant de les déployer
  • Limitez les capacités avec --cap-drop=ALL --cap-add=<nécessaire>
  • Utilisez des images chiffrées pour les données sensibles

Ces conventions rendent l'état de l'hôte lisible par quelqu'un d'autre que la personne qui a lancé les conteneurs, condition indispensable dès qu'une équipe partage la même machine.

  • Nommez vos conteneurs avec --name pour faciliter la gestion
  • Utilisez des réseaux personnalisés pour isoler les applications
  • Préférez les volumes nommés aux bind mounts pour les données persistantes
  • Tagguez vos images avec des versions précises (pas latest)

Ces trois réglages agissent sur des points distincts : le temps de démarrage d'un conteneur, la durée des constructions, et la stabilité de l'hôte lorsqu'un conteneur consomme plus que prévu.

  • Activez le lazy pulling pour les grandes images
  • Utilisez le cache BuildKit pour accélérer les builds
  • Configurez les limites de ressources avec --memory et --cpus
  1. nerdctl remplace Docker CLI avec une compatibilité complète et zéro dépendance à dockerd
  2. Syntaxe identique : nerdctl run, nerdctl build, nerdctl compose fonctionnent comme Docker
  3. Fonctionnalités avancées : lazy pulling, chiffrement, IPFS, checkpoints non disponibles dans Docker
  4. Mode rootless : sécurité renforcée avec bypass4netns pour les performances
  5. Compose intégré : pas besoin d'installer docker-compose séparément
  6. Bundle complet : nerdctl-full inclut containerd, runc, BuildKit et CNI plugins
  7. Checkpoints v2.2 : sauvegardez et restaurez l'état des conteneurs avec CRIU
  8. Manifests multi-arch : créez des images pour plusieurs architectures facilement

Ces liens mènent au dépôt et à la documentation officielle. Les notes de version publiées sur la page des releases font foi sur les fonctionnalités réellement disponibles dans la version que vous avez installée.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn