DB2 for i & .NET: apps Angular en Raspberry Pi con Docker

En este artículo, descubra el proceso de despliegue de aplicaciones en entornos heterogéneos mediante Docker. Explore un enfoque detallado para crear una red de aplicaciones interoperables y distribuidas.

Imagen ilustrativa del artículo

Desplegar aplicaciones de forma eficiente, rápida y reproducible en entornos heterogéneos puede parecer complejo. En este artículo, te invito a descubrir el proceso detallado de despliegue de una APi .NET back-end en contenedores Docker, acoplada a una aplicación front-end Angular, que desarrollé e introduje en un artículo anterior.

Juntos vamos a ver cómo utilizar Docker para desplegar estas aplicaciones de manera eficiente en ordenadores Raspberry Pi. Cada uno de estos pequeños ordenadores, funcionando como un servidor independiente en nuestra arquitectura, estará conectado a un servidor IBM i.

Nuestra API .NET, utilizando el proveedor de datos NTi, actúa como una capa de servicio, exponiendo los datos y la funcionalidad de una base de datos DB2 para i alojada en el IBM i, así como otra base de datos Postgre SQL que se ejecuta en una Raspberry 4. La aplicación Angular consume y utiliza estos servicios para proporcionar una interfaz de usuario.

Requisitos previos y entorno de desarrollo

💻 IDE:

La API .NET se ha desarrollado utilizando Visual Studio, aprovechando sus funcionalidades integradas para la gestión de contenedores Docker.
La aplicación ANGULAR se ha desarrollado utilizando Visual Studio Code, apreciado por su ligereza y flexibilidad, especialmente para proyectos JavaScript / TypeScript.

🍓 Sistema de destino:

Las aplicaciones están diseñadas para ser desplegadas en Raspberry Pi 4 y 5. Estos nanoordenadores con procesador ARM están conectados a un IBM i.

🐳 Docker:

Docker desktop, instalado en mi máquina de desarrollo, me permitirá contenerizar aplicaciones, facilitando su despliegue en diferentes arquitecturas de hardware, en particular las de la Raspberry Pi.

PARTE 1 - Despliegue de la API .NET.

Paso 1 - Creando el Dockerfile con VISUAL STUDIO.

El primer paso es crear un Dockerfile para la API .NET. Visual Studio facilita este proceso gracias a su integración nativa con Docker:

clic derecho en proyecto > Añadir > Soportado con Docker.

Visual Studio genera un Dockerfile adaptado a la aplicación, preconfigurado para el entorno .NET.

Este archivo define las instrucciones para construir la imagen Docker de la aplicación, incluyendo la base, construir, publicar y el paso final para ejecutar la aplicación.

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"]
  • Paso básico:** Utilice la imagen Docker oficial de ASP.NET para crear un entorno de ejecución para la aplicación. Los puertos 8080 y 8081 están expuestos para el tráfico HTTP y HTTPS.
  • Build:** Utiliza la imagen SDK para compilar la aplicación. La gestión de dependencias y la compilación se llevan a cabo en esta etapa.
  • Etapa de publicación:** Publica la aplicación compilada, lista para su despliegue.
  • Etapa final: ¨Prepara la imagen final copiando la aplicación publicada al entorno de ejecución.

Paso 2 - Añadir 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);

// Añade la configuración CORS para autorizar las peticiones de la aplicación Angular HotelAppManager. 

builder.Services.AddCors(options =>
{
    options.AddPolicy("MyCorsPolicy", policy =>
    {
        policy.AllowAnyOrigin()
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});

Para permitir que nuestra API .NET acepte peticiones de otros orígenes, como nuestra aplicación Angular que estará alojada en un servidor diferente, configuramos CORS (Cross Origin Resource Sharing) en el archivo "program.cs".

CORS es esencial, ya que permite a nuestra aplicación front-end comunicarse de forma sencilla con nuestro back-end.

Paso 3 - Configurando LaunchSettings.json

LaunchSettings.json en Visual Studio

Este archivo define varios perfiles para lanzar la aplicación, incluyendo el desarrollo local vía HTTP o HTTPS, así como Docker.

  • Los perfiles HTTP y HTTPS:** permiten lanzar la aplicación localmente, con o sin SSL, especificando la URL de lanzamiento, los puertos utilizados y las variables de entorno.
  • El perfil Docker:** indica a Visual Studio cómo lanzar la aplicación en Docker, incluyendo la asignación de puertos y el uso de SSL. Las variables de entorno se definen aquí para que coincidan con los puertos expuestos en el Dockerfile.

Paso 4 - Despliegue en DOCKER

Una vez que el Dockerfile, launchsettings y CORS han sido configurados, es el momento de construir la imagen DOCKER de la .NET APi usando la línea de comandos.

En la carpeta actual de nuestra aplicación, vamos a utilizar Docker Buildx para crear una imagen multi-arquitectura de .NET APi, que es esencial para desplegar la aplicación en la Raspberry Pi.

docker buildx build --platform linux/arm64/v8,linux/amd64 -t quentindaumerial/accessdataapi:latest --push -f Dockerfile .

La imagen se envía directamente a mi Docker Hub, confirmando que la compilación se ha completado.

Docker Hub tras la compilación de la imagen de la API .NET

Para validar el funcionamiento de la APi .NET en un entorno similar a nuestro objetivo de despliegue, ejecuto la imagen localmente utilizando "docker run".

Mapeando los puertos necesarios y configurando las variables de entorno para SSL, simulo el entorno de producción en mi máquina de desarrollo.

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

Al ir a https://localhost:7246/HotelCustomer/clients desde mi navegador web, puedo acceder a los datos expuestos por mi API directamente desde DB2 para i. Esta validación garantiza que mi API .NET está lista para su despliegue en la Raspberry 5.

API .NET ejecutándose localmente en Docker

Paso 5 - Enviar la imagen a la RASPBERRY Pi 5.

Después de empujar la imagen en el registro de mi Docker Hub, ahora es el momento de conectarse a la Raspberry Pi en SSH, descargar la imagen directamente desde mi hub, y lanzarla en un contenedor.

  1. Conéctate a la Raspberry 5 usando SSH:.

Conexión SSH al Raspberry Pi 5

  1. Descarga la imagen de mi Docker Hub:
docker image pull quentindaumerial/accessdataapi:latest

Paso 6 - Lanzar el contenedor Docker en la Raspberry 5.

Lanzo mi contenedor asignando su puerto 8080 al puerto 5040 en mi Raspberry Pi 5:

docker run -it -p 5040:8080 quentindaumerial/accessdataapi:latest

Y ya está. Mi API .NET se está ejecutando ahora en un contenedor Docker en mi Raspberry Pi 5, que a su vez está conectado a mi IBM i. Puedo comprobarlo directamente entrando en http://192.168.46.34:5040/hotelcustomer/clients.

API .NET desplegada en Raspberry Pi 5

PARTE 2 - Desplegando la aplicación ANGULAR.

Paso 1 - Preparando el Dockerfile.

Al igual que con la API .NET, para dockerizar nuestra aplicación ANGULAR, tendremos que ir a la carpeta de nuestra aplicación y crear un archivo llamado Dockerfile sin extensión.

Consta de dos etapas: build y run.

### 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

El paso de compilación utilizará la última versión de la imagen "node" para instalar las dependencias y compilar la aplicación Angular especificando una configuración de producción ( detallada en el paso 4 ).

El paso de ejecución utilizará la última versión de la imagen "nginx" para servir nuestra aplicación. Los archivos de distribución generados se copian en /usr/share/nginx/html, la carpeta por defecto utilizada por NGINX para servir contenedores web.

Paso 2 - Crear el archivo nginx.conf.

Este archivo configura NGINX para servir correctamente nuestra aplicación ANGULAR, soportando enrutamiento del lado del cliente.

events{}

http {
    include /etc/nginx/mime.types; 
    server {        
        root /usr/share/nginx/html/browser;
        index /index.html;
        location / {
            try_files $uri $uri/ /index.html;
        }
    }
}
  • El bloque "server" define dónde encontrar los archivos de la aplicación y cómo responder a las peticiones HTTP.

  • La directiva "try_files" indica a NGINX que sirva index.html para todas las rutas del lado del cliente.

Paso 3 - Configuración de los entornos de desarrollo y producción.

Como puedes ver en el Dockerfile, hemos especificado una compilación con "configuración de producción".

Esto se debe a que Angular es capaz de diferenciar y gestionar de forma nativa las configuraciones propias de los entornos de desarrollo y producción, para asegurar que la aplicación se comporta como se espera en cada contexto (especialmente la conexión a mi API).

  • Para desarrollo ("src/environments/environment.ts"):**

Contiene la configuración utilizada durante el desarrollo, incluida la URL base de la API que apunta al servidor de desarrollo configurado en el archivo launchsettings de nuestra API .NET.

export const environment = {
    production: false,
    apiBaseUrl: 'https://localhost:7246/'
};
  • Para producción ("src/entornos/entorno.prod.ts"):**

Contiene la configuración utilizada para la versión de producción de la aplicación con una URL que apunta al servidor de producción (en este caso nuestra segunda Raspberry Pi, accesible en la dirección 192.168.46.34, en el puerto 5040).

export const environment = {
  production: true,
  apiBaseUrl: 'http://192.168.46.34:5040/'
};

Estos archivos permiten un cambio simplificado entre las configuraciones de desarrollo y producción, simplemente cambiando la bandera "production" al construir la aplicación.

El comando ng serve de Angular me permite acceder a mi servidor de desarrollo en mi localhost, puerto 4200.

Aplicación Angular en desarrollo local con ng serve

Aplicación Angular mostrando datos de DB2 for i

Paso 4 - Construir la imagen Docker.

De la misma manera que nuestra API .NET, es importante construir la imagen multiplataforma para asegurar que la aplicación Angular es compatible con diferentes arquitecturas.

Así que una vez más usamos Docker Buildx para crear una imagen que funcione tanto en arquitecturas amd64 (típicas de PCs y servidores) como arm64/v8 (dispositivos arm como la Raspberry).

El siguiente comando inicia la construcción de la imagen y la empuja a mi Dockerhub:

docker buildx build --platform linux/amd64,linux/arm64,linux/arm64/v8 -t quentindaumerial/appdatamanager:latest --push --no-cache .

Compilación multi-arquitectura de la aplicación Angular con Docker Buildx

Mi imagen está actualizada en mi Dockerhub:

Imagen de Angular actualizada en Docker Hub

Paso 5 - Envío de la IMAGEN a la Raspberry 4.

Después de construir y empujar la imagen de mi aplicación Angular en Dockerhub, Me conecto a la Raspberry Pi 4 a través de SSH :

Conexión SSH al Raspberry Pi 4

Recupero la última versión de mi imagen desde mi hub, para que esté disponible en la Raspberry Pi:

docker image pull quentindaumerial/appdatamanager:latest

Descarga de la imagen Angular en Raspberry Pi 4

Paso 6 - Lanzar el contenedor Docker en la Raspberry 4.

Ahora que la imagen está descargada, lanzo un contenedor Docker para desplegar la aplicación Angular, mapeando el puerto 80 del contenedor al puerto 5000 de la Raspberry pi 4:

docker run -it --platform linux/arm64/v8 -p 5000:80 quentindaumerial/appdatamanager:latest

Ejecución de la aplicación Angular en Raspberry Pi 4 con Docker

Ahora se puede acceder a la aplicación a través de un navegador web en "**http://192.168.46.31:5000**":

Aplicación Angular accesible desde el navegador en Raspberry Pi 4

En particular, podemos ver que los datos provienen efectivamente de nuestra APi, que consume los datos expuestos por DB2 para i y recuperados a través de NTi desde .NET:

Aplicación Angular consumiendo la API .NET y mostrando datos de DB2 for i

CONCLUSIÓN

Configurando Dockerfiles específicos, configurando nginx.conf adecuadamente para Angular, y ajustando los CORS y parámetros de lanzamiento de nuestra APi .NET, es posible crear de forma sencilla un ecosistema en el que las dos aplicaciones funcionen perfectamente bien de forma aislada. ¿El resultado? Una recuperación de datos fluida y sencilla, que ilustra la interconexión en un entorno de contenedores.

El uso del conector NTi desempeña un papel esencial en nuestra API .NET, facilitando la conexión con DB2 para i. Demuestra que es posible ejecutar aplicaciones .NET CORE de forma nativa, interactuando con datos en IBM i, mientras se permanece en un entorno Dockerizado. La facilidad de despliegue de una API .NET y de una aplicación cliente, combinada con la capacidad de nuestro proveedor de datos NTi para operar de forma nativa en .NET, pone de manifiesto no sólo la sencillez de gestión de este tipo de aplicaciones, sino también su potencial de escalabilidad. Este proyecto es sólo un ejemplo de las muchas maneras en que podemos replantearnos hoy el uso de la tecnología para crear, innovar y optimizar los procesos de desarrollo y despliegue.

Espero que esta guía le haya proporcionado los conocimientos y la inspiración necesarios para explorar nuevos métodos y herramientas para sus propios proyectos. Docker está aquí para hacer que el despliegue de aplicaciones sea más sencillo, rápido y fiable, permitiéndole centrarse en lo que realmente importa: satisfacer eficazmente las necesidades específicas de cada proyecto del cliente.


Quentin Destrade