Fondamentaux
Initiation au cloud native
Avant de lire : Fondations Linux (namespaces, cgroups v2, descripteurs de fichier) et IaaS et cloud native (de quoi le moteur est responsable).
Le moteur est une couche fine et soigneuse au-dessus de fonctionnalités du noyau Linux et d’une poignée de spécifications ouvertes. Cette page vous donne juste assez de chaque concept pour lire le code, et dit où il vit dans ce dépôt. Après elle, vous pourrez prendre n’importe quel mécanisme — un namespace, une limite de cgroup, une couche d’image, une chaîne de pare-feu, le démarrage d’une VM, l’apply d’un manifeste — et nommer le fichier et le symbole qui l’implémente. Pour aller plus loin, suivez les liens officiels — ils valent mieux que n’importe quel résumé ici.
Les concepts sont enseignés une seule fois dans ce manuel. Les primitives du noyau (namespaces,
user namespaces, cgroups v2) sont enseignées en pratique dans
Fondations Linux, donc les sections 4.1 et 4.2 ne font que les
récapituler et les relier au code. Ce que chaque standard ouvert exige, et jusqu’où le moteur y
est conforme, se trouve dans Standards cloud native, plus loin dans le
parcours. Les chemins nomment des crates (crates/<couche>/<crate>) ; les couches sont expliquées
dans Architecture, et pour l’instant un chemin dit simplement où se trouve le
code.
Chaque section comporte trois parties : le concept, Dans Delonix (fichiers et symboles que
vous pouvez chercher avec grep), et Pour aller plus loin. Les chemins sont relatifs à la
racine du dépôt.
Pour vous orienter dans l’écosystème plus large, le CNCF Landscape et le CNCF Glossary sont de bonnes cartes. Les comparaisons avec runc, crun, containerd ou Podman n’apparaissent que là où elles aident à expliquer un choix de conception.
4.1 Namespaces Linux et fonctionnement rootless#
Récapitulatif. Un container est un processus démarré dans un nouvel ensemble de namespaces
(mount, PID, network, IPC, UTS, cgroup, user). Le user namespace est ce qui le rend rootless :
à l’intérieur, le processus est uid 0 sur les ressources que ce namespace possède ; à l’extérieur,
c’est un utilisateur ordinaire. Un utilisateur non privilégié ne peut mapper que son propre uid ;
une plage nécessite newuidmap/newgidmap et /etc/subuid. Les deux sont enseignés, avec des
commandes à taper, dans Fondations Linux — Namespaces et
User namespaces et mappage d’uid.
Certaines distributions restreignent en plus les user namespaces non privilégiés via AppArmor —
voir Environnement
pour les conséquences pratiques.
Dans Delonix
fn spawndanscrates/adapters/delonix-linux/src/lib.rsconstruit lesCloneFlags(CLONE_NEWNS,CLONE_NEWPID,CLONE_NEWNET,CLONE_NEWUSER, …) et appellenix::sched::clone. Le partage d’IPC/UTS entre membres d’un pod est géré parsetnsdanscontainer_init.write_userns_mapsdans le même fichier écrit les mappages depuis le parent : un mappage à un seul uid (0 <euid> 1) en rootless, ou une plage de subuid vianewuidmap/newgidmapquandhave_subid_helpers()indique qu’ils sont disponibles.USERNS_UID_BASE/USERNS_RANGEdéfinissent la plage utilisée en mode root.setup_rootfsmonte la racine du container et appellepivot_root;container_initest le code qui s’exécute dans les nouveaux namespaces avantexecvp.- Les opérations rootless sur des fichiers appartenant à des subuids mappés ré-exécutent le
binaire dans un user namespace mappé :
reexec_mapped,reexec_mapped_hold,remove_tree_mapped.
Pour aller plus loin : namespaces(7),
user_namespaces(7),
newuidmap(1),
subuid(5),
pivot_root(2).
4.2 cgroups v2 et délégation#
Récapitulatif. cgroup v2 est un arbre unique à /sys/fs/cgroup dont les fichiers
(memory.max, cpu.max, pids.max, memory.events) limitent et comptabilisent un groupe de
processus. Un utilisateur non privilégié ne peut écrire que dans une sous-arborescence que systemd
lui a déléguée, et un shell dans une scope de session SSH se trouve généralement en dehors —
si bien que des limites peuvent, en silence, ne pas s’y appliquer. L’arbre, la règle « pas de
processus internes » et la délégation sont enseignés en pratique dans
Fondations Linux — cgroups v2 ; le contrat de délégation en tant
que standard, et la conformité du moteur, se trouvent dans
Standards cloud native — 13.15.
Le moteur ne prend en charge que v2.
Dans Delonix
- Le mode root place les containers sous
delonix_compute::DELONIX_SLICE(/sys/fs/cgroup/delonix.slice). - Le mode rootless trouve le cgroup de service de l’utilisateur et crée des feuilles sous
<user@uid.service>/dlx-containers— voiruser_service_baseettry_delegated_basedanscrates/adapters/delonix-linux/src/lib.rs.cgroup_limits_applyrépond à « les limites s’appliqueront-elles sur cet hôte ? » sans démarrer de container. - La décision de conception sur le niveau intermédiaire est l’
ADR-0015 ; la façon dont le CRI suit la hiérarchie
de cgroups du kubelet est l’ADR-0038, avec
le parent du kubelet validé par
KubeCgroupParent::parsedanscrates/contexts/delonix-compute/src/record.rs.
Pour aller plus loin : Noyau Linux — Control Group v2,
systemd — Control Group APIs and Delegation,
cgroups(7).
4.3 Capabilities, seccomp, AppArmor, chemins masqués#
Le pouvoir de root se divise en capabilities (CAP_NET_ADMIN, CAP_SYS_ADMIN, …). Un
container conserve un petit ensemble par défaut et abandonne le reste. seccomp installe un
filtre BPF qui autorise ou refuse des appels système, réduisant la surface d’attaque du noyau.
AppArmor (et SELinux sur d’autres distributions) sont des Linux Security Modules qui confinent
un processus par profil. Enfin, les runtimes masquent des chemins sensibles de /proc et
/sys (montent quelque chose de vide par-dessus) et rendent d’autres lecture seule, parce que ces
fichiers révèlent des informations sur l’hôte ou permettent de le contrôler.
Un point subtil que le code documente : clone3 passe ses flags via un pointeur qu’un filtre
seccomp ne peut pas inspecter, si bien qu’un filtre qui bloque clone(CLONE_NEWUSER) doit aussi
faire échouer clone3 avec ENOSYS pour forcer la libc à revenir au clone filtrable.
Dans Delonix
- Capabilities :
KEPT_CAPSetresolve_cap_keepdanscrates/adapters/delonix-linux/src/capabilities.rs;drop_capabilitiesdanslib.rs. - seccomp :
apply_seccompdanscrates/adapters/delonix-linux/src/lib.rs(construit avec le crateseccompiler, y compris le pré-filtreclone3→ENOSYS) ; les profils JSON personnalisés sont analysés et compilés dansseccomp_profile.rs(parse,compile). - AppArmor :
apply_apparmordanslib.rs. - Chemins masqués et lecture seule :
DEFAULT_MASKED_PATHS,DEFAULT_READONLY_PATHS,apply_masked_paths,apply_readonly_paths,mask_proc_pathsdanslib.rs. - Les décisions de sécurité au niveau du nœud (politique, admission, événements, score) forment un
crate pur séparé :
evaluatedanscrates/contexts/delonix-security-runtime/src/admission.rs(ADR-0026).
Pour aller plus loin : capabilities(7),
noyau — Seccomp BPF,
Documentation AppArmor,
OCI runtime spec — Linux config
(les champs maskedPaths/readonlyPaths/seccomp que d’autres runtimes consomment).
4.4 Images OCI, stockage adressé par contenu et overlayfs#
L’Open Container Initiative publie trois spécifications :
- la image spec — une image est un manifeste (JSON) qui pointe vers une config et une liste ordonnée de layers (des tarballs), et éventuellement un index pointant vers un manifeste par plateforme ;
- la distribution spec — l’API HTTP que servent les registres (
/v2/<name>/manifests/<ref>,/v2/<name>/blobs/<digest>, authentification par jeton) ; - la runtime spec — comment un runtime tel que runc ou crun reçoit l’instruction d’exécuter un bundle de système de fichiers.
Tout est adressé par contenu : un blob est nommé par le digest SHA-256 de ses octets, si bien
qu’un client vérifie ce qu’il a téléchargé en le hachant. Un pull par digest (name@sha256:…)
n’est une garantie que si le manifeste lui-même est vérifié par rapport à ce digest, en plus de
chaque blob par rapport au manifeste.
À l’exécution, les couches sont empilées avec overlayfs : des lowerdir en lecture seule, un
upperdir inscriptible où les changements sont copiés, et un workdir. Beaucoup de containers
peuvent partager les mêmes couches inférieures.
Dans Delonix
- Client de registre (distribution spec) :
crates/adapters/delonix-oci/src/registry.rs— fonctionspull_from_registry*, les types de médiaACCEPT_MANIFEST, etverify_manifest_digest. Les types viennent du crateoci-spec. - Store de blobs adressé par contenu :
Casdanscrates/adapters/delonix-oci/src/cas.rs. - Écriture d’une archive au format OCI image layout :
write_oci_archivedanssave.rs. - Préparation de l’overlay :
ImageStore::prepare_overlaydansoverlay.rsécrit un marqueuroverlay-lowers(LOWERS_FILE) ; le montage lui-même se produit à l’intérieur des namespaces user et mount du container dansmount_overlay_if_marked(crates/adapters/delonix-linux/src/lib.rs), via la nouvelle API de montage — voir ADR-0016 et ADR-0037. - Le moteur exécute lui-même les containers plutôt que de confier un bundle de runtime OCI à runc/crun.
Pour aller plus loin : OCI image spec, OCI distribution spec, OCI runtime spec, noyau — Overlay Filesystem.
4.5 Réseau des containers#
Briques de base du réseau Linux :
- un network namespace a ses propres interfaces, routes et pare-feu ;
- une paire veth est un câble virtuel avec une extrémité dans chaque namespace ;
- une bridge est un commutateur virtuel reliant plusieurs extrémités veth ;
- nftables est le filtre de paquets et moteur NAT du noyau ; DNAT réécrit une destination
(comment un port publié atteint un container), et conntrack suit les flux pour que le
trafic de réponse d’une connexion autorisée passe (
ct state established,related) ; - slirp4netns donne une connectivité sortante à un network namespace non privilégié en émulant une pile TCP/IP en espace utilisateur, et redirige des ports de l’hôte vers celui-ci ;
- VXLAN transporte des trames L2 sur UDP entre hôtes, et WireGuard chiffre un tunnel.
CNI (Container Network Interface) est une spécification où un runtime exécute des binaires de
plugin (bridge, host-local, portmap, …) avec des commandes ADD/DEL et une configuration
JSON depuis /etc/cni/net.d. Les runtimes Kubernetes l’utilisent pour le réseau des pods.
Dans Delonix
- Le réseau rootless ne peut pas créer d’interfaces sur l’hôte, donc le moteur maintient un
network namespace holder de longue durée : un processus pin minimal possède les
namespaces, et un processus control redémarrable sert un socket Unix. Voir
start_pin,start_controletensure_updanscrates/adapters/delonix-sdn/src/infra.rs. - Attacher un workload :
attach_container(IPAM + commande de contrôle) etdo_attach(veth vers la bridge, à l’intérieur du holder). Les noms de bridge viennent debridge_name, dans le crate sans dépendancescrates/foundation/delonix-net-rules/src/lib.rs. - Sortie et redirection de ports :
slirp_attachetslirp_add_hostfwddanscrates/adapters/delonix-sdn/src/lib.rs(qui démarrentslirp4netns) ; la publication à l’intérieur du holder danspublish_port/do_publish(infra.rs). - Pare-feu :
table ip dlxingavec les base chainsfwguard,fwdeny,fwcontet la verdict mapfwmap(FWMAP), générée dansinfra.rs(do_firewall,apply_firewall_all,ns_set_joinpour les sets d’isolement de namespace). - DNS interne (nom standard
<name>.<namespace>.svc.delonix.internal, l’ancien<name>.<namespace>.delonix.internalrépond toujours ;service_fqdn,parse_internal_name) :dns_server_main,handle_dns,dns_resolve_for,dns_resolve_multi_fordansinfra.rs. - Réseaux overlay :
set_vxlan(infra.rs) et les assistants WireGuard danscrates/adapters/delonix-sdn/src/wg.rs, orchestrés parrealize_overlaydansbins/delonix-runtime-bin/src/cmd/network.rs. - CNI :
crates/adapters/delonix-sdn/src/cni.rs—add,del,readiness,attach_named_netns. L’usage en rootless est opt-in (enabled_confvérifieDELONIX_CNI=1) ; le chemin CRI en root utilise la chaîne CNI du nœud (root_cni_readinessdanscrates/interfaces/delonix-cri/src/runtime_svc.rs). - Décisions de topologie : ADR-0013, ADR-0014.
Pour aller plus loin : network_namespaces(7),
veth(4),
wiki nftables,
slirp4netns,
noyau — VXLAN,
WireGuard,
CNI et sa spécification.
4.6 Kubernetes : CRI, kubelet, kubeadm et kind#
Le kubelet est l’agent de nœud de Kubernetes. Il n’exécute pas lui-même les containers ; il
parle à un runtime de containers via la Container Runtime Interface, une API gRPC
(RuntimeService, ImageService) servie sur un socket Unix local. Le kubelet crée une pod
sandbox (RunPodSandbox) puis les containers à l’intérieur. Il a aussi un réglage de cgroup
driver (systemd ou cgroupfs) qui doit correspondre à la façon dont le runtime gère les
cgroups, sinon les cgroups du pod et ceux du container divergent.
kubeadm amorce un cluster sur des machines existantes (kubeadm init, kubeadm join).
kind exécute des nœuds Kubernetes sous forme de containers construits à partir de l’image
kindest/node.
Dans Delonix
crates/interfaces/delonix-criest un serveur CRIruntime.v1. Le protobuf estproto/api.protoà l’intérieur de ce crate, compilé parbuild.rsavectonic-build. Le binaire estsrc/bin/delonix-cri.rs.- Le cgroup driver rapporté au kubelet :
engine_cgroup_driverdansruntime_svc.rs; son commentaire de doc explique pourquoi la réponse est celle-là, et ce qui devrait changer pour que ce soit l’autre. - Un aller-retour sur du gRPC réel est testé dans
crates/interfaces/delonix-cri/tests/grpc_status.rs. - Commandes d’amorçage de cluster : kubeadm via SSH dans
bins/delonix-runtime-bin/src/cmd/cluster.rs(aveckubeadm_config.rs,etcd.rs,lb.rs), et des clusters locaux façon kind danskindmode.rs.
Pour aller plus loin : Kubernetes — Container Runtime Interface, dépôt cri-api, Configurer un cgroup driver, kubeadm, kind.
4.7 Virtualisation : KVM, virtio, Cloud Hypervisor, libvirt, cloud-init#
KVM est l’hyperviseur du noyau, exposé comme /dev/kvm ; un VMM en espace utilisateur
(QEMU, Cloud Hypervisor) l’utilise pour exécuter des invités. virtio est la famille de
périphériques paravirtuels (disque, réseau, partage de système de fichiers 9p) que les invités
utilisent pour des E/S efficaces. Cloud Hypervisor est un VMM en Rust centré sur les workloads
cloud, capable de s’exécuter sans privilège avec accès à /dev/kvm ; il démarre les invités via
un firmware (une build UEFI EDK2 ou rust-hypervisor-firmware) ou directement depuis une image de
noyau. libvirt gère des domaines QEMU/KVM décrits en XML, via virsh et libvirtd.
Les cloud images sont génériques ; la configuration par instance (hostname, clés SSH,
utilisateurs, réseau) vient de cloud-init, qui lit une datasource. La datasource NoCloud
est un petit ISO étiqueté cidata contenant user-data, meta-data et éventuellement
network-config.
Dans Delonix
- Le port est
VmBackenddanscrates/adapters/delonix-vm/src/lib.rs, implémenté parCloudHypervisorBackendetLibvirtBackendlà, et parProxmoxBackenddanscrates/providers/delonix-proxmox(ADR-0008). - Ordre de recherche du firmware Cloud Hypervisor :
DEFAULT_CH_FIRMWARES(EDK2CLOUDHV.fdavanthypervisor-fw) ; la ligne de commande du VMM est construite dansboot_ch. - XML de domaine libvirt :
libvirt_domain_xml. - Génération de la seed NoCloud :
generate_seed_isodansbins/delonix-runtime-bin/src/cmd/vm.rs. - Les VM sur le SDN rootless obtiennent un bail DHCP dérivé de leur MAC :
dhcp_lease_ipdanscrates/adapters/delonix-sdn/src/infra.rs. - Configuration pratique et pièges d’hôte connus : Construire des microVM.
Pour aller plus loin : noyau — KVM, spécification virtio (OASIS), Cloud Hypervisor et sa documentation, libvirt, cloud-init NoCloud.
4.8 Réconciliation déclarative#
Kubernetes a popularisé un modèle où les utilisateurs soumettent un état désiré sous forme
d’objets typés (apiVersion, kind, metadata, spec), et des contrôleurs le comparent
répétitivement à l’état réel et agissent pour converger. kubectl apply ajoute un diff à
trois voies : il stocke la dernière configuration appliquée sur l’objet, ce qui permet de
distinguer « vous avez retiré ce champ de votre fichier » (le rétablir) de « quelqu’un a défini ce
champ à la main » (le laisser tranquille).
Le principe, et ce qu’il vous demande quand vous ajoutez un Kind, se trouvent dans IaaS et cloud native — Déclaratif et convergent.
Dans Delonix
- Le moteur a ses propres Kinds dans des groupes d’API (
delonix api-resourcesles liste). Les faits sur chaque Kind (domaine, s’il converge, teardown, namespacing) vivent dans une seule table :KindFactsdanscrates/contexts/delonix-stack/src/kinds.rs. - Le planificateur est pur :
plan(desired, actual, stack)danscrates/contexts/delonix-stack/src/reconcile.rs. Le commentaire de module contient la table de vérité à trois voies, et le dernier spec appliqué est stocké sur la ressource elle-même sous l’annotationLAST_APPLIED(delonix.io/last-applied) — il n’y a pas de fichier d’état séparé. - La propriété est une étiquette sur la ressource ; l’historique de révisions se trouve dans
revision.rs(ADR-0019). - Les manifestes sont analysés dans
bins/delonix-runtime-bin/src/cmd/manifest.rs;stack plan/applyvivent danscmd/stack.rs. - Aucune boucle de contrôleur ne s’exécute en arrière-plan : la réconciliation se produit quand une commande s’exécute (daemonless). Le réconciliateur de pull proposé conserve cette propriété en étant un timer systemd qui invoque le même apply, et non un processus résident (ADR-0021, état Proposed).
Pour aller plus loin : Kubernetes — Objects,
Controllers,
Gestion déclarative avec kubectl apply.
4.9 Observabilité et l’interface MCP#
OpenTelemetry est un standard CNCF pour les traces, métriques et logs, exportés via OTLP
vers un collecteur. Prometheus récupère des métriques depuis un endpoint HTTP /metrics dans
un format d’exposition texte. Le Model Context Protocol est un protocole ouvert qui permet à
des clients d’IA de découvrir et d’appeler des outils exposés par un serveur, généralement via
stdio.
Dans Delonix
- Logging structuré et spans OTLP optionnels :
initdanscrates/adapters/delonix-telemetry/src/telemetry.rs(les spans ne sont exportés que quandDELONIX_OTLP_ENDPOINTest définie ; l’exportateur s’exécute sur son propre thread pour que la CLI synchrone n’ait besoin d’aucun runtime asynchrone). - Registre Prometheus (préfixe
delonix) et encodage texte :crates/adapters/delonix-telemetry/src/metrics.rs(encode). L’API de gestion locale sert/metricsdanscrates/interfaces/delonix-mgmt/src/lib.rs. - MCP :
crates/interfaces/delonix-mcp(construit surrmcp, transport stdio), avec le binaire dansbins/delonix-mcp-bin. Portée et limites : ADR-0025.
Pour aller plus loin : Documentation OpenTelemetry, Spécification OTLP, Prometheus — formats d’exposition, Model Context Protocol.
4.10 Daemonless, en un paragraphe#
containerd et le Docker Engine gardent un daemon résident qui possède l’état des containers ;
Podman a montré qu’un runtime peut à la place être une commande qui se termine, avec des
processus auxiliaires par container et systemd pour tout ce qui doit persister. Delonix suit le
second modèle : la CLI fait le travail et se termine, l’état ce sont des fichiers sous la racine
d’état protégés par flock (voir
Initiation à Rust §3.8), un processus
superviseur existe par container détaché, le holder réseau n’existe que tant que quelque chose en
a besoin, et la persistance au démarrage passe par des units systemd
(bins/delonix-runtime-bin/src/cmd/boot.rs). Les conséquences — bonnes et mauvaises — sont
discutées dans Architecture et
System Design Interview. Le principe lui-même, et la règle qu’un
nouveau daemon exige un ADR, se trouvent dans
IaaS et cloud native — Daemonless.