Despliegue de microservicios creados con Helidon, en Oracle Kubernetes Engine a través de Oracle Wercker. Parte 2 de 2.

Por Rolando Carrasco Oracle ACE Groundbreaker Ambassador
Publicado en Marzo 2019

Revisado por Juan Pablo Guizado




Oracle tiene diferentes herramientas y plataformas para el desarrollo y despliegue de aplicaciones, microservicios sobre Kubernetes, así como alternativas para Serverless.

Podemos identificar algunos componentes, relativamente obvios, así como algunos otros que son proyectos open-source apoyados por Oracle. Por ejemplo:

  1. Proyecto Helidon.io

  2. Oracle Kubernetes Engine. Esto está basado en Oracle Cloud Infrastructure (OCI),  y es tal cual un motor para el despliegue de clústers de Kubernetes

  3. Oracle Wercker. Es una herramienta de entrega continua para contenedores. Esto puede ser utilizado para desplegar contendores, en cualquier plataforma que soporte clúster de Kubernetes.

  4. GraalVM

  5. Y si quisiéramos irnos aun más lejos, podemos identificar a Oracle Fn Project y Oracle Functions, como una plataforma Serverless para la ejecución de funciones. De eso ya hemos escrito algunos artículos que puedes encontrar aquí: http://oracleradio.blogspot.com


En nuestro artículo anterior, vimos cómo aprovisionar y configurar un cluster de Kubernetes sobre Oracle Kubernetes Engine. También vimos cómo instalar el CLI de OCI, y a través de él pudimos generar nuestro kubeconfig file, para posteriormente usar kubectl para gestionar nuestro clúster.

Ahora ya tenemos el clúster ejecutándose sobre OCI, lo que vamos a hacer en este artículo es crear un microservicio a través de Helidon.io, y posteriormente automatizar su construcción, conteneirización y despliegue a Kubernetes a través de Oracle Wercker.

El desarrollador se va a dedicar a programar y dejar su código en el repositorio. De ahí Oracle Wercker lo tomará, generará un contenedor de Docker, lo publicará en el Container Registry y de allí lo mandará  a nuestro cluster de Kubernetes.


En este artículo vamos a:

  1. Crear un microservicio de ejemplo con Helidon.io, basado en MicroProfile
    • Ejecutar el microservicio localmente
    • Crear el contenedor localmente
    • Ejecutar el contenedor con el microservicio adentro de él
  2. Subir el código a un repositorio de GitHub
  3. Ingresar a Wercker
  4. Configurar Wercker para leer del repositorio de GitHub
  5. Crear los archivos que wercker utiliza para poder empaquetar y desplegar
  6. Crear un workflow de dos pasos: Build y Deploy
  7. Ejecutar el workflow



Crear microservicio de ejemplo con Helidon.io


La intención no es crear unas cuantas decenas de microservicios para realizar la ejemplificación, vamos a hacer uno, el más básico de Helidon y con eso haremos lo suficiente para ejecutar todo el ejemplo.

Si quieres conocer más de Helidon, te sugiero entres a Helidon.io . Incluso el ejemplo que haremos es justamente el getting started que allí viene.

Los pre-requisitos para lo que vamos a hacer a continuación, son:

  • Tener JDK 1.8+ instalado
  • Tener Docker instalado
  • Tener Maven instalado

Una vez que te asegures que tienes esas tres piezas en tu máquina, ejecutaremos los siguientes pasos:

  1. Crea una carpeta de trabajo, pensemos en Helidon. Si estás en Windows c:\Helidon
  2. Asegúrate de tener mvn y java en el path
  3. Ejecuta el siguiente comando:
    
    mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=io.helidon.archetypes
    -DarchetypeArtifactId=helidon-quickstart-mp -DarchetypeVersion=0.11.0 
    -DgroupId=io.helidon.examples -DartifactId=quickstart-mp 
    -Dpackage=io.helidon.examples.quickstart.mp
    

 (este es el ejemplo de MicroProfile).

La salida de este comando debe ser algo como esto:



Valida que salga BUILD SUCCESS.

El arquetipo genera un proyecto de Maven en tu directorio de trabajo, en nuestro caso: quickstart-mp.

Tu carpeta de trabajo debe verse así:



Y adentro de quickstart-mp:




4. Ahora vamos a realizar el build de la aplicación, así que en tu línea de comando ve a dicho directorio y ejecuta:

 mvn package


El resultado debe ser algo así:




5. La aplicación fue construida y podemos probarla, ejecutando el siguiente comando

 java -jar target/quickstart-mp.jar 


Debe suceder lo siguiente:




6. Una vez que ya subió, podemos probar los recursos:

curl -X GET http://localhost:8080/greet
{"message":"Hello World!"}

curl -X GET http://localhost:8080/greet/Joe
{"message":"Hello Joe!"}

curl -X PUT http://localhost:8080/greet/greeting/Hola
{"greeting":"Hola"}

curl -X GET http://localhost:8080/greet/Jose
{"message":"Hola Jose!"}


Hasta este punto, realmente hemos hecho poco, pero al mismo tiempo tenemos ya un microservicio creado muy rápidamente y no solo eso, sino que generó el arquetipo para poderlo empaquetar en Docker y así reducir el tiempo para poderlo conteneirizar.




7. Ahora generemos el contenedor de Docker. Para eso simplemente ejecuta lo siguiente:

 docker build -t quickstart-mp target 




8. Ahora vamos a ejecutar al microservicio adentro del contenedor

 docker run --rm -p 8080:8080 quickstart-mp:latest


Así ya el microservicio está ejecutándose adentro del navegador. Puedes probarlo igual que se probó hace unos pasos.


Con esto tenemos todo lo necesario para automatizar la construcción, la creación del contenedor y finalmente desplegarlo en el clúster de Kubernetes.

 

 

Subamos el código a github


En mi caso, este es mi repositorio: https://github.com/rcarrascosps/spsms

Crea tu propio repositorio y sube el código que se generó en el paso anterior. Los archivos: wercker.yml, así como los que empiezan con kubernetes (ver la sig imagen), cópialos de mi repositorio. O si quieres hacer un fork de mi repositorio, también es válido; al final es el mismo código.



El archivo wercker.yml, luce de la siguiente manera:

# docker box definition
box:
  id: maven:latest
  ports:
    - "8080"

# defining build pipeline
build:
  steps:
    - script:
      name: Maven Package
      code: mvn package && echo "Package successfully created"
    
    - internal/docker-push:
            entrypoint: java -jar ./target/quickstart-mp.jar
            working-dir: $WERCKER_ROOT
            tag: $WERCKER_GIT_COMMIT
            ports: "8080"
            username: $DOCKER_USERNAME
            password: $DOCKER_PASSWORD
            repository: $DOCKER_REPO
            registry: https://iad.ocir.io/v2
    - script:
      name: Container
      code: echo "Container successfully created"

# deploying to k8 cluster
deploy-to-kubernetes:
    box: openjdk:8-jre-alpine
    steps:

    # https://github.com/wercker/step-bash-template
    # This Wercker step will look for files in our repo with a .template extension.
    # It will expand any environment variables in those files, then remove the
    # template extension.
    - bash-template

    # The step above should leave us with a Kubernetes service and deployment yml files.
    # We'll create a directory to move them to.
    - script:
        name: Prepare Kubernetes files
        code: |
          mkdir $WERCKER_OUTPUT_DIR/kubernetes
          mv kubernetes_*.yml $WERCKER_OUTPUT_DIR/kubernetes
    # `apply` is a good command to use here, as it'll create Kubernetes entities if they
    are missing.
    - kubectl:
        name: deploy to kubernetes
        server: $OKE_MASTER
        token: $OKE_TOKEN
        insecure-skip-tls-verify: true
        command: apply -f $WERCKER_OUTPUT_DIR/kubernetes/

    # Watch the Kubernetes deployment. Once the pods are considered healthy the step will exit 0
    # If they aren't healthy within 60 seconds, it will exit with a non 0 exit code, and cause 
    the run to fail.
    - kubectl:
        name: check deployment status
        server: $OKE_MASTER
        token: $OKE_TOKEN
        insecure-skip-tls-verify: true
        command: rollout status deployment/microp


Básicamente está construyendo a nuestro microservicio y posteriormente, generando un contenedor para ser publicado en nuestro Oracle Registry.

El paso de build, es prácticamente lo que hicimos en la sección pasada, de manera manual. Nos referimos al: mvn package. Y el entrypoint para Docker, es:

java -jar ./target/quickstart-mp.jar


Posteriormente, el archivo de wercker.yml contiene el paso de publicación de la imagen; este paso es simplemente publicar la imagen en el registro.

Finalmente, viene el paso de deploy (deploy-to-kubernetes:), en el cual se está desplegando el contenedor sobre el cluster; esta sección hace uso de los archivos yml de kubernetes que están en el repositorio de github previamente mencionado. Esos son archivos de service y de deployment.

El archivo de kubernetes service, es este:

# This template file will have its environment variables expanded
# and the .template extension removed by the bash-template Wercker step.
# See wercker.yml.

apiVersion: v1
kind: Service
metadata:
  name: microp
  labels:
    app: microp
    commit: ${WERCKER_GIT_COMMIT}
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: microp
    commit: ${WERCKER_GIT_COMMIT}
  type: LoadBalancer


El nombre que le vamos a dar es el de: microp. El servicio estará escuchando en el puerto 80.

Y el yml del deployment, es:

# This template file will have its environment variables expanded
# and the .template extension removed by the bash-template Wercker step.
# See wercker.yml.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: microp
  labels:
    commit: ${WERCKER_GIT_COMMIT}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: microp
  template:
    metadata:
      labels:
        app: microp
        commit: ${WERCKER_GIT_COMMIT}
    spec:
      containers:
      - name: microp-server
        image: ${DOCKER_REPO}:${WERCKER_GIT_COMMIT}
        ports:
        - name: microp-server
          containerPort: 8080
          protocol: TCP
      imagePullSecrets:
      - name:  ${OKE_IMAGESECRET}


Para poder ya incorporarlo a Wercker, debemos de tener a la mano una serie de variables de ambiente que habrás identificado en el yml previamente descrito. Estas variables, son:

  • DOCKER_USERNAME
  • DOCKER_REPO
  • DOCKER_PASSWORD
  • OKE_IMAGESECRET
  • OKE_MASTER
  • OKE_TOKEN

El DOCKER_USERNAME y el DOCKER_REPO los tenemos a la mano, pero el resto de datos los debemos de obtener y ahora veremos cómo hacerlo.



DOCKER_USERNAME

Este es el usuario de administración que tengas en OCI. El formato es el siguiente:

<tenantName>/oracleidentitycloudservice/<user>

En donde, el tenantName y el user lo vas a sacar de aquí:


En el Dashboard de OCI, da click en el ícono del usuario y saca los datos que marcamos en amarillo. El primero es el user  y el segundo es el tenancy name.




DOCKER_REPO

El Docker repo lo vas a crear desde aquí:



Da click en el botón de Create Repository y dale un nombre, por ejemplo: spsocirrepo



Da click el botón de Submit y ahora lo verás listado de esta manera:



Con este dato, podrás formar el valor de la variable DOCKER_REPO. Será así:

us-ashburn-1.ocir.io/rcpsps/spsocirrepo

En donde la primera parte es la región (us-ashburn-1.ocir.io), la siguiente es el nombre del tenant (rcpsps). Y finalmente es el nombre nombre del repositorio: spsocirrepo.




DOCKER_PASSWORD

Este password lo vas a sacar de la pantalla del usuario en el OCI Dashboard; ten cuidado con este password, pues solo lo verás una vez.

Ve a esta pantalla:



Y da click en el botón de Create/Reset Password:



Saldrá la pantalla anterior, ahora vuelve a dar click en Create/Reset Password:


Toma nota de ese password, pues no lo volverás a ver.




OKE_IMAGESECRET

Este token hay que generarlo desde esta pantalla:



Da click en Generate Token y saldrá esta pantalla:



En este pantalla pon en Description algo con el cual referenciar a tu token y da click en Generate Token. Copia el valor que salga, pues lo vamos a utilizar en el siguiente paso.




OKE_IMAGESECRET

Este valor lo vas a crear ejecutando el siguiente comando:

export KUBECONFIG=~/kubeconfig
kubectl create secret docker-registry <SECRET NAME> --docker-server=<REGION.ocir.io> --docker-
username='<TENANCY/OCI_USERNAME>' --docker-password='<AUTH_TOKEN>' --docker-email='<EMAIL>'
  


Donde:

  1. <SECRET_NAME> es un valor que tú decides
  2. <REGION.ocir.io> es la región donde tengas tu OKE, por ejemplo: us-ashburn-1
  3. En username: coloca el nombre del usuario, con el formato que vimos en pasos anteriores.
  4. En <AUTH_TOKEN>, coloca el token generado en el paso anterior.



OKE_MASTER

Este valor lo vamos a sacar del kubeconfig  que generamos en el artículo anterior.


Copia la ubicación que viene después de server, en mi caso: https://c3wmnjsgi3t.us-ashburn-1.clusters.oci.oraclecloud.com:6443




OKE_TOKEN

En el caso del token, copia el valor que viene allí después de la sección de token, lo marco en amarillo en la imagen anterior.


Con esto tenemos todos los datos para poder ir a WERCKER y configurar nuestro workflow y pipelines.





CONFIGURACION EN WERCKER


Para entrar a Wercker, ve en tu navegador a: http://app.wercker.com



Aquí sugerimos entres con tu usuario de GITHUB.

Una vez que entres, verás esta pantalla:



Da click en el botón de: Create your first application, te llevará a esta pantalla:



Selecciona tu usuario en el dropdown, este será el usuario de github, y en el SCM escoge GitHub. Después da click en Next. En la siguiente pantalla, escoge tu repositorio en donde hayas subido el código (pasos anteriores).



Después da click en Next y saldrá esta pantalla:



Escoge la primera opción y finalmente da click en Next. Saldrá esta pantalla:



Revisa que los datos estén bien y da click en el botón de Create.

Con esto habrás creado una aplicación de Wercker apuntando a tu repositorio de Github.



Ahora vamos a crear unas variables de ambiente, para eso da click en la pestaña de Environment (fíjate en la pantalla anterior).

Una vez en environment, genera las siguientes variables de ambiente:



Todos los valores de dichas variables, ya los tenemos de los pasos anteriores. Simplemente genéralas y llena sus valores con los datos que ya tenemos.

Posteriormente, ve a tu pestaña de Workflows:



Genera un workflow con esos dos pasos, los nombres deben de coincidir con los que vienen en el yaml que revisamos en pasos anteriores, me refiero a este:  wercker.yml.



Ahí ve que contiene dos pipelines: build y deploy-to-kubernetes.

Una vez que lo tengas, estamos listos para ejecutarlo. Para esto ve a la pestaña de RUN:



Ve a tu código y haz un cambio. Posterior a eso, haz un commit. Esto para que se dispare le workflow de manera automática.

Por ejemplo, yo voy a cambiar en el mismo wercker.yml:



https://github.com/rcarrascosps/spsms/blob/master/wercker.yml

Voy a poner un signo de admiración adicional en la parte marcada en amarillo:



Vuelve a la pestaña de RUN y sin hacer nada, verás como ya se arrancó:



Está en la fase de build, que es nuestro primer pipeline.

Si das click sobre build, verás el detalle:



Y en cada paso también puedes ver el detalle, mira



Luego verás como pasa al siguiente pipeline:



Igualmente le puedes dar click para ver el detalle:



Ahí vemos cómo ejecutó todo lo que revisamos en el yaml de wercker en pasos anteriores.

Ahora podemos ir a nuestra máquina donde tenemos el kubeconfig y kubectl instalado y pedirle los servicios que se están ejecutando:



Ahí vemos a nuestra aplicación: microp. Recuerda que este nombre lo tomó de aquí:



https://github.com/rcarrascosps/spsms/blob/master/kubernetes_service.yml.template



Ahora probemos nuestra aplicación ya desplegada sobre nuestro cluster de kubernetes:



La IP es la que tomé de haber ejecutado kubectl get services

Esto también lo puedes ver en modo gráfico desde la consola de kubernetes. Para hacerlo, ejecuta:

 kubectl proxy 


Ve a la sección de Deployments y ve la cantidad de Pods que contienen a nuestra aplicación de microp:



Esto fue tomado del archivo de deployment, mira:



Haz el ejercicio de cambiar a 4 réplicas y que Wercker haga el resto:



En resumen, en estos dos artículos aprendimos a :

  1. Crear un primer microservicio con Helidon.io
  2. Crear un cluster de K8s con OKE
  3. Configurar un workflow de Wercker
  4. Construir un microservicio de Helidon.io, conteneirizarlo y desplegarlo en K8s, a través de Wercker.

Agradecimiento particular a Leonardo González, quien creo los yaml para Wercker y que participó activamente en que el ejercicio pudiera llevarse a cabo.




Rolando Carrasco es un Oracle ACE enfocado a las tecnologías de Middleware. Su experiencia es de casi 15 años en la integración de aplicaciones. Actualmente se desempeña como CTO de una firma mexicana de consultoría, llamada S&P Solutions. Rolando ha trabajado con tecnología Oracle desde el 2001, fue parte del equipo de Product Management de Oracle Fusion Middleware, por lo que tiene un background grande en el uso de estas tecnologías a lo largo de la región de latinoamérica. Rolando es co-líder del grupo de usuarios de Oracle en México.

Este artículo ha sido revisado por el equipo de productos Oracle y se encuentra en cumplimiento de las normas y prácticas para el uso de los productos Oracle.