Saltar al contenido

Sondas de Kubernetes para una aplicación de TIBCO BusinessWorks Container Edition

Foto de Blake Wisz en Unsplash

Introducción

Las sondas son cómo podemos decirle a Kubernetes que todo dentro del pod está funcionando como se espera. Kubernetes no tiene forma de saber qué está sucediendo dentro a nivel detallado y no tiene forma de saber para cada contenedor si está saludable o no, por eso necesitan ayuda del propio contenedor.

Imagina que eres el controlador de Kubernetes y tienes como ocho pods diferentes, uno con una aplicación por lotes de Java, otro con alguna instancia de Redis, otro con una aplicación de nodejs, otro con un microservicio de Flogo (Nota: ¿Aún no has oído hablar de Flogo? Tómate unos minutos para conocer una de las próximas novedades que puedes usar ahora para construir tus aplicaciones nativas en la nube), otro con una base de datos Oracle, otro con algún servidor web jetty y finalmente otro con una aplicación de BusinessWorks Container Edition. ¿Cómo puedes saber que cada componente está funcionando bien?

Primero, puedes pensar que puedes hacerlo con el componente de punto de entrada de tu Dockerfile ya que solo especificas un comando para ejecutar dentro de cada contenedor, así que verifica si ese proceso está en ejecución, ¿y eso significa que todo está saludable? Ok… bastante justo…

Pero, ¿esto es siempre cierto? ¿Un proceso en ejecución a nivel de SO/contenedor significa que todo está funcionando bien? Pensemos en la base de datos Oracle por un minuto, imagina que tienes un problema con la memoria compartida y se mantiene en un estado de inicialización para siempre, K8S va a verificar el comando, va a encontrar que está en ejecución y le dice a todo el clúster: ¡Ok! ¡No te preocupes! La base de datos está funcionando perfectamente, ¡adelante y envía tus consultas a ella!

Foto de Rod Long en Unsplash

Esto podría suceder con componentes similares como un servidor web o incluso con una aplicación en sí, pero es muy común cuando tienes servidores que pueden manejar implementaciones en él, como BusinessWorks Container Edition en sí. Y por eso esto es muy importante para nosotros como desarrolladores e incluso más importante para nosotros como administradores. ¡Así que empecemos!

Lo primero que vamos a hacer es construir una aplicación de BusinessWorks Container Edition, como este no es el propósito principal de este artículo, vamos a usar las mismas que he creado para la Integración de BusinessWorks Container Edition — Istio que puedes encontrar aquí.

Entonces, esta es una aplicación bastante simple que expone un servicio web SOAP. Todas las aplicaciones en BusinessWorks Container Edition (así como en BusinessWorks Enterprise Edition) tienen su propio estado, por lo que puedes preguntarles si están en ejecución o no, eso es algo que el «motor» interno de BusinessWorks Container (NOTA: Vamos a usar la palabra motor para simplificar cuando hablamos de los internos de BWCE. En detalle, el componente que conoce el estado de la aplicación es el AppNode interno que inicia el contenedor, pero mantengámoslo simple por ahora)

Sondas de Kubernetes

En Kubernetes, existe el concepto de «sonda» para realizar verificaciones de salud a tu contenedor. Esto se realiza configurando sondas de vivacidad o sondas de preparación.

  • Sonda de vivacidad: Kubernetes utiliza sondas de vivacidad para saber cuándo reiniciar un contenedor. Por ejemplo, las sondas de vivacidad podrían detectar un bloqueo, donde una aplicación está en ejecución, pero no puede avanzar.
  • Sonda de preparación: Kubernetes utiliza sondas de preparación para saber cuándo un contenedor está listo para comenzar a aceptar tráfico. Un pod se considera listo cuando todos sus contenedores están listos. Un uso de esta señal es controlar qué pods se utilizan como backends para los servicios. Cuando un pod no está listo, se elimina del balance de carga del servicio

Incluso cuando hay dos tipos de sondas para BusinessWorks Container Edition, ambas se manejan de la misma manera, la idea es la siguiente: Mientras la aplicación esté en ejecución, puedes comenzar a enviar tráfico y cuando no esté en ejecución necesitamos reiniciar el contenedor, por lo que eso lo hace más simple para nosotros.

Implementación de Sondas

Cada aplicación de BusinessWorks Container Edition que se inicia tiene una forma predeterminada de saber si está saludable o no. Esto se hace mediante un endpoint especial publicado por el propio motor:

http://localhost:7777/_ping/

Entonces, si tenemos una aplicación normal de BusinessWorks Container Edition desplegada en nuestro clúster de Kubernetes como la que teníamos para la integración de Istio, tenemos registros similares a estos:

Trazas de inicio de una aplicación de BusinessWorks Container Edition

Como puedes ver, los registros dicen que la aplicación está iniciada. Entonces, como no podemos lanzar una solicitud curl desde dentro del contenedor (ya que no hemos expuesto el puerto 7777 al exterior aún y curl no está instalado en la imagen base), lo primero que vamos a hacer es exponerlo al resto del clúster.

Para hacer eso, cambiamos nuestro archivo Deployment.yml que hemos usado a este:

Archivo Deployment.yml con el puerto 7777 expuesto

Ahora, podemos ir a cualquier contenedor en el clúster que tenga «curl» instalado o cualquier otra forma de lanzar una solicitud como esta con el código HTTP 200 y el mensaje «La aplicación está en ejecución».

Ejecución exitosa del endpoint _ping

NOTA: Si olvidas la última / e intentas invocar _ping en lugar de _ping/ vas a obtener un código HTTP 302 Found con la ubicación final como puedes ver aquí:

Ejecución del código HTTP 302 apuntando a _ping en lugar de _ping/

Ok, veamos qué pasa si ahora detenemos la aplicación. Para hacer eso vamos a entrar en el contenedor y usar la consola OSGi.

Para hacer eso, una vez que estés dentro del contenedor, ejecutas el siguiente comando:

ssh -p 1122 equinox@localhost

Va a pedir credenciales y usa la contraseña predeterminada ‘equinox’. Después de eso, te dará la oportunidad de crear un nuevo usuario y puedes usar las credenciales que te funcionen. En mi ejemplo, voy a usar admin / adminadmin (NOTA: La longitud mínima para una contraseña es de ocho (8) caracteres.

Y ahora, estamos dentro. Y esto nos permite la opción de ejecutar varios comandos, como este no es el tema principal de hoy voy a omitir toda la explicación, pero puedes echar un vistazo a este enlace con toda la información sobre esta consola.

Si ejecutamos frwk:la va a mostrar las aplicaciones desplegadas, en nuestro caso la única, como debería ser en la aplicación de BusinessWorks Container Edition:

Para detenerla, vamos a ejecutar el siguiente comando para listar todos los paquetes OSGi que tenemos en este momento en ejecución en el sistema:

frwk:lb

Ahora, encontramos los paquetes que pertenecen a nuestra aplicación (al menos dos paquetes (1 por módulo BW y otro para la aplicación)

Mostrando paquetes dentro de la aplicación BusinessWorks Container

Y ahora podemos detenerlo usando felix:stop <ID>, así que en mi caso, necesito ejecutar los siguientes comandos:

stop “603”

stop “604”

Comandos para detener los paquetes que pertenecen a la aplicación

Y ahora la aplicación está detenida

Consola OSGi mostrando la aplicación como Detenida

Entonces, si ahora intentamos lanzar el mismo comando curl que ejecutamos antes, obtenemos la siguiente salida:

Ejecución fallida del endpoint ping cuando la aplicación está detenida

Como puedes ver, un error HTTP 500 que significa que algo no está bien. Si ahora intentamos iniciar nuevamente la aplicación usando el comando de inicio de paquete (equivalente al comando de detención de paquete que usamos antes) para ambos paquetes de la aplicación, verás que la aplicación dice que está en ejecución nuevamente:

Y el comando tiene la salida HTTP 200 como debería tener y el mensaje «La aplicación está en ejecución»

Entonces, ahora, después de saber cómo funciona el endpoint _ping/ solo necesitamos agregarlo a nuestro archivo deployment.yml de Kubernetes. Así que modificamos nuevamente nuestro archivo de implementación para que sea algo como esto:

NOTA: Es bastante importante la presencia del parámetro initialDelaySeconds para asegurarse de que la aplicación tenga la opción de iniciarse antes de comenzar a ejecutar la sonda. En caso de que no pongas este valor, puedes obtener un bucle de reinicio en tu contenedor.

NOTA: El ejemplo muestra el puerto 7777 como un puerto exportado, pero esto solo es necesario para los pasos que hemos hecho antes y no será necesario en un entorno de producción real.

Así que ahora desplegamos nuevamente el archivo YML y una vez que tengamos la aplicación en ejecución, vamos a intentar el mismo enfoque, pero ahora como tenemos las sondas definidas tan pronto como detenga la aplicación, los contenedores se reiniciarán. ¡Veamos!

Como puedes ver en la imagen de arriba, después de que la aplicación se detiene, el contenedor se ha reiniciado y debido a eso, hemos sido expulsados de dentro del contenedor.

Así que eso es todo, espero que te ayude a configurar tus sondas y en caso de que necesites más detalles, por favor echa un vistazo a la documentación de Kubernetes sobre sondas httpGet para ver toda la configuración y opciones que puedes aplicarles.

Etiquetas:

Kubernetes Probes for a TIBCO BusinessWorks Container Edition Application

Photo by Blake Wisz on Unsplash

Introduction

Probes are how we’re able to say to Kubernetes that everything inside the pod is working as expected. Kubernetes has no way to know what’s happening inside at the fine-grained and has no way to know for each container if it is healthy or not, that’s why they need help from the container itself.

Imagine that you’re Kubernetes controller and you have like eight different pods , one with Java batch application, another with some Redis instance, other with nodejs application, other with a Flogo microservice (Note: Haven’t you heard about Flogo yet? Take some minutes to know about one of the next new things you can use now to build your cloud-native applications) , another with a Oracle database, other with some jetty web server and finally another with a BusinessWorks Container Edition application. How can you tell that every single component is working fine?

First, you can think that you can do it with the entrypoint component of your Dockerfile as you only specify one command to run inside each container, so check if that process is running, and that means that everything is healthy? Ok… fair enough…

But, is this true always? A running process at the OS/container level means that everything is working fine? Let’s think about the Oracle database for a minute, imagine that you have an issue with the shared memory and it keeps in an initializing status forever, K8S is going to check the command, it is going to find that is running and says to the whole cluster: Ok! Don’t worry! Database is working perfectly, go ahead and send your queries to it!!

Photo by Rod Long on Unsplash

This could happen with similar components like a web server or even with an application itself, but it is too common when you have servers that can handle deployments on it, like BusinessWorks Container Edition itself. And that’ why this is very important for us as developers and even more important for us as administrators. So, let’s start!

The first thing we’re going to do is to build a BusinessWorks Container Edition Application, as this is not the main purpose of this article, we’re going to use the same ones I’ve created for the BusinessWorks Container Edition — Istio Integration that you could find here.

So, this is a quite simple application that exposes a SOAP Web Service. All applications in BusinessWorks Container Edition (as well as in BusinessWorks Enterprise Edition) has its own status, so you can ask them if they’re Running or not, that something the BusinessWorks Container internal “engine” (NOTE: We’re going to use the word engine to simplify when we’re talking about the internals of BWCE. In detail, the component that knows the status of the application is the internal AppNode the container starts, but let’s keep it simple for now)

Kubernetes Probes

In Kubernetes, exists the “probe” concept to perform health check to your container. This is performed by configuring liveness probes or readiness probes.

  • Liveness probe: Kubernetes uses liveness probes to know when to restart a Container. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress.
  • Readiness probe: Kubernetes uses readiness probes to know when a Container is ready to start accepting traffic. A Pod is considered ready when all of its Containers are ready. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balance

Even when there are two types of probes for BusinessWorks Container Edition both are handling the same way, the idea is the following one: As long as the application is Running, you can start sending traffic and when it is not running we need to restart the container, so that makes it simpler for us.

Implementing Probes

Each BusinessWorks Container Edition application that is started has an out of the box way to know if it is healthy or not. This is done by a special endpoint published by the engine itself:

http://localhost:7777/_ping/

So, if we have a normal BusinessWorks Container Edition application deployed on our Kubernetes cluster as we had for the Istio integration we have logs similar to these ones:

Staring traces of a BusinessWorks Container Edition Application

As you can see logs says that the application is started. So, as we can’t launch a curl request from the inside the container (as we haven’t exposed the port 7777 to the outside yet and curl is not installed in the base image), the first thing we’re going to do is to expose it to the rest of the cluster.

To do that we change our Deployment.yml file that we have used to this one:

Deployment.yml file with the 7777 port exposed

Now, we can go to any container in the cluster that has “curl” installed or any other way to launch a request like this one with the HTTP 200 code and the message “Application is running”.

Successful execution of _ping endpoint

NOTE: If you forget the last / and try to invoke _ping instead of _ping/ you’re going to get an HTTP 302 Found code with the final location as you can see here:

HTTP 302 code execution were pointing to _ping instead of _ping/

Ok, let’s see what happens if now we stop the application. To do that we’re going to go inside the container and use the OSGi console.

To do that once you’re inside the container you execute the following command:

ssh -p 1122 equinox@localhost

It is going to ask for credentials and use the default password ‘equinox’. After that is going to give you the chance to create a new user and you can use whatever credentials work for you. In my example, I’m going to use admin / adminadmin (NOTE: Minimum length for a password is eight (8) characters.

And now, we’re in. And this allows us the option to execute several commands, as this is not the main topic for today I’m going to skip all the explanation but you can take a look at this link with all the info about this console.

If we execute frwk:la is going to show the applications deployed, in our case the only one, as it should be in BusinessWorks Container Edition application:

To stop it, we are going to execute the following command to list all the OSGi bundle we have at the moment running in the system:

frwk:lb

Now, we find the bundles that belong to our application (at least two bundles (1 per BW Module and another for the Application)

Showing bundles inside the BusinessWorks Container Application

And now we can stop it using felix:stop <ID>, so in my case, I need to execute the following commands:

stop “603”

stop “604”

Commands to stop the bundles that belong to the application

And now the application is stopped

OSGi console showing the application as Stopped

So, if now we try to launch the same curl command as we executed before, we’re getting the following output:

Failed execution of ping endpoint when Application is stopped

As you can see an HTTP 500 Error which means something is not fine. If now we try to start again the application using the start bundle command (equivalent to the stop bundle command that we used before) for both bundles of the application, you are going to see that the application says is running again:

And the command has the HTTP 200 output as it should have and the message “Application us running”

So, now, after knowing how the _ping/ endpoint works we only need to add it to our deployment.yml file from Kubernetes. So we modified again our deployment file to be something like this:

NOTE: It’s quite important the presence of initialDelaySeconds parameter to make sure the application has the option to start before start executing the probe. In case you don’t put this value you can get a Reboot Loop in your container.

NOTE: Example shows port 7777 as an exported port but this is only needed for the steps we’ve done before and you will not be needed in a real production environment.

So now we deploy again the YML file and once we get the application running we’re going to try the same approach, but now as we have the probes defined as soon as I stop the application containers has going to be restarted. Let’s see!

As you can see in the picture above after the application is Stopped the container has been restarted and because of that, we’ve got expelled from inside the container.

So, that’s all, I hope that helps you to set up your probes and in case you need more details, please take a look at the Kubernetes documentation about httpGet probes to see all the configuration and option that you can apply to them.