Raccomandazioni per l'avvio di Buildah all'interno del contenitore

Qual è il vantaggio di suddividere l'ambiente di esecuzione dei container in componenti strumentali separati? In particolare, il fatto che questi strumenti possano essere combinati in modo che si proteggano a vicenda.

Raccomandazioni per l'avvio di Buildah all'interno del contenitore

Molti sono attratti dall'idea di eseguire la costruzione di immagini container OCI nell'ambito di Kubernetes o un sistema simile. Supponiamo di avere un CI/CD che costruisce costantemente immagini, quindi qualcosa come Red Hat OpenShift/Kubernetes было бы весьма полезно с точки зрения распределения нагрузки при сборке. До недавних пор большинство людей просто давали контейнерам доступ к Docker-сокету и разрешали выполнять команду docker build. Abbiamo già mostrato diversi anni fa, che questo è molto insicuro, infatti è anche peggio che fornire accesso root senza password o sudo.

Perciò, le persone cercano costantemente di eseguire Buildah in un container. In breve, abbiamo creato un esempio la nostra visione su come sia meglio eseguire Buildah all'interno di un container e abbiamo pubblicato le relative immagini su quay.io/buildah. Iniziamo…

Configurazione

Queste immagini sono state costruite da Dockerfile, che possono essere trovati nel repository Buildah nella cartella buildahimage.
Qui esamineremo la versione stabile del 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 all'interno del container il programma fuse-overlay, poiché al momento OverlayFS può montare solo se gli vengono concessi privilegi SYS_ADMIN tramite le capacità Linux. E noi vogliamo eseguire i nostri container Buildah senza alcun privilegio di root. Fuse-overlay è abbastanza rapido e offre prestazioni migliori rispetto al driver di archiviazione VFS. Si noti che quando si esegue un container Buildah che utilizza 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 i repository aggiuntivi. Container/storage supporta il concetto di collegamento di repository immagine aggiuntivi in modalità sola lettura. Ad esempio, è possibile configurare un'area di archiviazione overlay su una macchina e poi montarla su un'altra macchina tramite NFS, utilizzando le immagini senza doverle scaricare tramite pull. Questo repository è necessario per poter collegare come volume un repository di immagini dall'host e utilizzarlo all'interno del container.

# 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

E infine, utilizzando la variabile d'ambiente BUILDAH_ISOLATION, diciamo che per impostazione predefinita il contenitore Buildah deve essere eseguito con isolamento chroot. Ulteriore isolamento non è necessario qui, poiché stiamo già lavorando all'interno di un contenitore. Per consentire a Buildah di creare i propri contenitori con separazione degli spazi dei nomi, è necessaria l'autorizzazione SYS_ADMIN, e per questo dovremo allentare le regole SELinux e SECCOMP per il contenitore, il che è contrario alla nostra impostazione di eseguire la build da un contenitore sicuro.

Eseguiamo Buildah all'interno del contenitore

Lo schema del contenitore Buildah sopra esaminato consente di variare in modo flessibile i modi di avviare tali contenitori.

Velocità contro sicurezza

La sicurezza informatica è sempre un compromesso tra la velocità di esecuzione del processo e quanto è protetto intorno ad esso. Questa affermazione è valida anche per la creazione di contenitori, quindi di seguito esamineremo le opzioni per tale compromesso.

Il contenitore d'immagine sopra esaminato conserverà il proprio archivio in /var/lib/containers. Pertanto, dobbiamo montare il contenuto in questa cartella, e il modo in cui lo faremo influenzerà notevolmente la rapidità di costruzione delle immagini dei contenitori.

Consideriamo tre opzioni.

Opzione 1. Se è richiesta la massima sicurezza, è possibile creare una propria cartella per containers/image per ogni contenitore e collegarla al contenitore tramite volume-mount. Inoltre, è possibile posizionare il context directory all'interno dello stesso contenitore, 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. Buildah in esecuzione in questo contenitore ha la massima sicurezza: non gli vengono concesse autorizzazioni root tramite capabilities, e vi si applicano tutte le restrizioni SECOMP e SELinux. Questo contenitore può essere eseguito anche con isolamento User Namespace, aggiungendo un'opzione come —uidmap 0:100000:10000.

Prestazioni. Tuttavia, le prestazioni qui sono minime, poiché ogni immagine dai registri dei contenitori viene copiato ogni volta sull'host, e la cache non funziona affatto. Alla fine del suo lavoro, il contenitore Buildah deve inviare l'immagine al registro e distruggere il contenuto sull'host. Quando l'immagine del contenitore verrà ricostruita la volta successiva, dovrà essere nuovamente scaricata dal registro, poiché a quel punto sull'host non rimarrà nulla.

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

# 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 container, poiché al container è permesso modificare lo storage dell'host e, potenzialmente, potrebbe iniettare un'immagine dannosa in Podman o CRI-O. Inoltre, sarà necessario disabilitare la separazione di SELinux affinché i processi all'interno del container Buildah possano interagire con lo storage dell'host. Si noti che questa opzione è comunque migliore del socket Docker, poiché il container è bloccato dalle altre funzionalità di sicurezza e non può semplicemente avviare un qualsiasi container sull'host.

Prestazioni. In questo caso, è massima, poiché viene utilizzata completamente la cache. Se Podman o CRI-O hanno già scaricato l'immagine necessaria sull'host, il processo Buildah all'interno del container non dovrà scaricarla di nuovo, e le successive costruzioni basate su questa immagine potranno anche prendere ciò che serve dalla cache.

Opzione 3. La sostanza di questo metodo è combinare più immagini in un unico progetto con una cartella comune per le immagini dei container.

# 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 i lanci, quindi tutte le ulteriori costruzioni all'interno del progetto beneficiano della cache.

Sicurezza. È una via di mezzo tra le opzioni 1 e 2. Da un lato, i container non hanno accesso ai contenuti sull'host e, di conseguenza, non possono iniettare nulla di dannoso nello storage delle immagini di Podman/CRI-O. Dall'altro lato, all'interno del proprio progetto, il container può interferire nella costruzione di altri container.

Prestazioni. In questo caso è peggiore rispetto all'utilizzo di una cache comune a livello di host, poiché non è possibile utilizzare immagini già scaricate in precedenza tramite Podman/CRI-O. Tuttavia, una volta che Buildah scarica l'immagine, questa immagine può essere utilizzata in tutte le costruzioni successive all'interno del progetto.

Storage aggiuntivi

A containers/storage Esiste una cosa fantastica chiamata archivi aggiuntivi (additional stores), grazie alla quale, durante l'avvio e la costruzione dei container, i motori dei container possono utilizzare archivi esterni di immagini in modalità di overlay read-only. In sostanza, nel file storage.conf si possono aggiungere uno o più archivi "solo lettura", affinché, al momento dell'avvio del container, il motore dei container cerchi l'immagine necessaria in essi. Inoltre, scaricherà l'immagine dal registro solo se non la trova in nessuno di questi archivi. Il motore dei container potrà scrivere solo negli archivi accessibili in scrittura…

Se scorriamo verso l'alto e guardiamo il Dockerfile che utilizziamo per costruire l'immagine quay.io/buildah/stable, troveremo queste righe:

# 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 container, dicendo al driver di storage di utilizzare “additionalimagestores” nella cartella /var/lib/shared. Nella riga successiva creiamo una cartella condivisa e aggiungiamo un paio di file di lock per evitare conflitti con containers/storage. In sostanza, stiamo semplicemente creando un archivio vuoto di immagini dei container.

Se montiamo containers/storage a un livello superiore a questa cartella, Buildah potrà utilizzare le immagini.

Ora torniamo alla Variante 2 esaminata sopra, quando un container Buildah può leggere e scrivere in containers/store sugli host e, di conseguenza, ha la massima efficienza grazie alla memorizzazione nella cache delle immagini a livello di Podman/CRI-O, ma offre il minimo di sicurezza, poiché può scrivere direttamente negli archivi. Aggiungendo qui archivi aggiuntivi, otteniamo il meglio di 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

Nota che /var/lib/containers/storage dell'host è montata in /var/lib/shared all'interno del container in modalità read-only. Pertanto, lavorando nel container, Buildah può utilizzare qualsiasi immagine che è stata precedentemente scaricata tramite Podman/CRI-O (salve, velocità), ma può scrivere solo nel proprio archivio (salve, sicurezza). Inoltre, nota che ciò avviene senza disattivare la separazione di SELinux per il container.

Un aspetto importante

In nessun caso è consigliabile rimuovere immagini dall'archivio sottostante. In caso contrario, il container Buildah potrebbe bloccarsi.

E non sono affatto tutti i vantaggi

Le possibilità di archiviazione aggiuntive non si limitano solo allo scenario descritto sopra. Ad esempio, è possibile memorizzare tutte le immagini dei container in uno spazio di archiviazione di rete comune e fornire accesso a tutti i container Buildah. Supponiamo di avere centinaia di immagini che il nostro sistema CI/CD utilizza regolarmente per costruire immagini dei container. Concentrando tutte queste immagini su un singolo host di archiviazione e utilizzando successivamente le soluzioni preferite di archiviazione di rete (NFS, Gluster, Ceph, ISCSI, S3…), ciò consente l'accesso condiviso a questo spazio di archiviazione a tutti i nodi Buildah o Kubernetes.

Ora è sufficiente montare questo spazio di archiviazione di rete nel container Buildah su /var/lib/shared e il gioco è fatto: i container Buildah non dovranno più scaricare le immagini tramite pull. In questo modo si elimina la fase di pre-popolamento e si è immediatamente pronte a distribuire i container.

E naturalmente, questo può essere utilizzato all'interno di un sistema Kubernetes attivo o di un'infrastruttura di container per eseguire e gestire i container ovunque senza dover scaricare immagini tramite pull. Inoltre, il registro dei container, ricevendo una richiesta push per caricare un'immagine aggiornata, può automaticamente inviare quest'immagine allo spazio di archiviazione di rete comune, dove diventa immediatamente disponibile a tutti i nodi.

Le dimensioni delle immagini dei container possono talvolta raggiungere diversi gigabyte. La funzionalità di archiviazione aggiuntiva consente di evitare la clonazione di tali immagini sui nodi e rende l'avvio dei container praticamente istantaneo.

Inoltre, attualmente stiamo lavorando su una nuova funzionalità di montaggio di volumi overlay che renderà la costruzione dei container ancora più veloce.

Conclusione

Eseguire Buildah all'interno di un container in un ambiente Kubernetes/CRI-O, Podman o persino in Docker è assolutamente fattibile, ed è anche semplice e molto più sicuro rispetto all'utilizzo di docker.socket. Abbiamo notevolmente aumentato la flessibilità nel lavoro con le immagini, e ora puoi eseguirle in vari modi per un equilibrio ottimale tra sicurezza e prestazioni.

La funzionalità di archiviazione aggiuntiva consente di accelerare o addirittura eliminare completamente il download delle immagini sui nodi.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster