Blog Agaetis

Les runtimes OCI

30/03/2021| François Travais read_time 5 min.
Retour au blog

Dans le premier article de cette série, nous avions présenté rapidement les runtimes OCI, ces outils qui permettent de transformer des images OCI en instances de conteneurs en marche. Nous allons ici faire un tour d’horizon des différentes catégories et implémentations de runtimes OCI.

Nous allons commencer par les native runtimes, se sont les runtimes les plus courants, ils utilisent directement les fonctionnalités du kernel de la machine hôte.

Suivrons les sandbox runtimes, des runtimes qui isolent un peu plus les conteneurs de la machine hôte en limitant les interactions entre le kernel et les conteneurs.

Et enfin nous nous intéresserons a Firecracker, qui est un VMM (Virtual Machine Monitor) dédié aux micro-VMs et conçu pour le serverless. C’est un outil complémentaire aux runtimes qui permet d’améliorer l’isolation des conteneurs.

Native runtimes

Les natives runtimes sont de loin les plus utilisés, se sont les runtimes par défaut de Docker, Podman, Containerd et CRI-O. Ils utilisent les fonctionnalités du kernel pour isoler le conteneur de la machine hôte. Le plus commun étant runc, et crun le challenger.

runc est le runtime de référence de l’OCI. Donné par Docker à l’OCI, il est écrit en Go. C’est le runtime par défaut de Docker, CRI-O et Containerd.

Ensuite viens crun, un runtime en C développé par Red Hat. Il est supposé plus performant que runc et est le runtime par défaut de Podman. Même si crun a supporté cgroups v2 avant runc, ce dernier a rattrapé son retard depuis.

Nous pouvons aussi mentionner ici LXC, qui utilise les fonctionnalités du kernel comme runc et crun, et permet de lancer des conteneur OCI. Mais à la différence des deux autres, LXC est conçu pour les conteneurs systèmes (par opposition aux conteneurs applicatifs), qui ne sont pas entièrement dédiés à une application mais qui tente de reproduire le comportement d’une VM classique.

Ces runtimes ont l’inconvénient de dépendre des fonctionnalités d’isolation du kernel, et ces mécanismes ne sont pas infaillibles, c’est pourquoi d’autres runtimes de natures différentes ont vu le jour pour tenter d’isoler un petit peu plus les conteneurs de la machine hôte et d’eux-mêmes.

Sandbox runtimes

Les sandbox runtimes limitent les interactions entre le conteneur et le kernel pour réduire au maximum la surface d’attaque, permettant ainsi une plus grande isolation. Dans cette catégorie nous allons voir gVisorNabla containers et Kata containers. Chacun utilisent une méthode différente pour y arriver;
gVisor implémente son propre kernel, Sentry, et son composant pour les interactions avec le système de fichiers, Gofer.

Source : gVisor

Tous les appels systèmes sont interceptés par gVisor et envoyés à Sentry, qui lui-même n’utilise que très peu d’appels au kernel. Il n’est pas non plus possible pour le conteneur de faire directement des appels systèmes. Sentry est écrit en Go pour limiter les bugs que peut contenir un kernel en C (cf. la doc de gVisor). Sentry n’implémente pas tous les appels systèmes d’un kernel classique (plus de détails ici).

Gofer quant à lui est chargé de faire le proxy pour les appels au système de fichiers, le conteneur n’a pas d’accès direct au système de fichiers.

De son côté Nabla containers utilise la technique de l’unikernel qui consiste à packager l’application avec une bibliothèque d’OS qui remplace un OS normal pour aboutir à une image de machine virtuelle minimale et dédiée à l’application.

Nabla n’utilise pas un VMM (Virtual Machine Monitor) classique (e.g. QEMU) mais un VMM spécifique, Nabla Tender, qui limite beaucoup plus les appels systèmes.

Nabla est une initiative d’IBM.

Source : Nabla container

Nabla containers n’utilisent que 7 appels systèmes sur les 300+ qui existent et limite ainsi la surface d’attaque. L’inconvénient est qu’il faut utiliser une image de base spécifique pour que l’image OCI soit compatible avec Nabla.

Nous pouvons également citer OSv dans cette catégorie, qui, comme Nabla containers, utilise le principe de l’unikernel mais sans apporter son propre VMM. Nous ne nous étendons pas plus que ça sur ce projet puisqu’il n’est que très peu maintenu de nos jours.

Kata containers est né de la fusion du projet Clear Containers d’Intel et de RunV d’Hyper.sh. Le projet est hébergé par l’Open Infrastructure Foundation (anciennement OpenStack Foundation).

Il lance les conteneurs dans une micro-VM dédiée, optimisée pour démarrer vite et conçue pour cet usage. Un composant sur la machine hôte permet de faire le proxy et d’envoyer les instructions à l’agent Kata via l’hyperviseur.

Source : Kata containers

Les micro-VMs sont des VMs avec un minimum de fonctionnalités, seulement le strict nécessaire pour faire fonctionner des conteneurs.

Kata containers supporte un petit panel d’hyperviseur : QEMU, NEMU (une version allégée de QEMU by Intel), cloud hypervisor (utilise KVM), Firecracker (quelques limitations tout de même) et ACRN.

Cette virtualisation induit nécessairement une perte de performance, mais qui reste plus intéressante que d’utiliser une VM classique et plus sécurisée qu’un runtime classique.

Ces sandbox runtimes permettent d’isoler les conteneurs, mais au prix de performances dégradées, et parfois plus : 

  • gVisor n’est pas compatible avec toutes les applications, notamment celles qui nécessitent un accès direct aux système de fichier, et il impactent aussi les performances.
  • Nabla container induit également une baisse de performance et plus important encore, il n’est pas tout à fait fini et ne semble plus très maintenu.
  • OSv n’est pratiquement plus maintenu.

En plus de ces sandbox runtimes, il existe d’autres technologies permettant d’isoler les conteneurs, et Firecracker est l’une d’elle.

Bonus : Firecracker

Firecracker est une initiative d’Amazon, c’est la technologie utilisée chez eux pour AWS Lambda et AWS Fargate. C’est un VMM (Virtual Machine Monitor) et non un runtime. Il utilise KVM, c’est une alternative à QEMU dédiée aux micro-VMs et conçu pour supporter le serverless (démarrage ultra-rapide, forte isolation entre instances…).
Firecracker a un overhead minimal et permet de faire tourner un grand nombre de micro-VMs sur la même machine hôte. Il utilise KVM pour faire fonctionner ces micro-VMs.

Source : Firecracker

En tant que tel, Firecracker n’a pas grand chose à faire dans un article sur les runtimes OCI, mais combiné à d’autres technologies, il permet de bénéficier des technologies de virtualisation pour l’isolation tout en gardant de très bonnes performances. Il est donc complémentaire d’un sandbox runtime.

Comme nous l’avons vu précédemment, Firecracker est compatible (sous conditions) avec Kata containers en plus de pouvoir être utilisé avec Containerd.

Conclusion

Les runtimes natifs utilisant les technologies fournis par le kernel comme runC et Crun peuvent ne pas être suffisant, dans certaines conditions, pour assurer une isolation suffisante des conteneurs.

Dans ce cas d’autres technologies peuvent être utilisées comme les sandbox runtimes, les plus matures étant gVisor et Kata containers. Ils permettent une meilleure isolation des conteneurs au prix d’une performance moindre et d’autres inconvénients selon la solution choisie.

En plus de ces sandbox runtimes, Firecracker permet lui aussi de mieux isoler les conteneurs tout en minimisant l’overhead. Il peut être combiné avec containerd ou Kata containers.

Dans la majorité des cas, les runtimes natifs représentent la solution la plus simple et efficace.

Un sujet vous intéresse ? Une question ? Contactez-nous

Nos adresses

Clermont-Ferrand
9, allée Evariste Galois
63170 Aubière
Tél. 04 73 35 47 51
Paris
21, rue de la banque
75002 Paris
Tél. 01 44 63 53 13
Lyon
52, Quai Rambaud
69002 Lyon