Docker Alternativen

Docker hat mit seinem einfachen Zugang zu Linux-Containern eine Revolution angestoßen: Containerisierte Anwendungen, Microservices, DevOps, GitOps und Kubernetes breiten sich spürbar aus. Und dann heißt es plötzlich: “Docker support in [kubernetes] is now deprecated and will be removed in a future release”.

Was bedeutet das für die eigene Arbeit mit Containern? Mit Kubernetes? Die gute Nachricht vorneweg: Viel muss man gar nicht ändern. Dieser Beitrag skizziert kurz die vorhandenen Alternativen, kategorisiert sie und gibt ein kurzes Beispiel für Anwendungsentwickler. Wer Interesse an mehr Details hat, sollte einen Blick auf unser Docker-Training werfen.

Was gibt es für Alternativen zu Docker?

Eine Google-Suche nach Docker-Alternativen liefert schnell eine umfangreiche Liste:

  • buildah
  • buildkit
  • by hand: skopeo, ostree, runc
  • containerd
  • cri-o
  • ftl
  • img
  • k3c
  • kaniko
  • (lxc)
  • (OpenVZ)
  • orca-build
  • packer
  • podman
  • pouch
  • (rkt)
  • source-to-image

Wofür eignet sich welche Alternative?

Wer sich bereits mit dem Thema beschäftigt hat, weiß, dass das ein kunterbunter Mix ist. Einige der gelisteten Werkzeuge entsprechen nicht mehr dem gegenwärtigen technischen Stand. Außerdem bedient beispielsweise cri-o eine gänzlich andere Zielgruppe als kaniko. In Klammern gesetzt sind Tools, die keine Rolle spielen. rkt hatte die Firma CoreOS ins Leben gerufen, noch bevor Red Hat sie kaufte. Es ist als Projekt inzwischen eingestellt. Auch Linux Containers (lxc) und OpenVZ passen nicht in diese Zusammenstellung. Beide zielen auf Betriebssystemvirtualisierung ab – im Gegensatz zu den Docker-typischen “Anwendungscontainern”.

Kategorisierung

Seit 2015 gibt es die Open Container Initiative (OCI). Dieses Projekt der Linux Foundation stellt für Images und Runtimes Spezifikationen zur Verfügung. Images müssen demnach die Dateien enthalten, die die Anwendung im Container zur Laufzeit benötigt. Die Runtime muss daraus Container erstellen. Bisher bediente Docker beide Anforderungen. Jetzt unterscheiden wir zwischen Tools, die Images bauen, und solchen, die diese Images als Container zum Laufen bringen. Die OCI-Standards stellen sicher, dass beispielsweise Image-Bau mit kaniko und Kubernetes mit cri-o eine gültige Kombination sind.

Backend in Kubernetes

Aus der Liste taugen cri-o und containerd als Container-Runtime im Kubernetes-Cluster. Und zwar nur als das. Beide bieten eine API, die Kubernetes über das sogenannte Container-Runtime-Interface (CRI) anspricht. Sie können Images aus Registries herunterladen und Container starten und beenden. Docker kann das auch und darüber hinaus noch einiges mehr – deswegen gibt es eine Zwischenschicht für Kubernetes: docker-shim. Das schränkt die Docker-API quasi darauf ein, was Kubernetes braucht und passt die API-Aufrufe an. Diese Zwischenschicht war bisher Kernkomponente von Kubernetes. Dass es das künftig nicht mehr ist, ist die Aussage des Eingangszitats aus den Kubernetes-Release-Notes.

cri-o ist eine komplett neue Implementierung der Runtime. Namensgebend sind das Container-Runtime-Interface und die Open Container Initiative (cri + oci = cri-o). Es stattet Container mit weniger der sogenannten Capabilities aus als Docker – Berechtigungen, die der Kernel Prozessen zuweist, z.B. das Recht, Dateiinhaber zu verändern. Wer bisher Gebrauch von den erweiterten Capabilities macht, die Docker bietet, könnte hier auf Probleme stoßen.

In diesem Fall könnte sich containerd anbieten. Das ist quasi der Kern von Docker, allerdings etwas entschlackt. Der direkte Weg führt von Docker hierhin: containerd verwendet die gleichen Libraries wie Docker und man kann davon ausgehen, dass sich im Betrieb nichts verändert.

In Build-Pipelines

Die große Neuerung ist, dass für den Bau und den Betrieb verschiedene Tools zum Einsatz kommen. Dass das funktioniert, stellt die OCI-Spezifikation sicher. Aber, wie schmerzlos geschieht das? An dieser Stelle noch einmal: Docker wird es weiterhin geben und es kann ganz hervorragend weiterhin Container-Images bauen. Seine Fehler behält es größtenteils: Es ist ein zentraler Daemon, der ziemlich viel darf. In unserem Training erläutern wir unter anderem, wie wir einen Dienst Docker-in-Docker “rootless” aufsetzen. Dadurch könen Entwickler*innen isoliert von der Infrastruktur und den Mitbenutzer*innen Container-Images bauen.

Meine Container-Projekte liegen alle in Form von Dockerfiles vor. Ansätze, die damit nicht umgehen können, verfolge ich bisher nur theoretisch. Wohlgemerkt: Nichts spricht dagegen, einen Ansatz zu wählen, der auf Dockerfiles verzichtet, mir ist nur ein Weg ohne Migration lieber. Zudem liegen die meisten Projekte – auch bei unseren Kundinnen und Kunden – in dieser Form vor, das ist gewissermaßen ein Standard.

GitLab-Pipeline mit verschiedenen Executors

Das Dockerfile und alle weiteren nötigen Daten liegen in einem Git-Repository. Bei der ATIX verwenden wir GitLab, das gleich eine CI/CD-Pipeline mitbringt. Erweitert man das Repository um eine .gitlab-ci.yml, läuft der Image-Bau und -Push nach jedem git push automatisch an. In dieser zusätzlichen Datei stehen die Anweisungen, wie aus dem Repository ein Image entsteht. Teilnehmer*innen unseres Trainings setzen das selbst auf und arbeiten damit, um die geschilderten Ansätze im Detail kennenzulernen. Natürlich lässt sich das Folgende auf andere Systeme übertragen. Zwei Ansätze möchte ich hier mit Beispielen vorstellen: kaniko und buildah.

Cloud-native: kaniko

Einen modernen Ansatz liefert kaniko, das sich ganz natürlich in Pipelines einfügt, die auch in einem Kubernetes-Cluster laufen. Folgende .gitlab-ci.yml baut aus dem Dockerfile ein Image und lädt es in die in GitLab integrierte Registry hoch.

---
build:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - mkdir -p /kaniko/.docker
    - >
      echo "{\"auths\":{\"$CI_REGISTRY\":{
        \"username\":\"$CI_REGISTRY_USER\",
        \"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - >
      /kaniko/executor
      ——context $CI_PROJECT_DIR
      ——dockerfile $CI_PROJECT_DIR/Dockerfile
      ——destination $CI_REGISTRY_IMAGE:latest
    - >
      /kaniko/executor
      ——context $CI_PROJECT_DIR
      ——dockerfile $CI_PROJECT_DIR/Dockerfile
      ——destination $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG

Die ganze Magie findet im Abschnitt script statt. Zuerst hinterlegt der Code Zugangsdaten für die interne Registry, dann baut und pusht er erst ein Image mit dem Tag latest, anschließend noch eines mit dem Tag $CI_COMMIT_REF_SLUG. Das ist eine automatisch gesetzte Variable, die den Branchnamen oder Tag in einer URL-konformen Version enthält. Diese Pipeline funktioniert mit dem Docker-Executor und erfordert keine weitere Konfiguration.

Geradlinig: buildah

Der zweite Ansatz ist allen vertraut, die sich mit Docker auskennen. Auch hier wieder ein Minimalbeispiel, das im gleichen Repository wie im Fall von kaniko liegen könnte:

build:
  stage: build
  image: my.registry:5000/image/mit/buildah:1.2
  tags:
    - docker
  before_script:
    - buildah login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - buildah bud -t $CI_REGISTRY_IMAGE:latest .
    - buildah push $CI_REGISTRY_IMAGE:latest
    - buildah push $CI_REGISTRY_IMAGE:latest $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG

Die erste script-Zeile verwendet die Direktive bud, kurz für build-using-dockerfile. Das impliziert, dass es einen alternativen Weg gibt.

Genau wie Docker startet buildah einen Prozess in einem eigenen Namespace. Darin laufen die Kommandos der RUNs im Dockerfile. Damit er das auch kann, braucht er die passenden Privilegien. Wer den Docker-Executor nutzt, muss für buildah die Container privilegiert laufen lassen und die Kommandos müssen als Root laufen.

Fazit

Auf dem Laptop setze ich primär weiterhin auf Docker oder weiche immer häufiger auf Buildah aus. Windows- und Mac-Nutzer können einfach bei Docker bleiben. Manche der genannten Tools bieten auch Binaries oder Pakete für Nicht-Linuxe an, aber der Umstieg ist nicht zwingend.

Was im Kubernetes-Backend werkelt, ist dann unwichtig, wenn man sich an die OCI-Spezifikationen gehalten hat. Die meisten Distributoren haben das ohnehin schon umgestellt. OpenShift setzt auf cri-o, bei Rancher bzw. SuSE hat man sich für containerd entschieden, wird aber auch docker-shim weiter pflegen.

Pipelines würde ich auf jeden Fall umstellen. Mein Favorit ist kaniko. Da ist der einzige Wermutstropfen, dass man auf das debug-Image zurückgreifen muss, also nicht die Standardausführung – zumindest für GitLab. Vielleicht ändert sich das noch.

Links

The following two tabs change content below.
Jan Bundesmann

Jan Bundesmann

Jan Bundesmann

Neueste Artikel von Jan Bundesmann (alle ansehen)

This post is also available in: English