{"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\/ro\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds","title":{"rendered":"Aplica\u021bii moderne pe OpenShift, partea 2: construc\u021bii legate chained builds","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Salut tuturor! Aceasta este a doua postare din seria noastr\u0103, \u00een care ar\u0103t\u0103m cum s\u0103 desf\u0103\u0219ur\u0103m aplica\u021bii web moderne pe Red Hat OpenShift. <\/p>\n<p><img decoding=\"async\" alt=\"Aplica\u021bii moderne pe OpenShift, partea 2: construc\u021bii legate chained builds\" src=\"\/wp-content\/uploads\/2020\/08\/b1f6ae855a69597c6e86c5198e4a628c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00cen postarea anterioar\u0103, am atins u\u0219or posibilit\u0103\u021bile noului imagini builder S2I (source-to-image), care este destinat construirii \u0219i desf\u0103\u0219ur\u0103rii aplica\u021biilor web moderne pe platforma OpenShift. Atunci ne-a interesat tema desf\u0103\u0219ur\u0103rii rapide a aplica\u021biei, iar ast\u0103zi vom analiza cum s\u0103 utiliz\u0103m imaginea S2I ca un builder 'curat' \u0219i s\u0103 o combin\u0103m cu asambl\u0103rile asociate din OpenShift.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Imagine builder curat\u0103<\/h3>\n<p>\nA\u0219a cum am men\u021bionat \u00een prima parte, majoritatea aplica\u021biilor web moderne au un a\u0219a-numit stadiu de construire, \u00een timpul c\u0103ruia au loc de obicei opera\u021bii precum transpilararea codului, concatenarea mai multor fi\u0219iere \u0219i minificarea. Fi\u0219ierele rezultate de la aceste opera\u021bii - \u0219i anume HTML static, JavaScript \u0219i CSS - sunt plasate \u00een dosarul output. Loca\u021bia acestui dosar depinde de instrumentele de construire utilizate, iar pentru React, acesta va fi dosarul .\\\/build (vom reveni la aceast\u0103 problem\u0103 mai jos).<\/p>\n<h4>Source-to-Image (S2I)<\/h4>\n<p>\n\u00cen aceast\u0103 postare nu ne ocup\u0103m deloc de tema 'ce este S2I \u0219i cum se folose\u0219te' (detalii despre aceasta pot fi g\u0103site <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.okd.io\/latest\/architecture\/core_concepts\/builds_and_image_streams.html#source-build\">aici<\/a><\/noindex>), dar este important s\u0103 \u00een\u021belegem clar cele dou\u0103 etape ale acestui proces pentru a \u00een\u021belege ce face imaginea Web App Builder.<\/p>\n<h4>Etapa de asamblare (assemble phase)<\/h4>\n<p>\nEtapa de asamblare este foarte asem\u0103n\u0103toare cu ceea ce se \u00eent\u00e2mpl\u0103 atunci c\u00e2nd rula\u021bi docker build \u0219i ob\u021bine\u021bi o nou\u0103 imagine Docker. Prin urmare, aceast\u0103 etap\u0103 are loc atunci c\u00e2nd porni\u021bi o construc\u021bie pe platforma OpenShift.<\/p>\n<p>\u00cen cazul imaginii Web App Builder, instalarea dependen\u021belor aplica\u021biei tale \u0219i ini\u021bierea construc\u021biei sunt gestionate de <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/bucharest-gold\/centos7-s2i-web-app\/blob\/master\/s2i\/assemble#L47\">assemble script<\/a><\/noindex>. \u00cen mod implicit, imaginea builder folose\u0219te construc\u021bia npm run build, dar aceasta poate fi suprascris\u0103 prin variabila de mediu NPM_BUILD.<\/p>\n<p>A\u0219a cum am men\u021bionat anterior, loca\u021bia aplica\u021biei finale, deja compilat\u0103, depinde de instrumentele utilizate. De exemplu, \u00een cazul React, aceasta va fi folderul \/build, iar pentru aplica\u021biile Angular \u2013 folderul project_name\/dist. \u0218i, a\u0219a cum a fost ar\u0103tat \u00een postarea anterioar\u0103, loca\u021bia catalogului output, care este setat implicit ca build, poate fi suprascris\u0103 prin variabila de mediu OUTPUT_DIR. De asemenea, av\u00e2nd \u00een vedere c\u0103 loca\u021bia folderului output difer\u0103 de la un framework la altul, pur \u0219i simplu copia\u021bi output-ul generat \u00een folderul standard din imagine, \u0219i anume \u00een \/opt\/apt-root\/output. Aceasta este important\u0103 pentru \u00een\u021belegerea p\u0103r\u021bii urm\u0103toare a acestui articol, dar s\u0103 trecem rapid la urm\u0103torul pas \u2013 etapa de rulare (run phase).<\/p>\n<h4>Etapa de rulare (run phase)<\/h4>\n<p>\nAceast\u0103 etap\u0103 apare atunci c\u00e2nd se face un apel docker run pentru o nou\u0103 imagine, creat\u0103 \u00een etapa de asamblare. Acest lucru se \u00eent\u00e2mpl\u0103 \u0219i atunci c\u00e2nd se desf\u0103\u0219oar\u0103 implementarea pe platforma OpenShift. \u00cen mod implicit <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/bucharest-gold\/centos7-s2i-web-app\/blob\/master\/s2i\/run\">scriptul de execu\u021bie<\/a><\/noindex> folose\u0219te <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/package\/serve\">serve module<\/a><\/noindex> pentru a servi con\u021binut static aflat \u00een catalogul output standard men\u021bionat mai sus.<\/p>\n<p>Aceast\u0103 metod\u0103 este bun\u0103 pentru desf\u0103\u0219urarea rapid\u0103 a aplica\u021biilor, dar \u00een general nu este recomandat s\u0103 serve\u021bi con\u021binut static \u00een acest mod. Deoarece \u00een realitate servim doar con\u021binut static, Node.js instalat \u00een imaginea noastr\u0103 nu este necesar \u2013 este suficient un server web.<\/p>\n<p>Cu alte cuvinte, la asamblare avem nevoie de un lucru, iar la execu\u021bie \u2013 de altul. \u00centr-o astfel de situa\u021bie, construc\u021biile \u00eenl\u0103n\u021buite (chained builds) devin utile.<\/p>\n<h3>Construc\u021bii \u00eenl\u0103n\u021buite (chained builds)<\/h3>\n<p>\nIat\u0103 ce scrie despre <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> \u00een documenta\u021bia OpenShift:<\/p>\n<blockquote><p>\u00abDou\u0103 construc\u021bii pot fi legate \u00eentre ele, una gener\u00e2nd o entitate compilat\u0103, iar cealalt\u0103 plas\u00e2nd aceast\u0103 entitate \u00eentr-o imagine separat\u0103, care este utilizat\u0103 pentru a rula aceast\u0103 entitate\u00bb.\n<\/p><\/blockquote>\n<p>\nCu alte cuvinte, putem folosi imaginea Web App Builder pentru a rula construc\u021bia noastr\u0103, iar apoi putem folosi imaginea serverului web, acela\u0219i NGINX, pentru a servi con\u021binutul nostru.<\/p>\n<p>Astfel, putem aplica imaginea Web App Builder ca un builder \u201ecurat\u201d \u0219i, \u00een acela\u0219i timp, avem o imagine runtime de dimensiuni reduse.<\/p>\n<p>Acum s\u0103 analiz\u0103m acest lucru printr-un exemplu concret.<\/p>\n<p>Pentru antrenament, vom folosi <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/react-web-app\">o aplica\u021bie React simpl\u0103<\/a><\/noindex>, creat\u0103 cu ajutorul instrumentului CLI create-react-app.<\/p>\n<p>S\u0103 aducem totul \u00eempreun\u0103 cu ajutorul <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/react-web-app\/blob\/master\/.openshiftio\/application.yaml\">fi\u0219ierului de \u0219ablon OpenShift<\/a><\/noindex>.<\/p>\n<p>S\u0103 detaliem acest fi\u0219ier \u0219i s\u0103 \u00eencepem cu sec\u021biunea parametrelor.<\/p>\n<pre><code class=\"plaintext\">parametrii:\n  - nume: SOURCE_REPOSITORY_URL\n    descriere: URL-ul surs\u0103 pentru aplica\u021bie\n    displayName: URL surs\u0103\n    necesar: adev\u0103rat\n  - nume: SOURCE_REPOSITORY_REF\n    descriere: Numele ramurii pentru aplica\u021bie\n    displayName: Ramura surs\u0103\n    valoare: master\n    necesar: adev\u0103rat\n  - nume: SOURCE_REPOSITORY_DIR\n    descriere: Locul din repo-ul surs\u0103 al aplica\u021biei\n    displayName: Director surs\u0103\n    valoare: .\n    necesar: adev\u0103rat\n  - nume: OUTPUT_DIR\n    descriere: Locul fi\u0219ierelor statice compilate din constructorul aplica\u021biilor tale web\n    displayName: Director de ie\u0219ire\n    valoare: build\n    necesar: fals\n<\/code><\/pre>\n<p>\nAici totul este destul de clar, dar trebuie s\u0103 acorda\u021bi aten\u021bie parametrului OUTPUT_DIR. Pentru aplica\u021bia React din exemplul nostru nu trebuie s\u0103 v\u0103 face\u021bi griji, deoarece React folose\u0219te ca director de ie\u0219ire valoarea implicit\u0103, dar \u00een cazul Angular sau altceva, acest parametru va trebui schimbat corespunz\u0103tor.<\/p>\n<p>Acum s\u0103 ne uit\u0103m la sec\u021biunea 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>\nUita\u021bi-v\u0103 la a treia \u0219i a patra imagine. Ambele sunt definite ca imagini Docker, iar aici este clar de unde provin.<\/p>\n<p>A treia imagine este web-app-builder, \u0219i provine din nodeshift\/ubi8-s2i-web-app cu eticheta 10.x pe <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/nodeshift\/ubi8-s2i-web-app\/\">Docker hub<\/a><\/noindex>.<\/p>\n<p>A patra este imaginea NGINX (versiunea 1.12) cu eticheta latest pe <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/centos\/nginx-112-centos7\/\">Docker hub<\/a><\/noindex>.<\/p>\n<p>Acum s\u0103 ne uit\u0103m la primele dou\u0103 imagini. Ambele sunt goale la \u00eenceput \u0219i sunt create doar \u00een etapa de construc\u021bie (build phase). Prima imagine - react-web-app-builder - va fi rezultatul etapei de asamblare, care va combina imaginea web-app-builder-runtime \u0219i codul nostru surs\u0103. De aceea am inclus \u00een numele acestei imagini \u201e-builder\u201d.<\/p>\n<p>A doua imagine - react-web-app-runtime - va fi rezultatul combin\u0103rii nginx-image-runtime \u0219i a unor fi\u0219iere din imaginea react-web-app-builder. Aceast\u0103 imagine va fi folosit\u0103 \u0219i la desf\u0103\u0219urare \u0219i va con\u021bine doar serverul web \u0219i HTML, JavaScript, CSS statice ale aplica\u021biei noastre.<\/p>\n<p>Confuz? Acum s\u0103 ne uit\u0103m la configura\u021biile de construc\u021bie \u0219i va fi pu\u021bin mai clar.<\/p>\n<p>\u00cen \u0219ablonul nostru exist\u0103 dou\u0103 configura\u021bii de construc\u021bie. Iat\u0103 prima dintre ele, \u0219i este destul de standard\u0103:<\/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 \/\/ 1\n    source:   \/\/ 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 \/\/ 3 \n            value: ${OUTPUT_DIR}\n        from:\n          kind: ImageStreamTag\n          name: web-app-builder-runtime:latest \/\/ 4\n        incremental: true \/\/ 5\n      type: Source\n    triggers: \/\/ 6\n    - github:\n        secret: ${GITHUB_WEBHOOK_SECRET}\n      type: GitHub\n    - type: ConfigChange\n    - imageChange: {}\n      type: ImageChange\n<\/code><\/pre>\n<p>\nA\u0219a cum vedem, linia cu eticheta 1 spune c\u0103 rezultatul acestei construc\u021bii va fi plasat \u00een imaginea react-web-app-builder, pe care am v\u0103zut-o mai devreme \u00een sec\u021biunea ImageStream.<\/p>\n<p>Linia cu eticheta 2 spune de unde se va lua codul. \u00cen cazul nostru, acesta este un repository git, iar loca\u021bia, ref \u0219i folderul de context sunt definite prin parametrii pe care i-am v\u0103zut mai sus.<\/p>\n<p>Linia cu eticheta 3 \u2013 aceasta a fost deja men\u021bionat\u0103 \u00een sec\u021biunea parameter. Ea adaug\u0103 o variabil\u0103 de mediu OUTPUT_DIR, care \u00een exemplul nostru este egal\u0103 cu build.<br \/>\nLinia cu eticheta 4 spune s\u0103 foloseasc\u0103 imaginea web-app-builder-runtime, pe care am v\u0103zut-o deja \u00een sec\u021biunea ImageStream.<\/p>\n<p>Linia cu eticheta 5 spune c\u0103 dorim s\u0103 folosim o construc\u021bie incremental\u0103, dac\u0103 imaginea S2I o suport\u0103, iar imaginea Web App Builder \u2013 o suport\u0103. La prima rulare, dup\u0103 finalizarea etapei de asamblare, imaginea va salva folderul node_modules \u00eentr-un fi\u0219ier arhivat. Apoi, la rul\u0103rile ulterioare, imaginea va decomprima pur \u0219i simplu acest folder pentru a reduce durata construc\u021biei.<\/p>\n<p>\u0218i, \u00een final, linia cu eticheta 6 \u2013 sunt doar c\u00e2\u021biva triggeri pentru a lansa construc\u021bia automat, f\u0103r\u0103 interven\u021bie manual\u0103, atunci c\u00e2nd ceva se schimb\u0103.<\/p>\n<p>\u00cen general, aceasta este o configura\u021bie standard de construit.<\/p>\n<p>Acum s\u0103 ne uit\u0103m la a doua configura\u021bie de construire. Este foarte asem\u0103n\u0103toare cu prima, dar exist\u0103 o diferen\u021b\u0103 important\u0103.<\/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 \/\/ 1\n    source: \/\/ 2\n      type: Image\n      images:\n        - from:\n            kind: ImageStreamTag\n            name: react-web-app-builder:latest \/\/ 3\n          paths:\n            - sourcePath: \/opt\/app-root\/output\/.  \/\/ 4\n              destinationDir: .  \/\/ 5\n    strategy: \/\/ 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 \/\/ 7\n<\/code><\/pre>\n<p>\nDeci, a doua configura\u021bie a compil\u0103rii este react-web-app-runtime, \u0219i \u00eencepe relativ standard.<\/p>\n<p>Linia cu eticheta 1 nu con\u021bine nimic nou \u2013 doar indic\u0103 faptul c\u0103 rezultatul compil\u0103rii este plasat \u00een imaginea react-web-app-runtime.<\/p>\n<p>Linia cu eticheta 2, ca \u00een configura\u021bia anterioar\u0103, indic\u0103 de unde s\u0103 lu\u0103m codul surs\u0103. Dar observa\u021bi c\u0103 aici spunem c\u0103 acesta este preluat dintr-o imagine. \u0218i anume, din imaginea pe care tocmai am creat-o \u2013 din react-web-app-builder (specificat\u0103 \u00een linia cu eticheta 3). Fi\u0219ierele pe care dorim s\u0103 le folosim se afl\u0103 \u00een interiorul imaginii \u0219i loca\u021bia lor acolo este specificat\u0103 \u00een linia cu eticheta 4, \u00een cazul nostru este \/opt\/app-root\/output\/. Dac\u0103 v\u0103 aminti\u021bi, exact acolo sunt plasate fi\u0219ierele generate ca rezultat al compil\u0103rii aplica\u021biei noastre.<\/p>\n<p>Directorul de destina\u021bie, specificat \u00een termenul cu eticheta 5, este pur \u0219i simplu directorul curent (toate acestea, amintim, se desf\u0103\u0219oar\u0103 \u00een interiorul unei chestii magice numit\u0103 OpenShift, nu pe computerul dumneavoastr\u0103 local).<\/p>\n<p>Sec\u021biunea strategy \u2013 linia cu eticheta 6 \u2013 este, de asemenea, similar\u0103 cu prima configura\u021bie a compil\u0103rii. Numai c\u0103 de aceast\u0103 dat\u0103 inten\u021bion\u0103m s\u0103 folosim nginx-image-runtime, pe care l-am v\u0103zut deja \u00een sec\u021biunea ImageStream.<\/p>\n<p>\u00cen final, linia cu eticheta 7 \u2013 este sec\u021biunea de declan\u0219atoare, care activeaz\u0103 aceast\u0103 compilare de fiecare dat\u0103 c\u00e2nd se schimb\u0103 imaginea react-web-app-builder.<\/p>\n<p>\u00cen rest, acest \u0219ablon con\u021bine o configura\u021bie standard de desf\u0103\u0219urare, precum \u0219i lucruri legate de servicii \u0219i rute, dar nu ne vom aprofunda \u00een acestea. Observa\u021bi c\u0103 imaginea care va fi desf\u0103\u0219urat\u0103 este imaginea react-web-app-runtime.<\/p>\n<h3>Desf\u0103\u0219urarea aplica\u021biei<\/h3>\n<p>\nDeci, dup\u0103 ce am aruncat o privire asupra \u0219ablonului, s\u0103 vedem cum s\u0103-l folosim pentru desf\u0103\u0219urarea aplica\u021biei.<\/p>\n<p>Putem folosi instrumentul client OpenShift numit oc pentru a desf\u0103\u0219ura \u0219ablonul nostru:<\/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>\nPrima comand\u0103 din ecranul de mai sus \u2013 este o modalitate inten\u021bionat ingineriasc\u0103 de a g\u0103si \u0219ablonul \/openshiftio\/application.yaml.<\/p>\n<p>A doua comand\u0103 pur \u0219i simplu creeaz\u0103 o nou\u0103 aplica\u021bie pe baza acestui \u0219ablon.<\/p>\n<p>Dup\u0103 ce aceste comenzi se execut\u0103, vom vedea c\u0103 avem dou\u0103 compil\u0103ri:<\/p>\n<p><img decoding=\"async\" alt=\"Aplica\u021bii moderne pe OpenShift, partea 2: construc\u021bii legate chained builds\" src=\"\/wp-content\/uploads\/2020\/08\/c6b2b2fcadfcd3e5a8a2adb4eff69bf2.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Iar \u00eentorc\u00e2ndu-ne pe ecranul Overview, vom vedea pod-ul care a fost lansat:<\/p>\n<p><img decoding=\"async\" alt=\"Aplica\u021bii moderne pe OpenShift, partea 2: construc\u021bii legate chained builds\" src=\"\/wp-content\/uploads\/2020\/08\/983fab3029d222555dc13790d4a3e70f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Un clic pe link \u2013 \u0219i vom ajunge la aplica\u021bia noastr\u0103, care reprezint\u0103 pagina aplica\u021biei React App implicit:<\/p>\n<p><img decoding=\"async\" alt=\"Aplica\u021bii moderne pe OpenShift, partea 2: construc\u021bii legate chained builds\" src=\"\/wp-content\/uploads\/2020\/08\/d5b658875e0e865bf456955aaac15464.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Anexa 1<\/h3>\n<p>\nPentru iubitorii de Angular, avem \u0219i noi <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/angular-web-app\">un exemplu de aplica\u021bie<\/a><\/noindex>.<\/p>\n<p>\u0218ablonul este similar, cu excep\u021bia variabilei OUTPUT_DIR.<\/p>\n<h3>Completarile 2<\/h3>\n<p>\n\u00cen acest articol, am folosit ca server web NGINX, dar este destul de u\u0219or s\u0103-l \u00eenlocuim cu Apache, pur \u0219i simplu schimb\u00e2nd \u00een fi\u0219ierul \u0219ablon. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/lholmquist\/react-web-app\/blob\/master\/.openshiftio\/application.yaml#L66\">imaginea NGINX<\/a><\/noindex> pe <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/centos\/httpd-24-centos7\/\">imaginea Apache<\/a><\/noindex>.<\/p>\n<h3>Concluzie<\/h3>\n<p>\n\u00cen prima parte a acestei serii, am ar\u0103tat cum s\u0103 implementa\u021bi rapid aplica\u021bii web moderne pe platforma OpenShift. Ast\u0103zi, vom analiza ce face imaginea Web App \u0219i cum se poate combina cu un server web curat de tip NGINX prin intermediul construirilor \u00eenlan\u021buite (chained build) pentru a organiza o construc\u021bie mai adecvat\u0103 pentru condi\u021biile de produc\u021bie. \u00cen urm\u0103torul, articol concluziv al acestei serii, v\u0103 vom ar\u0103ta cum s\u0103 rula\u021bi pe OpenShift un server de dezvoltare pentru aplica\u021bia dvs. \u0219i s\u0103 asigura\u021bi sincronizarea fi\u0219ierelor locale \u0219i de la distan\u021b\u0103.<\/p>\n<h3>Cuprinsul acestei serii de articole<\/h3>\n<p><\/p>\n<ul>\n<li>Partea 1: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/redhatrussia\/blog\/511954\/\">cum s\u0103 implementa\u021bi aplica\u021bii web moderne \u00een doar c\u00e2\u021biva pa\u0219i<\/a><\/noindex>;<\/li>\n<li>Partea 2: cum s\u0103 aplica\u021bi o nou\u0103 imagine S2I \u00eempreun\u0103 cu o imagine existent\u0103 de server HTTP, de exemplu, NGINX, folosind construc\u021bii \u00eenlan\u021buite OpenShift pentru a organiza implementarea \u00een produc\u021bie;<\/li>\n<li>Partea 3: cum s\u0103 rula\u021bi pe platforma OpenShift un server de dezvoltare pentru aplica\u021bia dvs. \u0219i s\u0103-l sincroniza\u021bi cu sistemul local de fi\u0219iere.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Resurse suplimentare<\/h3>\n<p><\/p>\n<ul>\n<li>Carte electronic\u0103 gratuit\u0103 <noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/books\/deploying-openshift\">Implementare pe OpenShift<\/a><\/noindex>.<\/li>\n<li>Informa\u021bii despre <noindex><a rel=\"nofollow\" href=\"https:\/\/developers.redhat.com\/topics\/kubernetes\/\">OpenShift \u0219i Kubernetes<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>Sursa: <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.1 - 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\/ro\/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.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Aplica\u021bii moderne pe OpenShift, partea 2: construc\u021bii \u00eenlan\u021buite (chained builds) | ProHoster","description":"Salut tuturor! Aceasta este a doua postare din seria noastr\u0103, \u00een care ar\u0103t\u0103m cum s\u0103 desf\u0103\u0219ur\u0103m aplica\u021bii web moderne pe Red Hat OpenShift.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/sovremennye-prilozheniya-na-openshift-chast-2-svyazannye-sborki-chained-builds","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/90874","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=90874"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/90874\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/90875"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=90874"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=90874"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=90874"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}