Die effiziente, schnelle und wiederholbare Bereitstellung von Anwendungen in heterogenen Umgebungen kann komplex erscheinen. In diesem Artikel möchte ich Ihnen einen detaillierten Einblick in die Bereitstellung einer .NET-Backend-API in Docker-Containern geben, die mit einer Angular-Front-End-Anwendung gekoppelt ist, die ich entwickelt und in einem früheren Artikel vorgestellt habe.
Wir werden uns gemeinsam ansehen, wie Sie Docker verwenden können, um diese Anwendungen effizient auf Raspberry Pis einzusetzen. Jeder dieser kleinen Computer, die in unserer Architektur als unabhängiger Server fungieren, wird mit einem IBM i-Server verbunden.
Unsere .NET-API dient mithilfe des NTi-Data-Providers als Service-Schicht, indem sie Daten und Funktionen aus einer auf IBM i gehosteten DB2 for i-Datenbank sowie einer weiteren Postgre SQL-Datenbank, die auf einem Raspberry 4 läuft, exponiert. Die Angular-Anwendung hingegen konsumiert und nutzt diese Dienste, um eine Benutzeroberfläche bereitzustellen.
Voraussetzungen und Entwicklungsumgebung.
💻 IDE:
Die .NET-API wurde mit Visual Studio entwickelt, wobei die eingebauten Funktionen für die Verwaltung von Docker-Containern genutzt wurden.
Die ANGULAR-Anwendung wurde mit Visual Studio Code entwickelt, der für seine Leichtigkeit und Flexibilität geschätzt wird, insbesondere für JavaScript / TypeScript-Projekte.
🍓 Zielsystem
Die Anwendungen sollen auf Raspberry Pi 4 und 5 eingesetzt werden. Diese Nanocomputer mit ARM-Prozessor sind mit einem IBM i verbunden.
🐳 Docker:
Docker desktop, das auf meinem Entwicklungsrechner installiert ist, wird es mir ermöglichen, die Anwendungen in Container zu packen, was ihren Einsatz auf verschiedenen Hardware-Architekturen, insbesondere Raspberry Pi, erleichtert.
TEIL 1 - Bereitstellung der .NET API.
Schritt 1 - Erstellen des Dockerfiles mit VISUAL STUDIO.
Der erste Schritt besteht darin, ein Dockerfile für die .NET-API zu erstellen. Visual Studio erleichtert diesen Prozess durch seine native Docker-Integration:
Rechtsklick auf das Projekt > Hinzufügen > Docker-Unterstützung.
Visual Studio generiert ein Dockerfile, das auf die Anwendung zugeschnitten und für die .NET-Umgebung vorkonfiguriert ist.
Diese Datei definiert die Anweisungen für den Aufbau des Docker-Images der Anwendung, einschließlich der Grundlage, des Aufbaus, der Veröffentlichung und des letzten Schritts zum Ausführen der Anwendung.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["AccessDataAPI.csproj", "."]
RUN dotnet restore "./././AccessDataAPI.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./AccessDataAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./AccessDataAPI.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AccessDataAPI.dll"]
- Schritt Basis: Verwende das offizielle Docker-Image von ASP.NET, um eine Laufzeitumgebung für die Anwendung zu erstellen. Die Ports 8080 und 8081 werden für HTTP- und HTTPS-Verkehr freigelegt.
- Schritt Build: Verwendet das SDK-Image, um die Anwendung zu kompilieren. In diesem Schritt werden die Abhängigkeiten verwaltet und die Kompilierung durchgeführt.
- Schritt Publish: Veröffentlicht die kompilierte Anwendung, die für den Einsatz bereit ist.
- Schritt Final: ¨Bereitet das endgültige Image vor, indem die veröffentlichte Anwendung in die Laufzeitumgebung kopiert wird.
Schritt 2 - Hinzufügen von CORS ( Cross Origin Resource Sharing ).
using AccessDataAPI.Services;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
var builder = WebApplication.CreateBuilder(args);
// Fügen Sie die CORS-Konfiguration hinzu, um Abfragen aus der Angular HotelAppManager-Anwendung zuzulassen.
builder.Services.AddCors(options =>
{
options.AddPolicy("MyCorsPolicy", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
Damit unsere .NET-API Anfragen von anderen Ursprüngen annehmen kann, wie z. B. unsere Angular-Anwendung, die auf einem anderen Server gehostet wird, richten wir CORS (Cross Origin Resource Sharing) in der Datei "program.cs" ein.
CORS sind essentiell, da sie es unserer Frontend-Anwendung ermöglichen, einfach mit unserem Backend zu kommunizieren.
Schritt 3 - Einrichten der LaunchSettings.json
Diese Datei definiert mehrere Profile für den Start der Anwendung, einschließlich der lokalen Entwicklung über HTTP oder HTTPS sowie Docker.
- Die HTTP- & HTTPS-Profile: Sie ermöglichen den lokalen Start der Anwendung, mit oder ohne SSL, und geben die Start-URL, die verwendeten Ports und die Umgebungsvariablen an.
- Das Docker-Profil: Es teilt Visual Studio mit, wie es die Anwendung in Docker zu starten beginnt, einschließlich der Port-Zuordnung und der Verwendung von SSL. Die Umgebungsvariablen werden hier so definiert, dass sie mit den im "Dockerfile" exponierten Ports übereinstimmen.
Schritt 4 - Einsatz auf DOCKER
Nachdem wir das Dockerfile, die Launchsettings und die CORS konfiguriert haben, ist es nun an der Zeit, das DOCKER-Image der .NET-API mithilfe der Befehlszeile zu erstellen.
Im aktuellen Ordner unserer Anwendung werden wir Docker Buildx verwenden, um ein Multi-Architektur-Image des .NET APi zu erstellen, das für die Bereitstellung der Anwendung auf dem Raspberry Pi unerlässlich ist.
docker buildx build --platform linux/arm64/v8,linux/amd64 -t quentindaumerial/accessdataapi:latest --push -f Dockerfile .
Das Image wird direkt an meinen Docker Hub gesendet und bestätigt den erfolgreichen Abschluss des Builds.
Um zu validieren, dass der .NET-API in einer unserem Einsatzziel ähnlichen Umgebung funktioniert, führe ich das Image lokal mit "docker run" aus.
Indem ich die erforderlichen Ports abbilde und die Umgebungsvariablen für SSL konfiguriere, simuliere ich die Produktionsumgebung auf meinem Entwicklungsrechner.
docker run --rm -it -p 7245:8080 -p 7246:8081 -e ASPNETCORE_HTTPS_PORTS=8081 -e ASPNETCORE_HTTP_PORTS=8080 -e ASPNETCORE_Kestrel__Certificates__Default__Password="password" -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx -v %USERPROFILE%\.aspnet\https:/https/ accessdataapi
Wenn ich von meinem Webbrowser aus auf https://localhost:7246/HotelCustomer/clients gehe, kann ich auf die von meiner API offengelegten Daten direkt aus DB2 for i zugreifen. Diese Validierung stellt sicher, dass meine .NET-API für den Einsatz auf dem Raspberry 5 bereit ist.
Schritt 5 - Senden Sie das Image an den RASPBERRY Pi 5.
Nachdem ich das Image in die Registry meines Docker Hub geschoben habe, ist es nun an der Zeit, sich mit dem Raspberry Pi über SSH zu verbinden, das Image direkt von meinem Hub herunterzuladen und es in einen Container zu starten.
- Verbindung zum Raspberry 5 über SSH:.
- Download des Bildes von meinem Docker Hub:
docker image pull quentindaumerial/accessdataapi:latest
Schritt 6 - Starten Sie den Docker-Container auf dem Raspberry 5.
Ich starte meinen Container, indem ich den Port 8080 des Containers auf den Port 5040 meines Raspberry Pi 5 abbilde:
docker run -it -p 5040:8080 quentindaumerial/accessdataapi:latest
Und das war's! Meine .NET-API läuft jetzt in einem Docker-Container auf meinem Raspberry Pi 5, der wiederum mit meinem IBM i verbunden ist. Ich kann das direkt überprüfen, indem ich die Adresse http://192.168.46.34:5040/hotelcustomer/clients besuche.
TEIL 2 - Deployment der ANGULAR-Anwendung.
Schritt 1 - Vorbereiten des Dockerfiles.
Wie bei der .NET-API müssen wir zum Docking unserer ANGULAR-Anwendung in den Ordner unserer Anwendung gehen und eine Datei namens Dockerfile ohne Erweiterung erstellen.
Sie besteht aus zwei Schritten: Bau und Ausführung.
### STAGE 1:BUILD ###
FROM node:latest AS build
WORKDIR /app
COPY package.json ./
RUN npm install
RUN npm build --configuration=production
### STAGE 2:RUN ###
FROM nginx:latest
COPY dist/app-data-manager usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
Der Build-Schritt wird die neueste Version des "node"-Images verwenden, um die Abhängigkeiten zu installieren und die Angular-Anwendung zu bauen, indem eine Produktionskonfiguration angegeben wird ( * wird später in Schritt 4 detailliert*).
Der Ausführungsschritt wird die neueste Version des "nginx"-Images verwenden, um unsere Anwendung zu bedienen. Die erzeugten Verteilungsdateien werden nach /usr/share/nginx/html kopiert, dem Standardordner, den NGINX zum Servieren von Webcontainern verwendet.
Schritt 2 - Erstellen Sie die Datei nginx.conf.
Diese Datei konfiguriert NGINX, um unsere ANGULAR-Anwendung korrekt zu bedienen, indem sie das clientseitige Routing unterstützt.
events{}
http {
include /etc/nginx/mime.types;
server {
root /usr/share/nginx/html/browser;
index /index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
}
Der Block "server" legt fest, wo die Dateien der Anwendung zu finden sind und wie HTTP-Anfragen beantwortet werden sollen.
Die "try_files"-Direktive weist NGINX an, index.html für alle clientseitig verwalteten Routen zu servieren.
Schritt 3 - Einrichten der Entwicklungs- und Produktionsumgebungen.
Wie Sie vielleicht im Dockerfile gesehen haben, haben wir einen Build mit "-configuration production" angegeben.
Angular ist nämlich in der Lage, nativ zwischen den spezifischen Konfigurationen der Entwicklungs- und Produktionsumgebung zu unterscheiden und diese zu verwalten, um sicherzustellen, dass sich die Anwendung in jedem Kontext (insbesondere bei der Verbindung mit meiner API) wie vorgesehen verhält.
- Für die Entwicklung ("src/environments/environment.ts"):**.
Enthält die während der Entwicklung verwendete Konfiguration, einschließlich der Basis-URL der API, die auf den Entwicklungsserver verweist, den wir in der Datei launchsettings unserer .NET-API konfiguriert haben.
export const environment = {
production: false,
apiBaseUrl: 'https://localhost:7246/'
};
- Für die Produktionsversion ("src/environments/environment.prod.ts"):.
Enthält die für die Produktionsversion der Anwendung verwendete Konfiguration mit einer URL, die auf den Produktionsserver zeigt ( hier unser zweiter Raspberry Pi, erreichbar unter der Adresse 192.168.46.34, auf Port 5040).
export const environment = {
production: true,
apiBaseUrl: 'http://192.168.46.34:5040/'
};
Diese Dateien ermöglichen ein vereinfachtes Umschalten zwischen Entwicklungs- und Produktionskonfigurationen, indem einfach das Flag "production" während des Builds der Anwendung geändert wird.
Der Befehl ng serve von Angular ermöglicht mir also den Zugriff auf meinen Entwicklungsserver auf meinem localhost, Port 4200.
Schritt 4 - Aufbau des Docker-Images.
Ähnlich wie bei unserer .NET-API ist es wichtig, das Image plattformübergreifend aufzubauen, um die Kompatibilität der Angular-Anwendung mit verschiedenen Architekturen zu gewährleisten.
Wir verwenden daher erneut Docker Buildx, um ein Image zu erstellen, das sowohl auf den Architekturen amd64 (typisch für PCs und Server) als auch arm64/v8 (Arm-Geräte wie der Raspberry) läuft.
Der folgende Befehl startet den Build des Images und schiebt es auf meinen Dockerhub:
docker buildx build --platform linux/amd64,linux/arm64,linux/arm64/v8 -t quentindaumerial/appdatamanager:latest --push --no-cache .
Mon image est bien mis à jour sur mon Dockerhub:
Schritt 5 - Senden Sie das BILD an Raspberry 4.
Nachdem ich das Image meiner Angular-Anwendung auf Dockerhub gebaut und gepusht habe, verbinde ich mich über SSH mit dem Raspberry Pi 4 :
Ich rufe die neueste Version meines Bildes von meinem Hub ab, um es auf dem Raspberry Pi verfügbar zu machen:
docker image pull quentindaumerial/appdatamanager:latest
Schritt 6 - Starten Sie den Docker-Container auf dem Raspberry 4.
Da das Bild nun heruntergeladen ist, starte ich einen Docker-Container, um die Angular-Anwendung einzusetzen, indem ich Port 80 des Containers auf Port 5000 des Raspberry pi 4 abbilde:
docker run -it --platform linux/arm64/v8 -p 5000:80 quentindaumerial/appdatamanager:latest
Die Anwendung ist nun über einen Webbrowser unter der Adresse "**http://192.168.46.31:5000**" erreichbar.
Insbesondere fällt auf, dass die Daten gut von unserem APi hochkommen, der die von DB2 for i ausgestellten und über NTi von .NET abgerufenen Daten konsumiert:
SCHLUSSFOLGERUNG
Durch die Einrichtung spezieller Dockerfiles, die richtige Konfiguration von nginx.conf für Angular sowie die Anpassung der CORS und der Startparameter unserer .NET-API ist es möglich, auf einfache Weise ein Ökosystem zu schaffen, in dem beide Anwendungen isoliert perfekt funktionieren. Was ist das Ergebnis? Ein reibungsloser und einfacher Datenabruf, der die Vernetzung in einer Containerumgebung veranschaulicht.
Die Verwendung des NTi-Connectors spielt hier eine wesentliche Rolle in unserer .NET-API, indem er die Verbindung zu DB2 for i erleichtert. Damit beweist er, dass es möglich ist, .NET CORE-Anwendungen nativ laufen zu lassen, die mit Daten auf IBM i interagieren, und dabei in einer Docker-Umgebung zu bleiben. Die einfache Bereitstellung einer .NET-API und einer Client-Anwendung in Verbindung mit der Fähigkeit unseres Datenanbieters NTi, nativ in .NET zu operieren, unterstreicht nicht nur die einfache Verwaltung solcher Anwendungen, sondern auch ihr Skalierungspotenzial. Dieses Projekt ist nur ein Beispiel für die vielen Möglichkeiten, wie wir den Einsatz von Technologien heute neu überdenken können, um zu kreieren, zu innovieren und Entwicklungs- und Einsatzprozesse zu optimieren.
*Ich hoffe, dass dieser Leitfaden Ihnen das Wissen und die Inspiration vermittelt hat, die Sie benötigen, um neue Methoden und Werkzeuge für Ihre eigenen Projekte zu erforschen. Docker ist dazu da, die Bereitstellung von Anwendungen zu vereinfachen, zu beschleunigen und zuverlässiger zu machen, damit Sie sich auf das konzentrieren können, was wirklich wichtig ist: die spezifischen Anforderungen jedes Kundenprojekts effektiv zu erfüllen.
Quentin Destrade