Meilleures pratiques pour exécuter Buildah dans un conteneur

Quelle est la beauté de diviser le temps d'exécution des conteneurs en composants instrumentaux séparés? En particulier, le fait que ces outils puissent commencer à se combiner pour se protéger mutuellement.



Beaucoup de gens sont attirés par l'idée de créer des OCI de conteneurs au sein de Kubernetes ou d'un système similaire. Supposons que nous ayons 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 pendant l'assemblage. Jusqu'à récemment, la plupart des gens donnaient simplement aux conteneurs un accès au socket docker et étaient autorisés à exécuter la commande docker build. Nous avons montré il y a plusieurs années que cela est très dangereux, en fait, c'est encore pire que de donner une racine ou un sudo sans mot de passe.

Par conséquent, les gens essaient constamment d'exécuter Buildah dans un conteneur. En bref, nous avons créé un exemple de la façon dont, à notre avis, il est préférable d'exécuter Buildah à l'intérieur du conteneur et de mettre les images appropriées sur quay.io/buildah . Commençons ...

Personnalisation


Ces images sont compilées à partir de Dockerfiles, qui peuvent être trouvées dans le référentiel Buildah dans le dossier buildahimage .
Ici, nous regardons la 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 de l'hôte, nous utilisons le programme fuse-overlay à l'intérieur du conteneur, car pour le moment OverlayFS ne peut être monté que s'il se voit octroyer les privilèges SYS_ADMIN en utilisant les capacités Linux. Et nous voulons exécuter nos conteneurs Buildah sans aucun privilège root. La superposition de fusibles est assez rapide et offre de meilleures performances que le pilote de stockage VFS. Notez que lorsque vous démarrez un conteneur Buildah à l'aide de 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 stockages d'images en lecture seule supplémentaires. Par exemple, vous pouvez configurer la zone de stockage de superposition sur une machine, puis utiliser NFS pour monter ce stockage sur une autre machine et utiliser des images à partir de celle-ci sans téléchargement via pull. Nous avons besoin de ce stockage pour pouvoir connecter une sorte de 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 disons que par défaut, le conteneur Buildah devrait commencer par l'isolement du chroot. Un isolement supplémentaire n'est pas nécessaire ici, car nous travaillons déjà dans le conteneur. Pour que Buildah crée ses propres conteneurs avec séparation des espaces de noms, le privilège SYS_ADMIN est requis, et pour cela, il sera nécessaire d'affaiblir les règles SELinux et SECCOMP pour le conteneur, ce qui contredit notre installation pour construire à partir d'un conteneur sécurisé.

Exécutez Buildah à l'intérieur du conteneur


Le schéma d'image de conteneur Buildah décrit ci-dessus vous permet de varier de manière flexible la façon dont vous exécutez ces conteneurs.

Vitesse vs sécurité


La sécurité informatique est toujours un compromis entre la vitesse du processus et la quantité de protection qui s'enroule autour de lui. Cette déclaration est également vraie lors de l'assemblage de conteneurs, donc ci-dessous, nous examinerons les options pour un tel compromis.

L'image de conteneur discutée ci-dessus conservera son référentiel dans / var / lib / containers. Par conséquent, nous devons monter le contenu dans ce dossier, et la façon dont nous le faisons affectera considérablement la vitesse d'assemblage des images de conteneur.

Prenons trois options.

Option 1. Si une sécurité maximale est requise, alors 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 en plus, 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 

La sécurité Buildah s'exécutant dans un tel conteneur a une sécurité maximale: il ne bénéficie d'aucun privilège root avec les outils de capacités, et toutes les restrictions SECOMP et SELinux s'y appliquent. Un tel conteneur peut même être exécuté avec l'isolement de l'espace de noms d'utilisateurs, en ajoutant une option comme --uidmap 0: 100000: 10000 .

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 à partir du mot «no way». Une fois son travail terminé, le conteneur Buildah doit envoyer l'image au registre et détruire le contenu sur l'hôte. Lorsque l'image de conteneur sera collectée la prochaine fois, elle devra être téléchargée à nouveau à partir du registre, car à ce moment-là, rien ne restera sur l'hôte.

Option 2. Si vous avez besoin de performances de niveau Docker, vous pouvez monter le conteneur / stockage 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 

La sécurité C'est le moyen le moins sûr de créer des conteneurs, car ici le conteneur est autorisé à modifier le stockage sur l'hôte, et il peut potentiellement glisser dans 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. Veuillez noter que cette option est toujours meilleure que la socket Docker, car le conteneur est bloqué par les fonctions de sécurité restantes et ne peut pas simplement récupérer et exécuter n'importe quel conteneur sur l'hôte.

Performance. Ici, c'est maximum, car la mise en cache est entièrement impliquée. Si Podman ou CRI-O a déjà réussi à télécharger l'image souhaitée sur l'hôte, le processus Buildah à l'intérieur du conteneur n'aura pas à la télécharger à nouveau, et les assemblys suivants basés sur cette image pourront également prendre le nécessaire dans le cache.

Option 3. L'essence de cette méthode est de combiner plusieurs images dans un projet avec un dossier partagé 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 démarrages, de sorte que toutes les générations suivantes au sein du projet profitent de la mise en cache.

La 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'image Podman / CRI-O. D'autre part, dans le cadre de son projet, un conteneur peut interférer avec l'assemblage d'autres conteneurs.

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

Stockage supplémentaire


Les conteneurs / stockage ont quelque chose de cool comme des magasins supplémentaires, grâce auxquels les moteurs de conteneurs peuvent utiliser des magasins d'images externes en mode de superposition en lecture seule lors du lancement et de la construction de conteneurs. En fait, vous pouvez ajouter un ou plusieurs stockages en lecture seule au fichier storage.conf afin que, lorsque le conteneur démarre, le moteur de conteneur y recherche l'image souhaitée. De plus, il ne téléchargera l'image du registre que s'il ne la trouve dans aucun de ces référentiels. Le moteur de conteneur ne pourra écrire que sur un stockage accessible en écriture ...

Si vous faites défiler vers le haut et voyez le Dockerfile, que nous utilisons pour construire l'image quay.io/buildah/stable, alors il y a de telles 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 disant au pilote de stockage d'utiliser "additionalimagestores" dans le dossier / var / lib / shared. Et dans la ligne suivante, créez un dossier partagé et ajoutez quelques fichiers de verrouillage afin qu'il n'y ait pas d'abus de conteneurs / stockage. Fondamentalement, nous créons simplement un stockage d'image de conteneur vide.

Si vous montez des conteneurs / stockage au-dessus de ce dossier, Buildah pourra utiliser des images.

Revenons maintenant à l'option 2 discutée ci-dessus, lorsqu'un conteneur Buildah peut lire et écrire dans des conteneurs / stocker sur des hôtes et, par conséquent, a des performances maximales en raison de la mise en cache d'image au niveau Podman / CRI-O, mais donne un minimum de sécurité, car il peut écrire directement en stockage. Et maintenant, nous allons fixer du stockage supplémentaire ici et tirer le meilleur parti de 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 l'hôte / var / lib / containers / storage est monté dans / 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 (salut, vitesse), mais ne peut écrire que dans son propre référentiel (salut, sécurité). Notez également que cela se fait sans désactiver la séparation SELinux pour le conteneur.

Nuance importante


En aucun cas, vous ne devez supprimer des images du stockage sous-jacent. Sinon, le conteneur Buildah peut s'envoler.

Et ce ne sont pas tous les avantages.


Les capacités de stockage supplémentaires ne sont pas limitées au scénario ci-dessus. Par exemple, vous pouvez placer toutes les images de conteneur dans un stockage réseau partagé et donner 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 créer des images de conteneurs. Nous concentrons toutes ces images sur un seul hôte de stockage puis, en utilisant les outils de stockage réseau préférés (NFS, Gluster, Ceph, ISCSI, S3 ...), ouvrons le stockage partagé à tous les nœuds Buildah ou Kubernetes.

Maintenant, il suffit 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 des images via pull. Ainsi, nous jetons la phase de pré-peuplement et sommes immédiatement prêts à déployer les conteneurs.

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

La taille des images de conteneur peut parfois atteindre plusieurs gigaoctets. La fonctionnalité des stockages supplémentaires vous permet de vous passer de clonage de ces images par nœuds et rend le lancement des conteneurs presque instantané.

De plus, nous travaillons actuellement sur une nouvelle fonction de montage de volume de superposition qui rendra l'assemblage des conteneurs encore plus rapide.

Conclusion


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

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

Source: https://habr.com/ru/post/fr470928/


All Articles