Ciao a tutti in questo blog! Questo è il terzo post di una serie in cui mostriamo come distribuire applicazioni web moderne su Red Hat OpenShift.

Nei due post precedenti, abbiamo illustrato come distribuire applicazioni web moderne in pochi passaggi e come usare la nuova immagine S2I insieme a un'immagine di server HTTP predefinita, come NGINX, utilizzando build collegate (chained builds) per organizzare distribuzioni in produzione.
Oggi mostreremo come avviare un server di sviluppo per la nostra applicazione sulla piattaforma OpenShift e sincronizzarlo con il file system locale, e discuteremo anche di cosa siano le OpenShift Pipelines e come possano essere utilizzate come alternativa alle build collegate.
OpenShift come ambiente di sviluppo
Flusso di lavoro di sviluppo
Come già accennato nel , il processo di sviluppo tipico per le applicazioni web moderne è essenzialmente un "server di sviluppo" che monitora le modifiche nei file locali. Quando queste si verificano, viene avviata la build dell'applicazione e poi questa viene aggiornata nel browser.
Nella maggior parte dei moderni framework, un tale "server di sviluppo" è integrato negli strumenti da riga di comando corrispondenti.
Esempio locale
Per iniziare, vediamo come funziona nel caso di un'esecuzione locale delle applicazioni. Prendiamo come esempio l'applicazione tratta nei precedenti articoli, anche se praticamente gli stessi concetti di flusso di lavoro si applicano in tutti gli altri moderni framework.
Dunque, per avviare il "server di sviluppo" nel nostro esempio con React, inseriamo il seguente comando:
$ npm run start
Allora nella finestra del terminale vedremo qualcosa del genere:

E la nostra applicazione si aprirà nel browser predefinito:

Ora, se apportiamo modifiche al file, l'applicazione dovrebbe aggiornarsi nel browser.
OK, con lo sviluppo in modalità locale è tutto chiaro, ma come ottenere lo stesso su OpenShift?
Server di sviluppo su OpenShift
Se ricordate, nel , abbiamo esaminato la cosiddetta fase di esecuzione (run phase) dell'immagine S2I e abbiamo visto che per impostazione predefinita la nostra applicazione web è gestita dal modulo serve.
Tuttavia, se guardiamo più da vicino Da quell'esempio, c'è una variabile di ambiente $NPM_RUN che consente di eseguire anche il proprio comando.
Ad esempio, è possibile utilizzare il modulo nodeshift per distribuire la nostra applicazione:
$ npx nodeshift --deploy.env NPM_RUN="yarn start" --dockerImage=nodeshift/ubi8-s2i-web-app
Nota: l'esempio sopra è fornito in forma abbreviata per illustrare l'idea generale.
Qui abbiamo aggiunto alla nostra distribuzione la variabile di ambiente NPM_RUN, che comunica al processo di esecuzione di avviare il comando yarn start, il quale avvia il server di sviluppo React all'interno del nostro pod OpenShift.
Se esaminiamo il log del pod in esecuzione, troveremo circa il seguente output:

Certo, tutto ciò non avrà senso fino a quando non saremo in grado di sincronizzare il codice locale con il codice che viene anch'esso monitorato per le modifiche, ma si trova su un server remoto.
Sincronizzazione del codice remoto e locale
Fortunatamente, nodeshift facilita la sincronizzazione, e per monitorare le modifiche possiamo utilizzare il comando watch.
Quindi, dopo aver eseguito il comando per distribuire il server di sviluppo per la nostra applicazione, possiamo tranquillamente usare il seguente comando:
$ npx nodeshift watch
Di conseguenza, verrà stabilita una connessione al pod in esecuzione che abbiamo creato poco prima, attivando la sincronizzazione dei nostri file locali con il cluster remoto, e i file nel nostro sistema locale inizieranno a essere monitorati per le modifiche.
Quindi, se ora aggiorniamo il file src/App.js, il sistema reagirà a queste modifiche, copierà le modifiche sul cluster remoto e avvierà il server di sviluppo, il quale aggiornerà quindi la nostra applicazione nel browser.
Per completezza, mostriamo come appaiono questi comandi nella loro interezza:
$ npx nodeshift --strictSSL=false --dockerImage=nodeshift/ubi8-s2i-web-app --build.env YARN_ENABLED=true --expose --deploy.env NPM_RUN="yarn start" --deploy.port 3000
$ npx nodeshift watch --strictSSL=false
Il comando watch è un'astrazione sopra il comando oc rsync, per maggiori informazioni su come funziona, si può leggere .
Questo è stato un esempio per React, ma la stessa metodologia può essere utilizzata anche con altri framework, basta impostare la variabile di ambiente NPM_RUN nel modo corretto.
Pipeline di OpenShift Pipelines

Successivamente parleremo di uno strumento chiamato OpenShift Pipelines e di come può essere utilizzato come alternativa alle build concatenate.
Che cos'è OpenShift Pipelines
OpenShift Pipelines è un sistema CI/CD basato sul cloud per l'integrazione continua e la consegna, progettato per organizzare pipeline utilizzando Tekton. Tekton è un framework CI/CD nativo Kubernetes flessibile e open source, che consente di automatizzare il deployment su varie piattaforme (Kubernetes, serverless, macchine virtuali, ecc.) astrarre rispetto al livello sottostante.
Per capire questo articolo è necessaria una certa familiarità con i Pipelines, quindi ti consigliamo vivamente di iniziare consultando .
Configurazione dell'ambiente di lavoro
Per sperimentare con gli esempi di questo articolo, devi prima preparare l'ambiente di lavoro:
- Installa e configura un cluster OpenShift 4. Nei nostri esempi utilizziamo CodeReady Containers (CRD), le istruzioni per l'installazione possono essere trovate .
- Una volta che il cluster è pronto, sarà necessario installare il Pipeline Operator. Non preoccuparti, è facile, le istruzioni per l'installazione .
- Scarica (tkn) .
- Esegui lo strumento da riga di comando create-react-app per creare un'applicazione che verrà poi distribuita (si tratta di un'app semplice ).
- (Facoltativo) Clona il repository per eseguire localmente l'esempio dell'app con il comando npm install e poi npm start.
Nel repository dell'applicazione ci sarà anche una cartella k8s, dove si troveranno i file YAML di Kubernetes/OpenShift utilizzati per il deployment dell'applicazione. Ci saranno Tasks, ClusterTasks, Resources e Pipelines che creeremo in questo .
Iniziamo
Per prima cosa, per il nostro esempio, è necessario creare un nuovo progetto nel cluster OpenShift. Chiamiamo questo progetto webapp-pipeline e lo creiamo con il seguente comando:
$ oc new-project webapp-pipeline
In seguito questo nome del progetto apparirà nel codice, quindi, se decidi di dargli un nome diverso, non dimenticare di modificare di conseguenza il codice degli esempi. Da questo punto in poi procederemo dal basso verso l'alto: prima creeremo tutti i componenti della pipeline e solo successivamente la pipeline stessa.
Quindi, prima di tutto…
Tasks
Creeremo un paio di attività (tasks) che poi aiuteranno a implementare l'applicazione nel nostro pipeline. La prima attività – apply_manifests_task – si occupa dell'applicazione dei YAML dei risorse Kubernetes (service, deployment e route) che si trovano nella cartella k8s della nostra applicazione. La seconda attività – update_deployment_task – è responsabile dell'aggiornamento dell'immagine già implementata a quella creata dal nostro pipeline.
Non preoccuparti se non è ancora molto chiaro. In realtà, queste attività sono una sorta di utilità e le esamineremo più in dettaglio tra poco. Ma per ora, creiamole semplicemente:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/update_deployment_task.yaml
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/apply_manifests_task.yaml
Poi, usando il comando tkn CLI, verifichiamo che le attività siano state create:
$ tkn task ls
NAME AGE
apply-manifests 1 minute ago
update-deployment 1 minute ago
Nota: queste sono attività locali del tuo progetto attuale.
Attività cluster (Cluster tasks)
Le attività cluster sono fondamentalmente le stesse delle normali attività. Cioè, sono una collezione riutilizzabile di passaggi che vengono combinati in vari modi quando si esegue una specifica attività. La differenza è che un'attività cluster è disponibile ovunque all'interno del cluster. Per vedere l'elenco delle attività cluster, che vengono create automaticamente quando si aggiunge il Pipeline Operator, utilizziamo di nuovo il comando tkn CLI:
$ tkn clustertask ls
NAME AGE
buildah 1 day ago
buildah-v0-10-0 1 day ago
jib-maven 1 day ago
kn 1 day ago
maven 1 day ago
openshift-client 1 day ago
openshift-client-v0-10-0 1 day ago
s2i 1 day ago
s2i-go 1 day ago
s2i-go-v0-10-0 1 day ago
s2i-java-11 1 day ago
s2i-java-11-v0-10-0 1 day ago
s2i-java-8 1 day ago
s2i-java-8-v0-10-0 1 day ago
s2i-nodejs 1 day ago
s2i-nodejs-v0-10-0 1 day ago
s2i-perl 1 day ago
s2i-perl-v0-10-0 1 day ago
s2i-php 1 day ago
s2i-php-v0-10-0 1 day ago
s2i-python-3 1 day ago
s2i-python-3-v0-10-0 1 day ago
s2i-ruby 1 day ago
s2i-ruby-v0-10-0 1 day ago
s2i-v0-10-0 1 day ago
Ora creiamo due attività cluster. La prima genererà un'immagine S2I e la invierà al registry interno di OpenShift; la seconda eseguirà la costruzione della nostra immagine basata su NGINX, utilizzando come contenuto l'applicazione già costruita da noi.
Creiamo e inviamo l'immagine
Nella creazione della prima attività, ripeteremo ciò che abbiamo già fatto nell'articolo precedente sulle build collegate. Ricordiamo che abbiamo utilizzato l'immagine S2I (ubi8-s2i-web-app) per "compilare" la nostra applicazione, ottenendo infine un'immagine memorizzata nel registro interno di OpenShift. Ora utilizzeremo questa immagine S2I dell'app web per creare un DockerFile per la nostra applicazione, e quindi utilizzeremo Buildah per eseguire una compilazione reale e inviare l'immagine risultante al registro interno di OpenShift, poiché è esattamente ciò che OpenShift fa quando distribuisci le tue applicazioni utilizzando NodeShift.
Ti chiedi da dove abbiamo preso tutte queste informazioni? Da , l'abbiamo semplicemente copiata e adattata a noi.
Ora creiamo l'attività cluster s2i-web-app:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/s2i-web-app-task.yaml
Non entreremo nei dettagli, ma ci fermeremo sul parametro OUTPUT_DIR:
params:
- name: OUTPUT_DIR
description: La posizione della directory di output della build
default: build
Per impostazione predefinita, questo parametro è uguale a build, ed è lì che React colloca il contenuto compilato. In altri framework si utilizzano percorsi diversi, ad esempio in Ember si usa dist. L'output della nostra prima attività cluster sarà un'immagine contenente l'HTML, il JavaScript e il CSS che abbiamo compilato.
Compiliamo un'immagine basata su NGINX
Per quanto riguarda la nostra seconda attività cluster, questa deve costruire un'immagine basata su NGINX, utilizzando il contenuto della nostra applicazione già compilata. In sostanza, questa è la parte della sezione precedente in cui abbiamo esaminato le build collegate.
A tal fine, proprio come sopra, creeremo l'attività cluster webapp-build-runtime:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/webapp-build-runtime-task.yaml
Se guardiamo il codice di queste attività cluster, vediamo che non viene specificato il repository Git con cui stiamo lavorando, né i nomi delle immagini che stiamo creando. Stiamo solo specificando cosa vogliamo passare in Git, o un'immagine in cui deve essere prodotto l'immagine finale. È per questo che queste attività cluster possono essere riutilizzate anche quando si lavora con altre applicazioni.
E qui passiamo elegantemente al punto successivo…
Risorse
Quindi, poiché, come abbiamo appena detto, i task di cluster devono essere il più generali possibile, dobbiamo creare risorse che saranno utilizzate in input (repository Git) e in output (immagini finali). La prima risorsa di cui abbiamo bisogno è Git, dove si trova la nostra applicazione, qualcosa del genere:
# This resource is the location of the git repo with the web application source
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: web-application-repo
spec:
type: git
params:
- name: url
value: https://github.com/nodeshift-starters/react-pipeline-example
- name: revision
value: master
Qui PipelineResource è di tipo git. La chiave url nella sezione params punta a un repository specifico e imposta il branch master (questo è facoltativo, ma lo scriviamo per completezza).
Ora dobbiamo creare una risorsa per l'immagine, dove saranno salvati i risultati dell'esecuzione del task s2i-web-app, si fa così:
# This resource is the result of running "npm run build", the resulting built files will be located in /opt/app-root/output
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: built-web-application-image
spec:
type: image
params:
- name: url
value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-application:latest
Qui PipelineResource è di tipo image, e il valore del parametro url punta al registro delle immagini interno di OpenShift, specificamente a quello che si trova nello spazio dei nomi webapp-pipeline. Non dimenticare di cambiare questo parametro se utilizzi un altro spazio dei nomi.
E, infine, l'ultima risorsa di cui avremo bisogno avrà anch'essa il tipo image e sarà l'immagine finale di NGINX, che verrà utilizzata durante il deployment:
# This resource is the image that will be just the static html, css, js files being run with nginx
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: runtime-web-application-image
spec:
type: image
params:
- name: url
value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtime-web-application:latest
E ancora, nota che questa risorsa salva l'immagine nel registro interno di OpenShift nello spazio dei nomi webapp-pipeline.
Per creare tutte queste risorse in una volta, utilizziamo il comando create:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/resources/resource.yaml
Puoi controllare che le risorse siano state create in questo modo:
$ tkn resource ls
Pipeline del pipeline
Ora che abbiamo tutti gli elementi necessari, creiamo il pipeline utilizzando il seguente comando:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/pipelines/build-and-deploy-react.yaml
Ma prima di eseguire questo comando, diamo un'occhiata a questi elementi. Il primo è il nome:
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: build-and-deploy-react
Poi, nella sezione spec vediamo l'indicazione delle risorse che abbiamo creato in precedenza:
spec:
resources:
- name: web-application-repo
type: git
- name: built-web-application-image
type: image
- name: runtime-web-application-image
type: image
Successivamente, creiamo i task che il nostro pipeline deve eseguire. Per prima cosa deve eseguire il task s2i-web-app che abbiamo già creato:
tasks:
- name: build-web-application
taskRef:
name: s2i-web-app
kind: ClusterTask
Questo task prende i parametri di input (risorsa gir) e di output (risorsa built-web-application-image). Inoltre, le passiamo un parametro speciale per evitare la verifica di TLS, poiché utilizziamo certificati self-signed:
risorse:
input:
- nome: sorgente
risorsa: web-application-repo
output:
- nome: immagine
risorsa: built-web-application-image
parametri:
- nome: TLSVERIFY
valore: "false"
Il prossimo compito è quasi identico, solo che qui viene chiamato il compito cluster webapp-build-runtime già creato da noi:
nome: build-runtime-image
taskRef:
nome: webapp-build-runtime
tipo: ClusterTask
Come per il compito precedente, stiamo passando una risorsa, ma ora si tratta di built-web-application-image (l'output del nostro compito precedente). E come output impostiamo di nuovo un'immagine. Poiché questo compito deve essere eseguito dopo il precedente, aggiungiamo il campo runAfter:
risorse:
input:
- nome: immagine
risorsa: built-web-application-image
output:
- nome: immagine
risorsa: runtime-web-application-image
parametri:
- nome: TLSVERIFY
valore: "false"
runAfter:
- build-web-application
I prossimi due compiti sono responsabili dell'applicazione dei file YAML del servizio, del percorso e del deployment, che si trovano nella cartella k8s della nostra applicazione web, e anche di aggiornare questo deployment quando vengono creati nuovi modelli. Questi due compiti cluster li abbiamo definiti all'inizio dell'articolo.
Avvio della pipeline
Quindi, tutte le parti della nostra pipeline sono state create, e la avvieremo con il seguente comando:
$ tkn pipeline start build-and-deploy-react
A questo punto, la riga di comando viene utilizzata in modalità interattiva e bisogna selezionare le risorse corrispondenti in risposta a ciascuna sua richiesta: per la risorsa git scegliamo web-application-repo, quindi per la risorsa della prima immagine – built-web-application-image, e infine per la risorsa della seconda immagine – runtime-web-application-image:
? Choose the git resource to use for web-application-repo: web-application-repo (https://github.com/nodeshift-starters/react-pipeline-example)
? Choose the image resource to use for built-web-application-image: built-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-
application:latest)
? Choose the image resource to use for runtime-web-application-image: runtime-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtim
e-web-application:latest)
Pipelinerun started: build-and-deploy-react-run-4xwsr
Ora controlliamo lo stato della pipeline con il seguente comando:
$ tkn pipeline logs -f
Dopo che la pipeline è stata avviata e l'applicazione è stata distribuita, richiediamo il percorso pubblicato con il seguente comando:
$ oc get route react-pipeline-example --template='http://{{.spec.host}}'
Per una maggiore visibilità, possiamo visualizzare la nostra pipeline in modalità Developer nella web console nella sezione Pipelines, come mostrato nella Fig. 1.

Fig.1. Panoramica delle pipeline in esecuzione.
Cliccando sulla pipeline in esecuzione si visualizzano ulteriori informazioni, come mostrato nella Fig.2.

Fig. 2. Ulteriori informazioni sulla pipeline.
Dopo ulteriori informazioni, possiamo visualizzare le applicazioni in esecuzione nella vista Topology, come mostrato nella Fig.3.

Fig 3. Pod in esecuzione.
Cliccando sul cerchio nell'angolo in alto a destra dell'icona si apre la nostra applicazione, come mostrato nella Fig.4.

Fig. 4. Applicazione React in esecuzione.
Conclusione
Quindi, abbiamo mostrato come avviare un server di sviluppo su OpenShift per la propria applicazione e sincronizzarlo con il sistema di file locale. Abbiamo anche esaminato come simulare un modello di chained-build utilizzando OpenShift Pipelines. Tutti i codici di esempio di questo articolo possono essere trovati .
Risorse aggiuntive (EN)
- Ebook gratuito
- Altri articoli su sul sito Red Hat
Annunci di prossimi webinar
Iniziamo una serie di webinar del venerdì sull'esperienza nativa di utilizzo di Red Hat OpenShift Container Platform e Kubernetes:
Fonte: habr.com
