Documentation for a newer release is available. View Latest

Configuración de despliegue del servidor HTM

1. Nombre de imagen y versión

Para desplegar el servidor Human Task Manager (HTM), necesita obtener la imagen de Docker del registro de contenedores de ICON Solutions.

Nombre de la imagen:

registry.ipf.iconsolutions.com/human-task-manager-app

Versionado:

Seguimos versionado semántico usando el formato MAJOR.MINOR.PATCH (p. ej., 1.3.9). Siempre debe referenciar una etiqueta de versión específica para asegurar la consistencia del despliegue y evitar actualizaciones no intencionales.

Ejemplo de configuración
image:
  name: registry.ipf.iconsolutions.com/human-task-manager-app
  tag: 1.3.9

Evite usar la etiqueta latest en entornos de producción.

2. Manifiestos de Kubernetes de ejemplo

El siguiente ejemplo muestra un despliegue básico del servidor Human Task Manager (HTM) usando manifiestos de Kubernetes. Pueden usarse como punto de partida para escribir charts de Helm o despliegues directos en K8s.

Este ejemplo incluye:

  • ConfigMap para la configuración de la aplicación

  • Deployment para la aplicación HTM

  • Service para exponer la aplicación HTM internamente

  • Configuración de Ingress

ConfigMap: htm-cm
apiVersion: v1
kind: ConfigMap
metadata:
  name: htm-cm
data:
  application.conf: |-
    ipf.mongodb.url = "${ipf.mongodb.url}"
    ipf.htm {
      event-processor.delegating.enabled = ${ipf.htm.event-processor.delegating.enabled}
      mongodb.purging.time-to-live = 15minutes
    }

    management.health.mongo.enabled = false

    event-processor {
      restart-settings {
        min-backoff = 500 millis
        max-backoff = 1 seconds
      }
    }

    akka {
      actor.provider = cluster

      remote.artery.canonical.hostname = ${POD_IP}
      # Use Kubernetes API to discover the cluster
      discovery {
        kubernetes-api {
          pod-label-selector = "app=%s"
        }
      }

      management {
        # use the Kubernetes API to create the cluster
        cluster.bootstrap {
          contact-point-discovery {
            discovery-method          = kubernetes-api
            service-name              = ${AKKA_CLUSTER_BOOTSTRAP_SERVICE_NAME}
            required-contact-point-nr = 1
            required-contact-point-nr = ${?REQUIRED_CONTACT_POINT_NR}
          }
        }
        # available from Akka management >= 1.0.0
        health-checks {
          readiness-path  = "health/ready"
          liveness-path   = "health/alive"
        }
      }

      cluster {
        seed-nodes = []
        downing-provider-class = "akka.cluster.sbr.SplitBrainResolverProvider"
        split-brain-resolver {
          active-strategy = keep-majority
          stable-after = 20s
        }
        sharding {
          remember-entities = off
          handoff-timeout = 8s
          least-shard-allocation-strategy.rebalance-absolute-limit = 20
          rebalance-interval = 2s
          number-of-shards = 100,
          distributed-data.majority-min-cap = ${akka.management.cluster.bootstrap.contact-point-discovery.required-contact-point-nr}
          snapshot-after = 50
        }
      }
    }

  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>

        <logger name="akka.stream.scaladsl.RestartWithBackoffSource" level="warn"/>
        <logger name="com.iconsolutions.ipf.core.connector" level="INFO"/>
        <logger name="com.iconsolutions.ipf.core.platform.read.processor" level="INFO"/>
        <logger name="com.iconsolutions.akka.persistence.mongodb" level="INFO"/>
        <logger name="com.iconsolutions.ipf.htm.notification.autoconfig.TaskNotificationAutoConfiguration" level="WARN"/>
        <logger name="com.iconsolutions.ipf.htm.task.task_manager.handlers.commands.processors.builtin.TaskManagerActionRevivalProcessor" level="DEBUG"/>

        <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
            <queueSize>8192</queueSize>
            <neverBlock>true</neverBlock>
            <appender-ref ref="CONSOLE" />
        </appender>

        <root level="info">
            <appender-ref ref="ASYNC"/>
        </root>
    </configuration>
Service y Deployment
apiVersion: v1
kind: Service
metadata:
  labels:
    app: human-task-manager
    product: ipfv2
  name: human-task-manager
spec:
  ports:
    - name: server-port
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: human-task-manager
    product: ipfv2
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: human-task-manager
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/path: "/"
    prometheus.io/port: "9001"
  labels:
    app: human-task-manager
    product: ipfv2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: human-task-manager
      product: ipfv2
  template:
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/path: "/"
        prometheus.io/port: "9001"
      labels:
        app: human-task-manager
        product: ipfv2
      name: human-task-manager
    spec:
      containers:
        - name: htm
          image: registry.ipf.iconsolutions.com/human-task-manager-app
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
            - name: debug-port
              containerPort: 5005
          livenessProbe:
            failureThreshold: 5
            httpGet:
              path: /actuator/health/liveness
              port: http
              scheme: HTTP
            initialDelaySeconds: 30
            periodSeconds: 2
            successThreshold: 1
            timeoutSeconds: 1
          readinessProbe:
            failureThreshold: 5
            httpGet:
              path: /actuator/health/readiness
              port: http
              scheme: HTTP
            initialDelaySeconds: 30
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 2
          env:
            - name: "POD_NAME"
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: "IPF_JAVA_ARGS"
              value: " -XX:+UseContainerSupport -XX:MaxRAMPercentage=60 -XX:InitialRAMPercentage=60
            -XX:-PreferContainerQuotaForCPUCount -Dma.glasnost.orika.writeClassFiles=false
            -Dma.glasnost.orika.writeSourceFiles=false"
            - name: "POD_IP"
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            - name: "KUBERNETES_NAMESPACE"
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: "AKKA_CLUSTER_BOOTSTRAP_SERVICE_NAME"
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['app']
          resources:
            requests:
              memory: 4Gi
              cpu: "4"
            limits:
              memory: 4Gi
          volumeMounts:
            - mountPath: /human-task-manager-app/conf/logback.xml
              name: config-volume
              subPath: logback.xml
            - mountPath: /human-task-manager-app/conf/application.conf
              name: config-volume
              subPath: application.conf
      volumes:
        - name: config-volume
          configMap:
            name: htm-cm
        - name: keystore
          secret:
            secretName: keystore
Ejemplo de Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: human-task-manager
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: htm.${ipf.ingress-domain}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: human-task-manager
                port:
                  number: 8080

Los placeholders como ${ipf.mongodb.url} y ${ipf.ingress-domain} deben reemplazarse con valores reales específicos de su entorno antes del despliegue.

Estos son manifiestos mínimos para demostración. Es posible que deba ampliarlos según su infraestructura (p. ej., secrets, TLS, almacenamiento persistente).

3. Requisitos de infraestructura

El servidor HTM depende de componentes de infraestructura externos que deben estar disponibles y correctamente configurados antes del despliegue.

MongoDB

HTM utiliza MongoDB como su almacén de datos principal.

  • Debe aprovisionar una instancia de MongoDB accesible desde el clúster.

  • La cadena de conexión a MongoDB debe proporcionarse a través del archivo de configuración usando el siguiente placeholder ipf.mongodb.url

Kafka

HTM puede enviar notificaciones cuando se cierran tareas, usando Apache Kafka.

  • Debe tener un clúster de Kafka accesible desde su entorno.

  • Cree tópicos de Kafka para notificaciones de tareas cerradas y registros de tareas.

  • Configure los nombres de los tópicos en el archivo de configuración mediante las variables htm.kafka.producer.topic e ipf.htm.async.register-task.kafka.producer.topic

4. Requisitos básicos de recursos

Para garantizar un rendimiento estable, el servidor HTM requiere los siguientes recursos base:

  • CPU: Mínimo de 4 cores

  • Memoria: Recomendado 4 GB

Estos valores deben considerarse el límite inferior para entornos de producción; los valores reales siempre deben determinarse ejecutando pruebas de carga adecuadas en días de simulación.