# React Docker Notizblock App (Full-Stack: Lokal, Swarm, Kubernetes & Helm)
Dies ist eine Full-Stack Notizblock-Anwendung, die mit React (Frontend) und Node.js/Express (Backend) erstellt wurde. Die Anwendung wurde für verschiedene Deployment-Szenarien konfiguriert: lokale Entwicklung mit Docker Compose, verteiltes Deployment auf Docker Swarm und Paketierung als **Helm Chart** für die Bereitstellung auf Kubernetes.
Die Kernanwendung (Notizblock) beinhaltet:
* Ein Frontend, das mit Vite gebaut und von Nginx als Webserver und Reverse Proxy ausgeliefert wird.
* Ein Backend, das eine REST-API für Notizen bereitstellt und Daten persistent in einer **PostgreSQL-Datenbank** speichert.
* Eine PostgreSQL-Datenbank als dedizierter Service, integriert als Subchart in der Helm-Konfiguration.
* Integrierte, aussagekräftige Healthchecks für Datenbank und Backend zur Sicherstellung der Diensteverfügbarkeit.
Zusätzlich wurden grundlegende Kubernetes-Konzepte (Deployment, Service, Ingress, Rolling Update, Rollback) anhand von Beispielanwendungen demonstriert.
## Projektstruktur
```text
.
├── .dockerignore
├── .env
├── .gitignore
├── README.md
├── docker-stack.yml
├── docker-compose.yml
├── sql_schema_and_queries.md
├── Reflexionsfragen.md
│
├── assets/
│ └── ...
│
├── backend/
│ # ... (Backend-Struktur wie zuvor)
│
├── frontend/
│
│
├── helm-charts/
│ └── notizblock-app-chart/ # Helm Chart für die Notizblock-Anwendung
│
│
├── kubernetes/
│ ├── 01-intro/
│ │ ├── k8s-intro-reflection.md
│ │ └── Screenshot_kubectl_get_nodes.png
│ ├── 02-deployment-service/
│ │ # ... (Dateien zur K8s Deployment/Service Aufgabe mit Nginx)
│ │ └── k8s-deployment-reflection.md
│ └── 03-ingress/
│ # ... (Dateien zur K8s Ingress Aufgabe)
│ └── k8s-ingress-reflection.md
│
└── terraform/
└── 01-first-steps/
├── main.tf
├── provider.tf
├── terraform-first-steps-reflection.md
└── assets/
├── Screenshot_terraform_init.png
└── Screenshot_terraform_plan.png- Vollständige CRUD-Operationen für Notizen.
- Statusumschaltung für Notizen (Erledigt/Offen).
- Persistente Datenspeicherung in PostgreSQL.
- Sichere API durch parametrisierte Abfragen und Eingabevalidierung.
- Containerisierung mit Docker.
- Orchestrierung mit Docker Compose (lokal), Docker Swarm (verteilt) und Paketierung als Helm Chart für Kubernetes.
- Node Affinity im Swarm.
- Frontend mit Nginx Reverse Proxy.
- Robuste Fehlerbehandlung und aussagekräftige Healthchecks.
- Frontend-Features: Light/Dark-Mode, Suche, Filter, Sortierung und "Fliegender Notizzettel".
- Docker & Docker Compose
kubectlKommandozeilen-Tool- Helm CLI (
helm version) - Ein lokales Kubernetes-Cluster (z.B. Kubernetes in Docker Desktop, Minikube, Kind)
- Multipass (optional, für Swarm-Setup)
- Git
- Ein Docker Hub Account
Für die lokale Entwicklung kann der Notizblock-Stack mit der docker-compose.yml Datei gestartet werden.
- Repository klonen und navigieren:
git clone https://github.com/sebriede6/Docker-Container cd Docker-Container .env-Datei erstellen: Erstelle eine.env-Datei im Projektwurzelverzeichnis mit Inhalt wie:DB_USER=myuser DB_PASSWORD= DB_NAME=notizblockdb BACKEND_PORT=3000 LOG_LEVEL=debug
- Datenbankschema erstellen:
docker compose up -d database # Warten bis DB healthy (prüfe mit: docker compose ps) docker exec -i postgres_db_service psql -U ${DB_USER:-myuser} -d ${DB_NAME:-notizblockdb} < backend/sql/initial_schema.sql docker exec -i postgres_db_service psql -U ${DB_USER:-myuser} -d ${DB_NAME:-notizblockdb} < backend/sql/update_schema_add_completed.sql
- Stack starten:
Die Notizblock-Anwendung ist unter
docker compose up --build -d
http://localhost:8080erreichbar.
Dieser Abschnitt beschreibt, wie die gesamte Full-Stack Notizblock-Anwendung als Helm Chart paketiert und auf einem lokalen Kubernetes-Cluster (z.B. Docker Desktop Kubernetes) installiert, aktualisiert und deinstalliert wird. Das PostgreSQL Subchart von Bitnami wird als Abhängigkeit für die Datenbank genutzt.
- Lokales Kubernetes-Cluster: Stelle sicher, dass dein lokales K8s-Cluster läuft und
kubectldarauf zugreift (kubectl config use-context docker-desktop). - Helm CLI: Muss installiert sein (
helm version). - Notizblock-App Images: Die Docker Images für dein Frontend (
DEIN_DOCKERHUB_BENUTZERNAME/mein-notizblock-frontend:latest) und Backend (DEIN_DOCKERHUB_BENUTZERNAME/mein-notizblock-backend:latest) müssen in einer erreichbaren Registry (z.B. Docker Hub) verfügbar sein. ErsetzeDEIN_DOCKERHUB_BENUTZERNAMEentsprechend.
Das Helm Chart für diese Anwendung befindet sich im Verzeichnis helm-charts/notizblock-app-chart/ und enthält:
Chart.yaml: Definiert das Chart und seine Abhängigkeit zum Bitnami PostgreSQL Chart (Aliasdatabase).values.yamltemplates/: Kubernetes Manifest-Templates für Backend, Frontend, Ingress und Secrets.charts/: Enthält das heruntergeladene PostgreSQL Subchart nachhelm dependency update.
- Navigiere in das Wurzelverzeichnis des Charts:
cd helm-charts/notizblock-app-chart - Abhängigkeiten aktualisieren:
helm dependency update - Chart installieren (ersetze Platzhalter):
helm install notizblock-release ./ \ --namespace default \ --set frontend.image.repository=DEIN_DOCKERHUB_BENUTZERNAME/mein-notizblock-frontend \ --set backend.image.repository=DEIN_DOCKERHUB_BENUTZERNAME/mein-notizblock-backend \ --set database.auth.password='DEIN_SICHERES_DB_PASSWORT' \ --set ingress.host='notizblock.local' \ --set ingress.className='nginx'
- Status und Ressourcen:
Warte, bis Pods
helm list -n default kubectl get all,pvc,secret -n default -l app.kubernetes.io/instance=notizblock-release
Running/Readyund PVCBoundsind. - Datenbankschema erstellen (nach Erstinstallation):
- Finde den PostgreSQL-Pod-Namen (z.B.
notizblock-release-database-postgresql-0) mit:kubectl get pods -n default -l app.kubernetes.io/instance=notizblock-release,app.kubernetes.io/name=postgresql - Kopiere SQL-Skripte in den Pod (Pfad relativ zum Chart-Verzeichnis):
kubectl cp ../../backend/sql/initial_schema.sql <POSTGRES_POD_NAME>:/tmp/initial_schema.sql -n default kubectl cp ../../backend/sql/update_schema_add_completed.sql <POSTGRES_POD_NAME>:/tmp/update_schema_add_completed.sql -n default
- Führe Skripte aus (ersetze User/DB-Name mit Werten aus
values.yamlunterdatabase.auth, z.B.notiz_user,notizblock_db):kubectl exec -it <POSTGRES_POD_NAME> -n default -- psql -U notiz_user -d notizblock_db -f /tmp/initial_schema.sql kubectl exec -it <POSTGRES_POD_NAME> -n default -- psql -U notiz_user -d notizblock_db -f /tmp/update_schema_add_completed.sql
- Finde den PostgreSQL-Pod-Namen (z.B.
- Lokale Hosts-Datei anpassen: Füge
127.0.0.1 notizblock.localhinzu und leere den DNS-Cache. - Browser-Test: Öffne
http://notizblock.local/.
helm upgrade notizblock-release ./ \
--namespace default \
--reuse-values \
--set frontend.replicaCount=2 \
--set database.auth.password='DEIN_SICHERES_DB_PASSWORT' helm uninstall notizblock-release --namespace default
Entferne den notizblock.local-Eintrag.
Diese Aufgabe diente der Einführung in Infrastructure as Code (IaC) mit Terraform. Es wurde eine einfache Terraform-Konfiguration entwickelt, um den Docker-Provider zu nutzen, einen Nginx-Container zu erstellen und dessen Inhalt dynamisch über Variablen zu steuern. Der grundlegende Terraform-Workflow (init, plan, apply, destroy) sowie die Verwendung von Input-Variablen und Outputs wurden praktisch angewendet.
Die Terraform-Konfigurationsdateien für diese Aufgabe befinden sich im Verzeichnis terraform/01-first-steps/ und umfassen:
provider.tf: Definiert denkreuzwerker/docker-Provider und konfiguriert ihn für die Interaktion mit dem lokalen Docker-Daemon.main.tf: Enthält die Ressourcendefinition für einendocker_container(Nginx). Der Containername, der exponierte Host-Port und der Inhalt derindex.htmlim Container werden über Variablen gesteuert. Einlocal-execProvisioner wird verwendet, um dieindex.htmldynamisch im Container zu erstellen.variables.tf: Definiert die Input-Variablen:container_name: Name des Docker-Containers (Typ:string, mit Default-Wert).external_port: Externer Host-Port, der auf den internen Port 80 des Containers gemappt wird (Typ:number).nginx_html_content: Der HTML-Inhalt für dieindex.html-Seite des Nginx-Containers (Typ:string, mit Default-Wert, der andere Variablen interpoliert).
outputs.tf: Definiert Outputs, um Informationen über die erstellten Ressourcen nach einemterraform applyanzuzeigen, wie z.B. den Containernamen, die Container-ID und den verwendeten externen Port.test.tfvars: Eine Beispieldatei zur Demonstration der Variablenübergabe. Hinweis: In einem realen Projekt würden.tfvars-Dateien mit sensiblen Daten nicht in die Versionskontrolle eingecheckt, sondern über.gitignoreausgeschlossen. Für diese Übung enthälttest.tfvarsnur nicht-sensible Beispielwerte.
Die folgenden Schritte beschreiben den vollständigen Workflow im Verzeichnis terraform/01-first-steps/:
-
Initialisierung (
terraform init): Dieser Befehl wird einmalig pro neuem Arbeitsverzeichnis oder nach Änderungen an den Provider-Anforderungen ausgeführt. Er lädt die notwendigen Provider-Plugins herunter (hier den Docker-Provider) und initialisiert das Backend (standardmäßig lokal).cd terraform/01-first-steps/ terraform initErfolgreicher Output sollte "Terraform has been successfully initialized!" anzeigen.
-
Planerstellung (
terraform plan): Dieser Befehl erstellt einen Ausführungsplan. Er zeigt, welche Aktionen Terraform durchführen würde, um den in den.tf-Dateien definierten Zustand zu erreichen, ohne tatsächlich Änderungen vorzunehmen.- Plan mit Default-Werten:
terraform plan
- Plan mit Werten aus einer
.tfvars-Datei:terraform plan -var-file="test.tfvars"
Erwarteter Output zeigt, welche Ressourcen erstellt (
+), geändert (~) oder zerstört (-) würden. - Plan mit Default-Werten:
-
Anwendung der Änderungen (
terraform apply): Dieser Befehl wendet die im Plan gezeigten Änderungen auf die Infrastruktur an.- Apply mit Werten aus einer
.tfvars-Datei:Terraform zeigt erneut den Plan und fragt interaktiv nach Bestätigung (terraform apply -var-file="test.tfvars"yes). Nach erfolgreicher Ausführung werden die definierten Output-Werte angezeigt. - Apply mit Überschreibung durch CLI-Variable:
Variablen, die per
-varauf der Kommandozeile übergeben werden, haben höhere Priorität als Werte aus.tfvars-Dateien oder Defaults.terraform apply -var-file="test.tfvars" -var="container_name=mein-cli-container"
- Apply mit Default-Werten (wenn keine
.tfvars-Datei oder CLI-Variablen für spezifische Werte angegeben werden): Wenn z.B.container_nameaustest.tfvarsentfernt wird, wird der Default-Wert ausvariables.tfverwendet.terraform apply # (Wenn test.tfvars z.B. nur external_port definiert)
- Apply mit Werten aus einer
-
Überprüfung der erstellten Ressourcen:
- Mit Docker-Befehlen:
docker ps(um den laufenden Container zu sehen). - Im Browser:
http://localhost:<external_port>(z.B.http://localhost:8888, wennexternal_portintest.tfvarsauf8888gesetzt wurde). Die Seite sollte den Inhalt ausvar.nginx_html_contentanzeigen.
- Mit Docker-Befehlen:
-
Anzeigen der Outputs: Nach einem erfolgreichen
applyoder jederzeit später:terraform output # Zeigt alle definierten Outputs terraform output container_name_output # Zeigt einen spezifischen Output
-
Zerstören der Infrastruktur (
terraform destroy): Dieser Befehl entfernt alle von Terraform in dieser Konfiguration erstellten Ressourcen.terraform destroy -var-file="test.tfvars" # Oder mit den passenden Variablen, die den aktuellen Zustand repräsentieren
Bestätigung mit
yesist erforderlich.
Die detaillierten Reflexionsantworten zu dieser Terraform-Aufgabe befinden sich in:
(terraform/01-first-steps/terraform-first-steps-reflection.md)*
Eine theoretische Ausarbeitung eines relationalen Datenbankmodells befindet sich in der Datei sql_schema_and_queries.md. Die für die Notizblock-Anwendung verwendeten Schemata sind backend/sql/initial_schema.sql und backend/sql/update_schema_add_completed.sql.
-
Sicherheit: Parametrisierte Abfragen im Backend, grundlegende Eingabevalidierung. Sensible Daten werden über Umgebungsvariablen oder Helm-Mechanismen verwaltet.
-
Module: ES-Module im Backend, komponentenbasiertes Frontend.
-
.gitignore / .dockerignore: Konfiguriert, um unnötige Dateien und sensible Informationen auszuschließen.
-
Desweiteren habe ich diese Anwendung in einem Cluster auf Azure deployed. Erreichbar unter dieser IP: http://131.189.216.129/