{"id":2588,"date":"2024-09-20T08:00:00","date_gmt":"2024-09-20T06:00:00","guid":{"rendered":"https:\/\/aptex.de\/?p=2588"},"modified":"2025-01-17T10:51:38","modified_gmt":"2025-01-17T09:51:38","slug":"angular-docker-container","status":"publish","type":"post","link":"https:\/\/aptex.de\/blog\/angular-docker-container\/","title":{"rendered":"Angular Docker Container: Deployment leicht gemacht"},"content":{"rendered":"\n
Du entwickelst mit Angular und fragst dich, wie du deine App am besten deployen kannst? Docker k\u00f6nnte die L\u00f6sung sein, die du suchst. In diesem Artikel erkl\u00e4ren wir, wie du Docker f\u00fcr 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\u00fcr Dockerfiles, die du direkt einsetzen kannst.<\/p>\n\n\n\n
Stell dir vor, du k\u00f6nntest deine gesamte Entwicklungsumgebung in ein handliches Paket schn\u00fcren \u2013 inklusive aller Abh\u00e4ngigkeiten und Einstellungen. Genau das macht Docker m\u00f6glich. Es ist wie ein virtueller Server f\u00fcr deine App, der alles enth\u00e4lt, was sie zum Laufen braucht. Aber was genau ist Docker eigentlich?<\/p>\n\n\n\n Docker ist eine Open-Source-Plattform, die es dir erm\u00f6glicht, Anwendungen in isolierten Umgebungen \u2013 sogenannten Containern \u2013 zu entwickeln, zu verpacken und auszuf\u00fchren. Diese Container sind leichtgewichtig, portabel und enthalten alles, was deine Anwendung ben\u00f6tigt: von der Codebasis \u00fcber die Laufzeitumgebung bis hin zu Systemwerkzeugen und Bibliotheken.<\/p>\n\n\n\n Warum solltest du Docker f\u00fcr deine Angular-Projekte in Betracht ziehen? Hier sind einige \u00fcberzeugende Gr\u00fcnde:<\/p>\n\n\n\n Genug der Theorie, lass uns praktisch werden. Hier ist eine Dockerfile, die deine Angular-App f\u00fcr die Produktion fit macht:<\/p>\n\n\n\n Dockerfile auf GitHub ansehen<\/a><\/p>\n\n\n\n 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\u00fcr deine Angular-Anwendung. <\/p>\n\n\n\n Du hast vielleicht bemerkt, dass diese Dockerfile in zwei Stufen aufgeteilt ist. Diesen Ansatz nennt man „Multi-Stage Build“. Aber warum machen wir das?<\/p>\n\n\n\n Der Vorteil dieses Ansatzes? Du bekommst ein viel kleineres Image, das nur die notwendigen Produktionsdateien enth\u00e4lt. Alle Build-Tools und Abh\u00e4ngigkeiten, die nur f\u00fcr den Build-Prozess ben\u00f6tigt werden, bleiben in der Build-Stage zur\u00fcck und belasten dein Produktions-Image nicht. Dies sorgt gleichzeitig auch f\u00fcr mehr Sicherheit.<\/p>\n\n\n\n default.conf auf GitHub ansehen<\/a><\/p>\n\n\n\n Hinweis: In unserem Beispiel lassen wir die Verwendung von SSL-Zertifikaten au\u00dfer acht. Erfahrungsgem\u00e4\u00df sind in Produktivumgebungen andere Dienste, wie bspw. Traefik vorgeschaltet und handhaben das SSL-Offloading, sodass dein Container selbst das nicht tun muss.<\/p>\n\n\n\n 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\u00fcr verwendest:<\/p>\n\n\n\n Das bedeutet das Command:<\/p>\n\n\n\n Nachdem der Build-Prozess abgeschlossen ist, kannst du deinen Container mit folgendem Befehl starten:<\/p>\n\n\n\n Hier wird der Container gestartet und der Port 80 des Containers (auf dem NGINX l\u00e4uft) wird auf den Port 8080 deines Host-Systems gemappt. Du kannst nun deine Angular-App unter Willst du noch mehr Performance aus deiner Angular-App herausholen? Dann schau dir dieses erweiterte Beispiel an, das NGINX mit Brotli-Kompression nutzt:<\/p>\n\n\n\n brotli.Dockerfile auf GitHub ansehen<\/a><\/p>\n\n\n\n F\u00fcr die Brotli-Kompression brauchst du noch eine angepasste NGINX-Konfiguration. Hier ein Beispiel f\u00fcr nginx-brotli.conf auf GitHub ansehen<\/a><\/p>\n\n\n\n Die ist unsere bevorzuge Angular Dockerfile, wie wir sie bereits f\u00fcr viele Anwendungen nutzen.<\/p>\n\n\n\n Der derzeit am weitesten verbreitete Kompressionsalgorithmus f\u00fcr Webinhalte, gzip<\/a>, ist ein effizientes Verfahren zur Datenkompression, das seit den 1990er Jahren verwendet wird und in fast allen modernen Webbrowsern und Servern unterst\u00fctzt wird. Brotli ist ein modernerer Kompressionsalgorithmus, der von Google entwickelt wurde.<\/p>\n\n\n\n Im Vergleich zu gzip bietet Brotli<\/a>:<\/p>\n\n\n\n
<\/figure>\n\n\n\nWarum Docker f\u00fcr Angular-Projekte?<\/h3>\n\n\n\n
\n
Dein erster Angular Docker Container: Schlank und schnell<\/h2>\n\n\n\n
# Build-Stage \/ Verwende Node.js als Basis-Image\nFROM node:alpine as build\n# Setze das Arbeitsverzeichnis\nWORKDIR \/app\n# Kopiere package.json und package-lock.json\nCOPY package*.json .\/\n# Installiere Abh\u00e4ngigkeiten\nRUN npm ci\n# Kopiere den restlichen Quellcode\nCOPY . .\n# Baue die Angular-App\nRUN npm run build\n\n# Production-Stage \/ Verwende NGINX als Basis-Image f\u00fcr die Produktionsumgebung\nFROM nginx:alpine\n# Kopiere die gebaute App in das NGINX-Verzeichnis\nCOPY --from=build \/app\/dist\/meine-angular-app \/usr\/share\/nginx\/html\n# Kopiere deine angepasste NGINX-Konfiguration (optional, aber empfohlen. Eine Beispiel Konfiguration findest du weiter unten)\nCOPY nginx.conf \/etc\/nginx\/nginx.conf\n# Port 80 freigeben, nginx l\u00e4uft auf diesem Port\nEXPOSE 80\nCMD [\"nginx\", \"-g\", \"daemon off;\"]<\/code><\/pre>\n\n\n\nDie zwei Stufen erkl\u00e4rt: Build und Produktion<\/h3>\n\n\n\n
\n
\n
package.json<\/code>-Dateien und installieren die Abh\u00e4ngigkeiten.<\/li>\n\n\n\n\n
\n
Nginx config<\/h3>\n\n\n\n
server {\n # Root-Verzeichnis f\u00fcr den Server setzen (wir kopieren unsere Anwendung hierher)\n root \/usr\/share\/nginx\/html;\n\n # Definieren der Standard-Indexdatei (Angular erstellt die Datei index.html f\u00fcr uns und sie befindet sich im oben genannten Verzeichnis)\n index index.html;\n\n # Cache-Header f\u00fcr Medien-ASsets\n location ~* \\.(?:cur|jpe?g|gif|htc|ico|png|xml|otf|ttf|eot|woff|woff2|svg)$ {\n access_log off;\n add_header Pragma \"must-revalidate, public\";\n add_header Cache-Control \"must-revalidate, public\";\n expires max;\n\n tcp_nodelay off;\n }\n\n # Cache-Header f\u00fcr HTML, CSS und JS-Dateien\n location ~* \\.(?:css|js|html)$ {\n access_log off;\n add_header Pragma \"must-revalidate, public\";\n add_header Cache-Control \"must-revalidate, public\";\n expires 2d;\n\n tcp_nodelay off;\n }\n\n # Konfiguration f\u00fcr den \/-Pfad\n location \/ {\n # Zun\u00e4chst versuchen wir die angeforderte URI auzuliefern\n # Klappt das nicht, versuchen wir es mit einem abschlie\u00dfenden Slash\n # Klappt auch das nicht, liefern wir die index.html aus.\n # Das ist n\u00f6tig, damit Angular-Routen korrekt augefl\u00f6st und ausgeliefert werden\n try_files $uri $uri\/ \/index.html;\n }\n}<\/code><\/pre>\n\n\n\nDocker-Container bauen und starten<\/h3>\n\n\n\n
docker build -t meine-angular-app .<\/code><\/pre>\n\n\n\n\n
docker build<\/code> ist der Befehl zum Erstellen eines Docker-Images.<\/li>\n\n\n\n-t meine-angular-app<\/code> gibt dem Image einen Tag (Namen). Ersetze „meine-angular-app“ durch einen Namen deiner Wahl.<\/li>\n\n\n\n.<\/code> am Ende gibt das Verzeichnis an, in dem sich die Dockerfile befindet. In diesem Fall ist es das aktuelle Verzeichnis.<\/li>\n<\/ul>\n\n\n\ndocker run -p 8080:80 meine-angular-app<\/code><\/pre>\n\n\n\nhttp:\/\/localhost:8080<\/code> aufrufen.<\/p>\n\n\n\nAngular Docker Container mit Extra-Power: NGINX und Brotli<\/h2>\n\n\n\n
# Build-Stage\nFROM node:alpine as build \/\/ siehe oben\nWORKDIR \/app\nCOPY package*.json .\/\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n# NGINX-Stage mit Brotli \nFROM nginx:alpine\nRUN apk add --no-cache brotli\nCOPY --from=build \/app\/dist\/meine-angular-app \/usr\/share\/nginx\/html\nCOPY nginx-brotli.conf \/etc\/nginx\/nginx.conf\nEXPOSE 80\nCMD [\"nginx\", \"-g\", \"daemon off;\"]<\/code><\/pre>\n\n\n\nnginx-brotli.conf<\/code>:<\/p>\n\n\n\nevents {\n worker_connections 1024;\n}\n\nhttp {\n brotli_comp_level 9;\n brotli_types application\/atom+xml application\/javascript application\/json application\/rss+xml\n application\/vnd.ms-fontobject application\/x-font-opentype application\/x-font-truetype\n application\/x-font-ttf application\/x-javascript application\/xhtml+xml application\/xml\n font\/eot font\/opentype font\/otf font\/truetype image\/svg+xml image\/vnd.microsoft.icon\n image\/x-icon image\/x-win-bitmap text\/css text\/javascript text\/plain text\/xml;\n\n include \/etc\/nginx\/mime.types;\n default_type application\/octet-stream;\n\n client_body_buffer_size 10K;\n client_header_buffer_size 1k;\n client_max_body_size 8m;\n large_client_header_buffers 4 16k;\n client_body_timeout 12;\n client_header_timeout 12;\n send_timeout 10;\n\n server {\n listen 80;\n server_name localhost;\n root \/usr\/share\/nginx\/html;\n index index.html;\n\n location ~* \\.(?:cur|jpe?g|gif|htc|ico|png|xml|otf|ttf|eot|woff|woff2|svg)$ {\n access_log off;\n add_header Pragma \"must-revalidate, public\";\n add_header Cache-Control \"must-revalidate, public\";\n expires max;\n \n tcp_nodelay off;\n }\n \n location ~* \\.(?:css|js|html)$ {\n access_log off;\n add_header Pragma \"must-revalidate, public\";\n add_header Cache-Control \"must-revalidate, public\";\n expires 2d;\n \n tcp_nodelay off;\n }\n \n location \/ {\n try_files $uri $uri\/ \/index.html;\n }\n\n proxy_buffer_size 128k;\n proxy_buffers 4 256k;\n proxy_busy_buffers_size 256k;\n }\n}<\/code><\/pre>\n\n\n\nWas macht Brotli so besonders?<\/h3>\n\n\n\n