Cómo generar Dockers de forma sencilla con S2I

En este post se pretende realizar una introducción al framework S2I (source to image) de Openshift para la generación automática de contenedores a partir de código fuente. Si bien es un framework desarrollado para Openshift, al utilizar este la tecnología Docker, nos servirá también para generar contenedores válidos para cualquier tipo de sistema que pueda ejecutar Docker. Actualmente ya existe soporte para generar contenedores para gran variedad de lenguajes y plataformas.

docker

Introducción

S2I utiliza como entrada un contenedor, scripts y el código fuente de tu aplicación y genera como resultado un contenedor listo para ejecutar tu aplicación. Lo que el desarrollador tiene que hacer es escribir los scripts en los que indicará cómo construir el artefacto a partir de su código fuente y cómo ejecutar dicho artefacto. En la mayoría de casos ni eso, ya que existen scripts estándar para varios lenguajes y arquitecturas. Estos scripts se ejecutarán dentro de un contenedor llamado ‘builder’ que se encargará de construir el contenedor que ejecuta tu aplicación. Actualmente existen ‘builders’ para diferentes lenguajes y plataformas como php, nodeJS, wildfly, ruby, python y perl, además de la posibilidad de construir tu propio ‘builder’, lo cual es bastante sencillo de realizar. En este post explicaremos cómo crear un ‘builder’ para construir contenedores de aplicaciones Spring-boot con Maven o Gradle.

Configuración de nuestro entorno

Para crear nuestros contenedores debemos tener S2I instalado, que podemos descargar aquí. Lógicamente también debemos tener Docker instalado, lo podéis descargar aquí.

Una vez instalados, en primer lugar creamos una carpeta que llamaremos sti-project donde tendremos todos nuestros recursos. Para inicializar un proyecto S2I, una vez instalado, ejecutaremos el siguiente comando: s2i create <image name> <destination directory>

1

Como vemos da una serie de errores en su ejecución en Windows a la hora de establecer permisos, pero no supone un problema. Finalmente nos creará la siguiente jerarquía de carpetas y ficheros:

2

S2I scripts

S2I define cuatro scripts:

  • Assemble: es el script encargado de construir el artefacto a partir de nuestro código fuente.
  • Run: ejecutará el artefacto generado.
  • Save-artifacts (opcional): utilizará el artefacto de la construcción anterior para la siguiente incremental.
  • Usage (opcional): información de uso.

Para nuestro caso de uso ya existen actualmente unos scripts estándar para la construcción de aplicaciones Spring-boot ya sea con Maven o con Gradle. Estos han sido desarrollados por un miembro del equipo de RedHat, Jorge Morales. Estos scripts se encuentran en su repositorio público de Github. En concreto os recomiendo que le echéis un vistazo a los más interesantes, el assemble y el run, el primero puede parecer algo largo pero si os fijáis es muy sencillo.

Contenedor ‘builder’

Como se ha mencionado previamente S2I utiliza como entrada también un contenedor. Este contenedor es el que se definirá en el Dockerfile y que es conocido como ‘builder’. En él será donde se inserten los scripts de S2I y el código fuente de nuestra aplicación y que generará el contenedor que ejecute la aplicación.

De la misma forma que con los scripts, también nos podemos encontrar la definición de dicho contenedor en el mismo repositorio, en concreto podéis ver el Dockerfile aquí.

En resumen para la construcción del contenedor se realizan las siguientes tareas:

  • Instalación de paquetes: como son Gradle y Maven para la construcción de la aplicación, la JDK para la ejecución de la misma.
  • Etiquetado: algunas de estas etiquetas son para la utilización del contenedor en Openshift, si no va a ser así no serán necesarias.
  • Copiar los scripts de S2I al contenedor.
  • Establecer el usuario con el que se ejecutará y setearlo como propietario de la carpeta donde se incluirá el artefacto.
  • Exponer el puerto 8080.

Construcción del contenedor ‘builder’

IMPORTANTE: La jerarquía de carpetas del contenedor que podéis encontrar en el repositorio que hemos comentado fue realizada con versiones antiguas del S2I, en concreto con la versión 1.0.1. Yo no he conseguido hacerlo funcionar con dicha versión. Versiones posteriores de S2I cambian el nombrado de algunos elementos de la jerarquía de directorios, por tanto no son compatibles con dicho repositorio. En este caso, para solucionarlo, debemos realizar unos pequeños cambios que se detallan a continuación en los scripts y Dockerfile. El resultado final de dichos cambios puede encontrarse en mi repositorio público de GitHub aquí. En concreto yo he utilizado la versión 1.0.5 de S2I para la construcción de los contenedores.

Los pasos que se han realizado para modificar el contenedor y los scripts son los siguientes (se indica fichero y línea y el nuevo valor):

  • Dockerfile:41: LABEL io.openshift.s2i.scripts-url=image:///usr/local/s2i
  • Dockerfile:42: COPY ./.s2i/bin/ /usr/local/s2i
  • assemble:13: exec /usr/local/s2i/usage

Como veis lo único que hay que hacer es cambiar las referencias de “sti” a “s2i”, esto es debido al cambio que se realizó en la librería en la versión 1.0.2. Así mismo mencionar que también he borrado el soporte a la construcción con Maven del fichero assemble.

Una vez hemos realizado estos cambios ya estamos listos para generar nuestro contenedor ‘builder’, en este caso lo llamaremos microservice_builder. Para construirlo ejecutaremos el siguiente comando docker desde la carpeta del proyecto: docker build -t microservice_builder:1.0.

3

Si listamos nuestras imágenes veremos como se ha añadido:

4

Este contenedor no servirá como ‘builder’ para construir los contenedores para ejecutar cualquiera de nuestras aplicaciones Spring-boot.

Construcción del contenedor de nuestra aplicación

Una vez tenemos disponible nuestro contenedor ‘builder’ utilizaremos S2I en conjunto con el mismo para generar el contenedor con nuestra aplicación. En este caso vamos a reutilizar una aplicación ‘tonta’ para pruebas, dicha aplicación simplemente responde “Hello Docker World” cuando es invocada. Podéis ver su código fuente aquí.

Para construir nuestro contenedor ejecutaremos el siguiente comando: s2i build <source_location> <builder_image> [<tag>]

5

Podemos ver por consola cómo se descarga las dependencias de Gradle y construye el proyecto. El parámetro source_location puede ser la ruta de un repositorio git o una ruta local. Si habéis echado un vistazo al script assemble, que se indicaba en la sección de scripts, veréis que existe una variable de entorno BUILDER_ARGS que nos permite personalizar el comando Maven o Gradle que lanza la construcción de nuestra aplicación. Para ello podemos utilizar el parámetro -e del comando build.

Podéis consultar un listado completo de los comandos de S2I y sus parámetros aquí y podéis ver su descripción aquíPodéis ver el flujo del proceso que realiza S2I durante un build en la siguiente imagen:

6

En resumen, lo que se hace es empaquetar los scripts y el código fuente en un tar que se inserta en la imagen para posteriormente descomprimirlo y ejecutar el script assemble. Si queréis conocer el proceso más en detalle podéis encontrarlo descrito aquí.

Volviendo a nuestro contenedor si listamos las imágenes de nuevo veremos la de nuestra aplicación my_gradle_app:1.0

7

Ahora solo nos queda ejecutar el contenedor para comprobar que funciona, para ello ejecutaremos:

8

Et voilà!

9

Siguientes pasos

Este pequeño post es solo el comienzo, se ha explicado cómo utilizar el framework y se han reutilizado contenedores y scripts ya diseñados para aplicaciones con Spring-boot. A partir de aquí podemos continuar escribiendo nuestros propios scripts y Dockerfile, probar la generación de contenedores de otros lenguajes o incluso probar a desplegar nuestro contenedor ‘builder’ en OSE como se explica aquí.

Conclusión

Como hemos visto es realmente sencillo construir contenedores para ejecutar nuestra aplicación Spring-boot o aplicaciones de cualquier otro lenguaje o plataforma. Incluso podemos automatizar la generación de los contenedores en una tarea Jenkins y que se lanze al detectar un cambio de código en el repositorio. Al ser Docker una tecnología soportada por una amplia variedad de clouds tanto públicas como privadas, esto nos permitirá desplegar nuestra aplicación en casi cualquier lugar, así que ya no tienes ninguna excusa para no utilizar contenedores.

Fuentes

Blog de Openshift – Using Openshift for Enterprise Grade Spring Boot Deployments

Blog de Openshift – How to Create an S2I Builder Image

S2I en Github

Abraham Rodríguez actualmente desarrolla funciones de ingeniero backend J2EE en Paradigma donde ya ha realizado diversos proyectos enfocados a arquitecturas de microservicios. Especializado en sistemas Cloud, ha trabajado con AWS y Openshift y es Certified Google Cloud Platform Developer. Cuenta con experiencia en diversos sectores como banca, telefonía, puntocom... Y es un gran defensor de las metodologías ágiles y el software libre."

Ver toda la actividad de José Abraham Rodríguez López

Recibe más artículos como este

Recibirás un email por cada nuevo artículo.. Acepto los términos legales

Posts relacionados

Escribe un comentario