Applicazioni moderne su OpenShift, parte 2: build concatenate

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

Applicazioni moderne su OpenShift, parte 2: build concatenate

Nel post precedente, abbiamo accennato leggermente alle funzionalità della nuova immagine del builder S2I (source-to-image), progettata per creare e distribuire applicazioni Web moderne sulla piattaforma OpenShift. Allora eravamo interessati all'argomento della distribuzione rapida di un'applicazione e oggi esamineremo come utilizzare un'immagine S2I come immagine di builder “pura” e combinarla con i relativi assembly OpenShift.

Immagine del builder pulita

Come accennato nella Parte XNUMX, la maggior parte delle applicazioni Web moderne dispone di una cosiddetta fase di compilazione, che in genere esegue operazioni come la transpilazione del codice, la concatenazione di più file e la minimizzazione. I file ottenuti come risultato di queste operazioni - e si tratta di HTML statico, JavaScript e CSS - vengono archiviati nella cartella di output. La posizione di questa cartella di solito dipende da quali strumenti di compilazione vengono utilizzati e per React questa sarà la cartella ./build (torneremo su questo più in dettaglio più avanti).

Da sorgente a immagine (S2I)

In questo post non tocchiamo l’argomento “cos’è S2I e come usarlo” (puoi leggere di più a riguardo qui), ma è importante essere chiari sui due passaggi di questo processo per comprendere cosa fa un'immagine di Web App Builder.

Fase di assemblaggio

La fase di assemblaggio è di natura molto simile a ciò che accade quando si esegue docker build e si ottiene una nuova immagine Docker. Di conseguenza, questa fase si verifica quando si avvia una build sulla piattaforma OpenShift.

Nel caso di un'immagine Web App Builder, è responsabile dell'installazione delle dipendenze dell'applicazione e dell'esecuzione della build. assemblare la sceneggiatura. Per impostazione predefinita, l'immagine del builder utilizza il costrutto npm run build, ma questo può essere sovrascritto tramite la variabile di ambiente NPM_BUILD.

Come abbiamo detto in precedenza, la posizione dell'applicazione finita e già creata dipende dagli strumenti utilizzati. Ad esempio, nel caso di React questa sarà la cartella ./build e per le applicazioni Angular sarà la cartella project_name/dist. E, come già mostrato nel post precedente, la posizione della directory di output, che è impostata su build per impostazione predefinita, può essere sovrascritta tramite la variabile d'ambiente OUTPUT_DIR. Bene, poiché la posizione della cartella di output differisce da framework a framework, basta copiare semplicemente l'output generato nella cartella standard nell'immagine, vale a dire /opt/apt-root/output. Questo è importante per comprendere il resto di questo articolo, ma per ora diamo un'occhiata rapidamente alla fase successiva: la fase di esecuzione.

fase di esecuzione

Questa fase si verifica quando viene effettuata una chiamata all'esecuzione della finestra mobile sulla nuova immagine creata durante la fase di assemblaggio. Lo stesso accade durante la distribuzione sulla piattaforma OpenShift. Predefinito esegui script usi servire il modulo per servire il contenuto statico situato nella directory di output standard sopra.

Questo metodo è utile per distribuire rapidamente le applicazioni, ma in genere non è consigliabile fornire contenuto statico in questo modo. Bene, poiché in realtà serviamo solo contenuto statico, non abbiamo bisogno di Node.js installato nella nostra immagine: sarà sufficiente un server web.

In altre parole, quando assembliamo abbiamo bisogno di una cosa, quando eseguiamo ne abbiamo bisogno di un'altra. In questa situazione, le build concatenate tornano utili.

Costruzioni concatenate

Questo è ciò di cui scrivono costruzioni concatenate nella documentazione di OpenShift:

"Due assembly possono essere collegati insieme, uno dei quali genera un'entità compilata e l'altro ospita quell'entità in un'immagine separata utilizzata per eseguire quell'entità."

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

Pertanto, possiamo utilizzare l'immagine Web App Builder come un builder “puro” e allo stesso tempo avere una piccola immagine runtime.

Ora esaminiamolo con un esempio specifico.

Per la formazione utilizzeremo semplice applicazione React, creato utilizzando lo strumento da riga di comando create-react-app.

Ci aiuterà a mettere tutto insieme File modello OpenShift.

Diamo un'occhiata a questo file in modo più dettagliato e iniziamo con la sezione dei parametri.

parameters:
  - name: SOURCE_REPOSITORY_URL
    description: The source URL for the application
    displayName: Source URL
    required: true
  - name: SOURCE_REPOSITORY_REF
    description: The branch name for the application
    displayName: Source Branch
    value: master
    required: true
  - name: SOURCE_REPOSITORY_DIR
    description: The location within the source repo of the application
    displayName: Source Directory
    value: .
    required: true
  - name: OUTPUT_DIR
    description: The location of the compiled static files from your web apps builder
    displayName: Output Directory
    value: build
    required: false

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

Ora diamo un'occhiata alla sezione 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'

Dai un'occhiata alla terza e alla quarta immagine. Sono entrambe definite immagini Docker e puoi vedere chiaramente da dove provengono.

La terza immagine è web-app-builder e proviene da nodeshift/ubi8-s2i-web-app contrassegnato con 10.x su Mozzo Docker.

La quarta è un'immagine NGINX (versione 1.12) con l'ultimo tag inserito Mozzo Docker.

Ora diamo un'occhiata alle prime due immagini. Sono entrambi vuoti all'inizio e vengono creati solo durante la fase di costruzione. La prima immagine, react-web-app-builder, sarà il risultato di una fase di assemblaggio che combinerà l'immagine web-app-builder-runtime e il nostro codice sorgente. Ecco perché abbiamo aggiunto "-builder" al nome di questa immagine.

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

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

Il nostro modello ha due configurazioni di build. Ecco il primo, 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 puoi vedere, la riga con etichetta 1 dice che il risultato di questa build verrà inserito nella stessa immagine react-web-app-builder che abbiamo visto poco prima nella sezione ImageStreams.

La riga etichettata 2 ti dice da dove prendere il codice. Nel nostro caso si tratta di un repository git e la posizione, il riferimento e la cartella di contesto sono determinati dai parametri che abbiamo già visto sopra.

La linea etichettata 3 è quella che abbiamo già visto nella sezione parametri. Aggiunge la variabile d'ambiente OUTPUT_DIR, che nel nostro esempio è build.
La riga etichettata 4 dice di utilizzare l'immagine web-app-builder-runtime, che abbiamo già visto nella sezione ImageStream.

La riga etichettata 5 indica che vogliamo utilizzare una build incrementale se l'immagine S2I la supporta e l'immagine Web App Builder lo fa. Al primo avvio, una volta completata la fase di assemblaggio, l'immagine salverà la cartella node_modules in un file di archivio. Quindi, nelle esecuzioni successive, l'immagine decomprimerà semplicemente questa cartella per ridurre i tempi di creazione.

E infine, la riga etichettata 6 contiene solo alcuni trigger per far sì che la compilazione venga eseguita automaticamente, senza intervento manuale, quando qualcosa cambia.

Nel complesso si tratta di una configurazione di build piuttosto standard.

Ora diamo un'occhiata alla seconda configurazione di build. È molto simile al primo, 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 build è react-web-app-runtime e inizia in modo piuttosto standard.

La riga etichettata 1 non è una novità: dice semplicemente che il risultato della compilazione viene inserito nell'immagine react-web-app-runtime.

La riga etichettata 2, come nella configurazione precedente, indica da dove ottenere il codice sorgente. Ma nota che qui stiamo dicendo che è preso dall'immagine. Inoltre, dall'immagine che abbiamo appena creato - da react-web-app-builder (indicato nella riga etichettata 3). I file che vogliamo utilizzare si trovano all'interno dell'immagine e la loro posizione è impostata nella riga etichettata 4, nel nostro caso è /opt/app-root/output/. Se ricordi, è qui che vengono archiviati i file generati in base ai risultati della creazione della nostra applicazione.

La cartella di destinazione specificata nel termine con l'etichetta 5 è semplicemente la directory corrente (questo è tutto, ricorda, in esecuzione all'interno di qualcosa di magico chiamato OpenShift e non sul tuo computer locale).

Anche la sezione strategia – riga etichettata 6 – è simile alla prima configurazione di build. Solo che questa volta utilizzeremo nginx-image-runtime, che abbiamo già visto nella sezione ImageStream.

Infine, la riga etichettata 7 è una sezione di trigger che attiverà questa build ogni volta che cambia l'immagine react-web-app-builder.

Altrimenti, questo modello contiene una configurazione di distribuzione piuttosto standard, nonché elementi relativi a servizi e percorsi, ma non entreremo troppo nel dettaglio. Tieni presente che l'immagine che verrà distribuita è l'immagine react-web-app-runtime.

Distribuzione dell'applicazione

Ora che abbiamo esaminato il modello, vediamo come utilizzarlo per distribuire un'applicazione.

Possiamo utilizzare lo strumento client OpenShift chiamato oc per distribuire il nostro modello:

$ 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 qui sopra è un modo deliberatamente ingegneristico per trovare template./openshiftio/application.yaml.

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

Dopo che questi comandi hanno funzionato, vedremo che abbiamo due assembly:

Applicazioni moderne su OpenShift, parte 2: build concatenate

E tornando alla schermata Panoramica, vedremo il pod lanciato:

Applicazioni moderne su OpenShift, parte 2: build concatenate

Fai clic sul collegamento e verrai indirizzato alla nostra app, che è la pagina dell'app React predefinita:

Applicazioni moderne su OpenShift, parte 2: build concatenate

Aggiornamento 1

Per gli amanti di Angular abbiamo anche applicazione di esempio.

Lo schema qui è lo stesso, ad eccezione della variabile OUTPUT_DIR.

Aggiornamento 2

In questo articolo abbiamo utilizzato NGINX come server web, ma è abbastanza semplice sostituirlo con Apache, basta cambiare il template nel file Immagine NGINX su Immagine dell'Apache.

conclusione

Nella prima parte di questa serie, abbiamo mostrato come distribuire rapidamente le moderne applicazioni web sulla piattaforma OpenShift. Oggi abbiamo esaminato cosa fa un'immagine di un'app Web e come può essere combinata con un server Web puro come NGINX utilizzando build concatenate per creare una build di applicazione più pronta per la produzione. Nel prossimo e ultimo articolo di questa serie, mostreremo come eseguire un server di sviluppo per la tua 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 utilizzare una nuova immagine S2I con un'immagine del server HTTP esistente, come NGINX, utilizzando gli assembly OpenShift associati per la distribuzione di produzione;
  • Parte 3: come eseguire un server di sviluppo per la tua applicazione sulla piattaforma OpenShift e sincronizzarlo con il file system locale.

Risorse addizionali

Fonte: habr.com

Aggiungi un commento