docker1

How To: Docker mit React und Node

Von am 19.06.2022

Docker gibt Entwickler:innenn die Möglichkeit, alle ihre Anwendungen in Containern zu verpacken. Diese Container können auf jedem Rechner ausgeführt werden, auf dem Docker installiert ist und die Applikation laufen kann. Dies ist eine großartige Möglichkeit, einen identen “Klon” einer Codebasis auf mehreren Systemen laufen zu lassen mit dem großen Vorteil, dass man sicher sein kann, dass alle identisch sind.

CI/CD-Workflows und DevOps-Testumgebungen werden durch die Verwendung von Docker, das im Wesentlichen eine Reihe von Softwaretools ist, die gemeinsam genutzt werden können, erheblich verbessert. Kubernetes ist ein weiteres Tool, das für den Betrieb mehrerer Docker-Container verwendet wird, allerdings in einem viel größeren Maßstab. Das wird vor allem relevant, wenn man bei seinen Anwendungen von Skalierbarkeit spricht.

In diesem Beitrag zeige ich, wie man ein NodeJS Express-Backend und ein React-Frontend in einem Docker-Container erstellt und betreibt.

Inbetriebnahme eines Node-Backends in Docker

Bevor ihr beginnt, solltet ihr sicherstellen, dass Docker auf eurem Computer installiert ist und läuft.

Nun navigieren wir in ein Verzeichnis, wo unser Docker-Container platziert werden soll. Anschließend werden folgenden Code-Zeilen ausgeführt.

mkdir my-app-docker
cd my-app-docker
touch docker-compose.yml
mkdir api
cd api
npm init -y
npm i express
touch app.js Dockerfile .dockerignore
cd ..

Wir haben ein Backend namens api eingerichtet und einige Docker-Dateien erstellt. Öffnen wir nun das Projekt in unserem Code-Editor und fügen den untenstehenden Code in die entsprechenden Dateien ein.

Fügen den Code in die Datei docker-compose.yml ein. Die Formatierung der yaml-Datei muss sorgfältig vorgenommen werden, da sonst Docker-Fehler auftreten, wenn versucht wird, die Datei auszuführen.

version: '3.8'
services:
  api:
    build: ./api
    container_name: api_backend
    ports:
      - '4000:4000'
    volumes:
      - ./api:/app
      - ./app/node_modules

Und folgender Codeblock wird in die app.js – Datei geschrieben und repräsentiert unser Node-Backend.

const express = require('express');

const app = express();

const port = process.env.PORT || 4000;

app.get('/', (req, res) => {
  res.send('Home Route');
});

app.listen(port, () =>
  console.log(`Server running on port ${port}, http://localhost:${port}`)
);

Anschließend kann man das .dockerignore – File so konfigurieren, dass der node_modules-Ordner, ähnlich wie beim Git-Ignore, nicht mitprotokolliert wird. Einfach folgende Zeile beifügen.

node_modules

Desweiteren wird folgender Code in die Datei Dockerfile hinzugefügt.

FROM node:16-alpine

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 4000

CMD ["node", "app.js"]

Abschließend wird noch folgender Abschnitt ins package.json – File hinzugefügt:

"scripts": {

 "start": "node app.js"

},

(Optional) Nodemon um automatische Server-Restarts bei Änderungen zu ermöglichen

Wenn man möchte, dass der Server jedes Mal neu startet, wenn man eine Änderung an den Dateien im Backend vornimmt, kann man ihn für die Verwendung von Nodemon konfigurieren.

Dazu ist es ausreichend, die Dockerfile– und package.json-Datei im api-Ordner zu aktualisieren.

Aktualisiere den Code in der Dockerdatei mit dem unten stehenden Code. Wir installieren nun Nodemon beim Start und verwenden dev als Ausführungsbefehl.

FROM node:16-alpine

RUN npm install -g nodemon

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 4000

CMD ["npm", "run", "dev"]

Natürlich muss auch das package.json-File wie folgt aktualisiert werden für die Verwendung Nodemon:

"scripts": {

 "start": "node app.js",

 "dev": "nodemon -L app.js"

},

Zusammengefasst wurde ein einfacher NodeJS Server mit Express, der auf Port 4000 läuft, aufgesetzt. Wichtig ist hierbei, dass auch der Port 4000 im Docker-Container “verwendet” wird, um sozusagen ein Mapping zu ermöglichen.

Starten des Servers

Um den Server außerhalb eines Docker-Containers (auf herkömmliche Art) mit Node wie gewohnt auszuführen, muss nur der folgende Code in der Kommandozeile eingegeben werden.

Dabei müssen vor allem die Inhalte des api-Ordners berücksichtigt werden. Wenn man http://localhost:4000 aufruft, sollte man die “Home-Route” in seinem Browserfenster sehen.

npm run start

Um die NodeJS Express-App innerhalb von Docker zum Laufen zu bringen, ist ein anderer Befehl erforderlich. Zunächst muss man sich im Stammverzeichnis befinden, in dem sich die Datei docker-compose.yml befindet. Anschließend führen wir den unten stehenden Befehl aus und die Anwendung sollte in einem Docker-Container laufen.

docker-compose up

Man muss natürlich darauf auchten, zuerst den Node-Server zu stoppen, da man nur einen Server auf Port 4000 laufen lassen kann.

Wenn man nun wieder auf http://localhost:4000 geht, sie man ebenso die “Home-Route”. Nur diesmal direkt aus Docker heraus.

Den Server kann man mit dem unten stehenden Befehl stoppen, oder man geht zur Docker-App und stoppt die Ausführung des Containers.

docker-compose down

Aufsetzen des React-Frontends in Docker

Im nächsten Schritt erstellen wir innerhalb unseres Docker-Containers ein React-Frontend. Dafür navigieren wir mittels der Kommandozeile in den Root-Ordner von my-app-docker. Einfach folgende Befehle fürs Setup ausführen:

npx create-react-app client
cd client
touch .dockerignore Dockerfile

Nun fügen wir den untenstehenden Code in die korrespondierenden Files ein:

Diese Zeile kommt, wie gewohnt, ins .dockerignore File:

node_modules

Genauso wie bereits oben, wird auch das Dockerfile File konfiguriert:

FROM node:17-alpine

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

Schließlich aktualisieren wir das docker-compose.yml File im Root-Ordner mit dem untenstehenden Codeblock. Im Gegensatz zu vorhin gibt es jetzt auch eine Sektion am Ende, die für die Einstellungen bzw. Konfigurationen des React-Frontend-Projektes stehen. Hier muss man wieder besonders vorsichtig mit der richtigen Formattierung des YAML-Files sein, um etwaige Docker-Fehler präventiv zu vermeiden.

version: '3.8'
services:
  api:
    build: ./api
    container_name: api_backend
    ports:
      - '4000:4000'
    volumes:
      - ./api:/app
      - ./app/node_modules
  client:
    build: ./client
    container_name: client_frontend
    ports:
      - '3000:3000'
    volumes:
      - ./client:/app
      - ./app/node_modules
    stdin_open: true
    tty: true

Grande finale – Starten der Applikation

Ähnlich wie vorhin kann man mit einem simplem Befehl die Applikation normal (außerhalb von Docker) starten. Sicher gehen, dass man im Folder der Client-App ist und den untenstehenden Befehl ausführen. Wenn man jetzt zu http://localhost:3000 geht, sollte man die Startseite einer Boilerplate-React-App sehen.

npm run start

Um die React-App innerhalb von Docker zum Laufen zu bringen, ist ein anderer Befehl erforderlich. Zunächst muss man sich im Root-Ordner befinden, in dem sich die Datei docker-compose.yml befindet. Anschließend sollte die App innerhalb eines Docker-Containers laufen, indem man den folgenden Befehl ausführen:

Natürlich darf auch hier nicht vergessen werden, die React-App auf Port 3000 zu beenden, da nur immer eine Applikation den Port 3000 verwenden kann.

docker-compose up

Erwartungsgemäß findet man auf http://localhost:3000 danach die laufende Applikation von React.

Schließen lässt sich die Anwendung hier, genauso wie beim Backend mit:

docker-compose down

Mit diesem Setup kann man ein NodeJS-Backend und ein React-Frontend gleichzeitig innerhalb von Docker laufen lassen! Wenn Fehler auftreten, muss man möglicherweise die Docker-Desktop-Anwendung öffnen und alle Images entfernen bzw. neu installieren, die mit diesem Projekt verbunden sind. Dann kann man versuchen, den Befehl docker-compose up erneut auszuführen und mit etwas Glück sollte dieses Mal alles wie erwartet funktionieren.

Quellen

Docker – Getting started

Towardsdev – React App In Docker

Beitrag kommentieren

(*) Pflichtfeld