QEMU : Utiliser des conteneurs avec une architecture a priori incompatible avec l'hôte

Saviez-vous que l’utilisation conjointe de Docker et QEMU permet d’utiliser par exemple un conteneur ARMv7 sur un hôte x86-AMD64 de manière (presque) totalement transparente ? Non vous ne rêvez pas, c’est même très simple à mettre en place !

Question:

Architecture x86, ARM ? Quèsaco ?

Ces noms d’architecture représentent la manière dont sont conçus et fonctionnent les microprocesseurs. La famille x86 est la plus répandue dans le monde des PC et des serveurs, il s’agit de l’ensemble des processeurs conçus par Intel et AMD, privilégiant la puissance de calcul. La famille ARM, développée par l’entreprise éponyme, privilégie l’efficacité énergétique ; elle équipe votre smartphone, les Raspberry Pi, et la plupart des objets connectés. Il existe plein d’autres architectures, comme MIPS, AVR, Risc-V… Un programme compilé pour une famille d’architecture ne fonctionnera directement sur aucune autre famille.

C’est là qu’intervient QEMU : QEMU est un logiciel libre et open-source qui permet d’émuler le comportement de n’importe quel architecture de microprocesseur, pour un programme conçu pour un système Linux ou BSD.

Question:

Mais pourquoi aurait-on besoin de mélanger ces architectures ?

Il y a plusieurs cas d’utilisation où il est utile émuler un microprocesseur différent de celui de la machine hôte, notamment durant des phases de développement ou de test d’un programme. Imaginez que vous développez un gros logiciel compilé pour des Raspberry Pi, architecture ARMv7, mais que votre poste de travail est équipé d’un microprocesseur x86-AMD64. Il y a alors 4 manières de compiler ce programme :

  • Compiler depuis une Raspberry Pi : cette solution fonctionne pour des petits projets, mais montre rapidement ses limites en matières de ressources matérielles disponibles (surtout la RAM), et est en général la plus lente des 4 solutions ;
  • Compiler depuis le poste de travail, avec un compilateur adapté : c’est la solution idéale sur le papier, mais plus le projet est complexe, possède de dépendances, plus cette solution est compliquée à mettre en place ;
  • Compiler depuis un serveur ARM puissant dans le «cloud» : cette solution est simple à mettre en place, mais ce n’est pas très courant d’avoir un tel serveur sous la main ;
  • Compiler depuis un OS Linux ARM émulé sur le poste de travail : cette solution permet la même flexibilité qu’un serveur ARM, c’est celle qui sera détaillée ci-dessous.

Question:

Mais alors, pourquoi cette dernière solution n’est-elle pas très courante ?

La possibilité d’exécuter un jeu d’instructions pour un microprocesseur différent vient avec une contrepartie : la performance qui devient mauvaise par rapport à la puissance de calcul du microprocesseur hôte. En effet, il est rarement possible de directement traduire une instruction d’une architecture A vers une instruction de l’architecture B, et c’est encore plus vrai entre ARM (dit RISC, jeu d’instructions restreint au minimum, moins d’une soixantaine en général) et x86 (dit CISC, jeu de plusieurs centaines d’instructions complexes). Le résultat c’est que pour exécuter une seule instruction de l’architecture A, il faut plusieurs instructions de l’architecture B (sélectionner la bonne suite d’instruction à exécuter, modifier la représentation des données si besoin, etc), pour un «coût» en cycle de calcul très supérieur ; ainsi, l’émulation a un impact très significatif sur la vitesse d’exécution.

Note:

À titre d’exemple, voici des performances mesurée pour la compilation de l’ IA des robots d’UTCoupe en 2019, utilisant un très gros outil C++ pour la robotique :

  1. ~40 secondes de compilation sur une machine possédant un Intel i7 haute-performance, avec 8 threads (files d’exécution parallèle);
  2. ~15 minutes depuis une Raspberry Pi 3, avec 1 thread (il n’y a pas assez de RAM pour utiliser plus de thread) ;
  3. ~5 minutes depuis le même PC avec le CPU Intel, avec 8 threads et QEMU+Docker.

  • technique/docker/general/quemu_cross_running.1602757703.txt.gz
  • de gblond