<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Docker Archives - Nerd Corner</title>
	<atom:link href="https://nerd-corner.com/de/tag/docker/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerd-corner.com/de/tag/docker/</link>
	<description>Craft your dreams!</description>
	<lastBuildDate>Wed, 26 Mar 2025 09:20:51 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.2</generator>

<image>
	<url>https://nerd-corner.com/wp-content/uploads/2019/10/cropped-LogoNerdCorner-2-32x32.png</url>
	<title>Docker Archives - Nerd Corner</title>
	<link>https://nerd-corner.com/de/tag/docker/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Deployment einer WebApp mit Kubernetes und Caddy</title>
		<link>https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/</link>
					<comments>https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Sun, 16 Feb 2025 17:20:29 +0000</pubDate>
				<category><![CDATA[Angular-DE]]></category>
		<category><![CDATA[App Entwicklung]]></category>
		<category><![CDATA[Software-DE]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Caddy]]></category>
		<category><![CDATA[Caddy Server]]></category>
		<category><![CDATA[Cluster]]></category>
		<category><![CDATA[ClusterIP]]></category>
		<category><![CDATA[ConfigMap]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[Domain Registrierung]]></category>
		<category><![CDATA[Hetzner]]></category>
		<category><![CDATA[Images]]></category>
		<category><![CDATA[Ingress]]></category>
		<category><![CDATA[Ingress Controller]]></category>
		<category><![CDATA[IP Adresse]]></category>
		<category><![CDATA[K3s]]></category>
		<category><![CDATA[Kubectl]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[LoadBalancer]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest.js]]></category>
		<category><![CDATA[Node Port]]></category>
		<category><![CDATA[Pods]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[Schritt für Schritt Anweisung]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Service]]></category>
		<category><![CDATA[Traefik]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1687</guid>

					<description><![CDATA[<p>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 &#8230; </p>
<p>The post <a href="https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/">Deployment einer WebApp mit Kubernetes und Caddy</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>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 (<span style="font-size: 1.125rem;">k3s) </span><span style="font-size: 1.125rem;">mit Caddy als Reverse Proxy ein.</span></p>
<p><em><strong>Das könnte dich ebenfalls interessieren: </strong><a href="https://nerd-corner.com/de/docker-images-erstellen-und-auf-docker-hub-hochladen/">Docker Images erstellen und auf Dockerhub hochladen</a></em></p>
<h2>Einen VPS bei Hetzner einrichten</h2>
<p>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.</p>
<h3>Was ist ein VPS?</h3>
<p>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.</p>
<h3>SSH-Zugriff auf den VPS</h3>
<p data-start="1137" data-end="1384">Nach dem Erstellen eines VPS erfolgt die Verwaltung meist über eine <strong data-start="1205" data-end="1227">Secure Shell (SSH)</strong>. SSH ist ein Protokoll, das verschlüsselte Verbindungen zu entfernten Servern ermöglicht. Um sich mit dem Server zu verbinden, nutzt man folgenden Befehl:</p>
<p data-start="1137" data-end="1384"><span style="background-color: #e9ebec; color: #222222; font-family: Monaco, Consolas, 'Andale Mono', 'DejaVu Sans Mono', monospace; font-size: 15px;">ssh root@&lt;IP-Adresse-des-Servers&gt;</span></p>
<p data-start="1430" data-end="1582">Falls ein SSH-Schlüssel hinterlegt wurde, kann die Authentifizierung per <strong data-start="1503" data-end="1535">Public-Key-Authentifizierung</strong> erfolgen, was sicherer als ein Passwort ist.</p>
<h3>Server bei Hetzner erstellen</h3>
<ol>
<li>Nach der Anmeldung in der Hetzner Cloud navigieren wir zu „Projekte“ und erstellen ein neues Projekt.</li>
<li>Danach wählen wir „Server hinzufügen“ und können eine Instanz konfigurieren.</li>
<li>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.</li>
</ol>
<h2>Domain einrichten</h2>
<p>Um die Anwendung später unter einer eigenen Domain zu erreichen, muss man eine Domain registrieren und mit dem Server verknüpfen.</p>
<h3>Domain bei Hetzner beantragen</h3>
<ol>
<li>In der Hetzner ConsoleH eine neue Domain registrieren oder eine bestehende Domain hinzufügen.</li>
<li>Um DNS-Einträge zu verwalten, müssen wir den DNS-Zugriff aktivieren.</li>
</ol>
<h3>Nameserver setzen</h3>
<p>Folgende Nameserver sollten genutzt werden:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">helium.ns.hetzner.de. 
hydrogen.ns.hetzner.com. 
oxygen.ns.hetzner.com.</pre>
<p>Diese neuen Nameserver bieten bessere Performance und Flexibilität im Vergleich zu den alten Hetzner-Nameservern:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">ns1.first-ns.de.
robotns2.second-ns.de.
robotns3.second-ns.com.</pre>
<p>Beide Nameserver Varianten sind aber möglich! Die DNS Änderungen brauchen etwas Zeit. Mit Tools wie <a href="https://mxtoolbox.com/">MXToolbox</a> können wir aber überprüfen, ob die Änderungen bereits stattgefunden haben.</p>
<h3>Domain mit dem Server verbinden</h3>
<p data-start="3155" data-end="3229">Nun muss die <strong data-start="3168" data-end="3219">IP-Adresse des Servers mit der Domain verknüpft</strong> werden:</p>
<ol data-start="3231" data-end="3512">
<li data-start="3231" data-end="3283">In der Hetzner Cloud zu <strong data-start="3258" data-end="3271">DNS-Zonen</strong> wechseln.</li>
<li data-start="3284" data-end="3323">Die registrierte Domain auswählen.</li>
<li data-start="3324" data-end="3411">Einen neuen <strong data-start="3339" data-end="3351">A-Record</strong> erstellen und die <strong data-start="3370" data-end="3386">IPv4-Adresse</strong> des Servers eintragen.</li>
<li data-start="3412" data-end="3512">Falls vorhanden, den <strong data-start="3436" data-end="3458">IPv6-Record (AAAA)</strong> entfernen, um Kompatibilitätsprobleme zu vermeiden.</li>
</ol>
<p data-start="3514" data-end="3621">Mit <a href="https://mxtoolbox.com/" target="_blank" rel="noopener" data-start="3518" data-end="3553">MXToolbox</a> kann man auch hier prüfen, ob die DNS-Änderungen bereits übernommen wurden.</p>
<h2>Kubernetes einrichten</h2>
<p>Kubernetes ist ein leistungsfähiges Orchestrierungstool für Container. Ich verwende <strong data-start="3756" data-end="3763">k3s</strong>, eine schlanke Kubernetes-Variante, die sich besonders gut für kleinere Umgebungen eignet.</p>
<h3 data-start="3858" data-end="3902">K3s auf dem Server installieren</h3>
<p data-start="3903" data-end="3980">Per SSH auf den Server verbinden und k3s mit folgendem Befehl installieren:</p>
<pre><code class="language-sh">curl -sfL https://get.k3s.io | sh - </code></pre>
<p><span style="font-size: 1.125rem;">Das Skript installiert k3s und startet den Kubernetes-Dienst. </span>Nach der Installation kann k3s mit folgendem Befehl überprüft werden:</p>
<pre><code class="language-sh">kubectl get nodes
</code></pre>
<p>k3s bringt eine eigene <code>kubectl</code>-Version mit, sodass keine separate Installation nötig ist.</p>
<h3>YAML-Files für FE, BE, MySQL und Redis erstellen</h3>
<p>Für das Deployment unserer Anwendung brauchen wir YAML-Dateien für:</p>
<ul>
<li>Frontend (Angular)</li>
<li>Backend (NestJS)</li>
<li>Datenbank (MySQL)</li>
<li>Session-Management (Redis)</li>
</ul>
<p>Eine <strong data-start="4641" data-end="4661">Deployment-Datei</strong> für das Backend könnte so aussehen:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">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
</pre>
<h2>Was sind Deployments und Services?</h2>
<ul>
<li><strong>Deployments</strong> verwalten die Bereitstellung und Skalierung von Containern.</li>
<li><strong>Services</strong> sorgen für eine stabile Netzwerkverbindung zwischen Containern.</li>
<li>ClusterIP bedeutet, dass der Service nur innerhalb des Kubernetes-Clusters erreichbar ist.</li>
</ul>
<h2>Caddy als Reverse Proxy einrichten</h2>
<p>Damit eingehender Traffic richtig verteilt wird, wird ein Reverse Proxy benötigt. K3s bringt standardmäßig <strong>Traefik</strong> mit, allerdings habe ich mich für eine einfachere Lösung entschieden: <strong>Caddy</strong>. Ich war echt erstaunt wie wenig Anleitungen bzw. Dokumentation es zu Caddy in Kombination mit Kubernetes gibt.</p>
<h3>Warum Kubernetes mit Caddy?</h3>
<ul>
<li>Automatische Let’s Encrypt SSL-Zertifikate</li>
<li>Einfache Konfiguration per <code>Caddyfile</code></li>
<li>Built-in Load Balancer</li>
</ul>
<h3>Traefik entfernen</h3>
<pre><code class="language-sh">kubectl delete helmrelease traefik -n kube-system
</code></pre>
<h3>Caddy Deployment erstellen</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">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</pre>
<p>Wichtig: Da Let’s Encrypt ein Rate-Limit hat, sollten Tests zunächst mit Staging-Zertifikaten erfolgen!</p>
<h2>Fazit</h2>
<p>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.</p>
<p>The post <a href="https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/">Deployment einer WebApp mit Kubernetes und Caddy</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Docker Images erstellen und auf Docker Hub hochladen</title>
		<link>https://nerd-corner.com/de/docker-images-erstellen-und-auf-docker-hub-hochladen/</link>
					<comments>https://nerd-corner.com/de/docker-images-erstellen-und-auf-docker-hub-hochladen/#respond</comments>
		
		<dc:creator><![CDATA[Nerds]]></dc:creator>
		<pubDate>Wed, 15 Jan 2025 11:44:13 +0000</pubDate>
				<category><![CDATA[Angular-DE]]></category>
		<category><![CDATA[App Entwicklung]]></category>
		<category><![CDATA[Software-DE]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[Anleitung]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Backend Server]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker Hub]]></category>
		<category><![CDATA[Docker Images]]></category>
		<category><![CDATA[Docker Repository]]></category>
		<category><![CDATA[frontend]]></category>
		<category><![CDATA[google cloud mysql]]></category>
		<category><![CDATA[Images]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[mySql]]></category>
		<category><![CDATA[Nest]]></category>
		<category><![CDATA[Nest.js]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[redis session management]]></category>
		<category><![CDATA[redis session management nest.js]]></category>
		<category><![CDATA[Repository]]></category>
		<category><![CDATA[Schritt für Schritt Anweisung]]></category>
		<guid isPermaLink="false">https://nerd-corner.com/?p=1680</guid>

					<description><![CDATA[<p>In diesem Beitrag zeige ich, wie man production-ready Docker Images für eine Web Anwendung mit Angular, NestJS, MySQL und Redis erstellt und anschließend auf Docker &#8230; </p>
<p>The post <a href="https://nerd-corner.com/de/docker-images-erstellen-und-auf-docker-hub-hochladen/">Docker Images erstellen und auf Docker Hub hochladen</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In diesem Beitrag zeige ich, wie man production-ready Docker Images für eine Web Anwendung mit Angular, NestJS, MySQL und Redis erstellt und anschließend auf Docker Hub veröffentlicht. Voraussetzung ist eine installierte Docker Umgebung.</p>
<p><em><strong>Das könnte dich ebenfalls interessieren:</strong> <a href="https://nerd-corner.com/de/erfahrungen-aus-der-praxis-nestjs-auf-vercel-hosten/">NestJS auf Vercel hosten</a></em></p>
<h2>Erstellung der Docker Compose Yml</h2>
<p>Mit Docker Compose können alle Komponenten einer Anwendung über eine einzige Konfigurationsdatei definiert und gemeinsam gebuildet bzw. gestartet werden.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">version: '3.8'

services:
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "3000:3000"
    depends_on:
      - mysql
      - redis
    environment:
      - DATABASE_URL=mysql://user:password@mysql:3306/db
      - SESSION_STORE=redis://redis:6379

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db
    ports:
      - "3306:3306"

  redis:
    image: redis:latest
    ports:
      - "6379:6379"</pre>
<h2>Erstellung der Env Datei</h2>
<p>Um Umgebungsvariablen zentral zu verwalten, erstellen wir eine <code>.env</code> Datei:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">DATABASE_URL=mysql://user:password@mysql:3306/db 
SESSION_STORE=redis://redis:6379</pre>
<p>Wichtig: Alle ENV-Variablen, die im Code verwendet werden, müssen auch in <code>docker-compose.yml</code> vorkommen!</p>
<h2>Docker-Image für das Frontend</h2>
<p>Das Angular-Frontend muss für die Produktion gebaut werden. Hier ein Beispiel-<code>Dockerfile</code>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build --prod

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf</pre>
<p>Da wir für den Build auf nginx angewiesen sind brauchen wir auch eine entsprechende Config Datei:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">server {
  listen 80;
  server_name _;

  location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /index.html;
  }
}</pre>
<h2>Docker-Image für das Backend</h2>
<p>Auch das NestJS-Backend muss gebaut werden. Hier ein optimiertes <code>Dockerfile</code></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic"># Build stage
FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app

COPY --from=build /app/dist ./dist
COPY package.json package-lock.json ./
RUN npm install --only=production
CMD ["node", "dist/main.js"]</pre>
<h2>Builden der App mit Docker Compose</h2>
<p>Nachdem alle Dockerfiles konfiguriert wurden können jetzt die Images gebuildet werden. Mit Docker compose ist das ganze wirklich einfach.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">docker compose up -d --build</pre>
<p>Anschließend sind die Images fertig, die Container gebaut und die App kann lokal direkt ausgetestet werden! Als letzer Schritt müssen die Images noch auf DockerHub hochgeladen werden, damit sie später leichter für das Deployment auf einem Server genutzt werden können.</p>
<h2>Hochladen auf Docker Hub</h2>
<p>Das Hochladen wird nachfolgend Schritt für Schritt erklärt:</p>
<ol>
<li>Erstelle einen Account bei <a href="https://hub.docker.com/">Docker Hub</a>.</li>
<li>Erstelle ein Repository für das Frontend und Backend (1 privates Repo ist aktuell kostenlos).</li>
<li>Baue die Images und tagge sie:
<pre class="EnlighterJSRAW" data-enlighter-language="generic">docker tag &lt;image-id&gt; dockerAccountName/frontend:latest
docker tag &lt;image-id&gt; dockerAccountName/backend:latest</pre>
</li>
<li>Melde dich an und pushe die Images:
<pre class="EnlighterJSRAW" data-enlighter-language="generic">docker login
docker push dockerAccountName/frontend:latest
docker push dockerAccountName/backend:latest</pre>
</li>
</ol>
<h2>Ausblick: Deployment mit Kubernetes</h2>
<p>Da die Images nun auf Docker Hub sind, steht dem Deployment nichts mehr im Wege. Ich habe mich für ein Kubernetes-Cluster auf einem Hetzner-VPS entschieden. <a href="https://nerd-corner.com/de/deployment-einer-webapp-mit-kubernetes-und-caddy/">Mehr Infos dazu hier</a>.</p>
<p>The post <a href="https://nerd-corner.com/de/docker-images-erstellen-und-auf-docker-hub-hochladen/">Docker Images erstellen und auf Docker Hub hochladen</a> appeared first on <a href="https://nerd-corner.com/de">Nerd Corner</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nerd-corner.com/de/docker-images-erstellen-und-auf-docker-hub-hochladen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
