Препоръки за стартиране на Buildah вътре в контейнер

Каква е привлекателността на разделянето на средите за изпълнение на контейнерите на отделни инструментални компоненти? По-специално, в това, че тези инструменти могат да се комбинират, за да се защитават един друг.

Препоръки за стартиране на Buildah вътре в контейнер

Много хора са привлечени от идеята за изграждане на контейнерни OCI-образи в рамките на Kubernetes или подобна система. Да предположим, че имаме CI/CD, която постоянно изгражда образи, тогава нещо като Red Hat OpenShift/Kubernetes было бы весьма полезно с точки зрения распределения нагрузки при сборке. До недавних пор большинство людей просто давали контейнерам доступ к Docker-сокету и разрешали выполнять команду docker build. Ние вече преди няколко години показахме, че това е много ненадеждно, всъщност, дори е по-лошо от даването на root или sudo без парола.

Поради това хората постоянно се опитват да стартират Buildah в контейнер. С две думи, ние създадохме пример как, според нашето мнение, е най-добре да стартираме Buildah вътре в контейнер и качихме съответните образи на quay.io/buildah. Да започнем…

Настройка

Тези образи са изградени от Dockerfiles, които можете да намерите в хранилището на Buildah в папката buildahimage.
Тук ще разгледаме стабилната версия на 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

Вместо OverlayFS, реализирана на ниво ядрото на хоста, ние използваме вътре в контейнера програмата fuse-overlay, тъй като в момента OverlayFS може да извършва монтиране само ако й се предоставят правомощия SYS_ADMIN чрез средства на Linux capabilities. А ние искаме да стартираме нашите Buildah-контейнери без никакви привилегии на ниво root. Fuse-overlay работи доста бързо и е с по-добра производителност от storage драйвера VFS. Обърнете внимание, че при стартиране на Buildah-контейнер, използващ Fuse, е необходимо да предоставите устройството /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

След това създаваме каталог за допълнителни хранилища. Container/storage поддържа концепцията за свързване на допълнителни read-only хранилища на образи. Например, можете да конфигурирате overlay storage area на една машина и след това с помощта на NFS да монтирате това хранилище на друга машина и да използвате образите от него без да изтегляте чрез pull. Това хранилище ни е нужно, за да можем да свържем като том някое хранилище на образи от хоста и да го използваме вътре в контейнера.

# 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

И накрая, използвайки променливата на околната среда BUILDAH_ISOLATION, ние казваме, че по подразбиране контейнерът на Buildah трябва да се стартира с изолация chroot. Допълнителна изолация не е необходима, тъй като вече работим в контейнер. За да може Buildah да създава свои собствени контейнери с разделяне на именни пространства, е необходимо право SYS_ADMIN, което налага да се отслабят правилата на SELinux и SECCOMP за контейнера, което е в противоречие с нашата настройка да изпълняваме сборка от безопасен контейнер.

Стартираме Buildah в контейнера

Разгледаната по-горе схема на образа на Buildah-контейнера позволява гъвкаво разнообразие в начините на стартиране на такива контейнери.

Скорост срещу безопасност

Компютърната безопасност винаги е компромис между скоростта на изпълнение на процеса и колко защита е наложена около него. Това твърдение е валидно и при изграждането на контейнери, затова по-долу ще разгледаме възможностите за такъв компромис.

Разглежданият по-горе контейнерен образ ще държи своето хранилище в /var/lib/containers. Затова трябва да подмонтираме съдържанието в тази папка, а начинът, по който ще го направим, ще има значително влияние върху скоростта на изграждане на контейнерните образи.

Нека разгледаме три варианта.

Вариант 1. Ако е нужна максимална безопасност, можем да създадем папка за всеки контейнер за containers/image и да я свържем към контейнера чрез volume-mount. Освен това, можем да поставим контекстната директория в самия контейнер, в папката /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

Сигурност. Работещият в такъв контейнер Buildah има максимална безопасност: не му се дават никакви root-привилегии чрез capabilities, и към него се прилагат всички ограничения на SECCOMP и SELinux. Такъв контейнер дори може да се стартира с изолация на потребителското пространство, добавяйки опция като —uidmap 0:100000:10000.

Производителност. Обаче, производителността е минимална, тъй като всички образи от контейнерните регистри всеки път се копират на хоста, и кеширането не работи изобщо. Завършвайки работата си, Buildah-контейнърът трябва да изпрати образа в регистъра и да унищожи съдържанието на хоста. Когато контейнерният образ трябва да се изгради отново, ще трябва да бъде изтеглен отново от регистъра, тъй като до този момент на хоста вече нищо не е останало.

Опция 2. Ако е необходима производителността на Docker, можем да подмонтираме container/storage на хоста директно в контейнера.

# 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

Сигурност. Това е най-малко безопасният начин за изграждане на контейнери, тъй като контейнерът има разрешение да модифицира хранилището на хоста и потенциално може да подаде на Podman или CRI-O злонамерен образ. Освен това, ще бъде необходимо да се деактивира разделението на SELinux, за да могат процесите в Buildah-контейнера да взаимодействат с хранилището на хоста. Обърнете внимание, че този вариант все още е по-добър от Docker сокета, тъй като контейнерът е блокиран от останалите функции за сигурност и не може просто да вземе и стартира някой контейнер на хоста.

Производителност. Тук тя е максимална, тъй като се използва изцяло кеширането. Ако Podman или CRI-O вече са изтеглили необходимия образ на хоста, то на процеса Buildah в контейнера няма да му се налага да го изтегля отново, а последващите изграждания на базата на този образ също ще могат да вземат необходимото от кеша.

Вариант 3. Същността на този метод е да се обединят няколко образа в един проект с обща папка за контейнерни образи.

# 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

В този пример не изтриваме папката на проекта (/var/lib/project3) между стартиранията, така че всички последващи изграждания в рамките на проекта се възползват от предимствата на кеширането.

Сигурност. Нещо средно между вариантите 1 и 2. От една страна, контейнерите нямат достъп до съдържанието на хоста и съответно не могат да подадат нещо лошо в хранилището на образи на Podman/CRI-O. От друга страна, в рамките на своя проект контейнерът може да се намесва в изграждането на други контейнери.

Производителност. Тук тя е по-слаба отколкото при използването на общо кеш на ниво хост, тъй като не могат да се използват образи, вече изтеглени по-рано с Podman/CRI-O. Въпреки това, след като Buildah изтегли образа, този образ може да се използва във всякакви последващи изграждания в рамките на проекта.

Допълнителни хранилища

В containers/storage Съществува нещо наистина полезно, наречено допълнителни хранилища (additional stores), благодарение на което при стартиране и изграждане на контейнери контейнерните двигатели могат да използват външни хранилища на образи в режим на само четене. По същество, в файла storage.conf може да се добавят едно или повече хранилища „само за четене“, така че при стартиране на контейнера контейнерният двигател да търси нужния образ в тях. Освен това, той ще изтегли образа от регистра, само ако не го намери в нито едно от тези хранилища. Контейнерният двигател ще може да записва само в достъпните за запис хранилища…

Ако се върнете нагоре и погледнете Dockerfile, който използваме за изграждане на образа quay.io/buildah/stable, ще видите следните редове:

# 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

В първия ред модифицираме /etc/containers/storage.conf в контейнерния образ, указвайки на драйвера за хранилища да използва “additionalimagestores” в папката /var/lib/shared. А в следващия ред създаваме обща папка и добавяме няколко lock-файла, за да избегнем конфликти от страна на containers/storage. По същество, просто създаваме празно хранилище на контейнерни образи.

Ако монтирате containers/storage на ниво над тази папка, Buildah ще може да използва образите.

Сега да се върнем към разгледания по-горе Вариант 2, при който Buildah-контейнерът може да чете и записва в containers/store на хостовете и, съответно, предлага максимална производителност чрез кеширане на образите на ниво Podman/CRI-O, но предлага минимална сигурност, тъй като може да записва направо в хранищата. А сега, ако добавим допълнителни хранилища, ще получим най-доброто от двата свята.

# 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

Обърнете внимание, че /var/lib/containers/storage на хоста е монтирано в /var/lib/shared вътре в контейнера в режим на само четене. Следователно, работейки в контейнера, Buildah може да използва всякакви образи, които преди това вече са изтеглени с помощта на Podman/CRI-O (здравей, скорост), но може да записва само в собственото си хранилище (здравей, сигурност). Също така имайте предвид, че това се прави без да се деактивира разделението на SELinux за контейнера.

Важно уточнение

Никога не трябва да се изтриват образи от основното хранилище. В противен случай Buildah-контейнерът може да се срине.

И това не са всички предимства

Възможностите за допълнителни хранилища не се ограничават само до описания сценарий. Например, можете да поставите всички контейнерни образи в обща мрежова хранилище и да предоставите достъп до него на всички Buildah контейнери. Да предположим, че разполагаме със стотици образи, които нашата CI/CD система редовно използва за изграждане на контейнерни образи. Концентрираме всичките тези образи на един хост-склад и след това, използвайки предпочитаните средства за мрежово съхранение (NFS, Gluster, Ceph, ISCSI, S3…), отваряме общ достъп до това хранилище за всички ноди на Buildah или Kubernetes.

Сега е достатъчно да монтирате това мрежово хранилище в контейнера Buildah на /var/lib/shared и всичко – контейнерите на Buildah вече няма да трябва да изтеглят образи чрез pull. По този начин премахваме фазата на предварително запълване (pre-population) и сме готови веднага да разгръщаме контейнери.

И разбира се, това може да се използва в рамките на съществуваща система Kubernetes или контейнерна инфраструктура, за да стартирате и изпълнявате контейнери навсякъде без каквото и да е изтегляне на образи чрез pull. Освен това, контейнерният регистър, получаващ push-заявка за зареждане на обновен образ, може автоматично да изпраща този образ в общата мрежова хранилище, където той моментално става достъпен за всички ноди.

Размерите на контейнерните образи понякога могат да достигнат много гигабайти. Функционалността на допълнителните хранилища позволява да се избегне клонирането на такива образи по нодите и прави стартирането на контейнери практически мигновено.

Освен това, в момента работим по нова функция за overlay volume mounts, която ще направи изграждането на контейнери още по-бързо.

Заключение

Изпълнението на Buildah в контейнера в среда Kubernetes/CRI-O, Podman или дори в Docker е напълно реалистично, а също така е просто и много по-безопасно, отколкото да се използва docker.socket. Значително увеличихме гъвкавостта при работа с образи, и сега можете да ги стартирате по различни начини за оптимален баланс между безопасност и производителност.

Функционалността на допълнителните хранилища позволява да се ускори или дори напълно да се премахне изтеглянето на образи на нодите.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster