Рэкамендацыі па запуску 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, рэалізаванай на ўзроўні Linux-ядра хаста, мы выкарыстоўваем усярэдзіне кантэйнера праграму 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. Акрамя таго, размяшчаць context directory у самым кантэйнеры, у тэчцы /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, і да яго ўжываюцца ўсе абмежаванні SECOMP і SELinux.Такі кантэйнер нават можна запускаць з ізаляцыяй User Namespace, дадаўшы опцыю накшталт -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 separation, каб змешчаныя ў 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), дзякуючы якой пры запуску і зборцы кантэйнераў кантэйнерныя рухавічкі могуць выкарыстоўваць вонкавыя сховішчы выяў у рэжыме read-only оверлея. Па сутнасці, у файл 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 усярэдзіне кантэйнернай выявы, кажучы storage-драйверу выкарыстаць “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 усярэдзіне кантэйнера ў рэжыме read-only. Таму працуючы ў кантэйнеры, Buildah можа выкарыстоўваць любыя выявы, якія раней ужо былі запампаваны сродкамі Podman/CRI-O (прывітанне, хуткасць), але пісаць пры гэтым можа толькі ў сваё ўласнае сховішча (прывітанне, бяспека). Таксама звернеце ўвагу, што гэта робіцца без адключэння SELinux separation для кантэйнера.

важны нюанс

Ні ў якім разе не варта выдаляць ніякія выявы з ніжэйлеглага сховішча. У адваротным выпадку 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

Дадаць каментар