Red Hat Pipelines con Vite
Published: 2023-10-03 14:24:01

---
title: Red Hat Pipelines con Vite
published: true
date: 2023-04-06 00:00:00 UTC
tags: 
canonical_url: 
---

# Intro

OpenShift offre diverse opzioni per creare e distribuire applicazioni e tra questi ci sono:

- **templates** : si tratta del modo più semplice per descrivere tutti gli oggetti necessari per rilasciare effettivamente un’applicazione in OpenShift (tipicamente, ma non esclusivamente, DeploymentConfig, Service, Route e forse BuildConfig) e avere il pieno controllo sulla loro configurazione;
- **Pipeline Jenkins** : sì, puoi usare il buon vecchio Jenkins per implementare il tuo processo CI/CD su OpenShift.

In questo caso, vogliamo però realizzare una pipeline che permetta di utilizzare del codice sorgente disponibile su un repository qualsiasi e di avviare il deploy dell’applicazione all’interno del cluster in maniera del tutto_automatica_.

Per farlo, è sufficiente utilizzare le [Red Hat OpenShift Pipelines](https://cloud.redhat.com/blog/introducing-openshift-pipelines), uno strumento potente tanto quanto complesso, che dietro le quinte utilizza Tekton, uno dei progetti open source più utilizzati in ambito CI/CD.

Andiamo per gradi: lo scenario per ripetere l’esperimento che verrà mostrato e che andremo a descrivere è abbastanza semplice:

- Il codice sorgente per l’applicazione si trova in un repository [GitHub](https://github.com/) pubblico (o privato);
- L’immagine del container creata durante il processo di compilazione viene inviata a un registry di immagini (come[Quay](https://quay.io/)) pubblico (o privato);
- Disponiamo di un cluster OpenShift attivo e funzionante da qualche parte, pronto per eseguire l’applicazione. Se non hai cluster a disposizione, puoi sempre utilizzare [OpenShift Local](https://developers.redhat.com/products/openshift-local/overview)!

Per il caso di esempio, useremo un’applicazione scritta in [Vite.js](https://vitejs.dev/) (il repository è in fondo nelle risorse utili), ma è possibile utilizzare qualsiasi altro esempio che abbia un Dockerfile valido e utilizzabile su OpenShift!

# Cos’è Tekton

Come descritto nel sito web del progetto open source [Tekton](https://tekton.dev/):

> Tekton è un framework open source potente e flessibile per la creazione di sistemi CI/CD, che consente agli sviluppatori di creare, testare e distribuire tra provider cloud e sistemi on-premise.

[Red Hat OpenShift Pipelines](https://docs.openshift.com/container-platform/4.11/cicd/pipelines/understanding-openshift-pipelines.html) è una soluzione CI/CD cloud-native completamente basata sulle risorse Kubernetes che utilizza i concetti e gli elementi costitutivi di Tekton per automatizzare le distribuzioni su più piattaforme astraendo i dettagli d’implementazione sottostanti. Tekton introduce una serie di Custom Resource Definitions (CRD) standard per la definizione di pipeline CI/CD portabili tra le distribuzioni Kubernetes.

# Concetti

## Concetti che _definiscono_ la pipeline

- _Pipeline_: la definizione della pipeline e le attività che dovrebbe svolgere
- _Task_: un numero di passaggi riutilizzabile e liberamente accoppiato che esegue un’attività specifica (ad esempio, la creazione di un’immagine del container)

## Concetti che **gestiscono** la pipeline

- _PipelineRun_: l’esecuzione e il risultato dell’esecuzione di un’istanza di una pipeline, che include una serie di TaskRun
- _TaskRun_: l’esecuzione e il risultato dell’esecuzione di un’istanza di un Task

## Concetto per _aiutare_ la pipeline a funzionare correttamente

- _PipelineResource_: risorse di questo tipo servono a fornire gli strumenti per poter lavorare e che sono fondamentali lungo tutto il flusso di lavoro, per esempio, un repository Git o un’immagine da utilizzare.

# Installazione dell’Operator

Prima ancora di pensare di utilizzare il framework OpenShift Pipelines, è necessario ovviamente installarlo nel  
cluster; Red Hat fornisce un operatore per semplificare il processo di installazione.

Andiamo nella console Web di OpenShift e, attraverso la prospettiva amministrativa, seleziona _Operators_ →_OperatorHub_ dal menu di navigazione a sinistra e quindi cerca l’operatore **Red Hat Pipelines** ; a questo punto, fai clic sul riquadro e quindi sul successivo pulsante _Installa_.

![](https://theredcode.it/img/pipelines1.png)

Manteniamo le impostazioni predefinite e proseguiamo con l’installazione, attendiamo che sia completata e vedremo una nuova voce nel menù di sinistra della prospettiva Developer, relativa alle Pipelines:

![](https://theredcode.it/img/pipeline2.png)

Con questi pochi semplici passaggi abbiamo installato OpenShift Pipelines e ora possiamo procedere a utilizzare questo framework basato su Tekton per creare una pipeline per costruire e distribuire applicazioni, ma sii paziente: abbiamo ancora bisogno di un paio di passaggi preliminari per mettere le basi.

# Configurazione di registry per le immagini e per il codice sorgente

L’immagine, una volta che sarà stata generata a partire dal codice sorgente, verrà pushata sia nel registry interno di OpenShift, sia su uno esterno, come forma di backup e/o rilascio: questo vuol dire che sarà necessario accedervi dal cluster con i giusti permessi di scrittura e lettura.

Nel caso di [Quay.io](https://quay.io/), è sufficiente creare un account (gratuito), creare un repository e poi aggiungere un robot account ai permessi con i permessi di lettura e scrittura.

![](https://theredcode.it/img/quayio-robotaccount.png)

A questo punto, cliccando sull’account appena creato, selezioniamo la sezione relativa a Kubernetes e scarichiamo il Secret che contiene il _pull secret_ che permette all’utente fittizio di collegarsi al repository e di operare:

![](https://theredcode.it/img/quayio-robotaccount-secret.png)

Prima di eseguire le pipeline OpenShift, dobbiamo assicurarci che siano disponibili le autorizzazioni corrette per accedere al codice e al registry che ospita l’immagine, e il modo per farlo è configurare un ServiceAccount su OpenShift in modo appropriato e collegare i Secret contenenti le informazioni giuste.

Partiamo dal codice sorgente: se si trova su un repository pubblico, non dobbiamo compiere ulteriori passaggi, e possiamo proseguire. Se invece il repository è privato, possiamo creare un Secret che ci permetta di inserire le informazioni per accedere al codice con il seguente comando:

```
oc create secret generic <YOUR_GITHUB_SECRET_NAME> \
 --from-literal=username=<YOUR_GITHUB_USERNAME> \
 --from-literal=password=<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN> \
 --type=kubernetes.io/basic-auth

#oc annotate secret <YOUR_GITHUB_SECRET_NAME> "tekton.dev/git-0=https://github.com"

```

Stesso discorso vale per il registry che ospiterà l’immagine: se il repository è pubblico, possiamo proseguire, altrimenti dovremo creare un Secret che ci permetta di inserire le informazioni per accedere in lettura e scrittura al registry con il seguente comando:

```
oc create secret docker-registry <YOUR_REGISTRY_SECRET_NAME> \
 --docker-server=<YOUR_REGISTRY_URL> \
 --docker-username=<YOUR_REGISTRY_USERNAME> \
 --docker-password=<YOUR_REGISTRY_PASSWORD>

```

# Aggiungere i permessi

Proseguiamo con il ServiceAccount: quando installi l’operatore, viene creato un ServiceAccount chiamato _pipeline_ per eseguire correttamente le attività e le pipeline di Tekton, quindi gli concederemo le autorizzazioni appropriate.

Aggiungiamo quindi i permessi che permetteranno al ServiceAccount _pipeline_ di operare: con il primo comando, specifichiamo che questo “utente” potrà gestire e accedere a tutte le risorse e i container presenti nei nodi computazionali. Chiaramente, si tratta di un permesso piuttosto “ampio”, quindi dovrebbe essere utilizzato solo per attività seguite da chi amministra il cluster.

Il secondo comando permette di modificare le risorse nel progetto, ma solamente quelle applicative: non potrà quindi vedere o modificare i ruoli degli utenti o dei gruppi, e questo gli servirà per poter avviare Deployment, Service e molto altro.

Con il terzo e il quarto comando andiamo a far riferimento al Secret creato in precedenza relativo al robot account del registry e lo colleghiamo al Serviceaccount _pipeline_, così che abbia le informazioni per agire con quel repository.

```
oc adm policy add-scc-to-user privileged -z pipeline

oc adm policy add-role-to-user edit -z pipeline

oc secrets link pipeline <YOUR_REGISTRY_SECRET_NAME>

oc secrets link default <YOUR_REGISTRY_SECRET_NAME> --for pull

```

È necessario un ultimo passaggio preparatorio prima di poter effettivamente eseguire le pipeline OpenShift.

In Tekton ogni Task viene eseguito nel proprio container quindi, per consentire a diversi Task di condividere i dati (ad esempio: un’attività recupera il codice sorgente da un repository e un’altra attività crea l’applicazione dal codice sorgente), dobbiamo inserire un volume nell’equazione.

Andiamo quindi a definire una PVC utilizzando un oggetto simile a quello seguente, anche molto dipende dalla StorageClass e in generale dal provisioner utilizzato:

```
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: pipeline-build
spec:
 accessModes:
 - ReadWriteOnce
 resources:
 requests:
 storage: 500Mi

```

# Definizione della pipeline

Dopo aver completato questi step di preparazione, ora possiamo creare la nostra pipeline. Puoi dare un’occhiata all’esempio nel file seguente: questo descrive quattro passaggi, eseguite in sequenza, che servono per ottenere il codice sorgente da un repository GitHub, creare un’immagine del container a partire da un Dockerfile, eseguirne il  
push in un registry, avviare il deploy su OpenShift e infine esporre l’applicazione con una route per l’accesso esterno.

```
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
 name: vite-deploy-example
spec:
 workspaces:
 - name: source
 steps:
 - name: ls
 image: image-registry.openshift-image-registry.svc:5000/openshift/cli:latest
 workingDir: /workspace/source
 command: ["/bin/bash", "-c"]
 args:
 - |-
 echo Listing files
 pwd
 ls -la
 echo -----------------------------------
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
 name: vite-with-docker
spec:
 type: git
 params:
 - name: url
 value: https://github.com/serenasensini/Vite-with-Docker
 - name: revision
 value: master
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
 name: vite-example-image
spec:
 type: image
 params:
 - name: url
 value: quay.io/ser_sensini/vite-example:0.0.1-build
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
 name: vite-example
spec:
 params:
 - default: vite-example
 description: name of the application to deploy
 name: APP_NAME
 type: string
 - default: https://github.com/serenasensini/Vite-with-Docker
 description: url of the git repo for the code of deployment
 name: GIT_REPO
 type: string
 - default: main
 description: revision to be used from repo of the code for deployment
 name: GIT_REVISION
 type: string
 - default: quay.io/ser_sensini/vite-example:0.0.1-build
 description: image to be built from the code
 name: IMAGE
 type: string
 - default: '5173'
 description: Port on the container that the service should direct traffic to.
 name: SERVICE_PORT
 type: string
 tasks:
 - name: fetch-repository
 params:
 - name: url
 value: $(params.GIT_REPO)
 - name: revision
 value: $(params.GIT_REVISION)
 - name: subdirectory
 value: ''
 - name: deleteExisting
 value: 'true'
 taskRef:
 kind: ClusterTask
 name: git-clone
 workspaces:
 - name: output
 workspace: workspace
 - name: build-image
 params:
 - name: TLSVERIFY
 value: 'false'
 - name: IMAGE
 value: $(params.IMAGE)
 runAfter:
 - fetch-repository
 taskRef:
 kind: ClusterTask
 name: buildah
 workspaces:
 - name: source
 workspace: workspace
 - name: deploy
 params:
 - name: SCRIPT
 value: >-
 oc new-app --name=$(params.APP_NAME) --image=$(params.IMAGE)
 --as-deployment-config
 runAfter:
 - build-image
 taskRef:
 kind: ClusterTask
 name: openshift-client
 - name: expose-route
 params:
 - name: SCRIPT
 value: oc expose service/$(params.APP_NAME) --port $(params.SERVICE_PORT)
 runAfter:
 - deploy
 taskRef:
 kind: ClusterTask
 name: openshift-client
 workspaces:
 - name: workspace

```

Scaviamo un po’ nell’anatomia della pipeline; all’inizio della sezione del codice, ci sono 2 aree:

- _workspace_, che definisce un’area di lavoro che può essere associata a uno storage permanente una volta eseguita la pipeline;
- _params_, dove sono definiti tutti i parametri che possono essere accettati dalla pipeline, con i loro valori di default, se presenti.

```
---
# ...
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
 name: vite-example
spec:
 params:
 ...
 tasks:
 ...
 workspaces:
 - name: workspace

```

Analizziamo i Task uno a uno: quello chiamato _fetch-repository_, che puoi trovare nel codice sottostante, è responsabile della clonazione del repository del codice sorgente; ha i propri parametri, il cui significato dovrebbe essere abbastanza chiaro e una sezione _workspaces_ che lega l’output alla cartella che è stato definita in precedenza tramite lo storage. Da notare inoltre che l’attività fa riferimento al clone **git ClusterTask** : i ClusterTask sono attività comunemente utili a livello di cluster implementate e rese disponibili da Red Hat OpenShift, in modo che tu possa semplicemente riutilizzarle senza reinventare la ruota.

```
...
tasks:
 - name: fetch-repository
 params:
 - name: url
 value: $(params.GIT_REPO)
 - name: revision
 value: $(params.GIT_REVISION)
 - name: subdirectory
 value: ''
 - name: deleteExisting
 value: 'true'
 taskRef:
 kind: ClusterTask
 name: git-clone
 workspaces:
 - name: output
 workspace: workspace
...

```

Il Task chiamato _build-image_ è responsabile della creazione e del push dell’immagine nel registry, in base al valore del parametro $(params.IMAGE); nel caso di esempio questo è [quay.io/ser\_sensini/vite-example:0.0.1-build](quay.io/ser_sensini/vite-example:0.0.1-build), quindi cercherà di eseguire il push al registry di Quay.io e creare un’immagine con il nome e il tag specificato.

Si basa su un ClusterTask che usa _buildah_, uno strumento molto simile a [Podman](https://theredcode.it/podman/cos-e-podman), che costruisce l’immagine sulla base di un Dockerfile; notare la sezione _runAfter_ che indica alla pipeline di eseguire l’attività solo dopo il completamento dell’attività _fetch-repository_.

```
...
tasks:
 - name: build-image
 params:
 - name: TLSVERIFY
 value: 'false'
 - name: IMAGE
 value: $(params.IMAGE)
 runAfter:
 - fetch-repository
 taskRef:
 kind: ClusterTask
 name: buildah
 workspaces:
 - name: source
 workspace: workspace
...

```

Il Task _deploy_ è responsabile del rilascio e dell’avvio dell’immagine, creata nel passaggio precedente, in OpenShift. Si noti che è basato su un altro ClusterTask, _openshift-client_, che consente di utilizzare la riga di comando _oc_ all’interno della pipeline; questo serve per permette l’utilizzo del comando _oc new-app_, che andrà a creare un Pod con il relativo controller DeploymentConfig a partire dall’immagine specificata.

```
tasks:
 - name: deploy
 params:
 - name: SCRIPT
 value: >-
 oc new-app --name=$(params.APP_NAME) --image=$(params.IMAGE)
 --as-deployment-config
 runAfter:
 - build-image
 taskRef:
 kind: ClusterTask
 name: openshift-client

```

Infine l’attività _expose-route_ è responsabile di creare una Route in OpenShift in modo che l’applicazione sia accessibile tramite browser con un protocollo HTTP.

```
tasks:
 - name: expose-route
 params:
 - name: SCRIPT
 value: oc expose service/$(params.APP_NAME) --port $(params.SERVICE_PORT)
 runAfter:
 - deploy
 taskRef:
 kind: ClusterTask
 name: openshift-client

```

Ora che abbiamo progettato e implementato una pipeline OpenShift, probabilmente vorremo utilizzarla, e possiamo farlo in un paio di modi: eseguire una pipeline tramite la riga di comando con la CLI di Tekton Pipelines o eseguire una pipeline utilizzando la GUI di OpenShift.

Rimaniamo sulla console di OpenShift, e selezioniamo la voce Pipelines dal menù di sinistra: una volta importato il file precedente, vedremo all’interno dell’elenco una nuova voce, relativa a quanto definito. Clicchiamo sul dettaglio della pipeline e clicchiamo su “Actions”, in alto a destra: questo ci permetterà di avviare la pipeline ed eseguire i diversi step previsti, che verranno mostrati con il relativo stato sul dettaglio di sinistra.

![](https://theredcode.it/img/pipeline3.png)

Avviando la pipeline, verrà creato un oggetto PipelineRun, che comportano una serie di TaskRun: ognuno di questi corrisponde a ogni Task descritto all’interno della Pipeline complessiva. Clicchiamo su “Start” tramite Actions e compiliamo i diversi campi, che corrispondono ai parametri definiti nella Pipeline: non ci dimentichiamo di associare al workspace il volume creato in precedenza, per permettere ai diversi Task di condividere i dati prodotti:

![](https://theredcode.it/img/pipeline4.png)

Per monitorare lo stato di esecuzione dei diversi Task, è possibile cliccare sui singoli riquadri di dettagli e vedere i log relativi ai singoli container.

![](https://theredcode.it/img/pipeline5.png)

Al termine dell’esecuzione, troveremo l’applicazione nella topologia del progetto, e potremo accedervi tramite la Route:

![](https://theredcode.it/img/vite.png)

Questo naturalmente è un esempio molto semplice, ma può essere esteso ad altri casi d’uso, che coinvolgono Task più complessi, piuttosto che un’applicazione diversa o un tipo di risorse differenti; questo articolo vuole essere solo una panoramica di cosa fare per utilizzare il framework OpenShift Pipelines per costruire una pipeline!

# Risorse utili

- [Codice sorgente dell’applicazione Vite](https://github.com/serenasensini/Vite-with-Docker)
- [Docker](https://amzn.to/3cSVvUG) - per cominciare bene con Docker e Kubernetes