{"id":90874,"date":"2020-08-07T01:42:20","date_gmt":"2020-08-06T23:42:20","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds"},"modified":"2020-08-07T01:42:20","modified_gmt":"2020-08-06T23:42:20","slug":"sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds","status":"publish","type":"post","link":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds","title":{"rendered":"Aplicaciones modernas en OpenShift, parte 2: compilaciones encadenadas","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00a1Hola a todos! Este es el segundo post de nuestra serie, donde mostramos c\u00f3mo desplegar aplicaciones web modernas en Red Hat OpenShift. <\/p>\n<p><img decoding=\"async\" alt=\"Aplicaciones modernas en OpenShift, parte 2: compilaciones encadenadas\" src=\"\/wp-content\/uploads\/2020\/08\/b1f6ae855a69597c6e86c5198e4a628c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEn el post anterior, tocamos ligeramente las capacidades de la nueva imagen base S2I (source-to-image), dise\u00f1ada para compilar y desplegar aplicaciones web modernas en la plataforma OpenShift. En aquel momento, nos interesaba el tema del despliegue r\u00e1pido de aplicaciones; hoy veremos c\u00f3mo utilizar la imagen S2I como una imagen base \u00ablimpia\u00bb y combinarla con las compilaciones relacionadas de OpenShift.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Imagen base limpia<\/h3>\n<p>\nComo mencionamos en la primera parte, la mayor\u00eda de las aplicaciones web modernas tiene lo que se llama una etapa de construcci\u00f3n, donde generalmente se realizan operaciones como la transpilaci\u00f3n de c\u00f3digo, la concatenaci\u00f3n de varios archivos y la minificaci\u00f3n. Los archivos resultantes de estas operaciones \u2013 que son HTML est\u00e1tico, JavaScript y CSS \u2013 se colocan en la carpeta de output. La ubicaci\u00f3n de esta carpeta generalmente depende de las herramientas de construcci\u00f3n que se utilicen, y para React, ser\u00eda la carpeta .\/build (volveremos a este asunto m\u00e1s adelante).<\/p>\n<h4>Source-to-Image (S2I)<\/h4>\n<p>\nEn este post, no tocamos en absoluto el tema de \u00abqu\u00e9 es S2I y c\u00f3mo usarlo\u00bb (se puede leer m\u00e1s sobre esto <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.okd.io\/latest\/architecture\/core_concepts\/builds_and_image_streams.html#source-build\">aqu\u00ed<\/a><\/noindex>), pero es importante tener en claro las dos etapas de este proceso para entender qu\u00e9 hace la imagen Web App Builder.<\/p>\n<h4>Etapa de ensamblaje (assemble phase)<\/h4>\n<p>\nLa 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\u00f3n en la plataforma OpenShift.<\/p>\n<p>En el caso de la imagen Web App Builder, la instalaci\u00f3n de las dependencias de tu aplicaci\u00f3n y la ejecuci\u00f3n de la construcci\u00f3n son gestionadas por <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/bucharest-gold\/centos7-s2i-web-app\/blob\/master\/s2i\/assemble#L47\">el script de ensamblaje<\/a><\/noindex>. Por defecto, la imagen base utiliza la construcci\u00f3n npm run build, pero se puede sobreescribir a trav\u00e9s de la variable de entorno NPM_BUILD.<\/p>\n<p>Como mencionamos anteriormente, la ubicaci\u00f3n de la aplicaci\u00f3n terminada y ya compilada depende de qu\u00e9 herramientas se utilicen. Por ejemplo, en el caso de React, ser\u00e1 la carpeta .\/build, y para las aplicaciones de Angular, ser\u00e1 la carpeta project_name\/dist. Y, como ya se mostr\u00f3 en la publicaci\u00f3n anterior, la ubicaci\u00f3n del cat\u00e1logo de salida, que por defecto se establece como build, se puede redefinir a trav\u00e9s de la variable de entorno OUTPUT_DIR. Y dado que la ubicaci\u00f3n de la carpeta de salida difiere de un marco a otro, simplemente copias la salida generada en la carpeta est\u00e1ndar de la imagen, es decir, en \/opt\/apt-root\/output. Esto es importante para entender la siguiente parte de este art\u00edculo; por ahora, revisemos r\u00e1pidamente la siguiente etapa: la fase de ejecuci\u00f3n (run phase).<\/p>\n<h4>Fase de ejecuci\u00f3n (run phase)<\/h4>\n<p>\nEsta etapa ocurre cuando se llama a docker run para una nueva imagen, creada en la etapa de ensamblaje. Tambi\u00e9n sucede durante el despliegue en la plataforma OpenShift. Por defecto <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/bucharest-gold\/centos7-s2i-web-app\/blob\/master\/s2i\/run\">run script<\/a><\/noindex> utiliza <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/package\/serve\">serve module<\/a><\/noindex> para servir contenido est\u00e1tico que se encuentra en el cat\u00e1logo de salida est\u00e1ndar mencionado anteriormente.<\/p>\n<p>Este m\u00e9todo es bueno para desplegar r\u00e1pidamente aplicaciones, pero en realidad no se recomienda servir contenido est\u00e1tico de esta manera. Como realmente solo estamos sirviendo contenido est\u00e1tico, el Node.js instalado dentro de nuestra imagen no es necesario; un servidor web es suficiente.<\/p>\n<p>En otras palabras, necesitamos una cosa al construir y otra al ejecutar. En esta situaci\u00f3n, las construcciones encadenadas (chained builds) ser\u00e1n \u00fatiles.<\/p>\n<h3>Construcciones encadenadas (chained builds)<\/h3>\n<p>\nEsto es lo que dicen sobre <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.okd.io\/latest\/dev_guide\/builds\/advanced_build_operations.html#dev-guide-chaining-builds\">chained builds<\/a><\/noindex> en la documentaci\u00f3n de OpenShift:<\/p>\n<blockquote><p>\u00abSe pueden vincular dos construcciones entre s\u00ed, donde una genera una entidad compilada y la otra coloca esta entidad en una imagen separada, que se utiliza para ejecutar esta entidad\u00bb.\n<\/p><\/blockquote>\n<p>\nEn otras palabras, podemos utilizar la imagen Web App Builder para ejecutar nuestra construcci\u00f3n y luego usar la imagen del servidor web, el mismo NGINX, para servir nuestro contenido.<\/p>\n<p>De este modo, podemos usar la imagen Web App Builder como un constructor \u2018limpio\u2019 y tener una imagen de runtime peque\u00f1a.<\/p>\n<p>Ahora vamos a desglosarlo con un ejemplo concreto.<\/p>\n<p>Para practicar, utilizaremos <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/react-web-app\">una simple aplicaci\u00f3n de React<\/a><\/noindex>, creada con la herramienta de l\u00ednea de comandos create-react-app.<\/p>\n<p>Ensamblar todo nos ayudar\u00e1 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/react-web-app\/blob\/master\/.openshiftio\/application.yaml\">el archivo de plantilla de OpenShift<\/a><\/noindex>.<\/p>\n<p>Analicemos este archivo en detalle, comenzando con la secci\u00f3n de par\u00e1metros.<\/p>\n<pre><code class=\"plaintext\">parameters:\n  - name: SOURCE_REPOSITORY_URL\n    description: La URL de origen para la aplicaci\u00f3n\n    displayName: URL de origen\n    required: true\n  - name: SOURCE_REPOSITORY_REF\n    description: El nombre de la rama para la aplicaci\u00f3n\n    displayName: Rama de origen\n    value: master\n    required: true\n  - name: SOURCE_REPOSITORY_DIR\n    description: La ubicaci\u00f3n dentro del repositorio de origen de la aplicaci\u00f3n\n    displayName: Directorio de origen\n    value: .\n    required: true\n  - name: OUTPUT_DIR\n    description: La ubicaci\u00f3n de los archivos est\u00e1ticos compilados desde el constructor de sus aplicaciones web\n    displayName: Directorio de salida\n    value: build\n    required: false\n<\/code><\/pre>\n<p>\nAqu\u00ed todo es bastante claro, pero vale la pena prestar atenci\u00f3n al par\u00e1metro OUTPUT_DIR. Para la aplicaci\u00f3n React de nuestro ejemplo no hay de qu\u00e9 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\u00e1metro deber\u00e1 cambiarse adecuadamente.<\/p>\n<p>Ahora echemos un vistazo a la secci\u00f3n de ImageStreams.<\/p>\n<pre><code class=\"plaintext\">- apiVersion: v1\n  kind: ImageStream\n  metadata:\n    name: react-web-app-builder  \/\/ 1 \n  spec: {}\n- apiVersion: v1\n  kind: ImageStream\n  metadata:\n    name: react-web-app-runtime  \/\/ 2 \n  spec: {}\n- apiVersion: v1\n  kind: ImageStream\n  metadata:\n    name: web-app-builder-runtime \/\/ 3\n  spec:\n    tags:\n    - name: latest\n      from:\n        kind: DockerImage\n        name: nodeshift\/ubi8-s2i-web-app:10.x\n- apiVersion: v1\n  kind: ImageStream\n  metadata:\n    name: nginx-image-runtime \/\/ 4\n  spec:\n    tags:\n    - name: latest\n      from:\n        kind: DockerImage\n        name: 'centos\/nginx-112-centos7:latest'\n<\/code><\/pre>\n<p>\nMire las tercera y cuarta im\u00e1genes. Ambas est\u00e1n definidas como im\u00e1genes de Docker, y aqu\u00ed es claramente visible de d\u00f3nde provienen.<\/p>\n<p>La tercera imagen es web-app-builder y proviene de nodeshift\/ubi8-s2i-web-app con la etiqueta 10.x en <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/nodeshift\/ubi8-s2i-web-app\/\">Docker hub<\/a><\/noindex>.<\/p>\n<p>La cuarta es la imagen NGINX (versi\u00f3n 1.12) con la etiqueta latest en <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/centos\/nginx-112-centos7\/\">Docker hub<\/a><\/noindex>.<\/p>\n<p>Ahora miremos las dos primeras im\u00e1genes. Ambas est\u00e1n vac\u00edas al inicio y se crean solo en la fase de compilaci\u00f3n. La primera imagen, react-web-app-builder, ser\u00e1 el resultado de la fase de ensamblaje, que unir\u00e1 la imagen web-app-builder-runtime y nuestro c\u00f3digo fuente. Por eso incluimos en el nombre de esta imagen \u00ab-builder\u00bb.<\/p>\n<p>La segunda imagen, react-web-app-runtime, ser\u00e1 el resultado de la uni\u00f3n de nginx-image-runtime y algunos archivos de la imagen react-web-app-builder. Esta imagen tambi\u00e9n se utilizar\u00e1 durante el despliegue y contendr\u00e1 solo el servidor web y el HTML est\u00e1tico, JavaScript, CSS de nuestra aplicaci\u00f3n.<\/p>\n<p>\u00bfConfuso? Ahora miremos las configuraciones de construcci\u00f3n y ser\u00e1 un poco m\u00e1s claro.<\/p>\n<p>En nuestra plantilla hay dos configuraciones de construcci\u00f3n. Esta es la primera de ellas, y es bastante est\u00e1ndar:<\/p>\n<pre><code class=\"plaintext\">  apiVersion: v1\n  kind: BuildConfig\n  metadata:\n    name: react-web-app-builder\n  spec:\n    output:\n      to:\n        kind: ImageStreamTag\n        name: react-web-app-builder:latest \u2500\u2500 1\n    source:   \u2500\u2500 2 \n      git:\n        uri: ${SOURCE_REPOSITORY_URL}\n        ref: ${SOURCE_REPOSITORY_REF}\n      contextDir: ${SOURCE_REPOSITORY_DIR}\n      type: Git\n    strategy:\n      sourceStrategy:\n        env:\n          - name: OUTPUT_DIR \u2500\u2500 3 \n            value: ${OUTPUT_DIR}\n        from:\n          kind: ImageStreamTag\n          name: web-app-builder-runtime:latest \u2500\u2500 4\n        incremental: true \u2500\u2500 5\n      type: Source\n    triggers: \u2500\u2500 6\n    - github:\n        secret: ${GITHUB_WEBHOOK_SECRET}\n      type: GitHub\n    - type: ConfigChange\n    - imageChange: {}\n      type: ImageChange\n<\/code><\/pre>\n<p>\nComo podemos ver, la l\u00ednea con la etiqueta 1 indica que el resultado de esta construcci\u00f3n se colocar\u00e1 en la imagen react-web-app-builder que vimos anteriormente en la secci\u00f3n de ImageStreams.<\/p>\n<p>La l\u00ednea con la etiqueta 2 indica de d\u00f3nde se debe obtener el c\u00f3digo. En nuestro caso, se trata de un repositorio git, y la ubicaci\u00f3n, ref y carpetas de contexto est\u00e1n definidas por par\u00e1metros que ya hemos visto arriba.<\/p>\n<p>La l\u00ednea con la etiqueta 3 es algo que ya hemos visto en la secci\u00f3n de par\u00e1metros. A\u00f1ade la variable de entorno OUTPUT_DIR, que en nuestro ejemplo es igual a build.<br \/>\nLa l\u00ednea con la etiqueta 4 indica que se debe usar la imagen web-app-builder-runtime, que ya vimos en la secci\u00f3n de ImageStreams.<\/p>\n<p>La l\u00ednea con la etiqueta 5 indica que queremos utilizar una construcci\u00f3n incremental, si la imagen S2I lo admite, y la imagen Web App Builder s\u00ed lo admite. En el primer lanzamiento, despu\u00e9s de que finalice la fase de ensamblaje, la imagen guardar\u00e1 la carpeta node_modules en un archivo comprimido. Luego, en lanzamientos posteriores, la imagen simplemente descomprimir\u00e1 esta carpeta para reducir la duraci\u00f3n de la construcci\u00f3n.<\/p>\n<p>Y, por \u00faltimo, la l\u00ednea con la etiqueta 6 son solo algunos desencadenadores, para que la construcci\u00f3n se inicie autom\u00e1ticamente sin intervenci\u00f3n manual, cuando algo cambia.<\/p>\n<p>En general, esta es una configuraci\u00f3n de construcci\u00f3n bastante est\u00e1ndar.<\/p>\n<p>Ahora echemos un vistazo a la segunda configuraci\u00f3n de construcci\u00f3n. Es muy parecida a la primera, pero hay una diferencia importante.<\/p>\n<pre><code class=\"plaintext\">apiVersion: v1\n  kind: BuildConfig\n  metadata:\n    name: react-web-app-runtime\n  spec:\n    output:\n      to:\n        kind: ImageStreamTag\n        name: react-web-app-runtime:latest \u2500\u2500 1\n    source: \u2500\u2500 2\n      type: Image\n      images:                              \n        - from:\n            kind: ImageStreamTag\n            name: react-web-app-builder:latest \u2500\u2500 3\n          paths:\n            - sourcePath: \/opt\/app-root\/output\/.  \u2500\u2500 4\n              destinationDir: .  \u2500\u2500 5\n             \n    strategy: \u2500\u2500 6\n      sourceStrategy:\n        from:\n          kind: ImageStreamTag\n          name: nginx-image-runtime:latest\n        incremental: true\n      type: Source\n    triggers:\n    - github:\n        secret: ${GITHUB_WEBHOOK_SECRET}\n      type: GitHub\n    - type: ConfigChange\n    - type: ImageChange\n      imageChange: {}\n    - type: ImageChange\n      imageChange:\n        from:\n          kind: ImageStreamTag\n          name: react-web-app-builder:latest \u2500\u2500 7\n<\/code><\/pre>\n<p>\nEntonces, la segunda configuraci\u00f3n de ensamblaje es react-web-app-runtime, y comienza de manera bastante est\u00e1ndar.<\/p>\n<p>En la l\u00ednea con la etiqueta 1 no hay nada nuevo: simplemente indica que el resultado del ensamblaje se coloca en la imagen react-web-app-runtime.<\/p>\n<p>La l\u00ednea con la etiqueta 2, al igual que en la configuraci\u00f3n anterior, indica de d\u00f3nde obtener el c\u00f3digo fuente. Pero tenga en cuenta que aqu\u00ed decimos que se obtiene de la imagen. Y de la imagen que acabamos de crear: de react-web-app-builder (indicado en la l\u00ednea con la etiqueta 3). Los archivos que queremos usar est\u00e1n dentro de la imagen y su ubicaci\u00f3n all\u00ed se especifica en la l\u00ednea con la etiqueta 4, en nuestro caso es \/opt\/app-root\/output\/. Si recuerdas, es precisamente all\u00ed donde se almacenan los archivos generados como resultado de la construcci\u00f3n de nuestra aplicaci\u00f3n.<\/p>\n<p>La carpeta de destino, establecida en la l\u00ednea con la etiqueta 5, es simplemente el directorio actual (todo esto, recordemos, est\u00e1 funcionando dentro de una cosa m\u00e1gica llamada OpenShift, no en su computadora local).<\/p>\n<p>La secci\u00f3n strategy - l\u00ednea con la etiqueta 6 - tambi\u00e9n es similar a la primera configuraci\u00f3n de ensamblaje. Solo que esta vez vamos a usar nginx-image-runtime, que ya hemos visto en la secci\u00f3n ImageStream.<\/p>\n<p>Finalmente, la l\u00ednea con la etiqueta 7 es la secci\u00f3n de desencadenadores que activa este ensamblaje cada vez que se cambia la imagen react-web-app-builder.<\/p>\n<p>Por lo dem\u00e1s, esta plantilla contiene una configuraci\u00f3n de implementaci\u00f3n bastante est\u00e1ndar, as\u00ed como elementos relacionados con servicios y rutas, pero no profundizaremos en eso. Tenga en cuenta que la imagen que se desplegar\u00e1 es la imagen react-web-app-runtime.<\/p>\n<h3>Despliegue de la aplicaci\u00f3n<\/h3>\n<p>\nEntonces, despu\u00e9s de revisar la plantilla, veamos c\u00f3mo utilizarla para desplegar la aplicaci\u00f3n.<\/p>\n<p>Podemos usar la herramienta cliente de OpenShift llamada oc para desplegar nuestra plantilla:<\/p>\n<pre><code class=\"plaintext\">$ find . | grep openshiftio | grep application | xargs -n 1 oc apply -f\n\n$ oc new-app --template react-web-app -p SOURCE_REPOSITORY_URL=https:\/\/github.com\/lholmquist\/react-web-app\n<\/code><\/pre>\n<p>\nEl primer comando en la pantalla anterior es una manera deliberadamente t\u00e9cnica de encontrar la plantilla .\/openshiftio\/application.yaml.<\/p>\n<p>El segundo comando simplemente crea una nueva aplicaci\u00f3n basada en esta plantilla.<\/p>\n<p>Despu\u00e9s de que estos comandos se ejecuten, veremos que tenemos dos ensamblajes:<\/p>\n<p><img decoding=\"async\" alt=\"Aplicaciones modernas en OpenShift, parte 2: compilaciones encadenadas\" src=\"\/wp-content\/uploads\/2020\/08\/c6b2b2fcadfcd3e5a8a2adb4eff69bf2.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Y al volver a la pantalla de Overview, veremos el pod en ejecuci\u00f3n:<\/p>\n<p><img decoding=\"async\" alt=\"Aplicaciones modernas en OpenShift, parte 2: compilaciones encadenadas\" src=\"\/wp-content\/uploads\/2020\/08\/983fab3029d222555dc13790d4a3e70f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Haciendo clic en el enlace, accederemos a nuestra aplicaci\u00f3n, que es la p\u00e1gina de la aplicaci\u00f3n React App por defecto:<\/p>\n<p><img decoding=\"async\" alt=\"Aplicaciones modernas en OpenShift, parte 2: compilaciones encadenadas\" src=\"\/wp-content\/uploads\/2020\/08\/d5b658875e0e865bf456955aaac15464.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Complemento 1<\/h3>\n<p>\nPara los aficionados a Angular, tambi\u00e9n tenemos <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/angular-web-app\">un ejemplo de aplicaci\u00f3n<\/a><\/noindex>.<\/p>\n<p>El patr\u00f3n aqu\u00ed es el mismo, excepto por la variable OUTPUT_DIR.<\/p>\n<h3>Complemento 2<\/h3>\n<p>\nEn este art\u00edculo utilizamos NGINX como servidor web, pero se puede reemplazar f\u00e1cilmente por Apache, simplemente cambiando en el archivo del patr\u00f3n <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/react-web-app\/blob\/master\/.openshiftio\/application.yaml#L66\">imagen de NGINX<\/a><\/noindex> en <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/centos\/httpd-24-centos7\/\">imagen de Apache<\/a><\/noindex>.<\/p>\n<h3>Conclusi\u00f3n<\/h3>\n<p>\nEn la primera parte de esta serie mostramos c\u00f3mo desplegar r\u00e1pidamente aplicaciones web modernas en la plataforma OpenShift. Hoy examinamos lo que hace una imagen de Web App y c\u00f3mo se puede combinar con un servidor web limpio como NGINX mediante builds encadenados para organizar una construcci\u00f3n m\u00e1s adecuada para entornos de producci\u00f3n. En el siguiente y \u00faltimo art\u00edculo de esta serie, mostraremos c\u00f3mo ejecutar un servidor de desarrollo para su aplicaci\u00f3n en OpenShift y sincronizar archivos locales y remotos.<\/p>\n<h3>Contenido de esta serie de art\u00edculos<\/h3>\n<p><\/p>\n<ul>\n<li>Parte 1: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/redhatrussia\/blog\/511954\/\">c\u00f3mo desplegar aplicaciones web modernas en solo unos pocos pasos<\/a><\/noindex>;<\/li>\n<li>Parte 2: c\u00f3mo 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\u00f3n;<\/li>\n<li>Parte 3: c\u00f3mo ejecutar un servidor de desarrollo para su aplicaci\u00f3n en la plataforma OpenShift y sincronizarlo con el sistema de archivos local.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Recursos adicionales<\/h3>\n<p><\/p>\n<ul>\n<li>Libro electr\u00f3nico gratuito <noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/books\/deploying-openshift\">Desplegando en OpenShift<\/a><\/noindex>.<\/li>\n<li>Informaci\u00f3n sobre <noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/topics\/kubernetes\/\">OpenShift y Kubernetes<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>Fuente: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/redhatrussia\/blog\/513948\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0421 \u0432\u0430\u043c\u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u0441\u0442 \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u0441\u0435\u0440\u0438\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u043a\u0430\u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430 Red Hat OpenShift \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u043f\u043e\u0441\u0442\u0435 \u043c\u044b \u0441\u043b\u0435\u0433\u043a\u0430 \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u043b\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043d\u043e\u0432\u043e\u0433\u043e builder-\u043e\u0431\u0440\u0430\u0437\u0430 S2I (source-to-image), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 OpenShift. \u0422\u043e\u0433\u0434\u0430 \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0430 \u0442\u0435\u043c\u0430 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":90875,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-90874","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0421 \u0432\u0430\u043c\u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u0441\u0442 \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u0441\u0435\u0440\u0438\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u043a\u0430\u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430 Red Hat OpenShift \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 OpenShift, \u0447\u0430\u0441\u0442\u044c 2: \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 chained builds | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0421 \u0432\u0430\u043c\u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u0441\u0442 \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u0441\u0435\u0440\u0438\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u043a\u0430\u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430 Red Hat OpenShift \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-08-06T23:42:20+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-08-06T23:42:20+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47 Aplicaciones modernas en OpenShift, parte 2: builds encadenados | ProHoster","description":"\u00a1Hola a todos! Este es el segundo post de nuestra serie, donde mostramos c\u00f3mo desplegar aplicaciones web modernas en Red Hat OpenShift.","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 OpenShift, \u0447\u0430\u0441\u0442\u044c 2: \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 chained builds | ProHoster","og:description":"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0421 \u0432\u0430\u043c\u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u0441\u0442 \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u0441\u0435\u0440\u0438\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u043a\u0430\u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430 Red Hat OpenShift \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.","og:url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-08-06T23:42:20+00:00","article:modified_time":"2020-08-06T23:42:20+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"90874","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 12:40:03","updated":"2022-10-04 00:42:31","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/90874","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=90874"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/90874\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/90875"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=90874"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=90874"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=90874"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}