Docker-Images in Kubernetes erstellen
Vitalis Ogbonna
3. Mai 2022
0 Min. LesezeitImmer mehr Entwickler hosten ihre CI/CD-Plattform auf Kubernetes. Dieser Ansatz spart durch Automatisierung Zeit, sorgt für konsistente Deployments und erleichtert die Überwachung und Verwaltung von Microservices. Das Erstellen von Container-Images in Kubernetes-Clustern bringt jedoch einige technische Hürden mit sich, für die Umgehungslösungen erforderlich sind.
In diesem Artikel stellen wir einige Möglichkeiten vor, Docker-Images in einem Kubernetes-Cluster für CI/CD-Prozesse zu erstellen. Außerdem besprechen wir die Vor- und Nachteile dieser Methoden.
Tools zum Erstellen von Docker-Images in Kubernetes
Wenn Sie schon einmal ein Container-Image erstellt haben, haben Sie wahrscheinlich einen Befehl wie docker build ausgeführt. Als Sie diesen Prozess automatisieren wollten, haben Sie Ihre CI/CD-Tools möglicherweise ebenfalls so eingerichtet, dass sie docker build verwenden. Für einfache CI-Server funktioniert das, doch irgendwann möchten Sie vielleicht eine CI-Plattform auf Kubernetes bereitstellen.
Die Herausforderung: Auf den Docker-Daemon kann nicht ohne Weiteres vom Kubernetes-Cluster aus zugegriffen werden. Deshalb müssen wir Alternativen nutzen und zugleich sicherstellen, dass die Integrität unserer Anwendung und Infrastruktur nicht beeinträchtigt wird.
Dafür gibt es verschiedene Tools:
Buildah ist auf das Erstellen von Open Container Initiative-(OCI-)Images spezialisiert. Die Befehle bilden alle Befehle einer Dockerfile nach. Damit lassen sich Images mit und ohne Dockerfiles erstellen, ohne Root-Berechtigungen zu benötigen.
img ist ein eigenständiges, daemonloses und unprivilegiertes Tool zum Erstellen von Container-Images, das mit Dockerfiles und OCI kompatibel ist. Es nutzt Caches effizient und kann mehrere Build-Phasen parallel ausführen, da es intern den DAG-Solver von BuildKit als Image-Builder verwendet.
kaniko erstellt Container-Images aus einer Dockerfile innerhalb eines Containers oder Kubernetes-Clusters. kaniko ist nicht auf einen Docker-Daemon angewiesen und führt jeden Dockerfile-Befehl vollständig im Userspace aus.
Docker in Docker bezeichnet eine Methode, mit der Docker innerhalb von Docker ausgeführt wird. Dabei werden Docker-Container in Kubernetes-Clustern erstellt, indem die Datei
/var/run/docker.sockals Volume in einen Docker-Container eingebunden wird.Sysbox Enterprise Edition (Sysbox-EE) von Nestybox ermöglicht es Rootless-Containern, Workloads wie Docker, systemd und Kubernetes wie virtuelle Maschinen auszuführen.
BuildKit CLI erstellt Single- und Multi-Architektur-OCI- und Docker-Images in Kubernetes-Clustern. Es ersetzt den Befehl docker build durch kubectl build, um Images in Kubernetes-Clustern zu erstellen.
Jib für Java-Container erstellt Container-Images, ohne eine Dockerfile oder eine Docker-Installation zu benötigen. Jib-Plugins gibt es für Maven und Gradle. Jib ist auch als Java-Bibliothek verfügbar.
KO ist ein schneller und einfacher Image-Builder für Go-Anwendungen. Er erstellt Images, indem er go build effektiv auf Ihrem lokalen Rechner ausführt, sodass Docker nicht installiert werden muss.
Sehen wir uns zwei beliebte Ansätze zum Erstellen von Docker-Images in einem Kubernetes-Cluster genauer an: Docker in Docker und kaniko.
Docker in Docker
Die Docker-in-Docker-Methode (DIND) wird häufig in CI/CD-Pipelines eingesetzt, in denen Images nach einem erfolgreichen Code-Build erstellt und gepusht werden. Außerdem wird diese Methode verwendet, um Jenkins in Deployment-Pipelines zu integrieren, zum Beispiel während Tests in Sandbox-Umgebungen.
Der DIND-Ansatz mag praktisch und einfach erscheinen. Der ehemalige Docker-Mitarbeiter und DIND-Mitwirkende Jérôme Petazzoni weist jedoch darauf hin, dass Docker diesen Ansatz entwickelt hat, um interne Prozesse zu beschleunigen, und nennt Sicherheitsbedenken als Grund, ihn nicht in Produktionsumgebungen einzusetzen.
Docker hat Container ursprünglich so entwickelt, dass sie beim DIND-Ansatz im privilegierten Modus ausgeführt werden. Der Docker-Daemon läuft als Root, daher läuft auch der Container auf dem Host als Root. Wer Zugriff auf den Docker-Socket hat, verfügt über Root-Zugriff und kann beliebige Software ausführen, neue Benutzer anlegen und auf alles zugreifen, was mit dem Container verbunden ist. Dadurch sind die Container anfällig für Angriffe, die sich in der gesamten Architektur ausbreiten können.
Da Kubernetes die Unterstützung für Dockershim offiziell eingestellt hat, wird das Einbinden von docker.sock auf dem Host künftig wahrscheinlich nicht mehr funktionieren – es sei denn, wir installieren Docker auf allen Kubernetes-Knoten. AWS bietet ein hilfreiches Tool, um die Verwendung des Docker-Sockets in Clustern zu erkennen.
Die DIND-Methode bringt außerdem Probleme mit der Kompatibilität von Storage-Treibern mit sich. Auch die Verwaltung von Image-Caches kann schwierig sein, da wir die Docker-Images bei jedem Build erneut abrufen müssen.
Eine Möglichkeit, diese Probleme zu lösen, ist der Einsatz von Tools, die zum Erstellen von Images keine Container-Runtime benötigen. Ein solches Tool ist kaniko, Googles Open-Source-Lösung zum Erstellen von Docker-Images in einem Kubernetes-Cluster.
kaniko
kaniko erstellt Container-Images aus einer Dockerfile innerhalb eines Containers oder Kubernetes-Clusters. Es ist nicht auf einen Docker-Daemon angewiesen und führt jeden Dockerfile-Befehl vollständig im Userspace aus. So können Sie Container-Images in Umgebungen erstellen, in denen ein Docker-Daemon nicht einfach oder sicher ausgeführt werden kann – etwa in standardmäßigen Kubernetes-Clustern.
Wir veranschaulichen den kaniko-Workflow mit kostenlosen, öffentlich verfügbaren Tools. Für dieses Tutorial benötigen Sie:
Docker Desktop auf Ihrem PC, mit aktiviertem Kubernetes
Ein gültiges Docker-Hub-Konto, damit sich der kaniko-Pod authentifizieren und das Docker-Image pushen kann
Ein GitHub-Konto, damit kaniko auf die Dockerfile zugreifen kann
Anhand dieses Beispielprojekts auf GitHub zeigen wir, wie kaniko funktioniert. Klonen Sie es mit git clone https://github.com/agavitalis/kaniko-kubernetes.git, um die Schritte nachzuvollziehen.
Dieses Beispielprojekt enthält zwei Dateien und eine README.md-Datei:
#sample project directory
kaniko-build-demo
dockerfilepod.ymlREADME.md
dockerfile enthält den folgenden Code für die Image-Build-Befehle:
Im kaniko-Konfigurationscode verwendet der kaniko Image-Executor die neueste Version. Außerdem haben wir den Speicherort unserer Dockerfile und unseres Image-Repositorys sowie den Namen unserer Image-Registry-Anmeldedaten in Kubernetes angegeben.
So funktioniert kaniko
kaniko funktioniert recht einfach. Das kaniko-Executor-Image gcr.io/kaniko-project/executor:latest führt die Dockerfile-Befehle aus, um Images zu erstellen. Es liest die angegebene Dockerfile, ruft das im FROM-Befehl definierte Basis-Image (in diesem Fall ubuntu) in das Dateisystem des angegebenen Containers ab und pusht anschließend die Images in eine Registry.
Nachdem kaniko das Basis-Image aus der FROM-Anweisung abgerufen hat, führt es jeden Befehl in der Dockerfile einzeln aus und erstellt nach jedem Befehl einen Snapshot des Userspace. Bei jedem Durchlauf fügt es die Snapshot-Ebene anschließend zur Basisebene hinzu.
Diese Konfigurationen legen wir in der Datei pod.yml fest:
context: Speicherort der Dockerfile. In diesem Fall liegt die Dockerfile im Stammverzeichnis des Repositorys. Verwenden Sie die VariablenGIT_USERNAMEundGIT_PASSWORD(API-Token), um sich bei privaten Git-Repositories zu authentifizieren.destination: Ersetzen Sie <dockerhub-username> durch Ihren Benutzernamen, damit kaniko das Image in die Docker-Hub-Registry pushen kann.docker-file: Pfad zur Dockerfile relativ zum Kontext.
Nachdem wir nun wissen, wie kaniko funktioniert, erstellen wir ein Kubernetes-Secret. Anschließend verwenden wir es, um ein Image zu erstellen und bereitzustellen.
Ein Kubernetes-Secret für Docker Hub erstellen
Damit kaniko auf Docker Hub zugreifen kann, müssen wir ein Kubernetes-Secret erstellen. Dafür benötigen wir folgende Angaben:
docker-server: Der Docker-Registry-Server, auf dem Ihre Images gehostet werden. Wenn Sie Docker Hub verwenden, muss der Werthttps://index.docker.io/v1/lauten.docker-username: Ihr Benutzername für die Docker-Registry.docker-password: Ihr Passwort für die Docker-Registry.docker-email: Die E-Mail-Adresse, die für Ihre Docker-Registry hinterlegt ist.
Führen Sie die folgenden Befehle aus und ersetzen Sie die Variablen jeweils durch die passenden Werte:
Mit dem obigen Befehl wird dieses Secret in den kaniko-Pod eingebunden, sodass die Authentifizierung beim Pushen des erstellten Images in eine Docker-Registry einfach ist. Sie sollten eine Bestätigungsmeldung wie diese erhalten:

Den kaniko-Pod zum Erstellen eines Docker-Images bereitstellen
Starten wir nun den Build, indem wir den Pod in unserem Kubernetes-Cluster erstellen. Stellen Sie den Pod mit folgendem Befehl bereit:

Damit wird der Image-Build gestartet und das Image anschließend in die angegebene Docker-Registry gepusht.
Mit folgendem Befehl können Sie die verfügbaren Pods in Ihrem Kubernetes-Cluster auflisten:

Dieser Befehl zeigt die verfügbaren Pods, ihren Status und ihr Alter an. (Beachten Sie, dass möglicherweise ein Fehler auftritt, wenn kaniko falsche Anmeldedaten verwendet oder in das falsche Repository pusht.)
Mit dem Befehl kubectl delete pod <pod-name> können Sie vorhandene Pods löschen.
Mit folgendem Befehl erhalten Sie umfassende Informationen zum gerade bereitgestellten Pod:

Mit folgendem Befehl können Sie sich außerdem das Build-Protokoll ansehen:

Weitere Befehle zum Erkunden und Beheben von Problemen sowie für zusätzliche Informationen zu Ihrem Cluster finden Sie im kubectl-Spickzettel.
Rufen Sie anschließend Docker Hub auf, um zu überprüfen, ob alles funktioniert hat und Ihre Images erfolgreich zu Docker bereitgestellt wurden.

Wir haben unser Docker-Image erfolgreich in einem Kubernetes-Cluster mit kaniko erstellt und bereitgestellt!
Snyk für Container-Sicherheit
kaniko bietet eine sichere Möglichkeit, Docker-Images in Kubernetes-Clustern zu erstellen. Es ruft die Dockerfile aus dem festgelegten Build-Kontext ab, erstellt das Image und pusht das Ergebnis in eine Image-Registry. Das leistungsstarke Caching-System beschleunigt die Erstellung Ihres Images.
Auch wenn Sie in Kubernetes keine unsichere Methode zum Erstellen Ihrer Docker-Images verwenden, können Sie weiterhin Sicherheitslücken in Kubernetes ausgesetzt sein. Snyk Container bietet eine zuverlässige Container-Sicherheitslösung, mit der Sie Schwachstellen in Cloud-nativen Anwendungen finden und beheben können. Snyk lässt sich nahtlos in Docker, GitHub, Kubernetes, Jenkins und andere Tools integrieren, damit Ihre Anwendung und Infrastruktur geschützt sind.
Container-Sicherheit mit Fokus auf Entwickler
Snyk findet und behebt automatisch Schwachstellen in Container-Images und Kubernetes-Workloads.



