Recommandations pour exécuter Buildah dans un conteneur

Quel est l'intérêt de découpler le runtime du conteneur en composants d'outils distincts ? Ces outils peuvent notamment commencer à être combinés pour se protéger mutuellement.

Recommandations pour exécuter Buildah dans un conteneur

De nombreuses personnes sont attirées par l'idée de créer des images OCI conteneurisées dans Kubernetes ou un système similaire. Disons que nous avons un CI/CD qui collecte constamment des images, alors quelque chose comme Red Hat OpenShift/Kubernetes serait très utile en termes d'équilibrage de charge lors des builds. Jusqu'à récemment, la plupart des gens donnaient simplement aux conteneurs accès à un socket Docker et leur permettaient d'exécuter la commande docker build. Il y a plusieurs années, nous avons montréque c'est très peu sécurisé, en fait, c'est encore pire que de donner root ou sudo sans mot de passe.

C'est pourquoi les gens essaient constamment d'exécuter Buildah dans un conteneur. Bref, nous avons créé exemple comment, à notre avis, est-il préférable d'exécuter Buildah dans un conteneur, et j'ai publié les images correspondantes sur quai.io/buildah. Commençons...

réglage

Ces images sont construites à partir de Dockerfiles, qui se trouvent dans le référentiel Buildah dans le dossier construire une image.
Ici, nous allons regarder version stable de 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 d'OverlayFS, implémenté au niveau du noyau Linux hôte, nous utilisons le programme à l'intérieur du conteneur superposition de fusibles, car actuellement OverlayFS ne peut être monté que si vous lui accordez les autorisations SYS_ADMIN à l'aide des fonctionnalités Linux. Et nous voulons exécuter nos conteneurs Buildah sans aucun privilège root. La superposition de fusibles fonctionne assez rapidement et offre de meilleures performances que le pilote de stockage VFS. Veuillez noter que lors de l'exécution d'un conteneur Buildah qui utilise Fuse, vous devez 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 un stockage supplémentaire. Conteneur/stockage prend en charge le concept de connexion de magasins d'images supplémentaires en lecture seule. Par exemple, vous pouvez configurer une zone de stockage superposée sur une machine, puis utiliser NFS pour monter ce stockage sur une autre machine et utiliser les images de celle-ci sans téléchargement via pull. Nous avons besoin de ce stockage pour pouvoir connecter du stockage d'images de l'hôte en tant que volume 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 demandons au conteneur Buildah de s'exécuter avec l'isolation chroot par défaut. Une isolation supplémentaire n'est pas nécessaire ici, puisque nous travaillons déjà dans un conteneur. Pour que Buildah puisse créer ses propres conteneurs séparés par des espaces de noms, le privilège SYS_ADMIN est requis, ce qui nécessiterait d'assouplir les règles SELinux et SECCOMP du conteneur, ce qui est contraire à notre préférence de construire à partir d'un conteneur sécurisé.

Exécuter Buildah dans un conteneur

Le diagramme d'image du conteneur Buildah discuté ci-dessus vous permet de varier de manière flexible les méthodes de lancement de ces conteneurs.

Vitesse contre sécurité

La sécurité informatique est toujours un compromis entre la vitesse du processus et le niveau de protection qui l'entoure. Cette affirmation est également vraie lors de l'assemblage de conteneurs, nous examinerons donc ci-dessous les options pour un tel compromis.

L'image du conteneur discutée ci-dessus conservera son stockage dans /var/lib/containers. Par conséquent, nous devons monter le contenu dans ce dossier, et la manière dont nous procédons affectera grandement la vitesse de création des images de conteneur.

Considérons trois options.

1 Option. Si une sécurité maximale est requise, pour chaque conteneur, vous pouvez créer votre propre dossier pour les conteneurs/image et le connecter au conteneur via le montage en volume. Et d’ailleurs, placez le répertoire contextuel dans le conteneur lui-même, 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 exécuté dans un tel conteneur a une sécurité maximale : il ne bénéficie d'aucun privilège root pour utiliser les capacités, et toutes les restrictions SECOMP et SELinux s'y appliquent. Un tel conteneur peut même être exécuté avec l'isolation de l'espace de noms utilisateur en ajoutant une option comme —uidmap 0 : 100000 10000 : XNUMX XNUMX.

Performance. Mais les performances ici sont minimes, car toutes les images des registres de conteneurs sont copiées à chaque fois sur l'hôte et la mise en cache ne fonctionne pas du tout. Une fois son travail terminé, le conteneur Buildah doit envoyer l'image au registre et détruire le contenu sur l'hôte. La prochaine fois que l'image du conteneur sera créée, elle devra être à nouveau téléchargée à partir du registre, car à ce moment-là, il n'y aura plus rien sur l'hôte.

2 Option. Si vous avez besoin de performances au niveau Docker, vous pouvez monter le conteneur/stockage 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é. Il s'agit du moyen le moins sécurisé de créer des conteneurs, car il permet au conteneur de modifier le stockage de l'hôte et pourrait potentiellement transmettre à Podman ou CRI-O une image malveillante. De plus, vous devrez désactiver la séparation SELinux afin que les processus du conteneur Buildah puissent interagir avec le stockage sur l'hôte. Notez que cette option est toujours meilleure qu'un socket Docker car le conteneur est verrouillé par les fonctionnalités de sécurité restantes et ne peut pas simplement exécuter un conteneur sur l'hôte.

Performance. Ici, c'est maximum, puisque la mise en cache est pleinement utilisée. Si Podman ou CRI-O ont déjà téléchargé 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 versions ultérieures basées sur cette image pourront également extraire ce dont ils ont besoin du cache. .

3 Option. L'essence de cette méthode est de combiner plusieurs images en un seul projet avec un dossier commun pour les images conteneurs.

# 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, de sorte que toutes les versions ultérieures du projet bénéficient de la mise en cache.

Sécurité. Quelque chose 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 glisser quelque chose de mauvais dans le stockage d'images Podman/CRI-O. En revanche, de par sa conception, un conteneur peut gêner l’assemblage d’autres conteneurs.

Performance. Ici, c'est pire que lors de l'utilisation d'un cache partagé au niveau de l'hôte, puisque vous ne pouvez pas utiliser des images déjà téléchargées à l'aide de Podman/CRI-O. Cependant, une fois que Buildah a téléchargé l'image, celle-ci peut être utilisée dans toutes les versions ultérieures du projet.

Stockage supplémentaire

У conteneurs/stockage Il existe une chose tellement intéressante que les magasins supplémentaires (magasins supplémentaires), grâce auxquels lors du lancement et de la construction de conteneurs, les moteurs de conteneurs peuvent utiliser des magasins d'images externes en mode superposition en lecture seule. Essentiellement, vous pouvez ajouter un ou plusieurs stockages en lecture seule au fichier storage.conf afin que lorsque vous démarrez le conteneur, le moteur du conteneur y recherche l'image souhaitée. De plus, il téléchargera l’image depuis le registre uniquement s’il ne la trouve dans aucun de ces stockages. Le moteur de conteneur ne pourra écrire que sur un stockage inscriptible...

Si vous faites défiler vers le haut et regardez le Dockerfile que nous utilisons pour construire l'image quay.io/buildah/stable, il y a des lignes comme celle-ci :

# 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, indiquant au pilote de stockage d'utiliser « supplémentaires d'images » dans le dossier /var/lib/shared. Et dans la ligne suivante, nous créons un dossier partagé et ajoutons quelques fichiers de verrouillage afin qu'il n'y ait pas d'abus de la part des conteneurs/stockage. Essentiellement, nous créons simplement un magasin d’images de conteneur vide.

Si vous montez des conteneurs/stockage à un niveau supérieur à ce dossier, Buildah pourra utiliser les images.

Revenons maintenant à l'option 2 discutée ci-dessus, lorsque le conteneur Buildah peut lire et écrire dans les conteneurs/stocker sur les hôtes et, par conséquent, a des performances maximales grâce à la mise en cache des images au niveau Podman/CRI-O, mais fournit un minimum de sécurité. puisqu'il peut écrire directement sur le stockage. Ajoutons maintenant du stockage supplémentaire ici 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 le /var/lib/containers/storage de l'hôte est monté sur /var/lib/shared à l'intérieur du conteneur en mode lecture seule. Par conséquent, en travaillant dans un conteneur, Buildah peut utiliser toutes les images précédemment téléchargées à l'aide de Podman/CRI-O (bonjour, vitesse), mais ne peut écrire que sur son propre stockage (bonjour, sécurité). Notez également que cela se fait sans désactiver la séparation SELinux pour le conteneur.

Nuance importante

Vous ne devez en aucun cas supprimer des images du référentiel sous-jacent. Sinon, le conteneur Buildah risque de planter.

Et ce ne sont pas tous les avantages

Les possibilités de stockage supplémentaire ne se limitent pas au scénario ci-dessus. Par exemple, vous pouvez placer toutes les images de conteneurs sur un stockage réseau partagé et y donner accès à tous les conteneurs Buildah. Disons que nous avons des centaines d'images que notre système CI/CD utilise régulièrement pour créer des images de conteneurs. Nous concentrons toutes ces images sur un seul hôte de stockage puis, à l'aide des outils de stockage réseau privilégiés (NFS, Gluster, Ceph, ISCSI, S3...), nous ouvrons l'accès général à ce stockage à tous les nœuds Buildah ou Kubernetes.

Il suffit maintenant de monter ce stockage réseau dans le conteneur Buildah sur /var/lib/shared et c'est tout - les conteneurs Buildah n'ont plus besoin de télécharger d'images via pull. Ainsi, nous abandonnons la phase de pré-population et sommes immédiatement prêts à déployer les conteneurs.

Et bien sûr, cela peut être utilisé dans un système Kubernetes en direct ou une infrastructure de conteneurs pour lancer et exécuter des conteneurs n'importe où sans aucun téléchargement d'images. De plus, le registre de conteneurs, recevant une demande push pour y télécharger une image mise à jour, peut automatiquement envoyer cette image vers un stockage réseau partagé, où elle devient instantanément disponible pour tous les nœuds.

Les images de conteneurs peuvent parfois atteindre plusieurs gigaoctets. La fonctionnalité de stockage supplémentaire vous permet d'éviter de cloner de telles images sur des nœuds et rend le lancement de conteneurs presque instantané.

De plus, nous travaillons actuellement sur une nouvelle fonctionnalité appelée montages de volumes superposés, qui rendra la construction de conteneurs encore plus rapide.

Conclusion

Exécuter Buildah dans un conteneur dans Kubernetes/CRI-O, Podman ou même Docker est réalisable, simple et beaucoup plus sécurisé que d'utiliser docker.socket. Nous avons considérablement augmenté la flexibilité de travail avec les images, afin que vous puissiez les exécuter de différentes manières pour optimiser l'équilibre entre sécurité et performances.

La fonctionnalité de stockage supplémentaire vous permet d'accélérer, voire d'éliminer complètement le téléchargement d'images vers les nœuds.

Source: habr.com

Ajouter un commentaire