Aplicaciones modernas de OpenShift, parte 3: OpenShift como entorno de desarrollo y canalizaciones de OpenShift

¡Hola a todos en este blog! Esta es la tercera publicación de una serie en la que le mostramos cómo implementar aplicaciones web modernas en Red Hat OpenShift.







En las dos publicaciones anteriores, cubrimos cómo implementar aplicaciones web modernas en solo unos pocos pasos, y cómo usar una nueva imagen S2I junto con una imagen de servidor HTTP lista para usar, como NGINX, usando compilaciones encadenadas para implementación de producción.



Hoy le 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é es OpenShift Pipelines y cómo puede usarlo como alternativa a los ensamblados vinculados.



OpenShift como entorno de desarrollo



Flujo de trabajo de desarrollo



Como se discutió en la primera publicación , un flujo de trabajo de desarrollo típico para aplicaciones web modernas es simplemente un "servidor de desarrollo" que monitorea los cambios en los archivos locales. Cuando suceden, se inicia la compilación de la aplicación y luego se actualiza en el navegador.



En la mayoría de los marcos modernos, este "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. Tome la aplicación React de artículos anteriores como ejemplo , aunque muchos de los mismos conceptos de flujo de trabajo se aplican a todos los demás marcos modernos.

Entonces, para iniciar el "servidor de desarrollo" en nuestro ejemplo de React, emitimos el siguiente comando:



$ npm run start


Luego, en la ventana del terminal veremos algo como lo siguiente:







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







Ahora, si hacemos cambios en el archivo, entonces la aplicación debería actualizarse en el navegador.



Bien, con el desarrollo local todo está claro, pero ¿cómo lograr lo mismo en OpenShift?



Servidor de desarrollo OpenShift



Si recuerdas, en el post anterior analizamos la llamada fase de ejecución de la imagen S2I y vimos que por defecto el módulo de servicio se encarga de dar servicio a nuestra aplicación web.



Sin embargo, si observa más de cerca el script de ejecución de ese ejemplo, verá que contiene la variable de entorno $ NPM_RUN, que le permite ejecutar su propio comando.



Por ejemplo, podemos usar el módulo nodeshift para implementar nuestra aplicación:



$ npx nodeshift --deploy.env NPM_RUN="yarn start" --dockerImage=nodeshift/ubi8-s2i-web-app


Nota: El ejemplo anterior se abrevia para ilustrar la idea general.



Aquí hemos agregado la variable de entorno NPM_RUN a nuestra implementación, que le dice al tiempo de ejecución que ejecute el comando yarn start, que inicia el servidor de desarrollo React dentro de nuestro pod OpenShift.



Si observa el registro de un pod en ejecución, habrá algo como lo siguiente:







Por supuesto, todo esto no se tratará de nada hasta que podamos sincronizar el código local con el código que también se supervisa para detectar cambios, pero vive en un servidor remoto.



Sincronización de código local y remoto



Afortunadamente, nodeshift puede ayudar fácilmente con la sincronización, y puede usar el comando de reloj para rastrear los cambios.



Entonces, después de haber ejecutado el comando para implementar el servidor de desarrollo para nuestra aplicación, podemos usar de manera segura el siguiente comando:



$ npx nodeshift watch


Como resultado, se establecerá una conexión con el 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 serán monitoreados para detectar cambios.



Por lo tanto, si ahora actualizamos el archivo src / App.js, el sistema reaccionará a estos cambios, los copiará en el clúster remoto e iniciará el servidor de desarrollo, que luego actualizará nuestra aplicación en el navegador.



Para completar, mostremos cómo se ven 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 además del comando oc rsync. Puede obtener más información sobre cómo funciona aquí .



Este fue un ejemplo para React, pero se puede usar exactamente el mismo método con otros marcos, solo configure la variable de entorno NPM_RUN según sea necesario.



Tuberías de Openshift









A continuación, hablaremos sobre una herramienta como OpenShift Pipelines y cómo se puede utilizar como alternativa a las compilaciones encadenadas.



¿Qué es OpenShift Pipelines?



OpenShift Pipelines es un sistema de entrega e integración continua de CI / CD basado en la nube para organizar tuberías utilizando Tekton. Tekton es un marco de CI / CD nativo de Kubernetes, de código abierto y flexible que automatiza las implementaciones en todas las plataformas (Kubernetes, sin servidor, máquinas virtuales, etc.) al abstraerse de la capa subyacente.



Se requiere cierto conocimiento de Pipelines para comprender este artículo, por lo que le recomendamos encarecidamente que primero lea el tutorial oficial .



Configurar el entorno de trabajo



Para jugar con los ejemplos de este artículo, primero debe preparar su entorno de producción:



  1. OpenShift 4. CodeReady Containers (CRD), .
  2. , , Pipeline Operator. , , .
  3. Tekton CLI (tkn) .
  4. create-react-app, , ( React).
  5. () , npm install npm start.


El repositorio de aplicaciones también tendrá una carpeta k8s, donde se ubicarán los YAML de Kubernetes / OpenShift utilizados para implementar la aplicación. Habrá Tareas, ClusterTasks, Recursos y Pipelines que crearemos en este repositorio .



Empecemos



El primer paso para nuestro ejemplo es crear un nuevo proyecto en el clúster de OpenShift. Llamemos a este proyecto webapp-pipeline y creémoslo con el siguiente comando:



$ oc new-project webapp-pipeline


Además, este nombre del proyecto aparecerá en el código, por lo que si decide ponerle otro nombre, no olvide editar el código de los ejemplos en consecuencia. A partir de este punto, no iremos de arriba hacia abajo, sino de abajo hacia arriba: es decir, primero crearemos todos los componentes del transportador, y solo entonces él mismo.



Entonces, primero que nada ...



Tareas



Creemos un par de tareas que luego nos ayudarán a implementar la aplicación a través de nuestra canalización. La primera tarea, apply_manifests_task, se encarga de aplicar YAML a esos recursos de Kubernetes (servicio, implementación y ruta) que se encuentran en la carpeta k8s de nuestra aplicación. La segunda tarea, update_deployment_task, es responsable de actualizar una imagen ya implementada a la creada por nuestra canalización.



No se preocupe si aún no está claro. De hecho, estas tareas son algo así como utilidades, y las discutiremos con más detalle más adelante. Por ahora, vamos a crearlos:



$ 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, usando el comando tkn CLI, verifique 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 su proyecto actual.



Tareas de clúster



Las tareas agrupadas son básicamente las mismas que las tareas simples. Es decir, es una colección reutilizable de pasos que se combinan de una forma u otra al iniciar una tarea específica. La diferencia es que la tarea del clúster está disponible en todas partes dentro del clúster. Para ver una lista de tareas de clúster que se crean automáticamente cuando se agrega el operador de canalización, use nuevamente 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 creemos dos tareas de clúster. El primero generará una imagen S2I y la enviará al registro interno de OpenShift; el segundo es construir nuestra imagen basada en NGINX usando la aplicación que ya hemos ensamblado como contenido.



Crea y envía la imagen



Al crear la primera tarea, repetiremos lo que ya hicimos en el artículo anterior sobre ensamblados vinculados. Recuerde que usamos la imagen S2I (ubi8-s2i-web-app) para "construir" nuestra aplicación y terminamos con la imagen almacenada en el registro interno de OpenShift. Ahora usaremos esta imagen S2I de la aplicación web para crear un DockerFile para nuestra aplicación, y luego usaremos Buildah para hacer la compilación real y enviar la imagen resultante al registro interno de OpenShift, ya que esto es exactamente lo que hace OpenShift cuando implementa el suyo. aplicaciones que utilizan NodeShift.



¿Cómo supimos todo esto, preguntas? De la versión oficial de Node.js oficial , simplemente lo copiamos y lo terminamos por nosotros mismos.



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 entraremos en detalles sobre esto, sino que nos detendremos en el parámetro OUTPUT_DIR:



params:
      - name: OUTPUT_DIR
        description: The location of the build output directory
        default: build


De forma predeterminada, este parámetro es igual a build, que es donde React coloca el contenido recopilado. Otros marcos usan diferentes rutas, por ejemplo, Ember usa dist. El resultado de nuestra primera tarea de clúster será una imagen que contiene el HTML, JavaScript y CSS que hemos recopilado.



Construyendo una imagen basada en NGINX



En cuanto a nuestra segunda tarea de clúster, debería recopilar una imagen basada en NGINX para nosotros utilizando el contenido de la aplicación que ya hemos recopilado. Básicamente, esta es la parte de la sección anterior en la que analizamos las compilaciones encadenadas.



Para hacer esto, nosotros, de la misma manera que un poco antes, creamos una 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 observa el código de estas tareas de clúster, puede ver que el repositorio de Git con el que estamos trabajando o los nombres de las imágenes que creamos no están especificados allí. Solo especificamos qué es exactamente lo que transferimos a Git, o una determinada imagen, donde debe mostrarse la imagen final. Es por eso que estas tareas de clúster se pueden reutilizar cuando se trabaja con otras aplicaciones.



Y aquí pasamos con gracia al siguiente punto ...



Recursos



Entonces, dado que, como acabamos de decir, las tareas de clúster deben generalizarse lo más posible, necesitamos crear recursos que se usarán en la entrada (repositorio Git) y la salida (imágenes finales). El primer recurso que necesitamos es Git, donde reside nuestra aplicación, algo 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 es de tipo git. La clave de URL en la sección params apunta a un repositorio específico y establece la rama maestra (esto es opcional, pero lo escribimos para completar).



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í, el PipelineResource es de tipo image, y el valor del parámetro url apunta al registro interno de imágenes de OpenShift, específicamente al del espacio de nombres webapp-pipeline. Recuerde cambiar este parámetro si está utilizando un espacio de nombres diferente.



Y finalmente, el último recurso que necesitaremos también será del tipo imagen y esta será la imagen final de NGINX, que luego se utilizará durante 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


Nuevamente, observe que este recurso almacena la imagen en el registro interno de OpenShift en el espacio de nombres webapp-pipeline.



Para crear todos estos recursos a la vez, use el comando create:



$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/resources/resource.yaml


Puede asegurarse de que los recursos se hayan creado así:



$ tkn resource ls


Pipeline pipeline



Ahora que tenemos todos los componentes necesarios, ensamblaremos un pipeline a partir de ellos, 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, echemos un vistazo a estos componentes. El primero es el nombre:



apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: build-and-deploy-react


Luego, en la sección de especificaciones, vemos una indicació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 tareas para que las complete nuestra canalización. En primer lugar, 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 parámetros de entrada (recurso gir) y salida (recurso de imagen de aplicación web integrado). También le pasamos un parámetro especial para que no verifique TLS ya que estamos usando certificados autofirmados:



resources:
        inputs:
          - name: source
            resource: web-application-repo
        outputs:
          - name: image
            resource: built-web-application-image
      params:
        - name: TLSVERIFY
          value: "false"


La siguiente tarea es casi la misma, solo que aquí se llama la tarea de clúster webapp-build-runtime ya creada:



name: build-runtime-image
    taskRef:
      name: webapp-build-runtime
      kind: ClusterTask


Al igual que con la tarea anterior, estamos pasando el recurso, pero ahora es una imagen de aplicación web integrada (el resultado de nuestra tarea anterior). Y como salida, volvemos a configurar la imagen. Dado que esta tarea debe realizarse después de la anterior, agregamos el campo runAfter:



resources:
        inputs:
          - name: image
            resource: built-web-application-image
        outputs:
          - name: image
            resource: runtime-web-application-image
        params:
        - name: TLSVERIFY
          value: "false"
      runAfter:
        - build-web-application


Las siguientes dos tareas son las encargadas de aplicar el servicio, ruta y despliegue de archivos YAML que viven en el directorio k8s de nuestra aplicación web, y también de actualizar este despliegue al crear nuevas imágenes. Establecemos estas dos tareas de clúster al principio del artículo.



Ejecutando el transportador



Entonces, se crean todas las partes de nuestra canalización y la comenzaremos con el siguiente comando:



$ tkn pipeline start build-and-deploy-react


En esta etapa, la línea de comando se usa de forma interactiva y debe seleccionar los recursos apropiados en respuesta a cada una de sus solicitudes: para el recurso git, seleccione web-application-repo, luego para el primer recurso de imagen: built-web-application-image y, finalmente, para segundo recurso de imagen –runtime-web-application-image:



? 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 de la canalización con el siguiente comando:



$ tkn pipeline logs -f


Una vez que se inicia la canalización y se implementa la aplicación, solicitamos la ruta publicada con el siguiente comando:



$ oc get route react-pipeline-example --template='http://{{.spec.host}}'


Para obtener más visibilidad, puede ver nuestra canalización en el modo Desarrollador de la consola web en la sección Pipelines , como se muestra en la Fig. 1.







Figura 1. Descripción general de las canalizaciones en ejecución.



Al hacer clic en una canalización en ejecución, se muestra información adicional, como se muestra en la Figura 2.







Figura: 2. Más información sobre la tubería.



Después de obtener más información, puede ver las aplicaciones en ejecución en la vista Topología , como se muestra en la Figura 3.







Fig 3. Pod para correr.



Al hacer clic en el círculo en la esquina superior derecha del icono, se abre nuestra aplicación, como se muestra en la Figura 4.







Figura: 4. Lanzamiento de la aplicación React.



Conclusión



Entonces, hemos mostrado cómo ejecutar un servidor de desarrollo para su aplicación en OpenShift y sincronizarlo con el sistema de archivos local. También vimos cómo imitar la plantilla de construcción encadenada usando OpenShift Pipelines. Todos los códigos de muestra de este artículo se pueden encontrar aquí .



Recursos adicionales (EN)







Próximos anuncios de seminarios web



Estamos iniciando una serie de seminarios web los viernes sobre la experiencia nativa de usar Red Hat OpenShift Container Platform y Kubernetes:






All Articles