Despliegue

Ejecutándose como una aplicación independiente

IPF Operational Dashboard puede ser creado con 2 maven perfiles:

  • contenedor- Genera docker contenedores

  • runnable- Genera un archivo jar ejecutable para funcionar como una aplicación independiente.

En este caso, estamos interesados en el archivo jar ejecutable.

Al construir IPF Operational Dashboard utilizando el arquetipo, tanto el container como el runnable pueden ser generados en el pom.xml.

Si desea generar el runnable, deberá invocar el perfil runnable de la siguiente manera:

mvn clean install -P runnable

Todos los archivos JAR ejecutables de IPF se producen como Spring Boot aplicaciones. Para ejecutar un IPF Operational Dashboard, usted debe ejecutar lo siguiente:

java -cp ipf-operational-dashboard-docker/target/com.iconsolutions.payments_ipf-operational-dashboard-docker_<version>-runnable.jar:config -Dconfig.override_with_env_vars=true -Dloader.main=com.iconsolutions.ipf.gui. BusinessOperationsMain org.springframework.boot.loader.launch. PropertiesLauncher
[IMPORTANTE]
====
Reemplace el `<version>` placeholder en el comando con su IPF específico Operational Dashboard construir la versión antes de la ejecución.

Por ejemplo, si su versión de compilación es 8. 7. 1, el archivo JAR sería: ipf-operational-dashboard-docker_8. 7. 1-runnable.jar

Si utiliza Windows, necesitamos reemplazar el primer ":" con un ";", a saber: "com.iconsolutions.payments_ipf-operational-dashboard-docker_<version>-runnable.jar;config"

Si usted está sobrescribiendo alguna de la configuración predeterminada para las aplicaciones, entonces, en este ejemplo, el archivo de configuración para la aplicación,application.conf, viviría en la carpeta de configuración como se define en :config. Luego aprovechamos el Spring Boot_Properties Launcher_ para cargar las propiedades en la aplicación.

=== Información adicional

Para empaquetar el javacript requerido para los módulos IPF que ha elegido servir para su IPF Operational Dashboard Necesitará estas dos secciones de código en el pom de su aplicación web:

<build>
    <resources>
        <resource>
            <directory>${project.build.directory}/static</directory>
            <targetPath>static</targetPath>
        </resource>
    </resources>
</build>
<build>
    <plugins>
        <plugin>
            <groupId>com.github.eirslett</groupId>
            <artifactId>frontend-maven-plugin</artifactId>
            <version>1.12.0</version>
            <configuration>
                <nodeVersion>v20.11.1</nodeVersion>
                <npmVersion>10.2.4</npmVersion>
                <installDirectory>${project.build.directory}</installDirectory>
            </configuration>
            <executions>
                <execution>
                    <id>install node and npm</id>
                    <goals>
                        <goal>install-node-and-npm</goal>
                    </goals>
                </execution>
                <execution>
                    <id>Build</id>
                    <goals>
                        <goal>npm</goal>
                    </goals>
                    <configuration>
                        <arguments>run build</arguments>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Deberá coincidir esto en su pom de servicio con el requerido java dependencias, ops-gui-service-ng-starter, su aplicación web, commons-codec y los módulos IPF que usted eligió:

<dependencies>
    <dependency>
        <groupId>com.iconsolutions.ipf.gui</groupId>
        <artifactId>ops-gui-service-ng-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.iconsolutions.payments</groupId>
        <artifactId>iconsolutions</artifactId>
    </dependency>
    <dependency>
        <groupId>com.iconsolutions.ipf.gui</groupId>
        <artifactId>ops-gui-service-ng-cluster</artifactId>
    </dependency>
    <dependency>
        <groupId>com.iconsolutions.ipf.gui</groupId>
        <artifactId>ops-gui-service-ng-htm</artifactId>
    </dependency>
    <dependency>
        <groupId>com.iconsolutions.ipf.gui</groupId>
        <artifactId>ops-gui-service-ng-metrics</artifactId>
    </dependency>
    <dependency>
        <groupId>com.iconsolutions.ipf.gui</groupId>
        <artifactId>ops-gui-service-ng-ods</artifactId>
    </dependency>
    <dependency>
        <groupId>com.iconsolutions.ipf.gui</groupId>
        <artifactId>ops-gui-service-ng-processing-settings</artifactId>
    </dependency>
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
    </dependency>
</dependencies>

Para crear el archivo jar ejecutable requerido.

== Construcción como Contenedor

Todas las aplicaciones que IPF produce se envían a ipf-lanzamientos en Nexus. Los archivos jar ejecutables estarán disponibles como un artefacto con un sufijo de runnable en el repositorio de Nexus para cada versión de la aplicación que necesite. Por ejemplo, si desea obtener la IPF Operational Dashboard el archivo jar ejecutable para la versión 8. 7. 1 lo encontrará en este enlace:

https://nexus.ipf.iconsolutions.com/repository/ipf-releases/com/iconsolutions/payments/ipf-operational-dashboard-docker/8. 7. 1/ipf-operational-dashboard-docker-8. 7. 1-runnable.jar

El siguiente Dockerfile puede ser utilizado como una plantilla para la integración con su propio contenedor base subyacente.

FROM registry.ipf.iconsolutions.com/ubi8-minimal-openjdk-17:latest

USER root

RUN mkdir -p /ipf-operational-dashboard-service/conf /ipf-operational-dashboard-service/lib

COPY ipf-operational-dashboard-docker-<ipf-dashboard-version>-runnable.jar /ipf-operational-dashboard-service/lib/
COPY cinnamon-agent-<cinnamon-version>.jar /ipf-operational-dashboard-service/lib/

WORKDIR /ipf-operational-dashboard-service
EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s --retries=1 CMD wget -qO- http://localhost:8080/actuator/health/ | grep UP || exit 1

ENTRYPOINT java \
    -javaagent:/ipf-operational-dashboard-service/lib/cinnamon-agent-<cinnamon-version>.jar \
    -cp "/ipf-operational-dashboard-service/lib/ipf-operational-dashboard-docker-<ipf-dashboard-version>-runnable.jar:/ipf-operational-dashboard-service/conf" \
    $IPF_OPS_GUI_SERVICE_JAVA_ARGS \
    -Dconfig.override_with_env_vars=true \
    -Dloader.main=com.iconsolutions.ipf.gui.BusinessOperationsMain \
    org.springframework.boot.loader.launch.PropertiesLauncher
Al construir el Dockerfile, asegúrese de:
  1. Establezca el <cinnamon-version> para hacer coincidir la versión de cinnamon-agent compatible con su versión de IPF

    • Esta versión se puede encontrar en el ${cinnamon.version} propiedad dentro del ipf-bom

  2. Reemplace <ipf-dashboard-version> con su IPF objetivo Operational Dashboard versión

Ambos valores deben ser especificados con precisión para garantizar un despliegue y compatibilidad adecuados.

== Kubernetes y OpenShift

El IPF Operational Dashboard opera como una aplicación sin estado y no agrupada, por lo que puede ser fácilmente desplegada utilizando los siguientes manifiestos.

apiVersion: apps/v1
kind: Deployment
metadata:
    name: ipf-operational-dashboard
    labels:
        app: operational-dashboard
        product: ipfv2
spec:
    replicas: 3
    selector:
        matchLabels:
            app: operational-dashboard
            product: ipfv2
    template:
        metadata:
            labels:
                app: operational-dashboard
                product: ipfv2
        spec:
            containers:
                - name: operational-dashboard
                  image: CONTAINER_REGISTRY/ipf-operational-dashboard-service:VERSION
                  imagePullPolicy: Always
                  ports:
                    - containerPort: 8080
                      name: server-port
                    - containerPort: 55001
                      name: akka-artery
                  env:
                    - name: IPF_PODNAME
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.name
                    - name: POD_IP
                      valueFrom:
                        fieldRef:
                          fieldPath: status.podIP
                    - name: POD_NAMESPACE
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.namespace
                    - name: "AKKA_CLUSTER_BOOTSTRAP_SERVICE_NAME"
                      valueFrom:
                        fieldRef:
                          apiVersion: v1
                          fieldPath: metadata.labels['app']
                    - name: IPF_JAVA_ARGS
                      value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=60 -XX:InitialRAMPercentage=60 -XX:-PreferContainerQuotaForCPUCount"
                  resources:
                    limits:
                      memory: 3.5Gi
                    requests:
                      memory: 2Gi
                      cpu: 500M
                  livenessProbe:
                    httpGet:
                      path: /actuator/health
                      port: server-port
                      scheme: HTTP
                    initialDelaySeconds: 60
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 3
                    successThreshold: 1
                  readinessProbe:
                    httpGet:
                      path: /actuator/health
                      port: server-port
                      scheme: HTTP
                    initialDelaySeconds: 60
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 3
                    successThreshold: 1
                  startupProbe:
                    httpGet:
                      path: /actuator/health
                      port: server-port
                      scheme: HTTP
                    periodSeconds: 10
                    failureThreshold: 30
                  volumeMounts:
                    - name: configuration-dashboard
                      mountPath: /operational-dashboard-service/conf
            volumes:
              - name: configuration-dashboard
                projected:
                  defaultMode: 420
                  sources:
                    - secret:
                      name: operational-dashboard
                      items:
                        - key: users.conf
                          mode: 420
                          path: users.conf
                    - configMap:
                      name: operational-dashboard-cm
                      items:
                        - key: logback.xml
                          mode: 420
                          path: logback.xml
                        - key: application.conf
                          mode: 420
                          path: application.conf
                    - configMap:
                        name: operational-dashboard-cm-summary-layout
                        items:
                          - key: summary-layout.conf
                            mode: 420
                            path: summary-layout.conf
                    - configMap:
                        name: ipf-operational-dashboard-cm-reason-codes
                        items:
                          - key: reason-codes.conf
                            mode: 420
                            path: reason-codes.conf
apiVersion: v1
kind: Service
metadata:
    name: operational-dashboard
    labels:
        app: operational-dashboard
        product: ipfv2
spec:
    selector:
        app: operational-dashboard
        product: ipfv2
    ports:
        - name: server-port
          protocol: TCP
          port: 8080
          targetPort: 8080
apiVersion: v1
kind: ConfigMap
metadata:
    name: ipf-operational-dashboard-cm
data:
    application.conf: |
        spring.data.mongodb.uri = "${ipf.mongodb.url}"
        
        ipf {
          business-operations = {
            auth = {
                jwt {
                  secret = ""
                  roles-claim = "roles"
                }
        
                cors {
                  allowed-origin-patterns = [ "*" ]
                }
        
                saml2 {
                  enabled = true
                  verification-certificate = "classpath:idp.crt"
                  registration-id = "sample-client"
                  single-sign-on-service-location = "https://simplesaml.${environment_name}.ipfdev.co.uk/simplesaml/saml2/idp/SSOService.php"
                  single-log-out-service-location = "https://simplesaml.${environment_name}.example.org/simplesaml/saml2/idp/SingleLogoutService.php"
                  identity-provider-entity-id = "https://simplesaml.${environment_name}.example.org/simplesaml/saml2/idp/metadata.php"
                  service-provider-entity-id = "sample-client"
                  want-authn-requests-signed = false
                  uid-attribute = "uid"
                  roles-attribute = "roles"
                  roles-separator = ","
                  return-url = "/"
                }
        
                oauth2 {
                  enabled = true
                  registrationId = "keycloak"
                  clientId = "login-app"
                  clientSecret = "802e7940-648b-4925-8079-24fa6dc47afe"
                  scopes = "openid, roles"
                  authorizationUri = "https://keycloak.${environment_name}.example.org/realms/demo/protocol/openid-connect/auth"
                  tokenUri = "https://keycloak.${environment_name}.example.org/realms/demo/protocol/openid-connect/token"
                  jwkSetUri = "https://keycloak.${environment_name}.example.org/realms/demo/protocol/openid-connect/certs"
                  returnUrl = "/"
                  rolesFromAttributes = true
                  rolesAttribute = "roles"
                  username = "preferred_username"
                }
            }
            audit = {
                enabled = true
            }
            cluster-management = {
              systems = [
                {
                  name = "Payments Service"
                  base-urls = [
                    "http://payment-service:8558"
                  ],
                  akka-management = true,
                  actuator = {
                    protocol = "http",
                    port = "8080"
                  }
                },
                {
                  name = "Notification Service"
                  base-urls = [
                    "http://notification-service:8558"
                  ],
                  akka-management = true,
                  actuator = {
                    protocol = "http",
                    port = "8080"
                  }
                },
                {
                  name = "ODS Ingestion"
                  base-urls = [
                    "http://ods-ingestion:8558"
                  ],
                  akka-management = true,
                  actuator = {
                    protocol = "http",
                    port = "8080"
                  }
                },
                {
                  name = "ODS Inquiry"
                  base-urls = [
                    "http://ods-inquiry:8080"
                  ],
                  akka-management = false,
                  actuator = {
                    protocol = "http",
                    port = "8080"
                  }
                }
              ]
            }
            metrics = {
              http = {
                client = {
                  host = "grafana"
                  port = "3000"
                  endpoint-url = "/api/health"
                }
              }
              metric-url = "http://grafana:3000",
              local-metric-url = "https://grafana.${environment_name}.example.org",
              call-timeout  = 30s,
              dashboards = [
                {
                  title: "Business Metrics",
                  name: "transactions",
                  id: "0000000001",
                  panels: [
                    {id: "1"},
                    {id: "2"},
                    {id: "15"},
                    {id: "16&var-lookback_period=1y"}
                  ],
                  columns: "2"
                },
                {
                  title: "Debtor Credit Transfer Metrics",
                  name: "transactions",
                  id: "0000000001",
                  panels: [
                    {id: "4&var-behaviour=DebtorCreditTransferBehaviour&var-latency_type=FULL_FLOW", colspan: "1"},
                    {id: "4&var-behaviour=DebtorCreditTransferBehaviour&var-latency_type=CSM_STATES_ONLY", colspan: "1"},
                    {id: "4&var-behaviour=DebtorCreditTransferBehaviour&var-latency_type=NO_CSM_STATES", colspan: "1"},
                    {id: "8&var-behaviour=DebtorCreditTransferBehaviour", colspan: "2"}
                  ],
                  columns: "3"
                },
                {
                  title: "Creditor Credit Transfer Metrics",
                  name: "transactions",
                  id: "0000000001",
                  panels: [
                    {id: "4&var-behaviour=CreditorCreditTransferBehaviour&var-latency_type=FULL_FLOW", colspan: "1"},
                    {id: "4&var-behaviour=CreditorCreditTransferBehaviour&var-latency_type=CSM_STATES_ONLY", colspan: "1"},
                    {id: "4&var-behaviour=CreditorCreditTransferBehaviour&var-latency_type=NO_CSM_STATES", colspan: "1"},
                    {id: "8&var-behaviour=CreditorCreditTransferBehaviour", colspan: "2"}
                  ],
                  columns: "3"
                },
                {
                  title: "Connector Metrics",
                  name: "ipf-connectors",
                  id: "0000000002",
                  panels: [
                    {id: "1"},
                    {id: "2"},
                    {id: "4", colspan: "2"},
                    {id: "5", colspan: "2"}
                  ],
                  columns: "2"
                }
              ]
            }
        
            payment-search = {
                ods = {
                  security = {
                    enabled = false
                    grant_type = "password"
                    client_id = "login-app"
                    client_secret = "802e7940-648b-4925-8079-24fa6dc47afe"
                    username = "test"
                    password = "p4ssw0rd"
                    jwt-certificate = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXrGmY331co1PX/tDGdMpChoaVfokUMxdrrRul4lLIGSOAEBRegLdmmmY7FgCSTtIhmkkwZWu3gaZLs5+oyld9ncXSL4OpQQvoCOd84RvWiHLhxPBynuYmypTQUP2kLeM3ntCsXI13SwN59tE/y4H/GVGTBDrfN2ELaS43OeZRpQuW1XqLWuyNGDCtC4V7cd+gld5uDBa93PUB40ypWqnYQVrC+PRiiiXcF6uyEgkOgMinR8LerKFi/iFpuMytJa9zW0d/O5aOceulWDjUJeqf+6EbonWjfJv5GMSKdsCjQ6rnq/a1gaxSyYeCctmqtUpu0Ogjjjwfwf3qkj6fWUawIDAQAB"
                  }
                }
                ods-inquiry-url = "http://ods-inquiry:8080"
                payment-summaries.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/views/summaries/payments"
                payment-details.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/views/details"
                system-events.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/catalogue/process-objects/system-events"
                message-logs.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/catalogue/process-objects/message-logs"
                process-flow-events.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/catalogue/process-objects/process-flow-events"
                payment-objects.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/all/payment-objects"
                custom-objects.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/all/custom-objects"
                auth-server.http.client.endpoint-url = ${ipf.business-operations.payment-search.ods-inquiry-url}"/realms/demo/protocol/openid-connect/token"
            }
          }
        }

    logback.xml: |
        <?xml version="1.0" encoding="UTF-8"?>
        <configuration>
          <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <target>System.out</target>
            <encoder>
              <pattern>[%date{ISO8601}] [%level] [%logger] [%marker] [%thread] - %msg%n</pattern>
            </encoder>
          </appender>
        
          <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
            <queueSize>8192</queueSize>
            <neverBlock>true</neverBlock>
            <appender-ref ref="CONSOLE" />
          </appender>
        
          <logger name="com.iconsolutions" level="ERROR"/>
        
          <root level="INFO">
            <appender-ref ref="ASYNC"/>
          </root>
        
        </configuration>