Einführung
Node.js ist eine JavaScript-Laufzeitumgebung, die in den letzten Jahren für die Entwicklung serverseitiger Anwendungen immer beliebter geworden ist.
Dieses Tutorial zeigt, wie man eine Node.js-Anwendung über Docker, Docker Hub und Docker Compose auf einem Cloud-Server bereitstellt.
Voraussetzungen
- Dieses Tutorial setzt voraus, dass Docker auf Ihrem lokalen System installiert ist. Falls Sie Docker noch nicht installiert haben, finden Sie Anweisungen zur Installation in der offiziellen Dokumentation.
- Sie benötigen außerdem einen Cloud-Server mit einer Linux-Distribution, vorzugsweise Ubuntu 24.04. Bei Verwendung einer anderen Distribution müssen Sie möglicherweise spezielle Anweisungen zur Installation von Docker auf dem Server befolgen.
- Für einige Schritte wird außerdem ein Docker Hub-Konto (kostenlos) benötigt, um das Docker-Image für die Anwendung hochzuladen.
- Falls Sie noch keine Erfahrung mit Docker haben, ist das kein Problem. Dieses Tutorial ist sehr einfach gehalten und erklärt die Kernkonzepte hinter dem, was wir tun.
- Sie benötigen eine Node.js-Anwendung, die Sie bereitstellen können.
Über Docker
Falls Sie gerade erst mit Docker anfangen, finden Sie hier einige Begriffe, die Sie sich einmal ansehen sollten, um sicherzustellen, dass wir vom Gleichen sprechen.
- Images: In Docker sind Images «Snapshots» oder Vorlagen eines Dateisystems und enthalten alles, was zum Ausführen einer Anwendung benötigt wird.
- Container: Dies sind tatsächlich laufende Instanzen der Anwendung. Sie werden erstellt, indem eine Vorlage (ein Image) genommen und in etwas umgewandelt wird, das gestartet werden kann und einen Zustand besitzt.
- Layer sind die Elemente, aus denen ein Docker-Image besteht. Jeder Layer baut auf einem vorherigen auf, wodurch die sogenannte Layer-Zwischenspeicherung ermöglicht wird. Das bedeutet, dass bei einer Änderung eines einzelnen Layers im Image nicht alle Layer neu erstellt oder geladen werden müssen.
- Registries sind Plattformen, auf denen Sie Images hochladen (pushen), um sie der Öffentlichkeit oder Nutzern mit Zugriffsrechten zugänglich zu machen. In diesem Tutorial verwenden wir Docker Hub, es gibt aber auch Alternativen von GCP, AWS, Azure, GitHub und anderen Anbietern.
Schritt 1 – Erstellen Sie eine Dockerfile
Erstellen Sie im Stammverzeichnis Ihres Node.js-Projekts eine Datei namens Dockerfile mit folgendem Inhalt:
FROM node:20.17
ENV NODE_ENV=production
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
EXPOSE 8080
CMD [ "node", "src/index.js" ]Eine Dockerfile ist die Datei, in der Sie die Anweisungen einfügen, die Docker zum Erstellen eines Images benötigt. Jede Anweisung repräsentiert die Erstellung einer Ebene, die eine Modifikation des Dateisystems des Images darstellt.
In diesem Fall erstellen wir unser Image anhand einer Vorlage, die manchmal auch Basis-Image genannt wird. In diesem Fall ist es node:20.17. Dies ist ein offizielles Image der Firma Docker. Weitere Informationen dazu finden Sie hier.
Im nächsten Schritt wird die Umgebungsvariable NODE_ENV auf „production“ gesetzt. Dies verhindert in erster Linie die Installation von Entwicklungspaketen beim Ausführen des folgenden npm install-Befehls, kann aber auch zu besseren Optimierungen in Modulen führen, auf die Sie möglicherweise angewiesen sind.
Mit dem Befehl WORKDIR wechseln wir in das Verzeichnis /app, welches wiederum zum Verzeichnis wird, in dem die folgenden Anweisungen ausgeführt werden.
Die Paketzeile COPY*.json kopiert die Dateien package.json und package-lock.json in den Ordner /app des Docker-Image-Dateisystems. Beachten Sie, dass der abschließende Punkt erforderlich ist, um das aktuelle Verzeichnis anzugeben.
Jetzt verwenden wir die RUN-Direktive, um Produktionsabhängigkeiten mit dem npm ci-Befehl zu installieren (ci steht für clean install und ist für den Einsatz in automatisierten Umgebungen konzipiert).
An dieser Stelle ist anzumerken, dass wir bisher nur die package*.json-Dateien in den Build-Ordner kopiert haben, anstatt das gesamte Projektverzeichnis. Dadurch können wir das Docker-Layer-Caching nutzen, sodass die Layer verwendet werden können, ohne dass ein erneuter Build erforderlich ist, solange die abhängigen Pakete unverändert bleiben.
Die folgende Zeile (COPY . .) kopiert die restlichen Dateien im Image.
Optional kann angegeben werden, dass ein bestimmter Netzwerkport des Containers freigegeben werden soll, sodass er von einer Webanwendung aufgerufen werden kann. Beachten Sie, dass die EXPOSE-Direktive den Port nicht tatsächlich freigibt: Wie die Dokumentation besagt, fungiert sie «als eine Art Dokument zwischen dem Ersteller des Images und dem Ausführenden des Containers über die zu veröffentlichenden Ports». .
Die letzte Direktive legt schließlich den Befehl fest, den Docker beim Start des Containers zum Ausführen der Anwendung verwenden soll. In diesem Fall gehen wir davon aus, dass der Einstiegspunkt der Anwendung die Datei index.js ist.
Es empfiehlt sich in der Regel, zusätzlich zur Dockerfile auch eine Datei namens .dockerignore anzulegen. Dadurch wird sichergestellt, dass beim Ausführen von COPY . keine unnötigen Dateien von Ihrem Computer in das Image kopiert werden.
.git
Dockerfile
node_modulesIn diesem Fall möchten wir nicht, dass Entwicklungsversionen von Verzeichnissen wie git oder node_modules in der von uns erstellten Vorlage verfügbar sind.
Schritt 2 – Bild erstellen
Nachdem wir nun eine Dockerfile haben, können wir Docker anweisen, diese zum Erstellen eines Images zu verwenden.
Der grundlegende Befehl hierfür sieht wie folgt aus und sollte im Hauptprojektordner ausgeführt werden:
docker build -t myproject .
Falls der Vorgang nicht erfolgreich abgeschlossen wird und die Fehlermeldung "/bin/sh -c npm ci" erscheint, ersetzen Sie npm ci in der Dockerfile durch npm install und versuchen Sie es erneut.
Die Option `-t` gibt den Image-Namen an, in diesem Fall `myproject`. Am Ende der Zeile müssen Sie Docker anweisen, die Dockerfile im aktuellen Verzeichnis zu suchen.
Hinweis: Beim ersten Ausführen des Builds dauert es eine Weile, da Docker alle Ebenen des Basis-Images (in diesem Fall Node.js 20.17) herunterladen muss.
Da wir dieses Image in die Online-Registry Docker Hub hochladen wollen (um von unserem Server darauf zugreifen zu können), müssen wir das Image nach einer bestimmten Namenskonvention benennen.
Der obige Befehl würde also folgendermaßen aussehen:
docker build -t username/myproject:latest .
Dabei ist „username“ Ihr Docker Hub-Benutzername und „last“ das Image-Tag. Ein Image kann mehrere Tags haben, daher sieht der Workflow manchmal ähnlich aus:
docker build -t myproject .
docker tag myproject username/myproject:latest
docker tag myproject username/myproject:20240905Diese Befehle erstellen ein Image und versehen es anschließend mit den Tags latest und 20240904 (das Datum, an dem dieses Tutorial zuletzt aktualisiert wurde).
Docker Hub löscht alte Images standardmäßig nicht, sodass Sie den Verlauf aller in die Registry hochgeladenen Images beibehalten können. Das Image mit dem neuesten Tag ist immer das zuletzt erstellte, während ältere Images mit einem Datum versehen werden.
Schritt 3 – Drücken Sie auf das Bild
Nachdem wir das Image erstellt haben, müssen wir es in die Registry hochladen. Führen Sie zunächst den folgenden Befehl aus, um sicherzustellen, dass Ihre Docker-Instanz bei Docker Hub authentifiziert ist:
docker login
Führen Sie anschließend den Befehl „docker push“ aus, um das Image mit allen Tags hochzuladen.
docker push username/myproject
Bei kleinen Anwendungen sollte dieser Befehl schnell abgeschlossen sein, da nur die Ebenen hochgeladen werden müssen, die zur Node.js-Anwendung und ihren JavaScript-Abhängigkeiten gehören.
Sobald Sie eine neue Version des Images haben, müssen Sie den Push-Befehl erneut ausführen, um sicherzustellen, dass er auf Docker Hub hochgeladen wird.
Schritt 4 – Docker auf Ubuntu 24.04 installieren
Nun können wir mit der Installation von Docker und Docker Compose auf dem Server fortfahren. Wie bereits in den Voraussetzungen erwähnt, wird hier davon ausgegangen, dass Sie bereits einen Ubuntu 24.04-Server eingerichtet haben.
Zunächst benötigt die Installation von Docker einige Systemabhängigkeiten, die mit den folgenden Befehlen installiert werden können:
sudo apt-get update
sudo apt-get install ca-certificates curlFügen Sie nun den offiziellen Docker-GPG-Schlüssel hinzu und konfigurieren Sie ein benutzerdefiniertes apt-Repository:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullAktualisieren Sie abschließend das apt-Verzeichnis erneut und installieren Sie Docker Community Edition:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginDer obige Befehl installiert außerdem Docker Compose, ein Tool, das die Verwaltung von Containern und deren Lebenszyklus erheblich vereinfacht.
Der letzte sinnvolle Schritt besteht darin, den aktuellen Ubuntu-Benutzer zur Docker-Gruppe hinzuzufügen, damit wir Docker-Befehle direkt von ihm ausführen können.
Dies lässt sich ganz einfach mit folgendem Befehl bewerkstelligen:
sudo gpasswd -a myuser docker
Überprüfen Sie, ob alles ordnungsgemäß verlaufen ist, indem Sie die folgenden Befehle ausführen:
docker --version
docker ps
docker compose versionWenn keine Fehler oder Warnungen angezeigt werden, können Sie loslegen.
Schritt 5 – Container mit Docker Compose ausführen
Erstellen Sie auf Ihrem Server eine Datei namens docker-compose.yml mit folgendem Inhalt:
services:
myproject:
container_name: 'myproject'
image: 'username/myproject'
restart: unless-stoppedDies ist eine sehr einfache Docker Compose-Datei, die einen einzelnen Container namens „myproject“ basierend auf dem Benutzernamen/Image „myproject“ von Docker Hub konfiguriert. Wenn Sie kein Label angeben, wird standardmäßig das letzte verwendet. Sie können aber auch ein bestimmtes Label festlegen.
services:
myproject:
container_name: 'myproject'
image: 'username/myproject:20240904'
restart: unless-stoppedSchließlich gibt das Attribut „restart“ an, dass der Container im Fehlerfall automatisch neu gestartet werden soll, sofern er nicht manuell gestoppt wird.
Wenn Sie diesen Compose-Befehl jetzt ausführen, wird das Docker-Image abgemeldet und Ihre Anwendung sollte hoffentlich funktionieren:
docker compose -f docker-compose.yml up
Dieser Befehl erstellt einen Container und führt ihn aus. Die Ausgabe des Containers wird von Docker erfasst und in der Konsole angezeigt. Drücken Sie Strg + C (oder Cmd + C) und warten Sie einige Sekunden, bis der Container beendet ist.
Wenn alles geklappt hat, können Sie den Container nun als Ghost ausführen, sodass er im Hintergrund weiterläuft, bis er gestoppt wird. Dies erreichen Sie, indem Sie die Option `-d` zum Befehl hinzufügen:
docker compose -f docker-compose.yml up -dBumm, Knoten! (Oh, ich meine es ernst!)
Werfen Sie unbedingt einen kurzen Blick in die Referenzdokumentation zur Compose-Datei. Dort finden Sie nützliche Funktionen, wie beispielsweise die Zuordnung von Netzwerkports zwischen Server und Container. Hier ist ein kurzes Beispiel, das den externen Port 80 dem internen Port 8080 zuordnet:
services:
myproject:
container_name: 'myproject'
image: 'username/myproject'
restart: unless-stopped
ports:
- '80:8080'Schritt 6 – Installieren Sie eine neue Version
Angenommen, Sie müssen eine Änderung an Ihrer Anwendung veröffentlichen. Sofern Sie keine automatisierten Builds aktiviert haben, müssen Sie die Schritte 2 und 3 so lange wiederholen, bis ein neues Image in Docker Hub erscheint.
Anschließend müssen Sie auf Ihrem Server das neue Image manuell abrufen, und zwar so:
docker compose -f docker-compose.yml pull
Und starten Sie den Container mit dem neuen Image neu:
docker compose -f docker-compose.yml up -d --force-recreate
Ergebnis
Super, du hast es geschafft! Das war die grundlegende Einführung in die Bereitstellung einer Node.js-Anwendung auf Ubuntu 24.04 mit Docker, Docker Hub und Docker Compose.
Wir haben gesehen, wie man eine einfache Dockerfile schreibt, wie man das Image erstellt, es hochlädt und auf dem Server bereitstellt.
Docker bietet mehr als dieses Tutorial abdeckt. Schauen Sie sich daher unbedingt die Docker- und Docker Compose-Dokumentation an, um mehr über die Konzepte und Funktionen zu erfahren.









