Questo post è scritto perché i nostri collaboratori hanno avuto molte conversazioni con i clienti sullo sviluppo di applicazioni su Kubernetes e sulle specificità di tale sviluppo su OpenShift.

Di solito iniziamo con la tesi che Kubernetes è semplicemente Kubernetes, mentre OpenShift è già una piattaforma Kubernetes, come Microsoft AKS o Amazon EKS. Ognuna di queste piattaforme ha i propri vantaggi, orientati a un pubblico specifico. Da lì, la conversazione si sposta su un confronto tra i punti di forza e di debolezza delle diverse piattaforme.
In generale, volevamo scrivere questo post con la conclusione del tipo «Ascoltate, non importa dove eseguire il codice, su OpenShift o su AKS, su EKS, su qualche Kubernetes personalizzato, sì, su qualsiasi Kubernetes (per brevità lo chiameremo KUK) – è davvero semplice, sia lì che là».
Poi avevamo pianificato di prendere il semplice «Hello World» e con il suo esempio mostrare cosa hanno in comune e quali sono le differenze tra KUK e Red Hat OpenShift Container Platform (d'ora in poi, OCP o semplicemente OpenShift).
Tuttavia, durante la scrittura di questo post, ci siamo resi conto che ci siamo abituati talmente tanto a utilizzare OpenShift che non ci rendiamo conto di come sia cresciuto e si sia trasformato in una piattaforma straordinaria, diventando molto più di un semplice distributore di Kubernetes. Abbiamo dato per scontata la maturità e la semplicità di OpenShift, trascurando la sua grandezza.
In generale, è giunto il momento di un sincero ravvedimento, e ora confronteremo passo passo l'implementazione del nostro «Hello World» su KUK e su OpenShift, e lo faremo nel modo più oggettivo possibile (tranne per il fatto di mostrare talvolta un'opinione personale sull'argomento). Se siete interessati a un'opinione puramente soggettiva su questo argomento, potete leggerla . In questo post ci atteneremo ai fatti e solo ai fatti.
Cluster
Quindi, per il nostro «Hello World» abbiamo bisogno di cluster. Diremo subito «no» a qualsiasi cloud pubblico, per non pagare server, registry, rete, trasferimenti di dati, ecc. Pertanto, scegliamo un semplice cluster a nodo singolo su (per KUK) e (per il cluster OpenShift). Entrambe queste opzioni sono davvero semplici da installare, ma richiederanno abbastanza risorse sul vostro laptop.

Costruzione su KUK
Bene, iniziamo.
Passo 1 – costruiamo la nostra immagine del contenitore
Iniziamo con il distribuire il nostro «Hello World» su minikube. Per questo avremo bisogno di:
- 1. Docker installato.
- 2. Git installato.
- 3. Maven installato (in realtà in questo progetto si utilizza il binario mvnw, quindi si può fare a meno di questo).
- 4. Il sorgente vero e proprio, ovvero una copia del repository
Per prima cosa dobbiamo creare un progetto Quarkus. Non preoccupatevi se non avete mai lavorato con il sito Quarkus.io: è facile. Basta scegliere i componenti che si desidera utilizzare nel progetto (RestEasy, Hibernate, Amazon SQS, Camel, ecc.), e poi Quarkus configurerà da solo, senza alcun vostro intervento, l’archetipo Maven e pubblicherà tutto su GitHub. In altre parole, basta un clic del mouse, ed è fatto. Questo è ciò che amiamo di Quarkus.

Il modo più semplice per costruire il nostro 'Hello World' in un'immagine container è utilizzare le estensioni quarkus-maven per Docker, che faranno tutto il lavoro necessario. Con l'arrivo di Quarkus, questo è diventato davvero facile e semplice: aggiungete l'estensione container-image-docker e potrete creare le immagini con i comandi Maven.
./mvnw quarkus:add-extension -Dextensions="container-image-docker"
E infine, eseguiamo la costruzione della nostra immagine utilizzando Maven. Di conseguenza, il nostro codice sorgente si trasforma in un'immagine container già pronta, che può essere eseguita nell'ambiente di esecuzione del container.

./mvnw -X clean package -Dquarkus.container-image.build=true
Ecco, quindi, tutto. Ora potete avviare il container con il comando docker run, mappando il nostro servizio sulla porta 8080, in modo che possa essere raggiunto.
docker run -i --rm -p 8080:8080 gcolman/quarkus-hello-world

Dopo che l'istanza del container è stata avviata, resta solo da controllare con il comando curl che il nostro servizio funzioni:
![]()
Quindi, tutto funziona, ed è stato davvero facile e semplice.
Passo 2 – inviamo il nostro container al repository di immagini container
Finora, l’immagine che abbiamo creato è memorizzata localmente, nel nostro archivio container locale. Se vogliamo utilizzare quest’immagine nel nostro ambiente Kubernetes, dobbiamo conservarla in un altro repository. In Kubernetes non ci sono queste funzioni, quindi utilizzeremo Docker Hub. Perché, prima di tutto, è gratuito, e in secondo luogo, (quasi) tutti lo fanno.
È anche molto semplice, ed è necessario solo avere un account su Docker Hub.
Quindi, facciamo il login su Docker Hub e inviamo la nostra immagine.

Passo 3 – avviamo Kubernetes
Ci sono molti modi per assemblare la configurazione Kubernetes per eseguire il nostro 'Hello World', ma useremo il metodo più semplice, proprio perché siamo così...
Per prima cosa, avviamo il cluster minikube:
minikube start
Passaggio 4 – distribuiamo la nostra immagine del contenitore
Ora dobbiamo convertire il nostro codice e l'immagine del contenitore nelle configurazioni di kubernetes. In altre parole, abbiamo bisogno di una definizione di pod e deployment che faccia riferimento alla nostra immagine del contenitore su dockerhub. Uno dei modi più semplici per farlo è eseguire il comando create deployment, specificando la nostra immagine:

kubectl create deployment hello-quarkus --image=gcolman/quarkus-hello-world:1.0.0-SNAPSHOT
Con questo comando abbiamo detto al nostro K8S di creare una configurazione di deployment che deve contenere la specifica del pod per la nostra immagine del contenitore. Questo comando applicherà anche questa configurazione al nostro cluster minikube, e creerà un deployment che scaricherà la nostra immagine del contenitore e avvierà un pod nel cluster.
Passaggio 5 – apriamo l'accesso al nostro servizio
Ora che abbiamo l'immagine del contenitore distribuita, è tempo di pensare a come configurare l'accesso esterno a questo servizio Restful, che è effettivamente programmato nel nostro codice.
Ci sono molti modi per farlo. Ad esempio, possiamo utilizzare il comando expose per creare automaticamente i componenti Kubernetes corrispondenti, come services e endpoints. Infatti, questo è esattamente ciò che faremo eseguendo il comando expose per il nostro oggetto di deployment:
kubectl expose deployment hello-quarkus --type=NodePort --port=8080
Fermiamoci un attimo sull'opzione "--type" del comando expose.
Quando facciamo expose e creiamo i componenti necessari per eseguire il nostro servizio, dobbiamo assicurarci, tra le altre cose, che dall'esterno sia possibile connettersi al servizio hello-quarkus, che si trova all'interno della nostra rete programmaticamente definita. E il parametro type ci consente di creare e collegare elementi come bilanciatori di carico, per instradare il traffico in questa rete.
Ad esempio, specificando type=LoadBalancer, iniziamo automaticamente un bilanciatore di carico nel cloud pubblico, per connetterci al nostro cluster Kubernetes. Questo, ovviamente, è fantastico, ma bisogna capire che questa configurazione sarà fortemente legata a un cloud pubblico specifico e sarà più difficile trasferirla tra gli istanze Kubernetes in ambienti diversi.
Nel nostro esempio type=NodePort, cioè il riferimento al nostro servizio avviene tramite l'indirizzo IP del nodo e il numero di porta. Questa opzione consente di non utilizzare alcun cloud pubblico, ma richiede una serie di passaggi aggiuntivi. Innanzitutto, è necessario un proprio bilanciatore di carico, quindi implementeremo nel nostro cluster il bilanciatore di carico NGINX.
Passo 6 – installiamo il bilanciatore di carico
Minikube ha una serie di funzionalità di piattaforma che semplificano la creazione dei componenti necessari per l'accesso esterno, come i controller ingress. Minikube viene fornito con il controller ingress Nginx, e non ci resta che abilitarlo e configurarlo.
minikube addons enable ingress
Ora, con un solo comando, creerò il controller ingress Nginx, che funzionerà all'interno del nostro cluster minikube:
ingress-nginx-controller-69ccf5d9d8-j5gs9 1/1 In esecuzione 1 33m
Passo 7 – Configuriamo l'ingress
Ora dobbiamo configurare il controller ingress Nginx affinché elabori le richieste hello-quarkus.


E, infine, dobbiamo applicare questa configurazione.

kubectl apply -f ingress.yml
![]()
Poiché stiamo facendo tutto questo sul nostro computer, aggiungiamo semplicemente l'indirizzo IP del nostro nodo nel file /etc/hosts, per indirizzare le richieste http al nostro minikube sul bilanciatore di carico NGINX.
192.168.99.100 hello-quarkus.info
Ora, il nostro servizio minikube è accessibile dall'esterno tramite il controller ingress Nginx.

Bene, è stato facile, vero? O non tanto?

Avvio su OpenShift (Code Ready Containers)
Ora vediamo come si fa tutto questo sulla Red Hat OpenShift Container Platform (OCP).
Come nel caso di minikube, scegliamo uno schema con cluster OpenShift a nodo singolo sotto forma di Code Ready Containers (CRC). In precedenza era chiamato minishift e si basava sul progetto OpenShift Origin, ora è CRC ed è costruito sulla piattaforma OpenShift Container di Red Hat.
Qui, scusate, non possiamo esprimerci senza dire: «OpenShift è fantastico!»
Inizialmente pensavamo di scrivere che lo sviluppo su OpenShift non differisce dallo sviluppo su Kubernetes. E in effetti è così. Ma mentre scrivevamo questo post, ci siamo ricordati di quanti ulteriori passaggi si devono compiere quando non si utilizza OpenShift, e per questo, ripetiamo, è fantastico. Ci piace quando tutto è fatto facilmente, e il modo in cui il nostro esempio si distribuisce e si avvia su OpenShift, rispetto a minikube, ci ha spinto a scrivere questo post.
Facciamo un rapido riepilogo del processo e vediamo cosa sarà necessario fare.
Quindi, nell'esempio con minikube, abbiamo iniziato con Docker... Aspetta, non abbiamo più bisogno che Docker sia installato sulla macchina.
E non abbiamo bisogno di git locale.
E nemmeno di Maven.
E non è necessario creare manualmente un'immagine del contenitore.
E non è necessario cercare un repository di immagini dei contenitori.
E non è necessario installare un ingress-controller.
E non è necessario configurare l'ingress.
Hai capito, giusto? Per distribuire e avviare la nostra applicazione su OpenShift, non è necessario nulla di quanto elencato sopra. E il processo avviene come segue.
Passo 1 – Avviamo il nostro cluster OpenShift
Utilizziamo Code Ready Containers di Red Hat, che è essenzialmente lo stesso di Minikube, ma con un cluster OpenShift a nodi singoli completamente funzionale.
crc start
Passo 2 – Costruiamo e distribuiamo l'applicazione nel cluster OpenShift
È proprio in questo passo che la semplicità e la comodità di OpenShift si manifestano in tutto il loro splendore. Come in tutte le distribuzioni di Kubernetes, abbiamo molte opzioni per avviare un'applicazione nel cluster. E, come nel caso di KUK, scegliamo deliberatamente il modo più semplice.
OpenShift è sempre stato progettato come una piattaforma per creare ed eseguire applicazioni contenitore. La creazione di contenitori è sempre stata una parte integrante di questa piattaforma, quindi ci sono molti risorse Kubernetes aggiuntive per i compiti correlati.
Utilizzeremo il processo Source 2 Image (S2I) di OpenShift, che ha diversi modi per prendere il nostro sorgente (codice o file binari) e trasformarlo in un'immagine del contenitore da eseguire nel cluster OpenShift.
A tal fine, avremo bisogno di due cose:
- Il nostro codice sorgente nel repository git
- Un'immagine builder, sulla base della quale verrà eseguita la creazione.
Esistono molte di queste immagini, supportate sia da Red Hat sia a livello di comunità, e utilizzeremo l'immagine OpenJDK, poiché sto creando un'applicazione Java.
Possiamo avviare la costruzione S2I sia dalla console grafica di OpenShift Developer sia dalla riga di comando. Utilizzeremo il comando new-app, specificando da dove prendere l'immagine builder e il nostro codice sorgente.

oc new-app registry.access.redhat.com/ubi8/openjdk-11:latest~https://github.com/gcolman/quarkus-hello-world.git
Tutto, la nostra applicazione è stata creata. Durante questo processo, S2I ha eseguito le seguenti operazioni:
- Ha creato un pod di build per varie operazioni legate alla creazione dell'applicazione.
- Ha creato la configurazione OpenShift Build.
- Ha scaricato l'immagine builder nel registro docker interno di OpenShift.
- Ha clonato "Hello World" nel repository locale.
- Ho visto che c'era un maven pom, quindi ho compilato l'applicazione usando maven.
- Ho creato una nuova immagine del container contenente l'applicazione Java compilata e ho posizionato quest'immagine nel registro dei container interno.
- Ho creato un Deployment Kubernetes con specifiche per il pod, il servizio, ecc.
- Ho avviato il deploy dell'immagine del container.
- Ho eliminato il build-pod di servizio.
In questo elenco ci sono molte cose, ma la cosa principale è che tutta la build avviene esclusivamente all'interno di OpenShift, il registro Docker interno si trova all'interno di OpenShift e il processo di build crea tutti i componenti Kubernetes e li avvia nel cluster.
Se si tiene traccia visivamente dell'avvio di S2I nella console, si può vedere come, durante la compilazione, si avvia il build pod.

Ora diamo un'occhiata ai log del builder pod: innanzitutto, si può vedere come maven svolge il suo lavoro e scarica le dipendenze per costruire la nostra applicazione java.

Dopo che la compilazione maven è terminata, viene avviata la costruzione dell'immagine del container e poi quest'immagine costruita viene inviata nel repository interno.

Tutto, il processo di costruzione è completato. Ora assicuriamoci che i pod e i servizi della nostra applicazione siano stati avviati nel cluster.
oc get service
![]()
Ecco fatto. Solo un comando. Non ci resta che esporre questo servizio per l'accesso esterno.
Passaggio 3 – esponiamo il servizio per l'accesso esterno
Come nel caso di KUK, sulla piattaforma OpenShift anche il nostro 'Hello World' ha bisogno di un router per indirizzare il traffico esterno verso il servizio all'interno del cluster. In OpenShift è molto semplice. In primo luogo, nel cluster è installato per impostazione predefinita un componente di instradamento HAProxy (può essere sostituito dallo stesso NGINX). In secondo luogo, ci sono risorse speciali e altamente configurabili chiamate Routes che somigliano agli oggetti Ingress nel vecchio e caro Kubernetes (in realtà, le Routes di OpenShift hanno avuto un forte impatto sul design degli oggetti Ingress, che ora possono essere utilizzati anche in OpenShift), ma per il nostro 'Hello World', e infatti nella maggior parte dei casi, ci basterà la Route standard senza configurazioni aggiuntive.
Per creare un FQDN instradabile per 'Hello World' (sì, in OpenShift c'è il proprio DNS per l'instradamento tramite i nomi dei servizi), eseguiremo semplicemente un expose per il nostro servizio:

oc expose service quarkus-hello-world
Se si guarda la Route appena creata, si può trovare l'FQDN e altre informazioni di instradamento:
oc get route
![]()
E infine, accediamo al nostro servizio dal browser:

E adesso è stato davvero facile!
Amiamo Kubernetes e tutto ciò che questa tecnologia permette di fare, così come amiamo la semplicità e la leggerezza. Kubernetes è stato creato per semplificare enormemente l'operatività di container distribuiti e scalabili, ma per il deploy delle applicazioni, oggi la sua semplicità non è più sufficiente. Ed è qui che entra in gioco OpenShift, che tiene il passo con i tempi e offre un Kubernetes progettato principalmente per gli sviluppatori. È stato dedicato un enorme sforzo per adattare la piattaforma OpenShift agli sviluppatori, compresa la creazione di strumenti come S2I, ODI, Developer Portal, OpenShift Operator Framework, integrazione con IDE, Developer Catalogues, integrazione con Helm, monitoraggio e molti altri.
Speriamo che questo articolo sia stato interessante e utile per voi. Ulteriori risorse, materiali e altre cose utili per lo sviluppo sulla piattaforma OpenShift possono essere trovate sul portale .
Fonte: habr.com
