HEADER_lecciones_de_software

Cómo desplegar una aplicación basada en microservicios

por Sergio Alberto Martínez, el 30 de marzo de 2020

Cómo desplegar una aplicación basada en microservicios

El propósito de este artículo es mostrar cómo se realiza un despliegue de una aplicación basada en microservicios inicialmente en un entorno Docker y luego desplegarlo en un sistema de orquestación de contenedores Openshift/OKD.

La arquitectura propuesta

La arquitectura se compone por microservicios de 2 clases, el primero es Redis (Caché) y el segundo tipo una API REST Stateless replicable que provee acceso a la base de datos en Memoria RAM Redis en sus dos modos de trabajo HashOperations (Base de datos NoSQL) con operaciones GET, POST, PUT, DELETE y ListOperations (Listas/Colas) con operaciones POP y PUSH.

arquitectura propuesta en microservicios

La aplicación

El esquema de la API rest es el siguiente:

  • Conseguir todos los objetos bajo la clave como un mapa
    GET: /api/v1/{redis_key}
  • Conseguir un objeto bajo la clave y su hash
    GET: /api/v1/{redis_key}/{hash_key}
  • Agregar un nuevo objeto, el método responde con su hash, el valor objeto debe ir dentro del body
    POST: /api/v1/{redis_key}
  • Actualizar un objeto con el hash específico, el valor del objeto debe ir dentro del body.
    PUT: /api/v1/{redis_key}/{hash_key}
    Nota: Al actualizar el objeto el hash se conserva
  • Eliminar el objeto bajo la clave y son el hash específico DELETE: /api/v1/{redis_key}/{hash_key}

Haciendo uso de esta API es posible almacenar datos temporalmente haciendo uso del poder de Redis de forma NoSQL. 

Operaciones con listas o colas

  • POP: Traer el último ingresado tiene como parámetro opcional right: false: para hacer LPOP o LPUSH, true: para hacer RPOP o LPUSH
    GET: /api/v1/list/{redis_key}
  • PUSH: agregar un elemento a la lista, también tiene como parámetro a right POST: /api/v1/list/{redis_key}

Haciendo uso de esta API es posible implementar colas tipo LIFO: Last In/First Out y FIFO: First In/First Out. 

Información general de la API

Importante: Cada redis_key solo se puede usar en un esquema, es decir, como una cola o como una base de datos NoSQL.

  • Esta API cuenta con un Job para realizar un snapshot cada 30 minutos de sí misma, el tiempo es configurable en application.yaml mediante una expresión cron. Mirese Variables de entorno
  • Para este ejemplo el controlador principal maneja los datos de la manera siguiente:
    K: redis_key del tipo String
    H: hash_key del tipo Integer
    V: value del tipo Object

Variables de entorno

  • REDIS_DB_HOST: Especifica la IP o Nombre del Servidor Redis, por defecto es localhost.
  • REDIS_DB_PORT: Especifica el Puerto del Servidor Redis, por defecto es 6379.
  • REDIS_DB_PASSWORD: Especifica la contraseña del Servidor Redis, por defecto no tiene valor.
  • REDIS_DB_DUMP_CRON: Especifica la expresión cron para el guardado automático Servidor
    Redis, por defecto es 0 */30 * * * *, esta expresión como esta específica que se le envía una orden para hacer un Snapshot en disco al Servidor Redis cada 30 minutos.

Las expresiones cron en Spring constan de 6 campos que especifican una condición a cumplir.

  1. Segundo: Valores de 0 a 59, admite usar el separador / para especificar una periodicidad Ej: */5 significa cada 5 segundos.
  2. Minuto: Valores de 0 a 59, admite usar el separador / para especificar una periodicidad.
  3. Hora: Valores de 0 a 23, admite usar el separador / para especificar una periodicidad, también admite el separador - que indica un rango Ej: 8-10 significa de 8AM a 10AM.
  4. Día del mes: Valores de 0 a 31, admite los separadores - y /.
    Mes: Valores de 1 a 12.
  5. Día de la semana: Acepta valores MON TUE WED THU FRI SAT SUN, también acepta el separador - y el comodín ?, Ej: MON-FRI significa de Lunes a Viernes.

Trabajo futuro

  • Se puede copiar el controlador y cambiar los tipos de datos en uno nuevo de acuerdo a las necesidades.
  • Aún falta implementar el tiempo de vida de los registros.
  • También sería útil agregar implementación para usar Redis en clúster y usar su servicio Sentinel, todo esto se puede hacer programáticamente.

Diagrama de clases

Diagrama de clases arquitectura microservicios

Las fuentes están en repositorio OKD-Despliegue

Despliegue de la aplicación

Archivos de despliegue con docker-compose

Con los siguientes dos archivos y con Docker Compose podemos:

  • Descargar el código fuente del repositorio.
  • Construir el artefacto de la API.
  • Construir y desplegar los microservicios en contenedores.

/docker-compose.yml

version: '3'
services:
  redis-api:
    build:
      dockerfile: Dockerfile
      context: ./redis-api
    ports:
      - "8080:8080"
    networks:
      - academia-pragma
    restart: unless-stopped
    deploy: # Este elemento es soportado por docker-swarm, no por docker-compose
      replicas: 3
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
    environment:
      - REDIS_DB_HOST=redis-db
      - REDIS_DB_PORT=6379
      - REDIS_DB_PASSWORD=
      - REDIS_DB_DUMP_CRON=0 */1 * * * *
  redis-db:
    image: redis
    ports:
      - "6379:6379"
    networks:
      - academia-pragma
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
    volumes:
      - redis-data:/data
  load-balancer:
    image: nginx
    ports:
      - "8080:8080"
    networks:
      - academia-pragma
    restart: unless-stopped
networks:
  academia-pragma:
    driver: bridge
volumes:
  redis-data:

/redis/Dockerfile

 

# Clonando repositorio
FROM alpine/git
WORKDIR /app
RUN ["git", "clone", "https://git.pragma.com.co/sergio.martinez/OKD-Despliegue.git"]

# Construccion de artefacto con Maven
FROM maven:3.5-jdk-8-alpine
WORKDIR /app
COPY --from=0 /app/OKD-Despliegue/redis /app
# Necesario para agregar la configuracion de proxy para que maven pueda conectarse
COPY --from=0 /app/OKD-Despliegue/proxy-settings.xml /root/.m2/settings.xml
RUN mvn install

# Construcción de la imagen del contenedor
ARG REDIS_DB_HOST=app_redis_db
ARG REDIS_DB_PORT
ARG REDIS_DB_PASSWORD
ARG REDIS_DB_DUMP_CRON
FROM registry.redhat.io/redhat-openjdk-18/openjdk18-openshift
COPY --from=1 /app/target/redis-0.0.1-SNAPSHOT.jar app.jar
USER root
RUN chmod a+r app.jar
USER jboss
ENV REDIS_DB_HOST=$REDIS_DB_HOST
ENV REDIS_DB_PORT=$REDIS_DB_PORT
ENV REDIS_DB_PASSWORD=$REDIS_DB_PASSWORD
ENV REDIS_DB_DUMP_CRON=$REDIS_DB_DUMP_CRON
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","./app.jar"]

El primer objetivo es correr la aplicación en Docker.

docker-compose up

Arquitectura obtenida con Docker

Despliegue en Openshift

El siguiente objetivo es desplegar la arquitectura en Openshift de manera manual.  Para hacer el despliegue en Openshift, tendríamos las posibilidades siguientes:

  • Construir la imagen con Docker y publicarla en un registry privado para luego desplegarla.
  • Desplegar directamente desde el código.

Despliegue usando la interfaz web y subiendo la imagen a un registro de imágenes

Construcción de la imagen

Con la imagen construida mediante el archivo Dockerfile Véase archivos de construccion

docker compose build .

Publicar la imágen en registry privado o en el registry de Openshift

docker login registry


docker tag redis-api registry/cuenta/redis-api
docker push registry/cuenta/redis-api

Despliegue usando archivos de Openshift

REDIS DATABASE

Variables de entorno

Cada campo está codificado en Base64

apiVersion: v1
data:
  DATABASE_SERVICE_NAME: cmVkaXM=
  MEMORY_LIMIT: NTEyTWk=
  NAMESPACE: b3BlbnNoaWZ0
  REDIS_PASSWORD: a2FwcGE=
  REDIS_VERSION: My4y
  VOLUME_CAPACITY: MUdp
kind: Secret
metadata:
  name: redis-conf-secret
type: Opaque

Imagen de Redis

apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
  labels:
    app: redis-db
  name: redis-db
spec:
  replicas: 1
  selector:
    app: redis-db
    deploymentconfig: redis-db
  strategy:
    activeDeadlineSeconds: 21600
    resources: {}
    rollingParams:
      intervalSeconds: 1
      maxSurge: 25%
      maxUnavailable: 25%
      timeoutSeconds: 600
      updatePeriodSeconds: 1
    type: Rolling
  template:
    metadata:
      labels:
        app: redis-db
        deploymentconfig: redis-db
    spec:
      containers:
        - envFrom:
            - secretRef:
                name: redis-conf-secret
          image: >-
            docker-registry.default.svc:5000/openshift/redis:latest
          imagePullPolicy: Always
          name: redis-db
          ports:
            - containerPort: 6379
              protocol: TCP
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /var/lib/redis/data
              name: redis-db-1
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
        - emptyDir: {}
          name: redis-db
  test: false

Servicio

apiVersion: v1
kind: Service
metadata:
  labels:
    app: redis-db
  name: redis-db
spec:
  clusterIP: 172.30.184.126
  ports:
    - name: 6379-tcp
      port: 6379
      protocol: TCP
      targetPort: 6379
  selector:
    deploymentconfig: redis-db
  sessionAffinity: None
  type: ClusterIP

REDIS API

Variables de entorno

apiVersion: v1
data:
  REDIS_DB_HOST:
  REDIS_DB_PORT: 6379
  REDIS_DB_PASSWORD:
  REDIS_DB_DUMP_CRON: 0 */1 * * * *
kind: Secret
metadata:
  name: redis-conf-secret
type: Opaque


Imagen de REDIS API

apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
  labels:
    app: redis-api
  name: redis-api
spec:
  replicas: 3
  selector:
    app: redis-api
    deploymentconfig: redis-api
  strategy:
    activeDeadlineSeconds: 21600
    resources: {}
    rollingParams:
      intervalSeconds: 1
      maxSurge: 25%
      maxUnavailable: 25%
      timeoutSeconds: 600
      updatePeriodSeconds: 1
    type: Rolling
  template:
    metadata:
      labels:
        app: redis-api
        deploymentconfig: redis-api
    spec:
      containers:
        - envFrom:
            - secretRef:
                name: redis-conf-secret
          image: >-
            sergioamza/redis-api:latest
          imagePullPolicy: Always
          name: redis-api
          ports:
            - containerPort: 8080
              protocol: TCP
            - containerPort: 8443
              protocol: TCP
            - containerPort: 8778
              protocol: TCP
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
  test: false
  triggers:
    - type: ConfigChange
    - imageChangeParams:
        automatic: true
        containerNames:
          - redis-api
        from:
          kind: ImageStreamTag
          name: 'redis-api:latest'
      type: ImageChange

Servicio

apiVersion: v1
kind: Service
metadata:
  labels:
    app: redis-api
  name: redis-api
spec:
  clusterIP: 172.30.150.51
  ports:
    - name: 8080-tcp
      port: 8080
      protocol: TCP
      targetPort: 8080
    - name: 8443-tcp
      port: 8443
      protocol: TCP
      targetPort: 8443
    - name: 8778-tcp
      port: 8778
      protocol: TCP
      targetPort: 8778
  selector:
    deploymentconfig: redis-api
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

Enrutamiento

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  labels:
    app: redis-api
  name: redis-api
spec:
  port:
    targetPort: 8080-tcp
  to:
    kind: Service
    name: redis-api
    weight: 100
  wildcardPolicy: None

Arquitectura obtenida microservicios

Conclusiones

  • Usando Openshift / OKD se pudo realizar un despliegue de una arquitectura de microservicios de forma ágil, con la seguridad como prioridad, debido al enfoque que tiene Openshft / OKD en ese aspecto.
  • Se obtuvo una arquitectura equivalente tanto en Docker como en OKD/Openshift.

Guía para crear una aplicación serverless en 4 pasos


 

 

Temas:Desarrollo de Software

Lecciones Pragma

Lecciones en Academia Pragma

Aquí encontrarás tutoriales técnicos para que apliques en temas de desarrollo de software, cloud, calidad en software y aplicaciones móviles. 

También puedes visitar nuestro Blog con contenido actual sobre Transformación Digital, Marketing, Conocimiento de Usuario y más. 

Blog

Suscríbete a la academia

Descarga la Guía para trabajar con ambientes IBM Websphere Portal