Recomandări pentru rularea Buildah în interiorul containerului

Ce este interesant în separarea mediului de execuție al containerelor în componente instrumentale separate? În special, este faptul că aceste instrumente pot fi combinate pentru a se proteja reciproc.

Recomandări pentru rularea Buildah în interiorul containerului

Mulți sunt atrași de ideea de a construi imagini OCI de containere în cadrul Kubernetes sau a unui sistem similar. Să presupunem că avem un CI/CD care construiește constant imagini, atunci ceva de genul Red Hat OpenShift/Kubernetes было бы весьма полезно с точки зрения распределения нагрузки при сборке. До недавних пор большинство людей просто давали контейнерам доступ к Docker-сокету и разрешали выполнять команду docker build. Am demonstrat cu câțiva ani în urmă, că este foarte nesigur, de fapt, este chiar mai rău decât a oferi acces root sau sudo fără parolă.

De aceea, oamenii încearcă constant să ruleze Buildah în container. Pe scurt, am creat exemplu ceea ce considerăm că este cea mai bună metodă de a rula Buildah în interiorul containerului și am publicat imaginile corespunzătoare pe quay.io/buildah. Să începem...

Configurare

Aceste imagini sunt construite din Dockerfiles pe care le puteți găsi în depozitul Buildah în folderul buildahimage.
Aici vom analiza versiunea stabilă a 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

În loc de OverlayFS, implementat la nivelul nucleului Linux al gazdei, folosim în interiorul containerului programul fuse-overlay, deoarece în acest moment OverlayFS poate monta doar dacă îi oferi privilegii SYS_ADMIN prin capabilitățile Linux. Iar noi dorim să rulăm containerele noastre Buildah fără privilegii de nivel root. Fuse-overlay funcționează destul de repede și are o performanță mai bună decât driverul de stocare VFS. Rețineți că, la rularea unui container Buildah care utilizează Fuse, este necesar să se ofere dispozitivul /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

Apoi, creăm un director pentru stocări suplimentare. Container/storage susține concepția de conectare a unor stocări de imagini read-only suplimentare. De exemplu, se poate configura o zonă de stocare overlay pe o mașină, iar apoi prin NFS se poate monta această stocare pe o altă mașină și folosi imaginile din ea fără a le descărca prin pull. Avem nevoie de această stocare pentru a putea monta ca volum o stocare de imagini de pe gazdă și a o folosi în interiorul containerului.

# 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

Și, în cele din urmă, folosind variabila de mediu BUILDAH_ISOLATION, spunem că, în mod implicit, containerul Buildah trebuie să fie pornit cu izolare chroot. O izolare suplimentară nu este necesară deoarece deja lucrăm în interiorul unui container. Pentru ca Buildah să creeze propriile sale containere cu separarea spațiilor de nume, este nevoie de privilegiul SYS_ADMIN, iar pentru aceasta va trebui să relaxăm regulile SELinux și SECCOMP pentru container, ceea ce contravine configurației noastre de a construi dintr-un container sigur.

Pornim Buildah în interiorul unui container

Schema containerului Buildah discutată mai sus permite varierea flexibilă a modurilor de a porni astfel de containere.

Viteză versus securitate

Securitatea computerului este întotdeauna un compromis între viteza de execuție a procesului și nivelul de protecție aplicat. Această afirmație este adevărată și în cazul construirii containerelor, de aceea mai jos vom examina opțiunile acestui compromis.

Imaginea de container discutată mai sus își va păstra stocarea în /var/lib/containers. Prin urmare, trebuie să montăm conținutul în această folder și modul în care facem acest lucru va influența semnificativ viteza de construire a imaginilor de containere.

Să luăm în considerare trei opțiuni.

Opțiunea 1. Dacă se cere securitate maximă, atunci pentru fiecare container se poate crea un folder propriu pentru containers/image și se poate monta în container prin volume-mount. În plus, directorul de context poate fi plasat în interiorul containerului, în folderul /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

Securitate. Un Buildah care funcționează în acest container are maximă securitate: nu i se oferă privilegii root prin intermediul capabilităților, iar toate restricțiile SECOMP și SELinux se aplică acestuia. Acest container poate fi chiar pornit cu izolare User Namespace, adăugând o opțiune precum —uidmap 0:100000:10000.

Performanță. Dar performanța aici este minimă, deoarece orice imagini din registrele de containere sunt copiate pe gazdă de fiecare dată, iar caching-ul nu funcționează deloc. La finalizarea funcționării, containerul Buildah trebuie să trimită imaginea în registru și să distrugă conținutul pe gazdă. Când imaginea de container va fi construită din nou, va trebui să fie descărcată din nou din registru, deoarece pe gazdă nu va mai rămâne nimic.

Opțiunea 2. Dacă ai nevoie de performanță la nivel de Docker, poți monta storage-ul containerului/host-ului direct în container.

# 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

Securitate. Aceasta este cea mai puțin sigură metodă de construire a containerelor, deoarece permite containerului să modifice storage-ul de pe host, ceea ce ar putea permite introducerea unei imagini malițioase în Podman sau CRI-O. În plus, va trebui să dezactivezi separarea SELinux, astfel încât procesele din containerul Buildah să poată interacționa cu storage-ul de pe host. Reține că această opțiune este totuși mai bună decât socket-ul Docker, deoarece containerul este blocat de funcțiile rămase de securitate și nu poate pur și simplu să pornească un container pe host.

Performanță. Aici este maximă, deoarece se utilizează complet caching-ul. Dacă Podman sau CRI-O au reușit deja să descarce imaginea necesară pe host, procesul Buildah din interiorul containerului nu va trebui să o descarce din nou, iar construcțiile ulterioare bazate pe această imagine vor putea, de asemenea, să ia ceea ce le trebuie din cache.

Opțiunea 3. Ideea acestei metode este de a combina mai multe imagini într-un singur proiect cu un folder comun pentru imaginile containerelor.

# 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

În acest exemplu, nu eliminăm folderul proiectului (/var/lib/project3) între rulări, astfel că toate construcțiile ulterioare în cadrul proiectului beneficiază de avantajele caching-ului.

Securitate. O combinație între opțiunile 1 și 2. Pe de o parte, containerele nu au acces la conținutul de pe host și, prin urmare, nu pot introduce nimic rău în storage-ul imaginilor Podman/CRI-O. Pe de altă parte, în cadrul propriului său proiect, containerul poate interveni în construcția altor containere.

Performanță. Aici este mai slab decât utilizarea unui cache comun la nivel de host, deoarece nu pot fi folosite imaginile deja descărcate anterior prin intermediul Podman/CRI-O. Cu toate acestea, după ce Buildah descarcă imaginea, aceasta poate fi utilizată în orice construcții ulterioare în cadrul proiectului.

Stocări suplimentare

În containers/storage Există o funcționalitate foarte interesantă numită stocări suplimentare (additional stores), care permite ca, la pornirea și construirea containerelor, motoarele de container să utilizeze stocări externe de imagini în modul read-only overlay. Practic, în fișierul storage.conf se pot adăuga una sau mai multe stocări „doar pentru citire”, astfel încât, la lansarea unui container, motorul de container să caute imaginea necesară în acestea. Aceasta va descărca imaginea din registru doar în cazul în care nu o găsește în niciuna dintre aceste stocări. Motorul de container va putea scrie doar în stocările disponibile pentru scriere…

Dacă derulăm în sus și ne uităm la Dockerfile-ul pe care îl folosim pentru a construi imaginea quay.io/buildah/stable, vom găsi următoarele linii:

# 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

În prima linie modificăm /etc/containers/storage.conf din interiorul imaginii containerului, spunând driverului de stocare să folosească „additionalimagestores” din folderul /var/lib/shared. Apoi, în următoarea linie, creăm un folder comun și adăugăm câteva fișiere de blocare pentru a evita conflictele cu containers/storage. Practic, creăm doar un depozit gol pentru imagini de container.

Dacă montăm containers/storage la un nivel superior acestui folder, Buildah va putea utiliza imaginile.

Acum ne întoarcem la Variantele 2 discutate anterior, în care containerul Buildah poate citi și scrie în containers/store pe gazde, având astfel cea mai mare performanță datorită cache-ului imaginilor la nivelul Podman/CRI-O, dar oferind un minim de securitate, deoarece poate scrie direct în stocări. Și acum, să adăugăm stocări suplimentare și vom obține cele mai bune părți din ambele lumi.

# 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

Rețineți că /var/lib/containers/storage al gazdelor este montat în /var/lib/shared din interiorul containerului în modul read-only. De aceea, lucrând în container, Buildah poate folosi orice imagini care au fost deja descărcate prin intermediul Podman/CRI-O (salut, viteză), dar poate scrie doar în propriul său depozit (salut, securitate). De asemenea, rețineți că acest lucru se realizează fără a dezactiva separarea SELinux pentru container.

Un detaliu important

În niciun caz nu trebuie să ștergeți imagini din depozitul de bază. În caz contrar, containerul Buildah poate să se blocheze.

Și acestea nu sunt toate avantajele

Capabilitățile stocării suplimentare nu se limitează doar la scenariul descris anterior. De exemplu, putem plasa toate imaginile containerelor într-un stocare de rețea comună și să oferim acces la acestea tuturor containerelor Buildah. Să presupunem că avem sute de imagini pe care sistemul nostru CI/CD le folosește în mod regulat pentru a construi imagini de containere. Concentrăm toate aceste imagini pe un singur host de stocare și apoi, folosind instrumentele de stocare a rețelei preferate (NFS, Gluster, Ceph, ISCSI, S3…), deschidem accesul comun la această stocare pentru toate nodurile Buildah sau Kubernetes.

Acum, este suficient să montăm această stocare de rețea în containerul Buildah pe /var/lib/shared și gata – containerele Buildah nu vor mai trebui să downloadeze imaginile prin pull. Astfel, eliminăm faza de pre-populating și suntem imediat gata să lansăm containere.

Și, desigur, acest lucru poate fi folosit în cadrul unei sisteme Kubernetes existente sau a unei infrastructuri de containere pentru a rula și gestiona containere în orice loc, fără a fi necesar să descărcăm imagini prin pull. În plus, registrul de containere, primind o cerere push pentru a încărca o imagine actualizată, poate trimite automat această imagine în stocarea de rețea comună, unde devine instantaneu disponibilă tuturor nodurilor.

Dimensiunile imaginilor containerelor pot ajunge uneori la câțiva gigabytes. Funcționalitatea stocărilor suplimentare permite evitarea clonării acestor imagini pe noduri și face lansarea containerelor aproape instantanee.

În plus, în acest moment lucrăm la o nouă funcție de montare a volumelor overlay, care va accelera și mai mult procesul de construcție a containerelor.

Concluzie

Executarea Buildah în interiorul unui container în medii Kubernetes/CRI-O, Podman sau chiar în Docker este complet realizabilă, mai ales că este simplă și mult mai sigură decât utilizarea docker.socket. Am crescut semnificativ flexibilitatea lucrului cu imagini, permițând acum rularea acestora în diverse moduri pentru un echilibru optim între securitate și performanță.

Funcționalitatea stocărilor suplimentare permite accelerarea sau chiar eliminarea completă a descărcării imaginilor pe noduri.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster