Recommandations pour exécuter Buildah à l'intérieur d'un conteneur

Quelle est la beauté de la séparation de l'environnement d'exécution des conteneurs en composants distincts ? En particulier, c'est que ces outils peuvent être combinés pour se protéger mutuellement.

Recommandations pour exécuter Buildah à l'intérieur d'un conteneur

Beaucoup sont attirés par l'idée de construire des images OCI pour conteneurs dans le cadre de Kubernetes ou d'un système similaire. Supposons que nous ayons un CI/CD qui construit en permanence des images, alors quelque chose comme Red Hat OpenShift/Kubernetes было бы весьма полезно с точки зрения распределения нагрузки при сборке. До недавних пор большинство людей просто давали контейнерам доступ к Docker-сокету и разрешали выполнять команду docker build. Nous avons déjà montré il y a quelques années, que ce n'est pas très sûr, en fait, c'est même pire que de donner un accès root sans mot de passe ou sudo.

C'est pourquoi les gens essaient constamment de faire fonctionner Buildah dans un conteneur. En résumé, nous avons créé exemple une manière, selon nous, de mieux exécuter Buildah à l'intérieur d'un conteneur, et nous avons mis les images correspondantes sur quay.io/buildah. Commençons…

Configuration

Ces images sont construites à partir de Dockerfiles que vous pouvez trouver dans le dépôt Buildah dans le dossier buildahimage.
Ici, nous allons examiner la version stable du Dockerfile.

# stable/Dockerfile
#
# Build a Buildah container image from the latest
# stable version of Buildah on the Fedoras Updates System.
# https://bodhi.fedoraproject.org/updates/?search=buildah
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM fedora:latest

# Don't include container-selinux and remove
# directories used by dnf that are just taking
# up space.
RUN yum -y install buildah fuse-overlayfs --exclude container-selinux; rm -rf /var/cache /var/log/dnf* /var/log/yum.*

# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf

Au lieu de OverlayFS, qui est implémenté au niveau du noyau Linux hôte, nous utilisons dans le conteneur le programme fuse-overlay, car pour l'instant, OverlayFS ne peut monter que si on lui donne les privilèges SYS_ADMIN par le biais des capacités Linux. Et nous voulons exécuter nos conteneurs Buildah sans aucun droit de root. Fuse-overlay fonctionne assez rapidement et offre de meilleures performances que le pilote de stockage VFS. Notez que lorsqu'on exécute un conteneur Buildah utilisant Fuse, il est nécessaire de fournir le périphérique /dev/fuse.

podman run --device /dev/fuse quay.io/buildahctr ...
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock

Ensuite, nous créons un répertoire pour les stockages supplémentaires. Container/storage supporte le concept de montage de stockages supplémentaires en lecture seule pour les images. Par exemple, on peut configurer un espace de stockage overlay sur une machine, puis le monter sur une autre machine via NFS et utiliser des images sans les télécharger par pull. Nous avons besoin de ce stockage pour pouvoir connecter en tant que volume un répertoire de stockage d'images depuis l'hôte et l'utiliser à l'intérieur du conteneur.

# Set up environment variables to note that this is
# not starting with user namespace and default to
# isolate the filesystem with chroot.
ENV _BUILDAH_STARTED_IN_USERNS="" BUILDAH_ISOLATION=chroot

Enfin, en utilisant la variable d'environnement BUILDAH_ISOLATION, nous indiquons que par défaut, le conteneur Buildah doit être exécuté avec l'isolation chroot. Une isolation supplémentaire n'est pas nécessaire ici, car nous travaillons déjà dans un conteneur. Pour que Buildah crée ses propres conteneurs avec séparation des espaces de noms, le privilège SYS_ADMIN est requis, ce qui nécessite de relâcher les règles SELinux et SECCOMP pour le conteneur, ce qui va à l'encontre de notre installation visant à effectuer la construction à partir d'un conteneur sécurisé.

Exécuter Buildah dans un conteneur

Le schéma de conteneur Buildah examiné ci-dessus permet de varier de manière flexible les méthodes de lancement de tels conteneurs.

Vitesse vs sécurité

La sécurité informatique est toujours un compromis entre la vitesse d'exécution d'un processus et le niveau de protection supplémentaire entourant ce processus. Cet énoncé est également vrai lors de la construction de conteneurs, c'est pourquoi nous examinerons ci-dessous les options pour ce compromis.

Le conteneur d'image examiné ci-dessus maintiendra son stockage dans /var/lib/containers. Par conséquent, nous devons monter le contenu dans ce dossier, et la manière dont nous le ferons aura un impact significatif sur la vitesse de construction des images de conteneurs.

Examinons trois options.

Option 1. Si une sécurité maximale est requise, il est possible de créer un dossier pour chaque conteneur pour containers/image et de le connecter au conteneur via volume-mount. De plus, placer le répertoire contextuel directement dans le conteneur, dans le dossier /build :

# mkdir /var/lib/containers1
# podman run -v ./build:/build:z -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable
buildah  -t image1 bud /build
# podman run -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable buildah  push  image1 registry.company.com/myuser
# rm -rf /var/lib/containers1

Sécurité. Buildah fonctionnant dans un tel conteneur a une sécurité maximale : il ne reçoit aucun privilège root par le biais des capabilities, et toutes les restrictions SECOMP et SELinux lui sont appliquées. Ce conteneur peut même être exécuté avec l'isolation User Namespace, en ajoutant une option comme —uidmap 0:100000:10000.

Performance. Cependant, la performance ici est minimale, car toutes les images des registres de conteneurs sont chaque fois copiées sur l'hôte, et le cache ne fonctionne pas du tout. En terminant son travail, le conteneur Buildah doit envoyer l'image au registre et supprimer le contenu sur l'hôte. Lorsque l'image du conteneur sera reconstruite la prochaine fois, elle devra être retéléchargée depuis le registre, car à ce moment-là, il ne restera plus rien sur l'hôte.

Option 2. Si une performance équivalente à celle de Docker est nécessaire, il est possible de monter container/storage de l'hôte directement dans le conteneur.

# podman run -v ./build:/build:z -v /var/lib/containers:/var/lib/containers --security-opt label:disabled quay.io/buildah/stable buildah  -t image2 bud /build
# podman run -v /var/lib/containers:/var/lib/containers --security-opt label:disabled  quay.io/buildah/stable buildah push image2 registry.company.com/myuser

Sécurité. C'est la méthode de construction de conteneurs la moins sécurisée, car ici le conteneur est autorisé à modifier le stockage sur l'hôte, et potentiellement il pourrait injecter une image malveillante à Podman ou CRI-O. De plus, il faudra désactiver la séparation SELinux pour que les processus à l'intérieur du conteneur Buildah puissent interagir avec le stockage sur l'hôte. Notez que cette option reste néanmoins préférable au socket Docker, car le conteneur est protégé par les autres fonctions de sécurité et ne peut pas simplement exécuter un conteneur sur l'hôte.

Performance. Ici, elle est maximale, car le cache est complètement utilisé. Si Podman ou CRI-O ont déjà réussi à télécharger l'image requise sur l'hôte, le processus Buildah à l'intérieur du conteneur n'aura pas besoin de la télécharger à nouveau, et les constructions ultérieures basées sur cette image pourront également tirer ce qui est nécessaire du cache.

Option 3. Le principe de cette méthode est de combiner plusieurs images en un seul projet avec un dossier commun pour les images de conteneur.

# mkdir /var/lib/project3
# podman run --security-opt label_level=s0:C100, C200 -v ./build:/build:z 
-v /var/lib/project3:/var/lib/containers:Z quay.io/buildah/stable buildah  -t image3 bud /build
# podman run --security-opt label_level=s0:C100, C200 
-v /var/lib/project3:/var/lib/containers quay.io/buildah/stable buildah push image3  registry.company.com/myuser

Dans cet exemple, nous ne supprimons pas le dossier du projet (/var/lib/project3) entre les exécutions, donc toutes les constructions ultérieures dans le cadre du projet bénéficient des avantages du cache.

Sécurité. Quelque part entre les options 1 et 2. D'une part, les conteneurs n'ont pas accès au contenu sur l'hôte et, par conséquent, ne peuvent pas injecter quelque chose de malveillant dans le stockage des images Podman/CRI-O. D'autre part, dans le cadre de son projet, un conteneur peut interférer avec la construction d'autres conteneurs.

Performance. Ici, elle est moins bonne que lors de l'utilisation d'un cache partagé au niveau de l'hôte, car il n'est pas possible d'utiliser des images déjà téléchargées auparavant par Podman/CRI-O. Cependant, une fois que Buildah a téléchargé l'image, cette image peut être utilisée dans toutes les constructions ultérieures dans le cadre du projet.

Dépôts supplémentaires

Il y a containers/storage Il existe quelque chose de vraiment cool, comme les magasins supplémentaires (additional stores), qui permettent aux moteurs de conteneurs d'utiliser des magasins d'images externes en mode lecture seule lors du démarrage et de l'assemblage des conteneurs. En gros, dans le fichier storage.conf, on peut ajouter un ou plusieurs magasins « seulement en lecture », afin que lors du démarrage du conteneur, le moteur de conteneur recherche l'image nécessaire dans ceux-ci. Il téléchargera l'image depuis le registre uniquement s'il ne la trouve dans aucun de ces magasins. Le moteur de conteneur pourra écrire uniquement dans les magasins accessibles en écriture...

Si vous faites défiler vers le haut et examinez le Dockerfile que nous utilisons pour construire l'image quay.io/buildah/stable, vous remarquerez ces lignes :

# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock

Dans la première ligne, nous modifions /etc/containers/storage.conf à l'intérieur de l'image du conteneur, en indiquant au driver de stockage d'utiliser "additionalimagestores" dans le dossier /var/lib/shared. Dans la ligne suivante, nous créons un dossier partagé et ajoutons quelques fichiers de verrouillage afin d'éviter les conflits avec containers/storage. En gros, nous créons simplement un magasin d'images de conteneurs vide.

Si nous montons containers/storage un niveau au-dessus de ce dossier, Buildah pourra utiliser les images.

Revenons maintenant à l'Option 2 considérée ci-dessus, où le conteneur Buildah peut lire et écrire dans containers/store sur les hôtes et, par conséquent, a des performances maximales grâce à la mise en cache des images au niveau de Podman/CRI-O, mais offre un minimum de sécurité, car il peut écrire directement dans les magasins. Ajoutons maintenant des magasins supplémentaires et obtenons le meilleur des deux mondes.

# mkdir /var/lib/containers4
# podman run -v ./build:/build:z -v /var/lib/containers/storage:/var/lib/shared:ro -v  /var/lib/containers4:/var/lib/containers:Z  quay.io/buildah/stable 
 buildah  -t image4 bud /build
# podman run -v /var/lib/containers/storage:/var/lib/shared:ro  
-v >/var/lib/containers4:/var/lib/containers:Z quay.io/buildah/stable buildah push image4  registry.company.com/myuser
# rm -rf /var/lib/continers4

Notez que /var/lib/containers/storage de l'hôte est monté dans /var/lib/shared à l'intérieur du conteneur en mode lecture seule. Par conséquent, tout en travaillant dans le conteneur, Buildah peut utiliser toutes les images qui avaient déjà été téléchargées par Podman/CRI-O (bonjour, vitesse), mais peut écrire uniquement dans son propre magasin (bonjour, sécurité). Notez également que cela se fait sans désactiver la séparation SELinux pour le conteneur.

Point important

Il ne faut en aucun cas supprimer des images du magasin sous-jacent. Sinon, le conteneur Buildah pourrait se crasher.

Et ce n'est pas là tous les avantages

Les capacités de stockage additionnel ne se limitent pas seulement au scénario décrit ci-dessus. Par exemple, il est possible de placer toutes les images de conteneurs dans un espace de stockage réseau partagé et d'en donner l'accès à tous les conteneurs Buildah. Supposons que nous ayons des centaines d'images que notre système CI/CD utilise régulièrement pour construire des images de conteneurs. Nous centralisons toutes ces images sur un seul hôte de stockage, puis, en utilisant les moyens de stockage en réseau préférés (NFS, Gluster, Ceph, ISCSI, S3…), nous ouvrons l'accès à ce stockage à tous les nœuds Buildah ou Kubernetes.

Il suffit maintenant de monter cet espace de stockage en réseau dans le conteneur Buildah à /var/lib/shared et c'est tout – les conteneurs Buildah n'auront plus besoin de télécharger les images via pull. Ainsi, nous éliminons la phase de pré-remplissage (pre-population) et sommes immédiatement prêts à déployer les conteneurs.

Et bien sûr, cela peut être utilisé dans le cadre d'un système Kubernetes ou d'une infrastructure de conteneurs existante, pour exécuter et faire fonctionner des conteneurs partout sans aucun téléchargement d'images via pull. De plus, un registre de conteneurs, recevant une requête push pour y télécharger une image mise à jour, peut automatiquement envoyer cette image dans un espace de stockage réseau commun, où elle devient instantanément accessible à tous les nœuds.

Les tailles des images de conteneurs peuvent parfois atteindre plusieurs gigaoctets. La fonctionnalité des stockages additionnels permet d'éviter le clonage de telles images sur les nœuds et rend le démarrage des conteneurs pratiquement instantané.

De plus, nous travaillons actuellement sur une nouvelle fonction de montage de volumes overlay, qui rendra la construction des conteneurs encore plus rapide.

Conclusion

Exécuter Buildah à l'intérieur d'un conteneur dans un environnement Kubernetes/CRI-O, Podman ou même Docker est tout à fait réalisable, et en plus, c'est simple et beaucoup plus sécurisé que d'utiliser docker.socket. Nous avons considérablement amélioré la flexibilité de travail avec les images, et maintenant vous pouvez les exécuter de différentes manières pour un équilibre optimal entre sécurité et performances.

La fonctionnalité des stockages additionnels permet d'accélérer ou même d'éliminer complètement le téléchargement d'images sur les nœuds.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster