Angular docker container

Angular Docker Container: Deployment leicht gemacht

Du entwickelst mit Angular und fragst dich, wie du deine App am besten deployen kannst? Docker könnte die Lösung sein, die du suchst. In diesem Artikel erklären wir, wie du Docker für deine Angular-Anwendungen nutzt und welche Vorteile das bringt. Wir zeigen dir, wie du ganz leicht deinen ersten Angular Docker Container erstellst und dazu gibt’s zwei praktische Beispiele für Dockerfiles, die du direkt einsetzen kannst.

Docker und Angular: Ein starkes Team

Stell dir vor, du könntest deine gesamte Entwicklungsumgebung in ein handliches Paket schnüren – inklusive aller Abhängigkeiten und Einstellungen. Genau das macht Docker möglich. Es ist wie ein virtueller Server für deine App, der alles enthält, was sie zum Laufen braucht. Aber was genau ist Docker eigentlich?

"Vater und Sohn sitzen auf einer Bank"-Meme.
Sohn: "It work's on my machine"
Vater: "Then we'll ship your machine"
And that is how docker was born

Docker ist eine Open-Source-Plattform, die es dir ermöglicht, Anwendungen in isolierten Umgebungen – sogenannten Containern – zu entwickeln, zu verpacken und auszuführen. Diese Container sind leichtgewichtig, portabel und enthalten alles, was deine Anwendung benötigt: von der Codebasis über die Laufzeitumgebung bis hin zu Systemwerkzeugen und Bibliotheken.

Warum Docker für Angular-Projekte?

Warum solltest du Docker für deine Angular-Projekte in Betracht ziehen? Hier sind einige überzeugende Gründe:

  1. Konsistente Entwicklungsumgebung: Mit Docker stellst du sicher, dass deine App in jeder Umgebung identisch läuft – sei es auf deinem Entwicklungsrechner, dem Testserver oder in der Produktionsumgebung. Keine bösen Überraschungen mehr wegen unterschiedlicher Systemkonfigurationen!
  2. Einfaches Deployment: Du sparst dir den Ärger mit komplexen Deployment-Prozessen. Mit Docker packst du deine gesamte Anwendung in einen Container und deployest sie mit wenigen Befehlen.
  3. Verbesserte Skalierbarkeit: Docker-Container lassen sich leicht replizieren und verteilen. Das macht es einfach, deine Angular-App bei steigendem Traffic zu skalieren.
  4. Isolierte Ausführung: Jeder Container läuft isoliert, was die Sicherheit erhöht und potenzielle Konflikte zwischen Anwendungen minimiert.
  5. Ressourceneffizienz: Im Vergleich zu virtuellen Maschinen sind Docker-Container deutlich ressourcenschonender, da sie sich die Verfügbaren Resourcen des Hosts effizient teilen.
  6. Schnellere Entwicklungszyklen: Docker ermöglicht es dir, schnell zwischen verschiedenen Versionen deiner App zu wechseln und neue Features in isolierten Umgebungen zu testen. Dies ermöglicht auch schnelle und unkomplizierte Rollbacks, sollte mal etwas schief gehen.
  7. Continuous Integration und Delivery: Docker integriert sich nahtlos in CI/CD-Pipelines, was automatisierte Tests und Deployments erleichtert.

Dein erster Angular Docker Container: Schlank und schnell

Genug der Theorie, lass uns praktisch werden. Hier ist eine Dockerfile, die deine Angular-App für die Produktion fit macht:

# Build-Stage / Verwende Node.js als Basis-Image
FROM node:alpine as build
# Setze das Arbeitsverzeichnis
WORKDIR /app
# Kopiere package.json und package-lock.json
COPY package*.json ./
# Installiere Abhängigkeiten
RUN npm ci
# Kopiere den restlichen Quellcode
COPY . .
# Baue die Angular-App
RUN npm run build

# Production-Stage / Verwende NGINX als Basis-Image für die Produktionsumgebung
FROM nginx:alpine
# Kopiere die gebaute App in das NGINX-Verzeichnis
COPY --from=build /app/dist/meine-angular-app /usr/share/nginx/html
# Kopiere deine angepasste NGINX-Konfiguration (optional, aber empfohlen. Eine Beispiel Konfiguration findest du weiter unten)
COPY nginx.conf /etc/nginx/nginx.conf
# Port 80 freigeben, nginx läuft auf diesem Port
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Und so schnell hast du deine erste Angular Dockerfile geschrieben! Aber was passiert hier? Zuerst bauen wir die App in einer Node.js-Umgebung. Dann packen wir das Ergebnis in ein schlankes NGINX-Image, das als Webserver dient. So bekommst du eine optimierte Produktionsumgebung für deine Angular-Anwendung.

Die zwei Stufen erklärt: Build und Produktion

Du hast vielleicht bemerkt, dass diese Dockerfile in zwei Stufen aufgeteilt ist. Diesen Ansatz nennt man „Multi-Stage Build“. Aber warum machen wir das?

  1. Build-Stage:
  • Hier nutzen wir ein Node.js-Image, um unsere Angular-App zu bauen.
  • Wir kopieren zuerst nur die package.json-Dateien und installieren die Abhängigkeiten.
  • Dann kopieren wir den Rest des Codes und bauen die App für die Produktion.
  1. Produktions-Stage:
  • Hier verwenden wir ein schlankes NGINX-Image als Basis.
  • Wir kopieren nur die gebauten Dateien aus der Build-Stage in dieses neue Image.
  • NGINX wird als Webserver konfiguriert, um unsere Angular-App auszuliefern.

Der Vorteil dieses Ansatzes? Du bekommst ein viel kleineres Image, das nur die notwendigen Produktionsdateien enthält. Alle Build-Tools und Abhängigkeiten, die nur für den Build-Prozess benötigt werden, bleiben in der Build-Stage zurück und belasten dein Produktions-Image nicht. Dies sorgt gleichzeitig auch für mehr Sicherheit.

Nginx config

server {
    # Root-Verzeichnis für den Server setzen (wir kopieren unsere Anwendung hierher)
    root /usr/share/nginx/html;

    # Definieren der Standard-Indexdatei (Angular erstellt die Datei index.html für uns und sie befindet sich im oben genannten Verzeichnis)
    index index.html;

    # Cache-Header für Medien-ASsets
    location ~* \.(?:cur|jpe?g|gif|htc|ico|png|xml|otf|ttf|eot|woff|woff2|svg)$ {
        access_log    off;
        add_header Pragma "must-revalidate, public";
        add_header Cache-Control "must-revalidate, public";
        expires       max;

        tcp_nodelay off;
    }

    # Cache-Header für HTML, CSS und JS-Dateien
    location ~* \.(?:css|js|html)$ {
        access_log    off;
        add_header Pragma "must-revalidate, public";
        add_header Cache-Control "must-revalidate, public";
        expires       2d;

        tcp_nodelay off;
    }

    # Konfiguration für den /-Pfad
    location / {
        # Zunächst versuchen wir die angeforderte URI auzuliefern
        # Klappt das nicht, versuchen wir es mit einem abschließenden Slash
        # Klappt auch das nicht, liefern wir die index.html aus.
        # Das ist nötig, damit Angular-Routen korrekt augeflöst und ausgeliefert werden
        try_files $uri $uri/ /index.html;
    }
}

Hinweis: In unserem Beispiel lassen wir die Verwendung von SSL-Zertifikaten außer acht. Erfahrungsgemäß sind in Produktivumgebungen andere Dienste, wie bspw. Traefik vorgeschaltet und handhaben das SSL-Offloading, sodass dein Container selbst das nicht tun muss.

Docker-Container bauen und starten

Nachdem du deine Dockerfile erstellt hast, ist es an der Zeit, deinen Angular Docker Container zu bauen und zu starten. Hier ist das Command, das du dafür verwendest:

docker build -t meine-angular-app .

Das bedeutet das Command:

  • docker build ist der Befehl zum Erstellen eines Docker-Images.
  • -t meine-angular-app gibt dem Image einen Tag (Namen). Ersetze „meine-angular-app“ durch einen Namen deiner Wahl.
  • Der Punkt . am Ende gibt das Verzeichnis an, in dem sich die Dockerfile befindet. In diesem Fall ist es das aktuelle Verzeichnis.

Nachdem der Build-Prozess abgeschlossen ist, kannst du deinen Container mit folgendem Befehl starten:

docker run -p 8080:80 meine-angular-app

Hier wird der Container gestartet und der Port 80 des Containers (auf dem NGINX läuft) wird auf den Port 8080 deines Host-Systems gemappt. Du kannst nun deine Angular-App unter http://localhost:8080 aufrufen.

Angular Docker Container mit Extra-Power: NGINX und Brotli

Willst du noch mehr Performance aus deiner Angular-App herausholen? Dann schau dir dieses erweiterte Beispiel an, das NGINX mit Brotli-Kompression nutzt:

# Build-Stage
FROM node:alpine as build // siehe oben
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# NGINX-Stage mit Brotli 
FROM nginx:alpine
RUN apk add --no-cache brotli
COPY --from=build /app/dist/meine-angular-app /usr/share/nginx/html
COPY nginx-brotli.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Für die Brotli-Kompression brauchst du noch eine angepasste NGINX-Konfiguration. Hier ein Beispiel für nginx-brotli.conf:

events {
    worker_connections 1024;
}

http {
    brotli_comp_level 9;
    brotli_types application/atom+xml application/javascript application/json application/rss+xml
            application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype
            application/x-font-ttf application/x-javascript application/xhtml+xml application/xml
            font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon
            image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    client_body_buffer_size 10K;
    client_header_buffer_size 1k;
    client_max_body_size 8m;
    large_client_header_buffers 4 16k;
    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;

    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html;
        index index.html;

        location ~* \.(?:cur|jpe?g|gif|htc|ico|png|xml|otf|ttf|eot|woff|woff2|svg)$ {
            access_log    off;
            add_header Pragma "must-revalidate, public";
            add_header Cache-Control "must-revalidate, public";
            expires       max;
    
            tcp_nodelay off;
        }
    
        location ~* \.(?:css|js|html)$ {
            access_log    off;
            add_header Pragma "must-revalidate, public";
            add_header Cache-Control "must-revalidate, public";
            expires       2d;
    
            tcp_nodelay off;
        }
    
        location / {
            try_files $uri $uri/ /index.html;
        }

        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }
}

Die ist unsere bevorzuge Angular Dockerfile, wie wir sie bereits für viele Anwendungen nutzen.

Was macht Brotli so besonders?

Der derzeit am weitesten verbreitete Kompressionsalgorithmus für Webinhalte, gzip, ist ein effizientes Verfahren zur Datenkompression, das seit den 1990er Jahren verwendet wird und in fast allen modernen Webbrowsern und Servern unterstützt wird. Brotli ist ein modernerer Kompressionsalgorithmus, der von Google entwickelt wurde.

Im Vergleich zu gzip bietet Brotli:

  • Höhere Kompressionsraten, besonders für Textdateien wie HTML, CSS und JavaScript
  • Schnellere Dekompression im Browser
  • Geringere Übertragungszeiten für deine Angular-App

Neben gzip und Brotli gibt es auch Zstandard (zstd), einen neueren Kompressionsalgorithmus, der von Facebook entwickelt wurde und sich durch hohe Kompressionsraten bei gleichzeitig sehr schneller Kompression und Dekompression auszeichnet. Während Brotli oft die besten Kompressionsraten erzielt, bietet Zstandard einen ausgezeichneten Kompromiss zwischen Kompressionsgeschwindigkeit und -effizienz, was es besonders für Szenarien interessant macht, in denen Echtzeitkompression erforderlich ist.

Durch die Aktivierung von Brotli in deiner NGINX-Konfiguration sorgst du dafür, dass deine Angular-Anwendung noch schneller ausgeliefert wird. Das verbessert nicht nur die Nutzererfahrung, sondern kann sich auch positiv auf dein SEO-Ranking auswirken.

Praktische Tipps für die Arbeit mit Angular und Docker

Hier sind einige Tipps, die dir bei der Arbeit mit Angular und Docker helfen:

  1. Nutze .dockerignore: Ähnlich wie .gitignore hilft dir eine .dockerignore-Datei, unnötige Dateien vom Docker-Build auszuschließen. Das macht deine Images kleiner und den Build-Prozess schneller.
  2. Caching von npm-Paketen: Wenn du häufig builds durchführst, kann das Caching von npm-Paketen viel Zeit sparen. Kopiere und installiere die package.json vor dem Rest deines Codes.
  3. Umgebungsvariablen: Nutze Umgebungsvariablen, um deine Angular-App für verschiedene Umgebungen zu konfigurieren, ohne den Code zu ändern.
  4. Health Checks: Implementiere Health Checks in deiner Angular-App und Docker-Konfiguration, um die Verfügbarkeit deiner Anwendung zu überwachen.
  5. Docker Compose für Entwicklung: Nutze Docker Compose, um deine Entwicklungsumgebung mit allen notwendigen Services (z.B. Datenbanken, APIs) zu definieren.

Warum du auf Docker setzen solltest

Es gibt viele gute Gründe, deine Angular-App in Docker-Containern laufen zu lassen:

  1. Du kannst sicher sein, dass deine App überall gleich läuft.
  2. Deployment wird zum Kinderspiel – ein Befehl genügt.
  3. Mit NGINX und Kompression holst du mehr Performance raus.
  4. Deine App wächst mit dem Traffic mit.
  5. Keine Sorge mehr vor Konflikten mit anderen Anwendungen.

Fazit: Docker macht dein Angular-Projekt fit für die Zukunft

Mit Docker machst du deine Angular-Entwicklung nicht nur einfacher, sondern auch zukunftssicherer. Die gezeigten Dockerfiles geben dir einen guten Startpunkt, um deine eigenen Angular Docker Container zu bauen.

Ob du es schlank magst oder die volle Power mit NGINX und Brotli willst – beide Ansätze helfen dir, deine Angular-Apps effizienter zu entwickeln und zu deployen.

Probier’s aus und sieh selbst, wie Docker deine Arbeit mit Angular vereinfacht. Mit einer gut geschriebenen Dockerfile bist du bestens gerüstet für moderne, schnelle und skalierbare Webanwendungen.

Denk daran: Die Reise mit Docker und Angular ist ein kontinuierlicher Lernprozess. Experimentiere, optimiere und passe die Dockerfile auf die individuellen Anforderungen deines Projekts an.

Du benötigst Unterstützung beim Deployment oder der Entwicklung deiner Angular-App? Dann schreib uns noch heute! Wir lieben Angular und helfen dir das beste aus deiner Anwendung herauszuholen.