Linee guida per l'esecuzione di Buildah all'interno di un contenitore

Qual è il vantaggio di separare il runtime del contenitore in componenti dello strumento separati? In particolare, il fatto che questi strumenti possano iniziare a essere combinati in modo da proteggersi a vicenda.

Linee guida per l'esecuzione di Buildah all'interno di un contenitore

Molte persone sono attratte dall'idea di creare immagini di contenitori OCI all'interno kubernetes o sistema simile. Supponiamo di avere un CI / CD che costruisce costantemente immagini, quindi qualcosa del genere Red Hat OpenShift/Kubernetes sarebbe molto utile in termini di bilanciamento del carico di compilazione. Fino a poco tempo fa, la maggior parte delle persone concedeva semplicemente ai container l'accesso a un socket Docker e consentiva loro di eseguire il comando docker build. Abbiamo mostrato alcuni anni fache questo è molto insicuro, infatti, è anche peggio che fornire root senza password o sudo.

Quindi le persone cercano costantemente di eseguire Buildah in un container. Insomma, abbiamo creato esempio come, a nostro avviso, è meglio eseguire Buildah all'interno di un contenitore e postare le immagini corrispondenti su quay.io/buildah. Iniziamo...

registrazione

Queste immagini sono create da Dockerfiles, che si trova nel repository Buildah nella cartella buildahimmagine.
Qui considereremo versione stabile di 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

Invece di OverlayFS implementato a livello del kernel Linux dell'host, utilizziamo il programma all'interno del contenitore sovrapposizione di fusibili, perché attualmente OverlayFS può essere montato solo se gli si assegnano le autorizzazioni SYS_ADMIN tramite le funzionalità di Linux. E vogliamo eseguire i nostri contenitori Buildah senza alcun privilegio di root. Fuse-overlay è piuttosto veloce e offre prestazioni migliori rispetto al driver di archiviazione VFS. Si noti che quando si esegue un contenitore Buildah utilizzando Fuse, è necessario fornire il dispositivo /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

Successivamente, creiamo una directory per repository aggiuntivi. contenitore/deposito supporta il concetto di collegamento di ulteriori repository di immagini di sola lettura. Ad esempio, è possibile configurare un'area di archiviazione sovrapposta su una macchina, quindi utilizzare NFS per montare questa archiviazione su un'altra macchina e utilizzare le immagini da essa senza scaricare tramite pull. Abbiamo bisogno di questo spazio di archiviazione per poter connettere alcuni archivi di immagini dall'host come volume e utilizzarli all'interno del contenitore.

# 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

Infine, utilizziamo la variabile d'ambiente BUILDAH_ISOLATION per indicare al contenitore Buildah di iniziare con l'isolamento chroot per impostazione predefinita. Qui non è richiesto un ulteriore isolamento, poiché stiamo già lavorando in un container. Affinché Buildah possa creare i propri contenitori separati dallo spazio dei nomi, è necessario il privilegio SYS_ADMIN, che richiederebbe l'allentamento delle regole SELinux e SECCOMP del contenitore, che sarebbero in conflitto con la nostra configurazione per compilare da un contenitore sicuro.

Esegui Buildah all'interno di un contenitore

Lo schema dell'immagine del contenitore Buildah discusso sopra consente di variare in modo flessibile il modo in cui tali contenitori vengono lanciati.

Velocità contro sicurezza

La sicurezza informatica è sempre un compromesso tra la velocità di un processo e la quantità di protezione che lo circonda. Questa affermazione è vera anche quando si assemblano contenitori, quindi di seguito considereremo le opzioni per un tale compromesso.

L'immagine del contenitore discussa sopra manterrà la sua memoria in /var/lib/containers. Pertanto, dobbiamo montare il contenuto in questa cartella e il modo in cui lo facciamo influirà notevolmente sulla velocità di creazione delle immagini del contenitore.

Consideriamo tre opzioni.

Opzione 1. Se è richiesta la massima sicurezza, per ogni contenitore è possibile creare la propria cartella per contenitori/immagine e collegarla al contenitore tramite il montaggio del volume. Inoltre, posiziona la directory di contesto nel contenitore stesso, nella cartella /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

Sicurezza. Un Buildah in esecuzione in un contenitore di questo tipo ha la massima sicurezza: non gli vengono assegnati privilegi di root dalle funzionalità e ad esso si applicano tutte le restrizioni SECOMP e SELinux.Un tale contenitore può anche essere eseguito con l'isolamento dello spazio dei nomi utente aggiungendo un'opzione come --uidmap 0:100000:10000.

Prestazioni. Ma le prestazioni qui sono minime, poiché tutte le immagini dai registri dei contenitori vengono copiate ogni volta sull'host e la memorizzazione nella cache non funziona dalla parola "assolutamente no". Al termine del suo lavoro, il contenitore Buildah deve inviare l'immagine al registro e distruggere il contenuto sull'host. La prossima volta che l'immagine del contenitore verrà creata, dovrà essere scaricata nuovamente dal registro, poiché a quel punto non rimarrà nulla sull'host.

Opzione 2. Se hai bisogno di prestazioni a livello di Docker, puoi montare il contenitore/spazio di archiviazione dell'host direttamente nel contenitore.

# 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

Sicurezza. Questo è il modo meno sicuro per creare contenitori, in quanto consente al contenitore di modificare l'archiviazione sull'host e potrebbe potenzialmente inserire un'immagine dannosa in Podman o CRI-O. Inoltre, sarà necessario disabilitare la separazione di SELinux in modo che i processi nel contenitore Buildah possano interagire con il repository sull'host. Tieni presente che questa opzione è ancora migliore di un socket Docker, poiché il contenitore è bloccato dalle funzionalità di sicurezza rimanenti e non può semplicemente prelevare ed eseguire alcun contenitore sull'host.

Prestazioni. Qui è massimo, poiché la memorizzazione nella cache è completamente coinvolta. Se Podman o CRI-O hanno già scaricato l'immagine desiderata sull'host, il processo Buildah all'interno del contenitore non dovrà scaricarla nuovamente e anche le build successive basate su questa immagine potranno prelevare quella necessaria dalla cache .

Opzione 3. L'essenza di questo metodo è combinare diverse immagini in un progetto con una cartella comune per le immagini del contenitore.

# 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

In questo esempio, non eliminiamo la cartella del progetto (/var/lib/project3) tra le esecuzioni, quindi tutte le build successive all'interno del progetto sfruttano la memorizzazione nella cache.

Sicurezza. Qualcosa tra le opzioni 1 e 2. Da un lato, i contenitori non hanno accesso ai contenuti sull'host e, di conseguenza, non possono inserire qualcosa di brutto nell'archivio immagini Podman / CRI-O. D'altra parte, all'interno del proprio progetto, un contenitore può interferire con l'assemblaggio di altri contenitori.

Prestazioni. Qui è peggio che utilizzare una cache condivisa a livello di host, poiché non è possibile utilizzare immagini che sono già state scaricate utilizzando Podman / CRI-O. Tuttavia, una volta che Buildah ha scaricato l'immagine, quell'immagine può essere utilizzata in qualsiasi build successiva all'interno del progetto.

Spazio di archiviazione aggiuntivo

У contenitori/stoccaggio c'è una cosa così interessante come negozi aggiuntivi (negozi aggiuntivi), grazie ai quali, quando si avviano e si creano container, i motori container possono utilizzare archivi di immagini esterni in modalità overlay di sola lettura. Infatti, puoi aggiungere uno o più archivi di sola lettura al file storage.conf, in modo che all'avvio del contenitore, il motore del contenitore cercherà al loro interno l'immagine desiderata. Inoltre, scaricherà l'immagine dal registro solo se non la trova in nessuno di questi archivi. Il motore del contenitore sarà in grado di scrivere solo nell'archivio scrivibile...

Se scorriamo verso l'alto e guardiamo il Dockerfile che usiamo per creare l'immagine quay.io/buildah/stable, ci sono righe come questa:

# 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

Nella prima riga, modifichiamo /etc/containers/storage.conf all'interno dell'immagine del contenitore, dicendo al driver di archiviazione di utilizzare "additionalimagestores" nella cartella /var/lib/shared. E nella riga successiva, creiamo una cartella condivisa e aggiungiamo un paio di file di blocco in modo che non vi siano abusi da contenitori/archiviazione. In sostanza, stiamo solo creando un archivio di immagini contenitore vuoto.

Se monti container/archiviazione un livello sopra questa cartella, Buildah sarà in grado di utilizzare le immagini.

Torniamo ora all'opzione 2 discussa sopra, quando il contenitore Buildah può leggere e scrivere su contenitori / archiviare su host e, di conseguenza, ha le massime prestazioni grazie alla memorizzazione nella cache delle immagini a livello di Podman / CRI-O, ma offre un minimo di sicurezza, poiché può scrivere direttamente in memoria. E ora aggiungeremo ulteriore spazio di archiviazione qui e otterremo il meglio da entrambi i mondi.

# 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

Si noti che /var/lib/containers/storage dell'host è montato su /var/lib/shared all'interno del contenitore in modalità di sola lettura. Pertanto, lavorando in un contenitore, Buildah può utilizzare qualsiasi immagine che sia già stata scaricata utilizzando Podman / CRI-O (ciao, velocità), ma può scrivere solo nel proprio archivio (ciao, sicurezza). Si noti inoltre che questo viene fatto senza disabilitare la separazione SELinux per il contenitore.

Sfumatura importante

In nessun caso le immagini devono essere eliminate dal repository sottostante. In caso contrario, il contenitore Buildah potrebbe bloccarsi.

E non sono tutti i vantaggi.

Le possibilità di spazio di archiviazione aggiuntivo non sono limitate allo scenario di cui sopra. Ad esempio, puoi posizionare tutte le immagini del contenitore in un archivio di rete condiviso e concedere l'accesso a tutti i contenitori Buildah. Supponiamo di avere centinaia di immagini che il nostro sistema CI/CD utilizza regolarmente per creare immagini containerizzate. Concentriamo tutte queste immagini su un singolo storage host e quindi, utilizzando gli strumenti di storage di rete preferiti (NFS, Gluster, Ceph, iSCSI, S3...), condividiamo questo storage con tutti i nodi Buildah o Kubernetes.

Ora è sufficiente montare questo archivio di rete nel contenitore Buildah su /var/lib/shared e il gioco è fatto: i contenitori Buildah non devono più scaricare le immagini tramite pull. Quindi, eliminiamo la fase di prepopolamento e siamo subito pronti a srotolare i container.

E, naturalmente, questo può essere utilizzato all'interno di un sistema Kubernetes live o di un'infrastruttura di container per avviare ed eseguire container ovunque senza alcun pull di immagini. Inoltre, quando un registro contenitori riceve una richiesta push per caricare un'immagine aggiornata, può inviare automaticamente questa immagine a uno storage di rete condiviso, dove è immediatamente disponibile per tutti i nodi.

Le immagini del contenitore a volte possono avere dimensioni di molti gigabyte. La funzionalità di archivi aggiuntivi elimina la necessità di clonare tali immagini per nodi e rende il lancio dei contenitori quasi istantaneo.

Inoltre, stiamo attualmente lavorando a una nuova funzione di montaggio del volume in sovrapposizione che renderà la costruzione dei container ancora più veloce.

conclusione

L'esecuzione di Buildah all'interno di un container in un ambiente Kubernetes/CRI-O, Podman o persino Docker è del tutto possibile ed è semplice e molto più sicura rispetto all'utilizzo di docker.socket. Abbiamo notevolmente aumentato la flessibilità di lavorare con le immagini e ora puoi eseguirle in vari modi per il miglior equilibrio tra sicurezza e prestazioni.

La funzionalità di archivi aggiuntivi consente di velocizzare o addirittura eliminare completamente il download delle immagini sui nodi.

Fonte: habr.com

Aggiungi un commento