¡Hola a todos! Este es el segundo post de nuestra serie, donde mostramos cómo desplegar aplicaciones web modernas en Red Hat OpenShift.

En el post anterior, tocamos ligeramente las capacidades de la nueva imagen base S2I (source-to-image), diseñada para compilar y desplegar aplicaciones web modernas en la plataforma OpenShift. En aquel momento, nos interesaba el tema del despliegue rápido de aplicaciones; hoy veremos cómo utilizar la imagen S2I como una imagen base «limpia» y combinarla con las compilaciones relacionadas de OpenShift.
Imagen base limpia
Como mencionamos en la primera parte, la mayoría de las aplicaciones web modernas tiene lo que se llama una etapa de construcción, donde generalmente se realizan operaciones como la transpilación de código, la concatenación de varios archivos y la minificación. Los archivos resultantes de estas operaciones – que son HTML estático, JavaScript y CSS – se colocan en la carpeta de output. La ubicación de esta carpeta generalmente depende de las herramientas de construcción que se utilicen, y para React, sería la carpeta ./build (volveremos a este asunto más adelante).
Source-to-Image (S2I)
En este post, no tocamos en absoluto el tema de «qué es S2I y cómo usarlo» (se puede leer más sobre esto ), pero es importante tener en claro las dos etapas de este proceso para entender qué hace la imagen Web App Builder.
Etapa de ensamblaje (assemble phase)
La etapa de ensamblaje es muy similar a lo que ocurre cuando ejecutas docker build y obtienes una nueva imagen Docker. Por lo tanto, esta etapa se activa al iniciar la compilación en la plataforma OpenShift.
En el caso de la imagen Web App Builder, la instalación de las dependencias de tu aplicación y la ejecución de la construcción son gestionadas por . Por defecto, la imagen base utiliza la construcción npm run build, pero se puede sobreescribir a través de la variable de entorno NPM_BUILD.
Como mencionamos anteriormente, la ubicación de la aplicación terminada y ya compilada depende de qué herramientas se utilicen. Por ejemplo, en el caso de React, será la carpeta ./build, y para las aplicaciones de Angular, será la carpeta project_name/dist. Y, como ya se mostró en la publicación anterior, la ubicación del catálogo de salida, que por defecto se establece como build, se puede redefinir a través de la variable de entorno OUTPUT_DIR. Y dado que la ubicación de la carpeta de salida difiere de un marco a otro, simplemente copias la salida generada en la carpeta estándar de la imagen, es decir, en /opt/apt-root/output. Esto es importante para entender la siguiente parte de este artículo; por ahora, revisemos rápidamente la siguiente etapa: la fase de ejecución (run phase).
Fase de ejecución (run phase)
Esta etapa ocurre cuando se llama a docker run para una nueva imagen, creada en la etapa de ensamblaje. También sucede durante el despliegue en la plataforma OpenShift. Por defecto utiliza para servir contenido estático que se encuentra en el catálogo de salida estándar mencionado anteriormente.
Este método es bueno para desplegar rápidamente aplicaciones, pero en realidad no se recomienda servir contenido estático de esta manera. Como realmente solo estamos sirviendo contenido estático, el Node.js instalado dentro de nuestra imagen no es necesario; un servidor web es suficiente.
En otras palabras, necesitamos una cosa al construir y otra al ejecutar. En esta situación, las construcciones encadenadas (chained builds) serán útiles.
Construcciones encadenadas (chained builds)
Esto es lo que dicen sobre en la documentación de OpenShift:
«Se pueden vincular dos construcciones entre sí, donde una genera una entidad compilada y la otra coloca esta entidad en una imagen separada, que se utiliza para ejecutar esta entidad».
En otras palabras, podemos utilizar la imagen Web App Builder para ejecutar nuestra construcción y luego usar la imagen del servidor web, el mismo NGINX, para servir nuestro contenido.
De este modo, podemos usar la imagen Web App Builder como un constructor ‘limpio’ y tener una imagen de runtime pequeña.
Ahora vamos a desglosarlo con un ejemplo concreto.
Para practicar, utilizaremos , creada con la herramienta de línea de comandos create-react-app.
Ensamblar todo nos ayudará .
Analicemos este archivo en detalle, comenzando con la sección de parámetros.
parameters:
- name: SOURCE_REPOSITORY_URL
description: La URL de origen para la aplicación
displayName: URL de origen
required: true
- name: SOURCE_REPOSITORY_REF
description: El nombre de la rama para la aplicación
displayName: Rama de origen
value: master
required: true
- name: SOURCE_REPOSITORY_DIR
description: La ubicación dentro del repositorio de origen de la aplicación
displayName: Directorio de origen
value: .
required: true
- name: OUTPUT_DIR
description: La ubicación de los archivos estáticos compilados desde el constructor de sus aplicaciones web
displayName: Directorio de salida
value: build
required: false
Aquí todo es bastante claro, pero vale la pena prestar atención al parámetro OUTPUT_DIR. Para la aplicación React de nuestro ejemplo no hay de qué preocuparse, ya que React utiliza como carpeta de salida el valor por defecto, pero en el caso de Angular o cualquier otra cosa, este parámetro deberá cambiarse adecuadamente.
Ahora echemos un vistazo a la sección de ImageStreams.
- apiVersion: v1
kind: ImageStream
metadata:
name: react-web-app-builder // 1
spec: {}
- apiVersion: v1
kind: ImageStream
metadata:
name: react-web-app-runtime // 2
spec: {}
- apiVersion: v1
kind: ImageStream
metadata:
name: web-app-builder-runtime // 3
spec:
tags:
- name: latest
from:
kind: DockerImage
name: nodeshift/ubi8-s2i-web-app:10.x
- apiVersion: v1
kind: ImageStream
metadata:
name: nginx-image-runtime // 4
spec:
tags:
- name: latest
from:
kind: DockerImage
name: 'centos/nginx-112-centos7:latest'
Mire las tercera y cuarta imágenes. Ambas están definidas como imágenes de Docker, y aquí es claramente visible de dónde provienen.
La tercera imagen es web-app-builder y proviene de nodeshift/ubi8-s2i-web-app con la etiqueta 10.x en .
La cuarta es la imagen NGINX (versión 1.12) con la etiqueta latest en .
Ahora miremos las dos primeras imágenes. Ambas están vacías al inicio y se crean solo en la fase de compilación. La primera imagen, react-web-app-builder, será el resultado de la fase de ensamblaje, que unirá la imagen web-app-builder-runtime y nuestro código fuente. Por eso incluimos en el nombre de esta imagen «-builder».
La segunda imagen, react-web-app-runtime, será el resultado de la unión de nginx-image-runtime y algunos archivos de la imagen react-web-app-builder. Esta imagen también se utilizará durante el despliegue y contendrá solo el servidor web y el HTML estático, JavaScript, CSS de nuestra aplicación.
¿Confuso? Ahora miremos las configuraciones de construcción y será un poco más claro.
En nuestra plantilla hay dos configuraciones de construcción. Esta es la primera de ellas, y es bastante estándar:
apiVersion: v1
kind: BuildConfig
metadata:
name: react-web-app-builder
spec:
output:
to:
kind: ImageStreamTag
name: react-web-app-builder:latest ── 1
source: ── 2
git:
uri: ${SOURCE_REPOSITORY_URL}
ref: ${SOURCE_REPOSITORY_REF}
contextDir: ${SOURCE_REPOSITORY_DIR}
type: Git
strategy:
sourceStrategy:
env:
- name: OUTPUT_DIR ── 3
value: ${OUTPUT_DIR}
from:
kind: ImageStreamTag
name: web-app-builder-runtime:latest ── 4
incremental: true ── 5
type: Source
triggers: ── 6
- github:
secret: ${GITHUB_WEBHOOK_SECRET}
type: GitHub
- type: ConfigChange
- imageChange: {}
type: ImageChange
Como podemos ver, la línea con la etiqueta 1 indica que el resultado de esta construcción se colocará en la imagen react-web-app-builder que vimos anteriormente en la sección de ImageStreams.
La línea con la etiqueta 2 indica de dónde se debe obtener el código. En nuestro caso, se trata de un repositorio git, y la ubicación, ref y carpetas de contexto están definidas por parámetros que ya hemos visto arriba.
La línea con la etiqueta 3 es algo que ya hemos visto en la sección de parámetros. Añade la variable de entorno OUTPUT_DIR, que en nuestro ejemplo es igual a build.
La línea con la etiqueta 4 indica que se debe usar la imagen web-app-builder-runtime, que ya vimos en la sección de ImageStreams.
La línea con la etiqueta 5 indica que queremos utilizar una construcción incremental, si la imagen S2I lo admite, y la imagen Web App Builder sí lo admite. En el primer lanzamiento, después de que finalice la fase de ensamblaje, la imagen guardará la carpeta node_modules en un archivo comprimido. Luego, en lanzamientos posteriores, la imagen simplemente descomprimirá esta carpeta para reducir la duración de la construcción.
Y, por último, la línea con la etiqueta 6 son solo algunos desencadenadores, para que la construcción se inicie automáticamente sin intervención manual, cuando algo cambia.
En general, esta es una configuración de construcción bastante estándar.
Ahora echemos un vistazo a la segunda configuración de construcción. Es muy parecida a la primera, pero hay una diferencia importante.
apiVersion: v1
kind: BuildConfig
metadata:
name: react-web-app-runtime
spec:
output:
to:
kind: ImageStreamTag
name: react-web-app-runtime:latest ── 1
source: ── 2
type: Image
images:
- from:
kind: ImageStreamTag
name: react-web-app-builder:latest ── 3
paths:
- sourcePath: /opt/app-root/output/. ── 4
destinationDir: . ── 5
strategy: ── 6
sourceStrategy:
from:
kind: ImageStreamTag
name: nginx-image-runtime:latest
incremental: true
type: Source
triggers:
- github:
secret: ${GITHUB_WEBHOOK_SECRET}
type: GitHub
- type: ConfigChange
- type: ImageChange
imageChange: {}
- type: ImageChange
imageChange:
from:
kind: ImageStreamTag
name: react-web-app-builder:latest ── 7
Entonces, la segunda configuración de ensamblaje es react-web-app-runtime, y comienza de manera bastante estándar.
En la línea con la etiqueta 1 no hay nada nuevo: simplemente indica que el resultado del ensamblaje se coloca en la imagen react-web-app-runtime.
La línea con la etiqueta 2, al igual que en la configuración anterior, indica de dónde obtener el código fuente. Pero tenga en cuenta que aquí decimos que se obtiene de la imagen. Y de la imagen que acabamos de crear: de react-web-app-builder (indicado en la línea con la etiqueta 3). Los archivos que queremos usar están dentro de la imagen y su ubicación allí se especifica en la línea con la etiqueta 4, en nuestro caso es /opt/app-root/output/. Si recuerdas, es precisamente allí donde se almacenan los archivos generados como resultado de la construcción de nuestra aplicación.
La carpeta de destino, establecida en la línea con la etiqueta 5, es simplemente el directorio actual (todo esto, recordemos, está funcionando dentro de una cosa mágica llamada OpenShift, no en su computadora local).
La sección strategy - línea con la etiqueta 6 - también es similar a la primera configuración de ensamblaje. Solo que esta vez vamos a usar nginx-image-runtime, que ya hemos visto en la sección ImageStream.
Finalmente, la línea con la etiqueta 7 es la sección de desencadenadores que activa este ensamblaje cada vez que se cambia la imagen react-web-app-builder.
Por lo demás, esta plantilla contiene una configuración de implementación bastante estándar, así como elementos relacionados con servicios y rutas, pero no profundizaremos en eso. Tenga en cuenta que la imagen que se desplegará es la imagen react-web-app-runtime.
Despliegue de la aplicación
Entonces, después de revisar la plantilla, veamos cómo utilizarla para desplegar la aplicación.
Podemos usar la herramienta cliente de OpenShift llamada oc para desplegar nuestra plantilla:
$ find . | grep openshiftio | grep application | xargs -n 1 oc apply -f
$ oc new-app --template react-web-app -p SOURCE_REPOSITORY_URL=https://github.com/lholmquist/react-web-app
El primer comando en la pantalla anterior es una manera deliberadamente técnica de encontrar la plantilla ./openshiftio/application.yaml.
El segundo comando simplemente crea una nueva aplicación basada en esta plantilla.
Después de que estos comandos se ejecuten, veremos que tenemos dos ensamblajes:

Y al volver a la pantalla de Overview, veremos el pod en ejecución:

Haciendo clic en el enlace, accederemos a nuestra aplicación, que es la página de la aplicación React App por defecto:

Complemento 1
Para los aficionados a Angular, también tenemos .
El patrón aquí es el mismo, excepto por la variable OUTPUT_DIR.
Complemento 2
En este artículo utilizamos NGINX como servidor web, pero se puede reemplazar fácilmente por Apache, simplemente cambiando en el archivo del patrón en .
Conclusión
En la primera parte de esta serie mostramos cómo desplegar rápidamente aplicaciones web modernas en la plataforma OpenShift. Hoy examinamos lo que hace una imagen de Web App y cómo se puede combinar con un servidor web limpio como NGINX mediante builds encadenados para organizar una construcción más adecuada para entornos de producción. En el siguiente y último artículo de esta serie, mostraremos cómo ejecutar un servidor de desarrollo para su aplicación en OpenShift y sincronizar archivos locales y remotos.
Contenido de esta serie de artículos
- Parte 1: ;
- Parte 2: cómo utilizar una nueva imagen S2I junto con una imagen de servidor HTTP existente, como NGINX, utilizando builds encadenados de OpenShift para un despliegue de producción;
- Parte 3: cómo ejecutar un servidor de desarrollo para su aplicación en la plataforma OpenShift y sincronizarlo con el sistema de archivos local.
Recursos adicionales
- Libro electrónico gratuito .
- Información sobre .
Fuente: habr.com
