Dockerfile vs Buildpacks: was solltest du für deine App nutzen?
Kurz gesagt
- Ein Dockerfile listet jeden Build-Schritt selbst; Cloud Native Buildpacks erkennen deine Sprache und bauen das Image aus deinem Quellcode ohne eines.
- Buildpacks passen zu Standard-Apps in unterstützten Sprachen und überlassen die Wartung des Base Images dem Builder; ein Dockerfile passt zu eigenen Systempaketen, ungewöhnlichen Stacks und voller Kontrolle über das Image.
- Beide erzeugen ein Container-Image, du kannst mit einem starten und später wechseln.
- Auf Nodion wählst du Buildpacks oder Dockerfile pro App: Buildpacks-Apps hören auf den PORT, den Nodion setzt, Dockerfile-Apps auf den Port aus EXPOSE oder dem Processes-Tab.
Ein Dockerfile und Buildpacks machen beide aus deinem Quellcode ein Container-Image. Der Unterschied ist, wer die Build-Schritte schreibt: beim Dockerfile du, bei Buildpacks leitet das Buildpack sie aus deinem Code ab. Nutze Buildpacks für eine Standard-Web-App in einer unterstützten Sprache und ein Dockerfile, wenn du volle Kontrolle über das Image brauchst oder einen Stack betreibst, den kein Buildpack erkennt.
Was ein Dockerfile ist
In Dockers eigenen Worten ist ein Dockerfile „ein Textdokument, das alle Befehle enthält, die ein User auf der Kommandozeile aufrufen könnte, um ein Image zusammenzusetzen“. Du wählst ein Base Image, installierst Systempakete, kopierst deinen Code, installierst Dependencies und setzt den Startbefehl. Jede Zeile ist deine, das heißt volle Kontrolle und volle Wartung.
FROM node:24-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"] Zwei Features prägen, wie Dockerfiles in der Praxis geschrieben werden:
- Layer-Cache: das Image wird in Layern gebaut, und Docker cached sie. Ändert sich ein Layer, wird jeder Layer danach ebenfalls neu gebaut. Deshalb kopiert das Beispiel
package.jsonund installiert Dependencies, bevor es den Rest des Codes kopiert. - Multi-Stage-Builds: mehrere
FROM-Anweisungen in einer Datei, jede startet eine neue Stage. Du kompilierst in einer Stage und kopierst nur das Ergebnis in ein kleines finales Image, Compiler und Build-Tools bleiben zurück.
Was Buildpacks sind
Ein Buildpack ist Software, die deinen Quellcode analysiert und ableitet, wie er gebaut wird. Cloud Native Buildpacks sind der offene Standard dafür. Ein Build läuft durch feste Phasen: Detect findet die Buildpacks, die zu deinem Code passen, Build macht aus dem Source lauffähige Artefakte (zum Beispiel, indem Runtime und Dependencies installiert und kompiliert werden), und Export schreibt das finale OCI-Image. Du brauchst kein Dockerfile; optionale Dateien wie ein Procfile oder project.toml können Build und Prozesse konfigurieren.
Drei Eigenschaften setzen Buildpacks ab:
- Getrennte Build- und Run-Images: Compiler und Header liegen im Build-Image, die App geht auf dem Run-Image ohne sie raus.
- Rebase: bekommt das Run-Image ein Update, zeigt
pack rebasedas App-Image auf die neue Basis, ohne die App neu zu bauen. - Reproduzierbarkeit: der Lifecycle setzt Layer-Timestamps auf ein festes Datum, dieselbe Source, derselbe Builder und dieselben Buildpacks erzeugen also dasselbe Image, solange die Buildpacks selbst reproduzierbaren Output erzeugen.
Mehr Hintergrund steht in Cloud Native Buildpacks erklärt.
Dockerfile vs Buildpacks auf einen Blick
| Dockerfile | Buildpacks | |
|---|---|---|
| Kontrolle | Voll: Base Image, Pakete, User, Dateilayout | Im Rahmen der Buildpack-Optionen: Versionspins, Procfile, Extra-Pakete |
| Wartung | Du aktualisierst Base Image und jeden Schritt | Der Maintainer des Builders aktualisiert Stack und Language Packs |
| Security-Updates | Rebuild mit einem gepatchten Base Image; du musst es merken | Builder-Updates bringen gepatchte Base Images in den nächsten Build; ein bestehendes Image braucht einen Rebuild oder ein explizites Rebase |
| Reproduzierbarkeit | Hängt davon ab, wie strikt du Images und Pakete pinnst | Für dieselben Inputs eingebaut, mit festen Layer-Timestamps |
| Build-Geschwindigkeit | Schnell mit gut geordnetem Layer-Cache; eine frühe Änderung baut alles danach neu | Gecachte Layer, etwa Dependencies, werden zwischen Builds wiederhergestellt |
| Multi-Stage | Ja, mehrere FROM-Stages | Nicht nötig: Build-Tools bleiben im Build-Image |
| Ungewöhnliche Stacks | Alles, was du in einem Image installieren kannst | Nur, was der Builder erkennt |
Wann du Buildpacks wählst
- Deine App ist in einer Sprache geschrieben, die der Builder unterstützt, etwa Node.js, Python, Ruby, PHP, Go, Rust, Java, .NET oder Elixir, oder sie ist eine statische Site.
- Du willst Base Images und OS-Pakete nicht selbst warten.
- Du betreibst viele Services und willst sie alle gleich bauen.
- Dein Team kennt die Sprache, nicht Docker.
Wann du ein Dockerfile wählst
- Du brauchst ein bestimmtes Base Image, Systempakete über das hinaus, was ein Buildpack installiert, oder einen eigenen User.
- Deine Sprache oder dein Framework erkennt der Builder nicht.
- Das Projekt liefert bereits ein funktionierendes Dockerfile, wie viele Open-Source-Apps.
- Du willst ein kleines Image aus einem Multi-Stage-Build oder dasselbe Image lokal, in CI und in Production.
Wie Nodion beides unterstützt
Unter Applications → New verbindest du ein Git-Repository und wählst Buildpacks oder Dockerfile. Der Scan bevorzugt Dockerfile, wenn er eines findet. Die Strategie kannst du später in Settings ändern; sie gilt beim nächsten Deploy. Wenn du woanders baust, deploye stattdessen ein vorgebautes Image.
Buildpacks auf Nodion
- Nodions eigene Cloud Native Buildpacks auf dem Stack
nodion-26(Ubuntu 26.04 LTS). Sie erkennen Node.js, Python, Ruby, PHP, Go, Rust, Elixir, Java, .NET und statische Sites. - Der Prozess läuft als Non-Root-User. Extra Debian-Pakete kommen in
project.tomloder eineAptfile; ihre Maintainer-Skripte laufen nicht. - Ein
Procfiledefiniert Process Types, sonst setzt ein Sprachdefault den Prozessweb. - Port: Nodion setzt
PORT. Höre darauf; die meisten Default-Commands fallen auf 8080 zurück, wenn er nicht gesetzt ist.
web: gunicorn myapp.wsgi --bind 0.0.0.0:$PORT
worker: python worker.py Dockerfile auf Nodion
- Das Basisverzeichnis ist der Build Context, und ein
.dockerignoredort wird beachtet. - Multi-Stage-Dateien funktionieren. Es gibt keinen Stage-Picker, die letzte Stage ist das, was läuft.
- Als Build markierte Umgebungsvariablen gehen als Build Args (
ARG) mit. BuildKit Secrets sind nicht verdrahtet. - Port: Nodion setzt
PORTbei einer Dockerfile-App nicht. Binde an den Port des Web-Prozesses, der ausEXPOSEvorausgefüllt und im Tab Processes änderbar ist; ist diese Liste leer, nutzt Nodion dasEXPOSEdes Images, dann 8080. Höre auf allen Interfaces, nicht nur localhost. - Health-Check: Readiness ist ein HTTP GET auf den Health-Check-Pfad in Settings (Default
/). Eine 2xx- oder 3xx-Response ist healthy. EinHEALTHCHECKim Image wird ignoriert. - Der
USERdes Images wird beachtet.
Die vollen Details stehen in den Buildpacks-Docs und den Dockerfile-Docs. Noch unsicher? Starte mit Buildpacks und ergänze ein Dockerfile an dem Tag, an dem du etwas brauchst, das sie nicht können.
Häufige Fragen
Brauche ich ein Dockerfile, um einen Container zu deployen?
Nein. Buildpacks bauen ein Container-Image direkt aus deinem Quellcode, ohne Dockerfile im Repository. Du kannst auch ein vorgebautes Image aus einer Registry deployen.
Sind Buildpacks besser als ein Dockerfile?
Keines ist generell besser. Buildpacks brauchen weniger Wartung für Standard-Apps in unterstützten Sprachen, ein Dockerfile gibt dir volle Kontrolle über das Image und funktioniert für jeden Stack.
Kann ich ein Multi-Stage-Dockerfile auf Nodion nutzen?
Ja. Multi-Stage-Dockerfiles funktionieren. Es gibt keinen Stage-Picker, die letzte Stage ist das Image, das läuft.
Auf welchen Port soll meine App hören?
Mit Buildpacks auf die Umgebungsvariable PORT, die Nodion setzt. Mit einem Dockerfile setzt Nodion PORT nicht: binde an den Port des Web-Prozesses, aus EXPOSE oder im Processes-Tab gesetzt, und höre auf allen Interfaces.