¡Hola a todos en este blog! Este es el tercer post de una serie en la que mostramos cómo desplegar aplicaciones web modernas en Red Hat OpenShift.

En las dos publicaciones anteriores, hablamos sobre cómo desplegar aplicaciones web modernas en solo unos pocos pasos y cómo usar una nueva imagen S2I junto con una imagen de servidor HTTP lista, como NGINX, con la ayuda de builds enlazados para organizar el despliegue de producción.
Hoy mostraremos cómo ejecutar un servidor de desarrollo para su aplicación en la plataforma OpenShift y sincronizarlo con el sistema de archivos local, además de hablar sobre qué son las OpenShift Pipelines y cómo se pueden utilizar como alternativa a los builds enlazados.
OpenShift como entorno de desarrollo
Flujo de trabajo de desarrollo (development workflow)
Como se mencionó en , el proceso típico de desarrollo para aplicaciones web modernas es simplemente un "servidor de desarrollo" que monitorea cambios en los archivos locales. Cuando ocurren, se inicia la construcción de la aplicación y luego se actualiza en el navegador.
En la mayoría de los frameworks modernos, dicho "servidor de desarrollo" está integrado en las herramientas de línea de comandos correspondientes.
Ejemplo local
Primero, veamos cómo funciona esto en el caso de ejecutar aplicaciones localmente. Tomemos como ejemplo la aplicación de los artículos anteriores, aunque prácticamente las mismas conceptos del flujo de trabajo se aplican en todos los demás frameworks modernos.
Así que, para iniciar el "servidor de desarrollo" en nuestro ejemplo con React, ingresamos el siguiente comando:
$ npm run start
Entonces, en la ventana de la terminal veríamos algo como esto:

Y nuestra aplicación se abrirá en el navegador por defecto:

Ahora, si hacemos cambios en el archivo, la aplicación debería actualizarse en el navegador.
Bien, con el desarrollo en modo local todo está claro, ¿y cómo conseguimos lo mismo en OpenShift?
Servidor de desarrollo en OpenShift
Si recuerdas, en , revisamos la llamada fase de ejecución (run phase) de la imagen S2I y vimos que por defecto el módulo serve se encarga de manejar nuestra aplicación web.
Sin embargo, si miramos más de cerca de ese ejemplo, hay una variable de entorno $NPM_RUN que permite ejecutar su propio comando.
Por ejemplo, se puede usar el módulo nodeshift para desplegar nuestra aplicación:
$ npx nodeshift --deploy.env NPM_RUN="yarn start" --dockerImage=nodeshift/ubi8-s2i-web-app
Nota: el ejemplo anterior se presenta de manera condensada para ilustrar la idea general.
Aquí hemos agregado a nuestro despliegue la variable de entorno NPM_RUN, que le indica al paso de ejecución que debe ejecutar el comando yarn start, que inicia el servidor de desarrollo de React dentro de nuestro pod de OpenShift.
Si miramos el registro del pod en funcionamiento, debería verse algo así:

Por supuesto, todo esto no tendrá sentido hasta que podamos sincronizar el código local con el código que también se controla en cuanto a cambios, pero que reside en un servidor remoto.
Sincronización de código remoto y local
Afortunadamente, nodeshift facilita la sincronización, y para rastrear cambios se puede utilizar el comando watch.
Así que después de ejecutar el comando para desplegar el servidor de desarrollo para nuestra aplicación, podemos usar el siguiente comando:
$ npx nodeshift watch
Como resultado, se conectará al pod en ejecución que creamos un poco antes, se activará la sincronización de nuestros archivos locales con el clúster remoto, y los archivos en nuestro sistema local comenzarán a ser monitoreados en busca de cambios.
Por lo tanto, si ahora actualizamos el archivo src/App.js, el sistema reaccionará ante esos cambios, los copiará en el clúster remoto y ejecutará el servidor de desarrollo, que luego actualizará nuestra aplicación en el navegador.
Para completar la imagen, mostraremos cómo lucen estos comandos en su totalidad:
$ npx nodeshift --strictSSL=false --dockerImage=nodeshift/ubi8-s2i-web-app --build.env YARN_ENABLED=true --expose --deploy.env NPM_RUN="yarn start" --deploy.port 3000
$ npx nodeshift watch --strictSSL=false
El comando watch es una abstracción sobre el comando oc rsync, para obtener más información sobre cómo funciona, puedes consultar. .
Este fue un ejemplo para React, pero el mismo método se puede utilizar con otros frameworks, solo debes definir la variable de entorno NPM_RUN de la manera adecuada.
Pipelines de OpenShift

A continuación, hablaremos sobre la herramienta conocida como OpenShift Pipelines y cómo se puede utilizar como una alternativa a las compilaciones encadenadas.
¿Qué son los OpenShift Pipelines?
OpenShift Pipelines es un sistema de CI/CD orientado a la nube, diseñado para organizar tuberías utilizando Tekton. Tekton es un marco de CI/CD nativo de Kubernetes, flexible y de código abierto, que permite automatizar el despliegue en diversas plataformas (Kubernetes, serverless, máquinas virtuales, etc.) al abstraer el nivel subyacente.
Para entender este artículo, se necesitan ciertos conocimientos sobre Pipelines, por lo que recomendamos encarecidamente que primero revises la .
Configuración del entorno de trabajo
Para experimentar con los ejemplos de este artículo, primero debes preparar el entorno de trabajo:
- Instalar y configurar un clúster OpenShift 4. En nuestros ejemplos, utilizamos CodeReady Containers (CRD), cuyas instrucciones de instalación puedes encontrar .
- Una vez que el clúster esté listo, debes instalar el Operator de Pipeline. No te preocupes, es fácil, las instrucciones para la instalación .
- Descargar (tkn) .
- Ejecutar la herramienta de línea de comandos create-react-app para crear una aplicación que luego será desplegada (es una aplicación simple ).
- (Opcional) Clonar el repositorio para ejecutar localmente el ejemplo de la aplicación con el comando npm install y luego npm start.
En el repositorio de la aplicación también habrá una carpeta k8s, donde estarán los YAML de Kubernetes/OpenShift utilizados para desplegar la aplicación. Allí habrá Tasks, ClusterTasks, Resources y Pipelines que crearemos en este .
Comencemos
Lo primero que necesitamos hacer para nuestro ejemplo es crear un nuevo proyecto en el clúster de OpenShift. Llamaremos a este proyecto webapp-pipeline y lo crearemos con el siguiente comando:
$ oc new-project webapp-pipeline
A partir de aquí, este nombre de proyecto se utilizará en el código, así que si decides nombrarlo de otra manera, no olvides ajustar el código de los ejemplos en consecuencia. Desde este punto, procederemos de abajo hacia arriba: es decir, primero crearemos todos los componentes de la tubería, y luego la propia tubería.
Así que, lo primero es...
Tareas Tasks
Crearemos un par de tareas (tasks) que luego ayudarán a desplegar la aplicación dentro de nuestro pipeline. La primera tarea, apply_manifests_task, se encarga de aplicar los recursos YAML de Kubernetes (service, deployment y route) que se encuentran en la carpeta k8s de nuestra aplicación. La segunda tarea, update_deployment_task, se encarga de actualizar la imagen ya desplegada a la que se crea en nuestro pipeline.
No te preocupes si aún no está muy claro. En realidad, estas tareas son algo así como utilidades, y las exploraremos más en detalle un poco más adelante. Por ahora, simplemente las crearemos:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/update_deployment_task.yaml
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/apply_manifests_task.yaml
Luego, usaremos el comando tkn CLI para verificar que se hayan creado las tareas:
$ tkn task ls
NAME AGE
apply-manifests 1 minute ago
update-deployment 1 minute ago
Nota: estas son tareas locales de tu proyecto actual.
Tareas de clúster Cluster tasks
Las tareas de clúster son, en general, lo mismo que las tareas normales. Es decir, son una colección reutilizable de pasos que se combinan de diversas maneras al ejecutar una tarea específica. La diferencia es que las tareas de clúster están disponibles en todo el clúster. Para ver la lista de tareas de clúster que se crean automáticamente al agregar el Pipeline Operator, nuevamente usaremos el comando tkn CLI:
$ tkn clustertask ls
NAME AGE
buildah 1 day ago
buildah-v0-10-0 1 day ago
jib-maven 1 day ago
kn 1 day ago
maven 1 day ago
openshift-client 1 day ago
openshift-client-v0-10-0 1 day ago
s2i 1 day ago
s2i-go 1 day ago
s2i-go-v0-10-0 1 day ago
s2i-java-11 1 day ago
s2i-java-11-v0-10-0 1 day ago
s2i-java-8 1 day ago
s2i-java-8-v0-10-0 1 day ago
s2i-nodejs 1 day ago
s2i-nodejs-v0-10-0 1 day ago
s2i-perl 1 day ago
s2i-perl-v0-10-0 1 day ago
s2i-php 1 day ago
s2i-php-v0-10-0 1 day ago
s2i-python-3 1 day ago
s2i-python-3-v0-10-0 1 day ago
s2i-ruby 1 day ago
s2i-ruby-v0-10-0 1 day ago
s2i-v0-10-0 1 day ago
Ahora crearemos dos tareas de clúster. La primera generará una imagen S2I y la enviará al registro interno de OpenShift; la segunda construirá nuestra imagen basada en NGINX, utilizando como contenido la aplicación que ya hemos compilado.
Creamos y enviamos la imagen
Al crear la primera tarea, repetiremos lo que ya hicimos en el artículo anterior sobre construcciones relacionadas. Recordemos que usamos la imagen S2I (ubi8-s2i-web-app) para "compilar" nuestra aplicación, y al final obtuvimos una imagen almacenada en el registro interno de OpenShift. Ahora utilizaremos esta imagen S2I de la aplicación web para crear un DockerFile para nuestra aplicación, y luego emplearemos Buildah para realizar la construcción real y enviar la imagen resultante al registro interno de OpenShift, ya que esto es exactamente lo que hace OpenShift cuando despliega sus aplicaciones usando NodeShift.
¿Se preguntan de dónde sacamos todo esto? De , solo la copiamos y la ajustamos a nuestras necesidades.
Entonces, ahora creamos la tarea de clúster s2i-web-app:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/s2i-web-app-task.yaml
No vamos a revisar esto en detalle, solo nos detendremos en el parámetro OUTPUT_DIR:
params:
- name: OUTPUT_DIR
description: La ubicación del directorio de salida de la construcción
default: build
Por defecto, este parámetro es igual a build, exactamente donde React coloca el contenido construido. En otros frameworks se utilizan otras rutas, por ejemplo, en Ember es dist. La salida de nuestra primera tarea de clúster será una imagen que contiene el HTML, JavaScript y CSS que hemos construido.
Construyendo la imagen basada en NGINX
En cuanto a nuestra segunda tarea de clúster, debe construir una imagen basada en NGINX, utilizando el contenido de la aplicación que ya hemos construido. De hecho, esta es la parte del segmento anterior donde tratamos las construcciones encadenadas.
Para esto, –exactamente como antes– crearemos la tarea de clúster webapp-build-runtime:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/webapp-build-runtime-task.yaml
Si vemos el código de estas tareas de clúster, podemos notar que no se especifica el repositorio Git con el que estamos trabajando, ni los nombres de las imágenes que estamos creando. Solo establecemos qué es lo que estamos pasando a Git, o alguna imagen que necesita recibir la imagen final. Por eso, estas tareas de clúster se pueden reutilizar al trabajar con otras aplicaciones.
Y aquí pasamos elegantemente al siguiente punto…
Recursos
Entonces, como acabamos de decir, las tareas en clúster deben ser lo más generales posible, necesitamos crear recursos que se utilizarán como entrada (repositorio Git) y salida (imágenes finales). El primer recurso que necesitamos es Git, donde se encuentra nuestra aplicación, algo así como esto:
# This resource is the location of the git repo with the web application source
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: web-application-repo
spec:
type: git
params:
- name: url
value: https://github.com/nodeshift-starters/react-pipeline-example
- name: revision
value: master
Aquí, PipelineResource tiene el tipo git. La clave url en la sección params indica el repositorio específico y establece la rama master (esto es opcional, pero lo escribimos para que sea completo).
Ahora necesitamos crear un recurso para la imagen, donde se guardarán los resultados de la tarea s2i-web-app, esto se hace así:
# This resource is the result of running "npm run build", the resulting built files will be located in /opt/app-root/output
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: built-web-application-image
spec:
type: image
params:
- name: url
value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-application:latest
Aquí, PipelineResource tiene el tipo imagen, y el valor del parámetro url indica el Registro de Imágenes interno de OpenShift, específicamente el que se encuentra en el espacio de nombres webapp-pipeline. No olvides cambiar este parámetro si usas otro espacio de nombres.
Y, por último, el último recurso que necesitaremos también tendrá el tipo imagen y será la imagen final de NGINX, que luego se utilizará en el despliegue:
# This resource is the image that will be just the static html, css, js files being run with nginx
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: runtime-web-application-image
spec:
type: image
params:
- name: url
value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtime-web-application:latest
Y de nuevo, tenga en cuenta que este recurso guarda la imagen en el registro interno de OpenShift en el espacio de nombres webapp-pipeline.
Para crear estos recursos de una vez, usaremos el comando create:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/resources/resource.yaml
Puedes asegurarte de que los recursos se han creado así:
$ tkn resource ls
Pipeline
Ahora que tenemos todos los componentes necesarios, vamos a ensamblar el pipeline, creándolo con el siguiente comando:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/pipelines/build-and-deploy-react.yaml
Pero, antes de ejecutar este comando, analicemos estos componentes. Primero, este es el nombre:
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: build-and-deploy-react
Luego, en la sección spec, vemos la declaración de los recursos que creamos anteriormente:
spec:
resources:
- name: web-application-repo
type: git
- name: built-web-application-image
type: image
- name: runtime-web-application-image
type: image
Luego creamos las tareas que debe realizar nuestro pipeline. Primero debe ejecutar la tarea s2i-web-app que ya hemos creado:
tasks:
- name: build-web-application
taskRef:
name: s2i-web-app
kind: ClusterTask
Esta tarea toma los parámetros de entrada (recurso git) y salida (recurso built-web-application-image). También le pasamos un parámetro especial para que no verifique TLS, ya que usamos certificados autofirmados:
recursos:
entradas:
- nombre: fuente
recurso: repositorio-de-aplicaciones-web
salidas:
- nombre: imagen
recurso: imagen-de-aplicación-web-construida
parámetros:
- nombre: TLSVERIFY
valor: "false"
La siguiente tarea es casi la misma, solo que aquí se llama a la tarea de clúster que ya hemos creado: webapp-build-runtime:
nombre: imagen-runtime-de-construcción
referenciaTarea:
nombre: webapp-build-runtime
tipo: TareaDeClúster
Al igual que con la tarea anterior, pasamos el recurso, pero ahora es la imagen-de-aplicación-web-construida (la salida de nuestra tarea anterior). Y como salida, nuevamente definimos la imagen. Dado que esta tarea debe ejecutarse después de la anterior, agregamos el campo runAfter:
recursos:
entradas:
- nombre: imagen
recurso: imagen-de-aplicación-web-construida
salidas:
- nombre: imagen
recurso: imagen-runtime-de-aplicación-web
parámetros:
- nombre: TLSVERIFY
valor: "false"
runAfter:
- build-web-application
Las siguientes dos tareas son responsables de aplicar los archivos YAML del servicio, la ruta y el despliegue, que residen en el directorio k8s de nuestra aplicación web, así como de actualizar este despliegue al crear nuevas imágenes. Estas dos tareas de clúster las definimos al principio del artículo.
Ejecutar el canal
Así que todas las partes de nuestro pipeline están creadas, y lo ejecutaremos con el siguiente comando:
$ tkn pipeline start build-and-deploy-react
En esta etapa, se utiliza la línea de comandos en modo interactivo y hay que seleccionar los recursos adecuados en respuesta a cada solicitud: para el recurso git seleccionamos repositorio-de-aplicaciones-web, luego para el recurso de la primera imagen – imagen-de-aplicación-web-construida, y finalmente, para el recurso de la segunda imagen – imagen-runtime-de-aplicación-web:
? Choose the git resource to use for web-application-repo: web-application-repo (https://github.com/nodeshift-starters/react-pipeline-example)
? Choose the image resource to use for built-web-application-image: built-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-
application:latest)
? Choose the image resource to use for runtime-web-application-image: runtime-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtim
e-web-application:latest)
Pipelinerun started: build-and-deploy-react-run-4xwsr
Ahora verifiquemos el estado del pipeline con el siguiente comando:
$ tkn pipeline logs -f
Una vez que el pipeline se inicie y la aplicación esté desplegada, solicitaremos la ruta publicada con el siguiente comando:
$ oc get route react-pipeline-example --template='http://{{.spec.host}}'
Para una mejor visualización, podemos ver nuestro pipeline en el modo Desarrollador de la consola web en la sección Pipelines., como se muestra en la Fig. 1.

Fig.1. Visión general de los pipelines en ejecución.
Hacer clic en el pipeline en ejecución muestra información adicional, como se muestra en la Fig.2.

Fig. 2. Información adicional sobre el pipeline.
Después de la información adicional, se pueden ver las aplicaciones en ejecución en la vista Topología, como se muestra en la Fig.3.

Fig 3. Pod en ejecución.
Hacer clic en el círculo en la esquina superior derecha del ícono abre nuestra aplicación, como se muestra en la Fig.4.

Fig. 4. Aplicación React en ejecución.
Conclusión
Así que hemos mostrado cómo iniciar un servidor de desarrollo en OpenShift para su aplicación y sincronizarlo con el sistema de archivos local. También hemos explorado cómo simular una plantilla de construcción encadenada utilizando OpenShift Pipelines. Todo el código de los ejemplos de este artículo se puede encontrar .
Recursos adicionales (EN)
- Libro electrónico gratuito
- Otros artículos sobre en el sitio de Red Hat
Anuncios de próximos seminarios web
Iniciamos una serie de seminarios web los viernes sobre la experiencia nativa de uso de Red Hat OpenShift Container Platform y Kubernetes:
Fuente: habr.com
