Zuletzt aktualisiert von Sascha Brockel am 08. Oktober 2023

In der Zeit der Microservices gilt Docker als Non plus ultra. Auch Frontend Anwendungen wie Angular oder Backend Anwendungen wie Spring Boot (Java) lassen sich einfach in Docker Containern nutzen. Bei der Präsentation einer Anwendung vor einer größeren Gruppe kann Ihnen dies nützlich sein.

Bei der Verwendung eines eigenen Servers können die Applikationen ganz einfach bereitgestellt werden und allen zugänglich gemacht werden. So kann jeder sich bereits bei einer Präsentation mit der Applikation vertraut machen.

Für das folgende Beispiel werden einige Programme und Dienste benötigt:

  • Gradle
  • Java 8 (JDK)
  • MySQL 8
  • Node.js (Version 10.13 oder neuer)
  • Docker

Man muss in Angular dafür sorgen, dass man die Verbindungen zwischen den Docker Containern noch zum Deployment setzen kann. Die Docker Container kommunizieren in einem internen Netzwerk miteinander und besitzen somit andere IP’s.

Ermöglicht wird dies in Docker durch Environment Variablen, die man aber nicht so einfach wie beispielsweise Spring Boot durch eine @Value Annotation setzen kann.

Um das Ganze also möglich zu machen muss ein neues Script im Ordner /assets erstellt und eingebunden werden. Die Datei nennen Sie env.js mit folgendem Inhalt:

Der hier angegebene Wert für apiUrl stellt den default Wert dar, falls die Variable nicht direkt durch Docker gesetzt wird. Dabei möchte ich noch einmal darauf hinweisen, dass der gesamte Code in den unten im Fazit verlinkten GitHub Repositories zu finden ist.

Damit das neu erstellte JavaScript nun beim Start von Angular ausgeführt wird müssen Sie es zur index.html hinzufügen.

Jetzt müssen Sie die eigentlichen Environment Dateien von Angular ändern, um mit diesen das Setzen durch Docker zu ermöglichen. Dazu muss im Ordner /environments die environment.ts wie folgt ergänzt werden. Dasselbe sollte auch bei der environment.prod.ts für den produktiven Betrieb getan werden. Dabei müssen Sie aber natürlich darauf achten, dass production: true ist.

Durch diese Änderung kommen die Werte nun aus unserem zuvor erstellten Script env.js. Aktuell gibt es aber noch keine Möglichkeit diese apiUrl aber auch dynamisch zum Deployment zu setzen.

Docker benötigt eine Möglichkeit auf einen vordefinierten Variablennamen zuzugreifen. Um das zu ermöglichen, müssen Sie ebenfalls im Ordner /assets noch eine Datei namens env.template.js anlegen. Vom Grundprinzip sieht die Datei aus wie die env.js nur mit dem Unterschied, dass wir nun den Variablennamen festlegen (hier API_URL).

Mit dem Befehl envsubst können Sie dann die Variablen die im Template gesetzt werden in die env.js einsetzen. Also beispielsweise mit einer Angabe von API_URL: http://localhost:8080. Das sieht dann im Endeffekt so aus:

Im user.service.ts muss environment als Variable importiert werden und kann dann als normale Deklaration genutzt werden. Somit kann auf die apiUrl zugegriffen werden und der hinterlegt Pfad beziehungsweise Adresse wird verwendet.

Dazu benötigen Sie ein Dockerfile. Dies finden Sie ebenfalls im GitHub Repository in dem Ordner docker.

Zu erst einmal wird node als Basis genutzt. Anschließend werden alle Dependencies des Projekts installiert und das Ganze direkt gebuildet. Die Konfiguration steht dabei auf dem produktiven Modus. Generell ermöglicht das Builden im Voraus weniger Last für denjenigen der das Docker Image herunterlädt und es starten will. Denn nichts muss mehr gebuildet werden. Dies sorgt vor allem für deutlich kleinere Imagegrößen.

So habe ich Bibliotheken wie Angular Material oder FontAwesome verwendet, aber dennoch nur eine Imagegröße von 10 MB erzielt (siehe https://hub.docker.com/r/saschabrockel/docker-spring-angular/tags). Ansonsten würde der gesamte node_modules Ordner mit in das Image gepackt werden. Somit würden schnell Größen von 400-700 MB erreicht werden.

Um die gebuildete Angular Anwendung nun auch aufrufbar zu machen müssen Sie nginx als Webserver noch dementsprechend konfigurieren. Dazu dient die nginx-custom.conf (auffindbar im frontend Ordner).

Die Anfragen an die URL’s werden immer weitergeleitet, es sei denn die URL existiert nicht. Dann wird der Benutzer immer auf die Startseite weitergeleitet.

Da man eine Webanwendung meist über eine direkte URL ohne Portangabe ausführen will, geben Sie hierfür den Port EXPOSE 80 an. Schlussendlich kommt dann das bereits vorhin vorgestellte Überschreiben der Environment Variablen.

Damit sind alle Vorkehrungen getroffen das Angular-Frontend nun mit einem beliebigen Backend zum Deployment zu verbinden.

In Spring Boot ist das Ganze etwas unkomplizierter, da bereits von Haus aus alle Voraussetzungen für das dynamische Setzen von Variablen existieren.

REST-Anfragen finden über den Controller statt und deshalb muss dieser auch unsere Variable enthalten. Ermöglicht wird das Ganze im UserController durch die @Value Annotation.

Dies dient lediglich als kleiner Exkurs, da dies in diesem Beispielprojekt nicht verwendet wird. Es hat aber dieselbe Funktion wie das Setzen in Angular. Somit könnte möglicherweise ein weiterer Spring Boot Server angesprochen werden.

Damit die Variable nun auch gesetzt werden kann muss der in der @Value Annotation angegebene Name nun auch in der Eigenschaftsdatei application.properties mit einem Default Wert deklariert werden.

Alle sich in application.properties befindlichen Angaben können in Docker durch die Angabe der entsprechenden Environment Variable überschrieben werden. Somit auch die spätere im Abschnitt Docker nötige Deklaration der Datenbankverbindung.

Der letzte zu beachtende Teil ist das leidige Thema CORS. Grundsätzlich ist CORS wichtig für die Sicherheit, aber oft nicht so trivial einzurichten. Es legt fest, welche Webanwendungen einer anderen Domain Zugriff auf den Server haben können sollen.

Nach meinem aktuellen Erkenntnisstand ist es leider nicht möglich die CORS Konfiguration ebenfalls zum Deployment festzulegen. Dies muss bereits vor dem Builden des Images geschehen. Die Konfiguration finden wir in der WebSecurityConfig.

Wichtig ist für unserer Vorhaben der Punkt config.setAllowedOrigins(). Hiermit legen wir fest, welche Domains nun eine Anfrage an den Server schicken dürfen. In unserem Fall eigentlich nur localhost:4200 für das Development, dann localhost für die Verwendung in Docker auf Windows. Als Beispiel eben dann auch die Angabe http://your-domain.com von der dann Anfragen geschickt werden könnten.

Natürlich können auch CORS Einstellungen weiterhin auf Controller Ebene mit der @CrossOrigin Annotation getroffen werden. Wichtig ist, dass es ein CorsFilter ist, da bei einer CorsConfigurationSource die Einstellungen bei diesem Beispielrojekt nicht wirken.

Zu guter Letzt kommen wir dazu das Ganze in Docker zu verknüpfen und auszuführen. Das Dockerfile des Backends überspringe ich in der Erklärung, da es dort keine Besonderheiten gibt.

Der Angular Abschnitt ist sehr trivial. Der Container läuft solange er nicht gestoppt wird. Der Port ist wie bereits im Frontend Abschnitt erwähnt 80, um keine Angabe des Ports im Browser zu benötigen. Nun kommt die Environment Variable zum Tragen. API_URL wird definiert und zeigt auf die Adresse des Spring Boot Containers. Das Netzwerk dient dem Austausch der Container untereinander.

Spring Boot sieht sehr ähnlich aus. Hierbei setzen wir dann im Environment vor allem die Variablen, die die Datenbankverbindung setzen. Es ist wichtig, dass die Variablen mit denen, die für das Erstellen der Datenbank genutzt werden, übereinstimmen.

So stimmen spring.datasource.username und MYSQL_USER überein, damit die Verbindung überhaupt erst hergestellt werden kann. Speziell wird es nochmals bei der genauen Deklaration der Datenbank. MYSQL_DATABASE: dockerSpringAngular gibt den Namen der Datenbank vor. Um diese dann aber zu verwenden müssen wir die dementsprechend spring.datasource.url anpassen. Hier ein Vergleich der Zeile in application.properties und in der docker-compose.yml.

Statt localhost geben wir nun den Namen des Datenbankcontainers (db) an, um die Verbindung herzustellen. Außerdem fallen die weiteren Attribute auf Docker-Ebene weg.

Es gibt zu beachten, dass mit der aktuellen docker-compose.yml keine Daten gespeichert werden, da keine Volumes festgelegt wurden.

Nun haben Sie gelernt wie man Angular mit Spring Boot in Docker deployen kann. Hierbei wie man die einzelnen API-Endpunkte bei der Definition der Docker Services definieren kann und welche Anpassungen dafür vorgenommen werden müssen.

Wenn die Voraussetzungen geschaffen wurden, ist es einfach Anpassungen beim Deployment wie beispielsweise das Wechseln des Servers durchzuführen. Probiert es sehr gerne selbst aus.

Das Ganze sollte dann im Browser so aussehen. In den einzelnen Projektordnern des GitHub Repository finden Sie README’s mit Dokumentation und Schnellzugriffen auf einzelne Dateien.
Quelle zum Setzen der Angular Variablen: https://pumpingco.de/blog/environment-variables-angular-docker/

Den gesamten Source Code finden Sie auf GitHub.
Die Docker Images gibt es im DockerHub.


0 Kommentare

Schreibe einen Kommentar

Avatar-Platzhalter

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

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

de_DE