1 points par GN⁺ 2023-10-24 | 1 commentaires | Partager sur WhatsApp
  • Lors de la Hackweek 22 de SUSE, un POC d’un unikernel capable d’exécuter des modules WebAssembly a été réalisé, et son implémentation est présentée en plusieurs parties
  • Pour porter directement une application classique sur un unikernel, il faut aussi faire correspondre ses dépendances, mais une plateforme WebAssembly définit beaucoup plus clairement la frontière des fonctionnalités que le runtime doit fournir
  • Une application Spiderlightning ne demande que des fonctionnalités comme le Key/Value, et que l’hôte l’implémente avec Redis ou Azure Cosmos DB, le même module .wasm n’a pas besoin de connaître la différence
  • La base retenue est l’unikernel Rust RustyHermit ; comme Wasmtime et Wasmer ne se compilaient pas, le choix s’est porté sur wasmi, un runtime 100 % Rust
  • Après avoir ajouté la prise en charge de wasmi à wit-bindgen pour s’aligner sur le Component Model et WIT, les fonctionnalités Key/Value côté hôte ont été scaffoldées afin d’exécuter keyvalue-demo

Projet Hackweek et objectifs

  • Pendant la Hackweek 22 de SUSE, le projet Build a unikernel that runs WebAssembly a été mené
  • L’implémentation complète était trop longue pour tenir dans un seul article, elle a donc été découpée en plusieurs billets, et celui-ci en est la première partie
  • Le code du POC est publié à part, mais aucun lien URL effectif n’est fourni dans le texte source

Pourquoi utiliser ensemble unikernels et WebAssembly

  • Pour un développeur d’applications, le portage vers un unikernel représente une lourde contrainte
    • L’application et toutes ses dépendances doivent être compatibles avec l’unikernel cible
    • Des correctifs peuvent être nécessaires dans toute la pile applicative
  • De leur côté, les mainteneurs d’unikernels doivent aussi dépenser beaucoup d’énergie pour permettre l’exécution fluide d’applications arbitraires
    • Parce qu’il est difficile de prédire quels primitives système utiliseront les applications des utilisateurs
  • À l’inverse, viser des plateformes WebAssembly comme Spin ou Spiderlightning clarifie l’ensemble de fonctionnalités que le runtime doit fournir
  • Dans un scénario Spiderlightning, l’application peut demander au runtime une fonctionnalité de stockage Key/Value
    • Que l’hôte implémente cette fonctionnalité avec Redis ou avec Azure Cosmos DB, cela reste transparent pour l’application
    • Le même module .wasm peut s’exécuter sur différentes implémentations hôte

Architecture cible

  • Si une application unikernel peut exécuter des modules WebAssembly et prendre en charge l’ensemble d’API Spiderlightning, alors la même application Spiderlightning peut fonctionner aussi bien sur le runtime slight classique que sur cet unikernel
  • Le développeur d’applications n’a rien de plus à faire, et le module Wasm n’a pas besoin de savoir où il s’exécute
  • La complexité est concentrée chez le développeur de l’unikernel, mais le périmètre à implémenter reste bien plus clair que « prendre en charge l’exécution de toutes les applications »

Implémentation sur la base de RustyHermit

  • La base choisie est RustyHermit
    • Il s’agit d’un unikernel écrit en Rust
    • Il est inclus dans Rust nightly, ce qui offre une expérience de développement proche de celle d’une application Rust classique
  • La compilation d’applications RustyHermit est relativement simple
    • La documentation est un peu dispersée, mais de bonne qualité, et les exemples sont très utiles
  • On ne peut pas supposer que tous les crates Rust fonctionneront tels quels sur RustyHermit, et cette contrainte a influencé le développement du POC

Choix du runtime WebAssembly

  • Le runtime préféré, Wasmtime, ne se compile pas sur RustyHermit
    • Beaucoup de dépendances supposent la présence de libc ou d’autres bibliothèques bas niveau
  • wasmer rencontre le même problème
  • WebAssembly Micro Runtime a aussi été envisagé, mais le choix a été fait d’utiliser un runtime écrit en Rust afin de conserver une « expérience RustyHermit complète »
  • Le choix final s’est porté sur wasmi, un runtime WebAssembly 100 % Rust
    • Il fonctionne bien sur RustyHermit
    • Sa conception s’inspire de Wasmtime, ce qui a permis de réutiliser une grande partie des connaissances existantes

WebAssembly Component Model et WIT

  • Spiderlightning utilise la proposition WebAssembly Component Model
    • Pour fournir des fonctionnalités au guest WebAssembly
    • Et pour permettre à l’hôte de consommer les fonctionnalités fournies par le guest WebAssembly
  • La communication entre l’hôte et le guest utilise des types définis avec Wasm Interface Type
  • La démo utilise le Component Model selon le flux suivant
    • Le guest demande à l’hôte de démarrer un serveur HTTP et lui transmet les routes HTTP à enregistrer ainsi que les noms des fonctions de gestion internes
      • Le type http-server est utilisé, et le guest consomme ici une fonctionnalité fournie par l’hôte
    • L’hôte traite les requêtes HTTP entrantes à partir des informations de routage fournies par le guest
      • Le handler HTTP est une fonction exposée par le guest WebAssembly
      • Le serveur consomme une fonctionnalité fournie par le guest et communique via le type http-handler
    • Certains handlers HTTP interagissent avec un stockage Key/Value
      • Dans ce cas également, le guest utilise une fonctionnalité fournie par l’hôte, définie par le type keyvalue

Extension de wit-bindgen et exécution de la démo

  • Pour chaque type WIT, il faut du code côté guest jouant le rôle de SDK, ainsi que du code d’implémentation côté hôte
  • wit-bindgen est un outil CLI qui génère le code hôte/guest à partir de fichiers .wit
  • Dans ce POC, il suffisait d’implémenter uniquement l’interface côté hôte à l’intérieur de l’unikernel
  • Le code généré par wit-bindgen s’appuie sur le runtime WebAssembly pour réaliser les opérations de bas niveau
    • Le code généré dépend donc du langage de programmation et du runtime WebAssembly utilisé côté hôte
  • Comme wasmi n’était pas pris en charge par wit-bindgen, celui-ci a été étendu pour gérer wasmi
  • Ensuite, le code côté hôte pour la fonctionnalité Key/Value a été scaffoldé, puis une implémentation simple du trait hôte a été ajoutée
    • Le code hôte se limitait à afficher des informations de débogage
  • À ce stade, il était possible d’exécuter sans modification keyvalue-demo du projet Spiderlightning

Aperçu de la partie suivante

  • Il existe un enregistrement montrant l’application unikernel exécuter la démo Spiderlightning http-server
  • La partie suivante abordera Rust async, Redis et quelques erreurs étranges

1 commentaires

 
GN⁺ 2023-10-24
Commentaires Hacker News
  • Ça ne vous fait pas immédiatement penser à https://www.destroyallsoftware.com/talks/the-birth-and-death... ?

  • Pour quelqu’un qui n’est pas hacker de systèmes d’exploitation mais qui veut un unikernel, quelle serait l’approche la plus aboutie ?
    Les options qui me viennent à l’esprit sont : transformer l’application en module du noyau Linux et la charger dans un noyau classique en ignorant l’espace utilisateur, réduire drastiquement Linux et y greffer son propre code, partir d’un projet d’unikernel sur GitHub, ou élaguer un autre système d’exploitation comme FreeBSD
    J’aime bien l’idée d’une machine x64 dans une VM connectée à une carte réseau, qui se comporte comme une ressource de calcul généraliste, avec des tâches assignées en envoyant des données par le réseau. Comme c’est plus contraignant qu’un daemon en espace utilisateur, ça n’avait pas encore beaucoup de valeur, mais si j’ai un jour du temps, je me demande par où commencer pour bidouiller au niveau OS

    • Red Hat étudie Linux-as-unikernel depuis 2018 : https://research.redhat.com/blog/article/unikernel-linux-ukl...
      Unikernel Linux (UKL) est parti d’une tentative d’exploiter la configurabilité de Linux, avec pour objectif un noyau couvrant aussi bien les systèmes d’exploitation généralistes que les unikernels spécialisés par application et matériel. io_uring et eBPF sont aussi mentionnés comme domaines liés : io_uring répartit le coût des appels système, tandis qu’eBPF est une autre façon, certes limitée, d’exécuter du code en espace noyau
      Code : https://github.com/unikernelLinux/ukl
      UKL est un petit patch pour Linux et glibc, qui permet de construire de nombreux programmes en unikernels sans modification. Le programme est lié avec le noyau Linux et le vmlinuz final, s’exécute en espace noyau, peut démarrer sur bare metal ou dans une VM, et peut utiliser presque toutes les fonctionnalités et pilotes de Linux
    • Si l’on suppose une base Linux, il suffit d’abord de créer une application compilée statiquement, de la placer comme unique fichier dans un initramfs, de la nommer simplement /init, puis de l’embarquer dans le noyau et de démarrer dessus
      L’app devient alors PID 1 et, en pratique, le seul processus ; à part quelques threads noyau, on peut faire ce qu’on veut
    • Unikraft mérite aussi le détour : https://unikraft.org
      Il prend en charge plusieurs langages et apps, x86/ARM64, QEMU/Firecracker, et peut aussi exécuter en unikernel des ELF construits sous Linux : https://unikraft.org/guides/bincompat
      Le Discord est ici : https://unikraft.org/discord
    • Pour OCaml, il existe le framework MirageOS : https://mirage.io/
      Si vous voulez apprendre OCaml tout en visant un unikernel, c’est une voie possible
    • Il y a essentiellement trois façons de créer un unikernel : minimiser un système d’exploitation généraliste existant, contourner le système d’exploitation, ou partir de zéro
      On trouve plus de détails dans la documentation d’Unikraft : https://unikraft.org/docs/concepts/design-principles#approac...
  • Beau projet. J’aime le fait que WASM ait été conçu dès le départ avec le sandboxing et la portabilité en tête
    J’aurais aimé que WASM existe dans les années 90 à la place de JavaScript, et j’ai l’impression que WASM va tout dévorer. Ce que je souhaite le plus, c’est la pérennité. Il y a aujourd’hui beaucoup de programmes qu’on ne peut plus exécuter, les vieux jeux en étant l’exemple typique. Une spécification simple a davantage de chances de survivre longtemps, donc l’ajout de nouvelles fonctionnalités m’inquiète un peu, mais l’avenir du binaire semble passionnant

    • Aussi difficile que ce soit à croire, dans les années 90, les navigateurs web étaient globalement vus comme des explorateurs de documents hypertexte, pas comme des remplaçants de systèmes d’exploitation
      Ce n’est pas pour rien que JS était au départ limité à du scripting de base, comme les gestionnaires de clics ou la validation de formulaires. S’il est devenu autre chose, ce n’est pas seulement à cause de défauts de conception de JS, mais aussi des usages dans lesquels on l’a forcé à entrer. Utiliser le navigateur comme mécanisme de distribution pour ce genre d’apps est très loin de ce qu’imaginaient Tim Berners-Lee ou Marc Andreesen
      À l’époque, le camp du « réseau est l’ordinateur » proposait des clients X légers pour des apps plus riches : https://en.wikipedia.org/wiki/Network_Computer
      J’ai des sentiments mitigés sur WASM. Pour l’instant, il est entouré d’un grand voile de hype et de nouveauté. Si l’on traite le navigateur web comme un simple viewport pour les fantasmes de langage du moment des designers UI et des développeurs, beaucoup de mauvaises choses arrivent côté accessibilité, lecteurs d’écran, etc.
      La tendance à considérer WASM hors du navigateur comme une VM universelle est aussi une voie déjà empruntée il y a 30 ans. C’était ce que la JVM essayait de faire, mais apparemment ce n’est plus « cool » aujourd’hui
    • Naïvement, j’aimerais que le web se scinde entre des apps WASM sandboxées et du contenu documentaire qui n’aurait même pas besoin de JS
      Je ne sais pas bien à quoi devrait ressembler l’entre-deux, ni pourquoi on devrait le vouloir. Mais, en pratique, WASM risque aussi d’engloutir le contenu documentaire, et alors les bloqueurs de pub et les modes lecture pourraient être fichus
    • Je pense qu’il fallait JavaScript, ou quelque chose de similaire, pour que ça fonctionne. Sinon, l’écosystème aurait probablement été infecté par un truc comme Java
  • J’adore vraiment. Parmi les technologies liées, il y en avait plusieurs que je n’avais jamais vues, donc j’ai tout mis en favoris
    Ensuite, j’aimerais essayer de configurer une connexion WireGuard vers l’hyperviseur. L’établissement de la connexion pourrait aussi passer par quelque chose comme Tailscale
    Ainsi, le WebAssembly de cette machine parlerait directement au WebAssembly de cette autre machine. Ce ne serait pas un processus qui ouvre une connexion TCP vers un emplacement arbitraire, mais une architecture où la communication se fait sur la base de la configuration et des permissions transmises

  • Avec du retard, quelqu’un a-t-il déjà envisagé d’exécuter Zephyr comme unikernel ? https://docs.zephyrproject.org/latest/boards/x86/acrn/doc/in...

  • Combien de temps avant l’arrivée d’un matériel dédié à WASM ?

    • À strictement parler, je pense que ça n’arrivera jamais. Au sens très étroit, parce que WASM n’est pas suffisamment spécifié pour cela
      Cela dit, quelqu’un pourrait créer un truc du genre « en surface c’est du wasm, mais en dessous il y a en réalité du RISC-V »
    • Quelqu’un finira sûrement par le faire. Il y a bien eu des machines Lisp et des CPU dédiés à la JVM
      Mais je pense que ce type de matériel restera toujours une niche. Parce qu’exécuter WASM sur du matériel standard sera généralement plus rapide. WASM lui-même a été conçu pour tourner rapidement sur du matériel standard, et les économies d’échelle des processeurs généralistes sont bien meilleures
      L’International Conference on Functional Programming s’appelait au départ Functional Programming and Computer Architecture, mais on a ensuite trouvé comment compiler efficacement des langages fonctionnels à évaluation paresseuse comme Haskell sur du matériel existant
      C’est pareil pour les machines Lisp et Java. L’une des raisons pour lesquelles on ne voit presque plus ce genre de machines, c’est que la technologie des compilateurs a rattrapé son retard
  • Quels sont les cas d’usage des unikernels et de WASM ?

    • Je ne parlerai pas de WASM. Sinon je risque de passer en mode « les jeunes d’aujourd’hui… »
      À mon sens, la valeur des unikernels tient à 1) la performance : jeter ce qui est inutile et ramener ce qui est nécessaire en « ring 0 » pour grappiller ne serait-ce que quelques cycles, 2) la simplification : la possibilité de réduire la complexité en supprimant les parties inutiles, 3) la sécurité : là encore, la possibilité de modifier la surface d’attaque en réduisant ce qui n’est pas nécessaire
      Cela dit, je ne pense pas que ce soit adapté à la façon dont beaucoup de gens sur ce forum écrivent des microservices ou des applis web. Les usages sont plus proches de la création de composants d’infrastructure, comme des bases de données ou des load balancers
    • Les micro-VM peuvent concurrencer les conteneurs Linux pour certaines tâches, avec l’avantage de ne pas exposer le noyau Linux à du code auquel on fait moins confiance
      C’est pourquoi certains fournisseurs d’edge cloud convertissent les images Docker en micro-VM lorsqu’ils les exécutent
      Cela dit, à l’edge, WASM dans une micro-VM peut avoir du mal à rivaliser avec le WASM sandboxé de l’edge. Du point de vue du fournisseur, ce dernier a probablement plus de facilité à ajouter des fonctions de frontière utiles et des intégrations
    • L’objectif semble être d’élargir les endroits où WASM peut aller. Après le navigateur et les conteneurs Docker, cela inclut désormais jusqu’à des systèmes d’exploitation légers pouvant être déployés sur des appareils embarqués
  • Comme cela avait été « annoncé » il y a longtemps dans Birth & Death of Javascript, l’idée était qu’un jour apparaîtrait un unikernel capable d’exécuter en espace noyau un runtime à garbage collection sûr, ce qui permettrait alors de supprimer du CPU la prise en charge du mapping de mémoire virtuelle pour le rendre plus rapide.
    En 2014, l’auteur pensait à JS et asm.js, mais aujourd’hui WASM semble être cette voie. J’ai hâte, haha
    https://www.destroyallsoftware.com/talks/the-birth-and-death...

    • La logique de la vidéo était que, puisque le navigateur est de toute façon un processus unique et que tout s’exécute dans ce processus, cette séparation n’est pas nécessaire.
      Mais depuis, on a appris qu’un navigateur monoprocessus est un cauchemar de sécurité, et les navigateurs actuels ne sont plus monoprocessus afin de permettre un sandboxing correct.
      Cela dit, il est intéressant de voir à quel point cette vidéo était proche de la bonne réponse, et aussi en quoi elle se trompait.
    • L’évolution de JavaScript/WASM va de la conception pour des applis exécutées dans le navigateur → l’écriture d’apps desktop et serveur → l’écriture de systèmes d’exploitation ou de noyaux.
      C’est difficile à formuler précisément, mais cela a quelque chose de familier. Indice : cela commence aussi par un « J ».
    • JavaStation était un ordinateur en réseau développé par Sun Microsystems entre 1996 et 2000, destiné à n’exécuter que des applications Java.
      https://en.wikipedia.org/wiki/JavaStation
    • La mémoire virtuelle et la pagination ne servent pas seulement à la protection, à la sécurité et à l’isolation des processus. Elles fournissent aussi un ensemble d’abstractions pour l’utilisation efficace de la mémoire physique et la gestion mémoire.
      L’utilisation virtuelle d’un processus peut dépasser son RSS même sans que ce soit dû au swapping, et le système d’exploitation comme l’allocateur travaillent ensemble pour gérer cela assez intelligemment dans les cas courants.
      Il est donc difficile de dire que s’en débarrasser apporterait automatiquement un gain de performance. D’autant plus si l’on passe par une couche de VM WASM assez lente.
      Pour certaines applications, par exemple les bases de données, les exécuter comme unikernel ou les rapprocher davantage du noyau avec un accès direct à la MMU peut être très bénéfique : https://github.com/tuhhosg/exmap & https://github.com/viktorleis/vmcache & https://www.cs.cit.tum.de/fileadmin/w00cfj/dis/_my_direct_up...
      Mais pour des applications générales qui supposent le standard POSIX ou partent du principe que leur environnement d’exécution ressemble à un ordinateur généraliste moderne, j’ai des doutes. Au final, on risque de réécrire en code utilisateur une grande partie de ce que faisait la couche VMM.
    • Supprimer la prise en charge du mapping de mémoire virtuelle a de moins en moins de sens à mesure qu’on y réfléchit.
      Les moteurs JS dépendent du VMM, et WASM aussi de plusieurs façons. Presque tous les programmes non triviaux hors embarqué reposent subtilement sur l’existence du VMM. En particulier, certaines technologies de VM autour des micro-VM utilisent aussi le VMM, et les unikernels n’ont vraiment de sens que lorsqu’ils sont utilisés comme VM.