Docker für Angular Multi-Stage Builds
Docker hat mit Version 17.05 sogenannte Multi-Stage Builds eingeführt. Dieser Beitrag zeigt, wie Docker-Multi-Stage-Builds effektiv für Angular-Anwendungen eingesetzt werden können und um was es sich bei Docker-Multi-Stage-Builds überhaupt handelt.
Typischerweise werden Docker-Container eingesetzt, um damit eine gekapselte Umgebung zur Ausführung von Programmen anzubieten. Oft sind das Dienstanwendungen, die dank Docker umgebungsagnostisch betrieben werden können - eine wichtige Eigenschaft im Zeitalter von Clouddeployment. Beispiele hierfür sind langlaufende Anwendungen, die Dienste bereitstellen, die durch anderen Anwendungen oder direkt durch einen Nutzer in Anspruch genommen werden. Solche Anwendungen finden sich häufig im Backend.
Tip
|
Wie Docker sich für Spring Boot und Angular Anwendungen einsetzen lässt, wird ausführlich in Docker für lokale Tests mit Angular und Spring Boot erklärt. |
Docker Build-Container
Docker eignet sich jedoch auch für die Verwendung mit sehr kurzlebigen Anwendungen, die lediglich einen Zweck erfüllen und nach getaner Arbeit nicht mehr benötigt werden. Zum Beispiel können sich damit Builds sehr einfach umsetzen lassen, ohne dass das System, auf dem der Build durchgeführt wird, sämtliche Werkzeuge und eine möglicherweise komplexe Umgebung bereitstellen muss.
In dem Artikel NetBeans Docker und ROOT wurde gezeigt, wie Docker für die Entwicklung von C++ Programmen mit komplexen Library-Abhängigkeiten nutzen lässt, ohne dabei auf eine IDE Integration verzichten zu müssen.
Typische Build-Container stellen so z.B. Maven, Gradle oder andere Buildchains und ggf. benötigte Bibliotheken zur Verfügung. Das funktioniert dann auch für TypeScript- und Angular-Anwendungen.
AngularCLI Docker Build-Container
Zur Veranschaulichung soll eine einfache Angular-Anwendung verwendet werden.
Am einfachsten lässt sich ein neues Projekt mit Angular CLI erzeugen.
Ist Angular CLI bereits installiert, so erzeugt der Aufruf von ng new MyProject
ein neues Projekt.
Ist noch kein Angular CLI installiert, so kann dazu ein Docker-Build-Container verwendet werden, wie für den eigentlich Build auch.
Als fertige Docker-Images für Angular CLI stehen zur Auswahl:
Image |
Beschreibung |
Minimales Angular CLI und NPM Setup |
|
Angular CLI und Abhängigkeiten mit headless Browser für Karma |
|
Angular CLI und Abhängigkeiten für e2e Tests mit Protractor in Docker |
Für einen einfachen Build ohne Tests reicht daher das trion/ng-cli
Image.
Befindet man sich bereits im Verzeichnis mit der Angular-Anwendung, könnte ein Build unter Verwendung des Docker-Build-Containers so aussehen:
docker run -u $(id -u) --rm -v "$PWD":/app trion/ng-cli \ npm install && ng build --prod --aot --sourcemaps
Tip
|
Die trion/ng-cli* Images werden durch Docker Tags für die jeweilige Version von Angular-CLI breitgestellt. Damit lässt sich die Version spezifizieren und Umstellungen besser planen und kontrollieren.
|
Nun liegen die Buildergebnisse im aktuellen Verzeichnis. Zur weiteren Distribution und ggf. für lokale Tests nahe an einer echten Umgebung gilt es nun die Anwendung in ein Docker-Image zu verpacken, auf Basis dessen dann Docker-Container gestartet werden können.
Angular Docker Image
Angular-Anwendungen werden in einem Webbrowser ausgeführt, aber die Auslieferung geschieht in der Regel durch einen Webserver. Da die Angular-Anwendung lediglich aus statischen HTML, CSS und JavaScript Dateien besteht, bietet sich ein schlanker Webserver wie nginx an. Lediglich für das Angular-Routing müssen ein paar Rewrite-Regeln erstellt werden, damit auch der direkte Einsprung in eine Route und das Neuladen korrekt funktionieren.
Die nginx Konfiguration für eine Angular-Anwendung könnte zum Beispiel so aussehen:
server { listen 8080; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri$args $uri$args/ $uri $uri/ /index.html =404; } }
Für das Beispiel wird angenommen, dass mit Angular-CLI der Angular-Frontendbuild umgesetzt ist, und sich die Ergebnisse im dist
Ordner befinden.
Damit stellt sich ein mögliches Dockerfile
wie folgt dar:
FROM nginx:alpine EXPOSE 8080 COPY dist /usr/share/nginx/html/ COPY nginx/default.conf /etc/nginx/conf.d/default.conf.template RUN chown -R nginx /etc/nginx CMD ["/bin/sh","-c",\ "cp /etc/nginx/conf.d/default.conf.template\ /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]
Die nginx Konfigurationsdatei kann dann z.B. in einem nginx
Unterordner des Angularprojekts abgelegt werden.
Nachdem die Angular Anwendung mittels ng build
gebaut wurde, kann das Resultat gemeinsam mit nginx zu einem Image vereinigt werden.
Um das Image zu bauen und unter dem Namen trion/angular-app
verfügbar zu machen, wird aus dem Verzeichnis mit der Angular-Anwendung folgendes Kommando verwendet:
docker build -t trion/angular-app .
Multi-Stage Docker Images
Für den Build der Angular-Anwendung wurde nun ein Docker-Image verwendet, genauso wie zur Ausführung mit dem nginx-Webserver.
Seit Docker 17.05 gibt es sogenannte Multi-Stage Builds.
Dies Feature trägt dem relativ häufigen Anwendungsfall Rechnung, dass für einen Build unterschiedliche Docker Images in den verschiedenen Buildphasen zum Einsatz kommen.
Statt den Ablauf dann manuell - und damit fehleranfällig - oder per eigenem Script abzubilden, erlaubt Docker nun mehrere Stufen in einem Dockerfile
zu bechreiben.
Dabei können Daten selektiv aus einem Container in den nächsten propagiert werden.
Für das Beispiel mit dem Build auf Basis von Angular-CLI und dem Laufzeitimage auf Basis des nginx-Webservers können beide Phasen nun in einem Dockerfile abgebildet werden.
Die wesentlichen Unterschiede im Vergleich zu den einzelnen Dockerfiles sind dabei die Nutzung mehrerer Basisimages (FROM
) Kopien von Daten statt der Verwendung von Volume-Mounts.
Beispiel für einen Multistage-Build:
FROM trion/ng-cli:latest AS ngcli #(1) USER root WORKDIR /app COPY . . #(2) RUN npm install RUN ng build --prod --aot --progress=false FROM nginx:alpine AS app #(3) ENV PORT=8080 EXPOSE 8080 COPY --from=ngcli /app/dist /usr/share/nginx/html/ #(4) COPY nginx/default.conf /etc/nginx/conf.d/default.conf.template RUN chown -R nginx /etc/nginx CMD ["/bin/sh","-c",\ "cp /etc/nginx/conf.d/default.conf.template \ /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]
-
Angular-CLI-Basisimage mit Alias Namen 'ngcli'
-
Statt eines Volume-Mounts werden die Quellen in den Buildcontainer kopiert
-
Wechsel des Docker Base-Image für den Ausführungscontainer
-
Buildergebnisse aus dem Buildcontainer werden in den Ausführungscontainer kopiert
Der Verzicht auf Volumemounts deutet schon darauf hin, dass Multistage-Builds sich auch sehr gut für CI Umgebungen und Continous Deployment eignen. Ein Einsatz auf Entwicklerarbeitsplätzen ist ebenfalls denkbar, insbesondere wenn es um den Test im Zusammenhang mit dem Container geht.
Zu den Themen Angular als auch Docker bieten wir sowohl Unterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.