Kategorien: | HowTos |
---|---|
Tags: | Buildah Docker Open Source Software |
Lange Zeit war Docker das Standard-Tool zum Erstellen und Betreiben von Containern.
Durch die starke Verbreitung der Technologie gibt es mittlerweile deutlich mehr Tools, die einzelne Teilbereiche des Gespannes aus Docker-Daemon und Docker-CLI übernehmen. Auch im Hinblick auf den Aspekt der Sicherheit ist der root-Rechte benötigende Docker-Daemon für viele Nutzer nicht unbedingt die erste Wahl.
Buildah ist neben Podman und Skopeo Teil der RedHat-Containertools und übernimmt den Abschnitt für Erstellung und Modifizierung von Containern und Images.
Die Tools wurden dabei nach dem bekannten Unix-Prinzip entwickelt, so dass es kleinere Programme beinhaltet, die jedoch gut zusammenarbeiten und jeweils einen eigenen Teilbereich abdecken.
Buildah wurde in der Version 1.0 am 07.05.2018 veröffentlicht und ist unter Apache 2.0 lizenziert. Die Implementierung erfolgt in Golang und wird in erster Instanz von der „containers organisation“ vorangetrieben. Diese beinhaltet sowohl RedHat-Mitarbeiter, wie auch externe Entwickler.
Der Code kann auf Github eingesehen werden. Die Entwicklung erfolgt dabei in keinem festen Releasezyklus. So können sowohl Monate wie auch Wochen zwischen den Versionen liegen, je nachdem ob genügend neue Features für einen Release implementiert wurden.
Eine zentrale Komponente von Buildah und auch Podman ist die libpod, die es ermöglicht Container im Userspace zu starten und Images zu erstellen. Diese setzt auf slirp4netns, fuse-overlayfs und die /etc/sub(u|g)id auf.
Seit Kernelversion 3.8 sind network- bzw. usernamespaces nutzbar. Jedoch werden für die Erstellung eines Interfaces, das diese nutzen kann, immer noch root-Rechte benötigt.
slirp4netns umgeht diese Problematik, in dem es ein TAP-Device innerhalb des neuen Namespaces mit dem usermode TCP-IP-Stack verbindet. Details dazu sind im Projekt auf Github zu finden.
fuse-overlayfs stellt eine Implementierung von overlay+shiftfs in FUSE (Filesystem in Userspace) bereit. Dieses ermöglicht Nutzern Container-Dateisysteme auch ohne root-Rechte zu erstellen und anzupassen. Details dazu finden sich auf dem Projekt-Github.
Sowohl /etc/subuid als auch /etc/subgid sind Teil der shadow-utils auf aktuellen Systemen und definieren welche uids und gids ein Nutzer des Systems beanspruchen darf.
Als Standard bekommt jeder neu angelegte Nutzer eines Systems 65536 ids zugeteilt (sowohl uid, wie auch gid). Es sind jedoch auch größere oder mehrere Ranges möglich. Diese müssen allerdings manuell angepasst werden und es ist darauf zu achten, dass es keine Überschneidungen gibt. Auch ist es möglich, dass beiden Dateien auf älteren Systemen manuell angelegt / angepasst werden müssen. Mindestens seit Fedora 30 sind diese Teil der Standardinstallation.
Diese IDs werden beim Betrieb von libpod für die uid/gid innerhalb von Containern genutzt.
Folgend ein Beispiel:
[builder@buildah ~]$ cat /etc/subuid builder:100000:65536 wracker:165536:65536 [builder@buildah ~]$ cat /etc/subgid builder:100000:65536 wracker:165536:65536
Hier ist zu sehen, dass der Nutzer builder
uids/gids im Bereich von 100000 bis 165535 nutzen darf. Neue Nutzer bekommen (ohne manuelle Anpassungen) den entsprechend nächsten Block zugeteilt.
Buildah ist auf den gängigen Distributionen entweder direkt paketiert (z.B. Fedora, Archlinux, Suse, Gentoo) oder aber per Dritt-Repo verfügbar (Debian und Derivate).
Unter Fedora ist es zum Zeitpunkt der Erstellung dieses Artikel noch notwendig zusätzlich das Paket seccomp
zu installieren, da es hier in der letzten Version Probleme mit den Abhängigkeiten gibt. So wäre der Aufruf sudo dnf install buildah libseccomp
unter Fedora und sudo pacman -S buildah
unter Archlinux.
Für die Debian-Derivate gibt es das Kubic-Repository, in dem aktuelle Pakete verfügbar sind.
Debian selbst enthält das Paket zunächst nur in den unstable-Repositories. Für Ubuntu oder Debian stable muss Kubic genutzt werden.
Selbstredend ist eine manuelle Installation über die Quellen ebenfalls möglich. Eine Komplette Liste der Installationsmöglichkeiten findet sich auf Github.
Nach der Installation von Buildah sollte der Aufruf in etwa die folgende Ausgabe liefern:
[builder@buildah ~]$ buildah A tool that facilitates building OCI images Usage: buildah [flags] buildah [command] # ...
Die Konfiguration findet in einzelnen Dateien im Ordner /etc/containers
für die globale Konfiguration statt, oder in $HOME/.config/containers
für die Konfiguration der einzelnen Nutzer. Die Nutzerkonfiguration überschreibt dabei wie immer die globale.
Folgende Dateien sind dabei in den Ordnern, bzw. mindestens global, zu finden:
Hier wird definiert mit welchem Treiber und in welchen Ordner die Images bzw. der interne Storage der Container gespeichert werden soll.
Beispiel der globalen Konfiguration:
[root@buildah containers]# grep -v "^#\|^$" /etc/containers/storage.conf [storage] driver = "overlay" runroot = "/var/run/containers/storage" graphroot = "/var/lib/containers/storage" # ...
Beispiel einer Konfiguration eines Nutzers:
[builder@buildah containers]$ cat ~/.config/containers/storage.conf [storage] driver = "overlay" runroot = "/var/tmp/1000" graphroot = "/home/builder/.local/share/containers/storage" # ...
Hier wird pro Zeile ein Mount definiert, der immer in jeden auf dem System bzw. unter dem Nutzer gestarteten Container eingebunden werden soll.
Diese Möglichkeit wird meist genutzt um häufig genutzt Credentials oder Zertifikate in einen Container zu mounten (z.B: /usr/share/rhel/secrets:/run/secrets
für RHEL-Subscriptions). Hier ist ggf. darauf zu achten, dass die Mount-Wünsche nicht mit bestehenden SELinux-Konfigurationen kollidieren. Im Problemfall wäre hier das /var/log/audit/audit.log
zu prüfen.
Konfiguration der verfügbaren Container-Registries im V1-Format. Hier können analog zu Docker-Konfiguration die genutzten Registries freigegeben oder auch ungewollte Blockiert werden. Bei Mehrfachangaben werden die Registries der Reihe nach angefragt.
Auch wenn es sich hier um „V1“ handelt und „V2“ bereits verfügbar ist, so ist dies die stabile und auch empfohlene Variante seine Repositories zu definieren.
Beispiel einer registries.conf:
[root@buildah containers]# grep -v "^#\|^$" /etc/containers/registries.conf [registries.search] registries = ['registry.access.redhat.com', 'registry.fedoraproject.org', 'registry.centos.org', 'docker.io'] [registries.insecure] registries = [] [registries.block] registries = []
Stellt die aktuell noch in der Beta befindlichen Version 2 der Registry-Konfiguration dar. Im Ordner registries.d
finden sich verschiedene Dateien,
welche jeweils Registries konfigurieren.
In dieser Version wird auf das Feature der sigstores
(Signature-Stores) gesetzt, welches jedoch aktuell nur von wenigen Registries überhaupt unterstützt wird.
Es wird dabei zwischen sigstore-staging
(nur schreibend) und sigstore
(lesend und schreibend) unterschieden. So soll das Image z.B. im sigstore-staging
nur erstellt werden um es anschließend im sigstore
zu signieren und zu veröffentlichen.
Folgend eine Beispielkonfiguration:
docker: privateregistry.com: sigstore: http://privateregistry.com/sigstore/ sigstore-staging: /mnt/nfs/privateregistry/sigstore
Da es sich bei dem Feature jedoch um ein Beta-Feature ohne breite Unterstützung handelt soll hier an dieser Stelle nicht weiter darauf eingegangen werden.
Details dazu finden sich auf Github.
Viele Befehle der Buildah-CLI sind mit der Docker-CLI soweit kompatibel und nur um eigene Optionen ergänzt. So z.B. ps
, images
, pull
, push
, rm
, usw.
Im Unterschied zu Docker kann jedoch auch die CLI genutzt werden um neue Container und Images zu erstellen. Dafür stehen dann Optionen wie run,add,copy o.ä. bereit. Dies erlaubt eine sehr gute Automatisierbarkeit bzw. Parametrisierbarkeit der Erstellung, da hier mittels einfacher Shell-Befehle statt eines Dockerfile-Images gebaut werden können.
Es werden bei der Erstellung zwei verschiedene Formate unterstützt, die sich jedoch nur im Manifest unterscheiden: DockerV2 und OCI (standard).
Der erste Schritt um ein Image zu erstellen lautet z.B. buildah from centos
, welches analog zum Dockerfile FROM das Basisimage definiert. Buildah wird das Image herunterladen und einen entsprechenden Container erstellen.
Um nun Anpassungen am Basisimage vorzunehmen kann z.B. buildah run $newcontainer dnf install wget
ausgeführt werden. Der run
Befehl führt ebenfalls, wieder analog zu Docker, einen Befehl innerhalb des Container aus. Um ENV-Variablen wie einen Proxy o.ä. zu definieren kann buildah config
genutzt werden.
So z.B. buildah config --created-by "DaniloE" $newcontainer
um den Autor zu definieren. Mit config
lassen sich diverse Optionen im Container setzen wie z.B. env, cmd, author, port, user. Details dazu unter man buildah-config
.
Um Dateien in einen Container zu kopieren kann copy/add genutzt werden. z.B. buildah copy/add $newcontainer ./hello /hello
.
copy
kopiert dabei Dateien eines lokalen Pfades in den Container während add
einen Pfad oder eine URL akzeptiert.
Um aus dem angepassten Container ein neues Image zu erstellen wird nach Abschluss der Anpassungen z.B. buildah commit $newcontainer hellocontainer
oder buildah commit $newcontainer docker://localhost:5000/hellocontainer
genutzt. Dieses erstellt ein Image aus 2 Layern (Basis-Image + alle Änderungen).
Sollte es aus z.B. Platzgründen nötig sein dies auf einen Layer zu reduzieren kann der Parameter --squash
genutzt werden. --rm
löscht bei diesem Aufruf auch gleich den Zugrunde liegenden Arbeitscontainer.
Zusammenfassend sähe ein Skript um einen Container zu bauen z.B. aus wie folgt:
newcontainer=$(buildah from centos) buildah run $newcontainer touch /test buildah copy $newcontainer ./hello /hello buildah config --cmd /hello $newcontainer buildah config --created-by "DaniloE" $newcontainer buildah config --author "DaniloE" $newcontainer buildah config --label name=simple-helloworld $newcontainer buildah commit --rm $newcontainer hellocontainer
Buildah hat natürlich im Zuge der Docker-Kompatibilität eine Möglichkeit Container aus bestehenden Dockerfiles zu erstellen.
Hierzu wird der Aufruf buildah bud
(build-using-dockerfile) genutzt.
Es erstellt ein Image aus einem Containerfile und einer Buildcontext-URL.
Wird kein Buildcontext übergeben ist $(pwd) automatisch gesetzt und hier wird auf das Dockerfile erwartet. Es ist aber auch möglich mit Remote-Sourcen zu arbeiten.
Weitere Möglichkeiten wären z.B. als Context ein Git-Repository zu übergeben. Hier wird der Inhalt des Repositories in ein temporäres Verzeichnis ausgecheckt (default „/var/tmp“) und im Ergebnis das Dockerfile erwartet.
Alternativ funktioniert dies auch mit einer Archiv URL. Hier wird das Archiv (xz,bzip2,gzip) ebenfalls in das temporäre Verzeichnis heruntergeladen, entpackt und als Context behandelt
Mit z.B. -f files/Dockfile
wird der Pfad zum Dockerfile angegeben. Dies kann sowohl ein lokales Verzeichnis sein, oder aber ein Unterverzeichnis im Git oder Archiv.
Wichtig: Bei der Übergabe eines remote-context wird der Parameter immer auf den Inhalt der Remote Sources angewandt, nicht auf einen lokalen Pfad. Es ist also nicht möglich ein lokales Dockerfile und einen Remote-Context zu verbinden.
Weitere Informationen zu Parametern und Optionen sind unter man buildah-bud
ausführlich dokumentiert.
Folgend noch einige Beispielaufrufe zur Veranschaulichung:
buildah bud --iidfile "id.txt" --squash -t "hello:dev" .
buildah bud github.com/scollier/purpletest
buildah bud -f dev/Containerfile https://10.10.10.1/docker/context.tar.gz
Buildah bietet auch die Option, Images komplett neu zu erstellen ohne ein vorangegangenes Basisimage zu nutzen.
Hierfür wird ein neuer Container mit buildah from scratch
erstellt.
Dieser beinhaltet keine Dateien sondern lediglich ein leeres Dateisystem, das man anschließend befüllt.
So können z.B. mit der lokalen Paketverwaltung Pakete installiert oder aber lediglich Binaries in das Dateisystem übertragen werden.
Folgend ein Beispielskript für die Erstellung eines Containers from scratch mit der CLI.
newcontainer=$(buildah from scratch) scratchmnt=$(buildah mount ${newcontainer}) dnf install --installroot ${scratchmnt} --releasever 30 bash coreutils --setopt install_weak_deps=false -y
Es wird ein neuer, leerer Container erstellt, das Dateisystem des Containers in ein temporäres Verzeichnis gemounted und mit Bordmitteln Pakete inkl. Abhängigkeiten installiert.
Für die Nutzung als unprivilegierter User gibt es hier jedoch einen wichtigen Punkt zu beachten.
So bricht das buildah mount
ohne root Rechte ab:
[builder@buildah ~]$ newcontainer=$(buildah from centos) [builder@buildah ~]$ buildah mount $newcontainer cannot mount using driver overlay in rootless mode. You need to run it in a `buildah unshare` session
Um diese Problematik zu umgehen muss die Containererstellung in einem separaten Namespace durchgeführt werden.
Dieser wird mittels buildah unshare
erstellt und auch direkt aktiviert. Da in diesem sowohl uid wie auch gid als root gesetzt sind lässt sich das FS entsprechend mounten.
[builder@buildah ~]$ buildah unshare [root@buildah ~]# newcontainer=$(buildah from centos) [root@buildah ~]# buildah mount $newcontainer /home/builder/.local/share/containers/storage/overlay/... [root@buildah ~]# ls -l /home/builder/.local/share/containers/storage/... insgesamt 16 -rw-r--r--. 1 root root 12076 5. Dez 2018 anaconda-post.log lrwxrwxrwx. 1 root root 7 5. Dez 2018 bin -> usr/bin drwxr-xr-x. 2 root root 6 5. Dez 2018 dev drwxr-xr-x. 47 root root 4096 5. Dez 2018 etc
Dieser Umstand klingt erst einmal problematisch, ist in der Praxis jedoch nicht, sofern man die Container automatisiert erstellt.
Ein Beispielskript findet sich unter man buildah-unshare
.
| Applikation | Punkte |
| ----------- | ---------------------------------------------- |
| Buildkit | * benötigt Daemon + CLI |
| | * schneller bei großen/Komplexen Builds |
| | * kompatibel mit verschiedenen Imagefile |
| | * z.B. Docker-/Mocker-/Gopperfile |
| | * rootless Mode noch experimental |
| Kaniko | * Nur Unterstützung für Dockerfiles |
| | * speziell für Builds in Containern/Kubernetes |
| | * Nur Kaniko-eigenes Image empfohlen |
| | * Empfohlen für Gitlab CI/CD [] |
Falls Sie Unterstützung beim Einsatz von Docker oder Buildah benötigen, steht Ihnen unser Open Source Support Center zur Verfügung – Falls gewünscht auch 24 Stunden am Tag, an 365 Tagen im Jahr.
Wir freuen uns auf Ihre Kontaktaufnahme.
Kategorien: | HowTos |
---|---|
Tags: | Buildah Docker Open Source Software |
über den Autor
Berater
zur Person
Danilo ist seit 2016 Berater bei der credativ GmbH. Sein fachlicher Fokus liegt bei Containertechnologien wie Kubernetes, Podman, Docker und deren Ökosystem. Außerdem hat er Erfahrung mit Projekten und Schulungen im Bereich RDBMS (MySQL/Mariadb und PostgreSQL<sup>®</sup>). Seit 2015 ist er ebenfalls im Organisationsteam der deutschen PostgreSQL<sup>®</sup> Konferenz PGConf.DE.