Kubernetes Caddy

Deployment einer WebApp mit Kubernetes und Caddy

Nachdem im letzten Beitrag beschrieben wurde, wie man produktionsreife Docker-Images erstellt und auf Docker Hub hochlädt, geht es nun darum, diese Images auf einem Server bereitzustellen. Ziel ist es, die Webanwendung über eine eigene Domain für alle zugänglich zu machen. Dafür nutzen wir einen Virtual Private Server (VPS) von Hetzner und setzen Kubernetes (k3s) mit Caddy als Reverse Proxy ein.

Das könnte dich ebenfalls interessieren: Docker Images erstellen und auf Dockerhub hochladen

Einen VPS bei Hetzner einrichten

Hetzner bietet oft Empfehlungslinks mit Guthaben-Vorteilen für Neukunden. Selbstverständlich kann man auch andere Anbieter nutzen, aber Hetzner ist preislich attraktiv und bietet solide Leistungen.

Was ist ein VPS?

Ein Virtual Private Server (VPS) ist ein virtueller Server, der auf einer physischen Maschine betrieben wird und als eigenständiger Server agiert. Er bietet mehr Kontrolle als klassisches Shared Hosting und ist eine kostengünstige Alternative zu dedizierten Servern. Der Zugriff erfolgt in der Regel per SSH (Secure Shell), wodurch wir den Server über die Kommandozeile steuern können.

SSH-Zugriff auf den VPS

Nach dem Erstellen eines VPS erfolgt die Verwaltung meist über eine Secure Shell (SSH). SSH ist ein Protokoll, das verschlüsselte Verbindungen zu entfernten Servern ermöglicht. Um sich mit dem Server zu verbinden, nutzt man folgenden Befehl:

ssh root@<IP-Adresse-des-Servers>

Falls ein SSH-Schlüssel hinterlegt wurde, kann die Authentifizierung per Public-Key-Authentifizierung erfolgen, was sicherer als ein Passwort ist.

Server bei Hetzner erstellen

  1. Nach der Anmeldung in der Hetzner Cloud navigieren wir zu „Projekte“ und erstellen ein neues Projekt.
  2. Danach wählen wir „Server hinzufügen“ und können eine Instanz konfigurieren.
  3. Für den Anfang reicht oft das günstigste Modell aus. Ich empfehle jedoch, die Option für eine IPv4-Adresse zu aktivieren, da rein IPv6-basierte Setups oft Kompatibilitätsprobleme verursachen.

Domain einrichten

Um die Anwendung später unter einer eigenen Domain zu erreichen, muss man eine Domain registrieren und mit dem Server verknüpfen.

Domain bei Hetzner beantragen

  1. In der Hetzner ConsoleH eine neue Domain registrieren oder eine bestehende Domain hinzufügen.
  2. Um DNS-Einträge zu verwalten, müssen wir den DNS-Zugriff aktivieren.

Nameserver setzen

Folgende Nameserver sollten genutzt werden:

helium.ns.hetzner.de. 
hydrogen.ns.hetzner.com. 
oxygen.ns.hetzner.com.

Diese neuen Nameserver bieten bessere Performance und Flexibilität im Vergleich zu den alten Hetzner-Nameservern:

ns1.first-ns.de.
robotns2.second-ns.de.
robotns3.second-ns.com.

Beide Nameserver Varianten sind aber möglich! Die DNS Änderungen brauchen etwas Zeit. Mit Tools wie MXToolbox können wir aber überprüfen, ob die Änderungen bereits stattgefunden haben.

Domain mit dem Server verbinden

Nun muss die IP-Adresse des Servers mit der Domain verknüpft werden:

  1. In der Hetzner Cloud zu DNS-Zonen wechseln.
  2. Die registrierte Domain auswählen.
  3. Einen neuen A-Record erstellen und die IPv4-Adresse des Servers eintragen.
  4. Falls vorhanden, den IPv6-Record (AAAA) entfernen, um Kompatibilitätsprobleme zu vermeiden.

Mit MXToolbox kann man auch hier prüfen, ob die DNS-Änderungen bereits übernommen wurden.

Kubernetes einrichten

Kubernetes ist ein leistungsfähiges Orchestrierungstool für Container. Ich verwende k3s, eine schlanke Kubernetes-Variante, die sich besonders gut für kleinere Umgebungen eignet.

K3s auf dem Server installieren

Per SSH auf den Server verbinden und k3s mit folgendem Befehl installieren:

curl -sfL https://get.k3s.io | sh - 

Das Skript installiert k3s und startet den Kubernetes-Dienst. Nach der Installation kann k3s mit folgendem Befehl überprüft werden:

kubectl get nodes

k3s bringt eine eigene kubectl-Version mit, sodass keine separate Installation nötig ist.

YAML-Files für FE, BE, MySQL und Redis erstellen

Für das Deployment unserer Anwendung brauchen wir YAML-Dateien für:

  • Frontend (Angular)
  • Backend (NestJS)
  • Datenbank (MySQL)
  • Session-Management (Redis)

Eine Deployment-Datei für das Backend könnte so aussehen:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
        - name: backend
          image: dockerhub-user/backend:latest
          ports:
            - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: ClusterIP

Was sind Deployments und Services?

  • Deployments verwalten die Bereitstellung und Skalierung von Containern.
  • Services sorgen für eine stabile Netzwerkverbindung zwischen Containern.
  • ClusterIP bedeutet, dass der Service nur innerhalb des Kubernetes-Clusters erreichbar ist.

Caddy als Reverse Proxy einrichten

Damit eingehender Traffic richtig verteilt wird, wird ein Reverse Proxy benötigt. K3s bringt standardmäßig Traefik mit, allerdings habe ich mich für eine einfachere Lösung entschieden: Caddy. Ich war echt erstaunt wie wenig Anleitungen bzw. Dokumentation es zu Caddy in Kombination mit Kubernetes gibt.

Warum Kubernetes mit Caddy?

  • Automatische Let’s Encrypt SSL-Zertifikate
  • Einfache Konfiguration per Caddyfile
  • Built-in Load Balancer

Traefik entfernen

kubectl delete helmrelease traefik -n kube-system

Caddy Deployment erstellen

apiVersion: apps/v1
kind: Deployment
metadata:
  name: caddy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: caddy
  template:
    metadata:
      labels:
        app: caddy
    spec:
      containers:
        - name: caddy
          image: caddy
          volumeMounts:
            - name: caddy-config
              mountPath: /etc/caddy/Caddyfile
      volumes:
        - name: caddy-config
          configMap:
            name: caddy-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: caddy-config
data:
  Caddyfile: |

    example.com {
        reverse_proxy backend-service:3000
    }

---
apiVersion: v1
kind: Service
metadata:
  name: caddy-service
spec:
  type: LoadBalancer
  selector:
    app: caddy
  ports:
    - port: 80
      targetPort: 80
    - port: 443
      targetPort: 443

Wichtig: Da Let’s Encrypt ein Rate-Limit hat, sollten Tests zunächst mit Staging-Zertifikaten erfolgen!

Fazit

Nach diesen Schritten läuft die Anwendung nun in einem Kubernetes-Cluster auf einem Hetzner VPS und ist über eine eigene Domain erreichbar. Als nächstes würde es sich anbieten eine automatische CI/CD-Pipeline einzurichten, um neue Versionen ohne manuellen Aufwand zu deployen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Cookie Consent mit Real Cookie Banner