Applicazioni moderne su OpenShift, parte 2: build collegate chained builds

Ciao a tutti! Questo è il secondo post della nostra serie in cui mostriamo come distribuire moderne applicazioni web su Red Hat OpenShift.

Applicazioni moderne su OpenShift, parte 2: build collegate chained builds

Nel post precedente abbiamo accennato alle funzionalità della nuova immagine builder S2I (source-to-image), progettata per la costruzione e distribuzione di moderne applicazioni web sulla piattaforma OpenShift. Allora ci interessava il tema della rapida distribuzione delle applicazioni, mentre oggi vedremo come utilizzare l'immagine S2I come immagine builder «pulita» e combinarla con le build correlate di OpenShift.

Immagine builder pulita

Come abbiamo menzionato nella prima parte, la maggior parte delle moderne applicazioni web ha un cosiddetto stadio di costruzione, in cui di solito vengono eseguite operazioni come la transpiling del codice, la concatenazione di più file e la minificazione. I file risultanti da queste operazioni – ovvero HTML, JavaScript e CSS statici – vengono collocati nella cartella di output. La posizione di questa cartella dipende solitamente dagli strumenti di costruzione utilizzati, e per React sarà la cartella . /build (torneremo su questo punto più avanti).

Source-to-Image (S2I)

In questo post non tocchiamo affatto il tema «cos'è S2I e come usarlo» (puoi leggere di più qui), ma è importante avere ben chiari due stadi di questo processo per comprendere cosa faccia l'immagine Web App Builder.

Stadio di assemblaggio (assemble phase)

Lo stadio di assemblaggio è molto simile a quello che accade quando esegui docker build e ottieni una nuova immagine Docker. Di conseguenza, questo stadio si verifica quando avvii una build sulla piattaforma OpenShift.

Nel caso dell'immagine Web App Builder, l'installazione delle dipendenze della tua applicazione e l'avvio della build sono gestiti da assemble script. Di default, l'immagine builder utilizza la struttura npm run build, ma può essere sovrascritta tramite la variabile d'ambiente NPM_BUILD.

Come abbiamo detto in precedenza, la posizione dell'applicazione finale, già assemblata, dipende dagli strumenti utilizzati. Ad esempio, nel caso di React, sarà la cartella ./build, mentre per le applicazioni Angular sarà la cartella project_name/dist. E, come già mostrato nel post precedente, la posizione della cartella output, che è impostata di default come build, può essere sovrascritta mediante la variabile d'ambiente OUTPUT_DIR. E poiché la posizione della cartella output varia da framework a framework, si copia semplicemente l'output generato nella cartella standard nell'immagine, cioè in /opt/apt-root/output. Questo è importante per comprendere la parte successiva di questo articolo, ma per ora diamo un'occhiata rapidamente alla fase successiva: avvio (run phase).

Fase di avvio (run phase)

Questa fase si verifica quando viene eseguito un comando docker run per una nuova immagine creata nella fase di assemblaggio. Si verifica anche durante il deployment sulla piattaforma OpenShift. Per impostazione predefinita run script utilizza serve module per servire contenuti statici presenti nella suddetta cartella output standard.

Questo metodo è utile per il rapido deployment delle applicazioni, ma in realtà non è raccomandato servire contenuti statici in questo modo. Dato che in pratica serviamo solo contenuti statici, Node.js installato all'interno della nostra immagine non è necessario: basta un server web.

In altre parole, durante l'assemblaggio abbiamo bisogno di una cosa, durante l'esecuzione di un'altra. In questa situazione sono utili le build collegate (chained builds).

Build collegate (chained builds)

Ecco cosa si dice riguardo a chained builds nella documentazione di OpenShift:

«Due build possono essere collegate tra loro, in cui una genera un'entità compilata e l'altra posiziona quest'entità in un'immagine separata, utilizzata per eseguire tale entità».

In altre parole, possiamo utilizzare l'immagine Web App Builder per eseguire la nostra build, e poi utilizzare l'immagine del server web, lo stesso NGINX, per servire i nostri contenuti.

In questo modo, possiamo utilizzare l'immagine Web App Builder come builder «pulito» e avere al contempo un'immagine runtime di dimensioni ridotte.

Ora esaminiamo questo attraverso un esempio concreto.

Per l'esercitazione utilizzeremo una semplice applicazione React, creata con lo strumento da riga di comando create-react-app.

Per mettere tutto insieme ci aiuterà il file di template di OpenShift.

Esaminiamo questo file più nel dettaglio e iniziamo dalla sezione dei parametri.

parameters:
  - name: SOURCE_REPOSITORY_URL
    description: L'URL sorgente dell'applicazione
    displayName: URL Sorgente
    required: true
  - name: SOURCE_REPOSITORY_REF
    description: Il nome del branch dell'applicazione
    displayName: Branch Sorgente
    value: master
    required: true
  - name: SOURCE_REPOSITORY_DIR
    description: La posizione all'interno del repository sorgente dell'applicazione
    displayName: Directory Sorgente
    value: .
    required: true
  - name: OUTPUT_DIR
    description: La posizione dei file statici compilati dal tuo builder di applicazioni web
    displayName: Directory di Output
    value: build
    required: false

Qui tutto è piuttosto chiaro, ma vale la pena prestare attenzione al parametro OUTPUT_DIR. Per l'applicazione React del nostro esempio non c'è nulla di cui preoccuparsi, poiché React utilizza come directory di output il valore predefinito, ma nel caso di Angular o di altro, questo parametro dovrà essere modificato di conseguenza.

Ora diamo un'occhiata alla sezione degli ImageStream.

- 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'

Guarda il terzo e il quarto immagine. Entrambi sono definiti come immagini Docker e qui è chiaramente visibile da dove provengono.

La terza immagine è web-app-builder, e viene da nodeshift/ubi8-s2i-web-app con il tag 10.x su Docker hub.

La quarta è l'immagine NGINX (versione 1.12) con il tag latest su Docker hub.

Ora diamo un'occhiata alle prime due immagini. Sono entrambe vuote all'inizio e vengono create solo durante la fase di build. La prima immagine – react-web-app-builder – sarà il risultato della fase di assemblaggio, che unirà l'immagine web-app-builder-runtime e il nostro codice sorgente. Ecco perché abbiamo scritto 'builder' nel nome di quest'immagine.

La seconda immagine – react-web-app-runtime – sarà il risultato della combinazione di nginx-image-runtime e alcuni file dall'immagine react-web-app-builder. Questa immagine sarà utilizzata anche durante il deploy e conterrà solo il server web e il HTML statico, JavaScript e CSS della nostra applicazione.

Complicato? Ora diamo un'occhiata alle configurazioni di build e diventerà un po' più chiaro.

Nel nostro template ci sono due configurazioni di build. Ecco la prima di esse, ed è piuttosto standard:

  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

Come possiamo vedere, la riga con l'etichetta 1 indica che il risultato di questa build sarà collocato nell'immagine react-web-app-builder, che abbiamo visto poco prima nella sezione ImageStream.

La riga con l'etichetta 2 indica da dove prendere il codice. Nel nostro caso si tratta di un repository git, e la posizione, il ref e la cartella di contesto sono definiti dalle variabili che abbiamo già visto sopra.

La riga con l'etichetta 3 – l'abbiamo già vista nella sezione parameters. Aggiunge la variabile d'ambiente OUTPUT_DIR, che nel nostro esempio è uguale a build.
La riga con l'etichetta 4 indica di utilizzare l'immagine web-app-builder-runtime, che abbiamo già visto nella sezione ImageStream.

La riga con l'etichetta 5 indica che vogliamo utilizzare una build incrementale, se l'immagine S2I la supporta, e l'immagine Web App Builder lo supporta. Durante il primo avvio, al termine della fase di assemblaggio, l'immagine salverà la cartella node_modules in un file di archivio. Nei successivi avvii, l'immagine decomprimerà semplicemente questa cartella per ridurre il tempo di build.

E infine, la riga con l'etichetta 6 – sono solo alcuni trigger, affinché la build si avvii automaticamente, senza intervento manuale, quando qualcosa cambia.

In generale, si tratta di una configurazione di build abbastanza standard.

Ora diamo un'occhiata alla seconda configurazione di build. È molto simile alla prima, ma c'è una differenza 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

Quindi, la seconda configurazione di compilation è react-web-app-runtime, e inizia in modo abbastanza standard.

Nella riga contrassegnata con 1 non c'è nulla di nuovo: dice semplicemente che il risultato della compilazione viene messo nell'immagine react-web-app-runtime.

La riga contrassegnata con 2, come nella configurazione precedente, indica da dove prendere il codice sorgente. Ma notate che qui diciamo che viene preso dall'immagine. Ed è quell'immagine che abbiamo appena creato – da react-web-app-builder (indicata nella riga contrassegnata con 3). I file che vogliamo utilizzare si trovano all'interno dell'immagine e la loro posizione è specificata nella riga contrassegnata con 4, nel nostro caso è /opt/app-root/output/. Se ricordate, è proprio lì che vengono messi i file generati dai risultati della compilazione della nostra applicazione.

La cartella di destinazione, specificata nella riga contrassegnata con 5, è semplicemente la cartella corrente (tutto questo, ricordiamo, gira all'interno di una sorta di cosa magica chiamata OpenShift, e non sul vostro computer locale).

La sezione strategy – la riga contrassegnata con 6 – è simile alla prima configurazione di compilation. Solo che questa volta intendiamo usare nginx-image-runtime, che abbiamo già visto nella sezione ImageStream.

Infine, la riga contrassegnata con 7 è la sezione dei trigger che attivano questa compilazione ogni volta che cambia l'immagine react-web-app-builder.

Per il resto, questo template contiene una configurazione di deployment piuttosto standard, così come elementi relativi ai servizi e ai percorsi, ma non ci andremo a soffermare. Notate che l'immagine che verrà distribuita è l'immagine react-web-app-runtime.

Distribuzione dell'applicazione

Quindi, dopo aver esaminato il template, vediamo come utilizzarlo per la distribuzione dell'applicazione.

Possiamo usare lo strumento client di OpenShift chiamato oc per distribuire il nostro template:

$ 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

Il primo comando nello screenshot sopra è un modo volutamente ingegneristico per trovare il template ./openshiftio/application.yaml.

Il secondo comando crea semplicemente una nuova applicazione basata su questo template.

Dopo che questi comandi saranno stati eseguiti, vedremo che abbiamo due compilazioni:

Applicazioni moderne su OpenShift, parte 2: build collegate chained builds

E tornando allo schermo di Panoramica, vedremo il pod avviato:

Applicazioni moderne su OpenShift, parte 2: build collegate chained builds

Un clic sul link e passeremo alla nostra applicazione, che è una pagina dell'applicazione React App per impostazione predefinita:

Applicazioni moderne su OpenShift, parte 2: build collegate chained builds

Supplemento 1

Per gli appassionati di Angular abbiamo anche un esempio di applicazione.

Il modello qui è lo stesso, ad eccezione della variabile OUTPUT_DIR.

Supplemento 2

In questo articolo abbiamo usato NGINX come server web, ma è piuttosto semplice sostituirlo con Apache, basta modificare il file del modello immagine NGINX in immagine Apache.

Conclusione

Nella prima parte di questa serie abbiamo mostrato come distribuire rapidamente applicazioni web moderne sulla piattaforma OpenShift. Oggi abbiamo esaminato cosa fa l'immagine Web App e come può essere combinata con un server web puro come NGINX utilizzando build collegate (chained build) per organizzare una build più adatta per l'ambiente di produzione. Nel prossimo e ultimo articolo di questa serie, mostreremo come avviare un server di sviluppo per la propria applicazione su OpenShift e garantire la sincronizzazione dei file locali e remoti.

Contenuto di questa serie di articoli

  • Parte 1: come distribuire applicazioni web moderne in pochi passaggi;
  • Parte 2: come applicare una nuova immagine S2I insieme a un'immagine HTTP server esistente, come NGINX, utilizzando build collegate di OpenShift, per organizzare una distribuzione per la produzione;
  • Parte 3: come avviare un server di sviluppo per la propria applicazione sulla piattaforma OpenShift e sincronizzarlo con il filesystem locale.

Risorse aggiuntive

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster