Esegui il deployment di un'applicazione Micronaut containerizzata con Jib in Google Kubernetes Engine

1. Panoramica

Informazioni su Micronaut

Micronaut è un framework full-stack moderno basato su JVM per la creazione di microservizi modulari e facilmente testabili e applicazioni serverless. Micronaut mira a offrire tempi di avvio rapidi, un throughput elevato e un utilizzo della memoria minimo. Gli sviluppatori possono sviluppare con Micronaut in Java, Groovy o Kotlin.

Micronaut fornisce:

  • Tempi di avvio rapidi e basso consumo di memoria: i framework IoC basati sulla reflection caricano e memorizzano nella cache i dati di reflection per ogni singolo campo, metodo e costruttore nel codice, mentre con Micronaut i tempi di avvio dell'applicazione e il consumo di memoria non sono vincolati alle dimensioni del codebase.
  • Client HTTP dichiarativo, reattivo e in fase di compilazione: crea in modo dichiarativo client HTTP reattivi, implementati in fase di compilazione, riducendo il consumo di memoria.
  • Server HTTP non bloccante basato su Netty: con una curva di apprendimento graduale, il server HTTP di Micronaut semplifica al massimo l'esposizione di API che possono essere utilizzate dai client HTTP.
  • Test rapidi e semplici: configura facilmente server e client nei test unitari ed eseguili istantaneamente.
  • Efficiente iniezione delle dipendenze e AOP in fase di compilazione: Micronaut fornisce una semplice API di programmazione orientata agli aspetti in fase di compilazione che non utilizza la reflection.
  • Crea app completamente reattive e non bloccanti: Micronaut supporta qualsiasi framework che implementa Reactive Streams, tra cui RxJava e Reactor.

Per ulteriori informazioni, visita il sito web di Micronaut.

Informazioni su Kubernetes

Kubernetes è un progetto open source eseguibile in numerosi ambienti, dai laptop ai cluster multinodo ad alta affidabilità, dai cloud pubblici ai deployment on-premise, dalle macchine virtuali alle soluzioni bare metal.

In questo lab, esegui il deployment di un semplice microservizio Micronaut basato su Groovy in Kubernetes in esecuzione su Kubernetes Engine.

Lo scopo di questo codelab è eseguire il microservizio come servizio replicato in esecuzione su Kubernetes. Prendi il codice che hai sviluppato sul tuo computer, lo trasformi in un'immagine container Docker e poi esegui l'immagine su Kubernetes Engine.

Ecco un diagramma delle varie parti in gioco in questo codelab per aiutarti a capire come si combinano. Utilizza questo elenco come riferimento man mano che avanzi nel codelab. Tutto dovrebbe avere senso quando arriverai alla fine (ma sentiti libero di ignorarlo per ora).

Kubernetes Codelab Diagram 1 (2).png

Ai fini di questo codelab, l'utilizzo di un ambiente gestito come Kubernetes Engine (una versione di Kubernetes ospitata da Google in esecuzione su Compute Engine) ti consente di concentrarti maggiormente sull'esperienza con Kubernetes anziché sulla configurazione dell'infrastruttura sottostante.

Se ti interessa eseguire Kubernetes sulla tua macchina locale, ad esempio un laptop di sviluppo, ti consigliamo di dare un'occhiata a Minikube. In questo modo è possibile configurare facilmente un cluster Kubernetes a un singolo nodo a scopo di sviluppo e test. Se vuoi, puoi utilizzare Minikube per seguire questo codelab.

Informazioni su Jib

Jib è uno strumento open source che consente di creare immagini Docker e OCI per le tue applicazioni Java. È disponibile come plug-in per Maven e Gradle e come libreria Java.

Jib mira a essere:

  • Veloce: esegui rapidamente il deployment delle modifiche. Jib separa l'applicazione in più livelli, dividendo le dipendenze dalle classi. Ora non devi più attendere che Docker ricompili l'intera applicazione Java, ma puoi eseguire il deployment solo dei livelli modificati.
  • Riproducibile: la ricreazione dell'immagine container con gli stessi contenuti genera sempre la stessa immagine. Non attivare mai più un aggiornamento non necessario.
  • Senza daemon: riduci le dipendenze della CLI. Crea la tua immagine Docker da Maven o Gradle ed esegui il push in qualsiasi registro a tua scelta. Non dovrai più scrivere Dockerfile e chiamare docker build/push.

Puoi trovare maggiori informazioni su Jib nella pagina del progetto su GitHub.

Informazioni su questo tutorial

Questo tutorial utilizza il codice di esempio dello strumento Jib per creare container per applicazioni Java.

L'esempio è un semplice servizio Hello World che utilizza il framework Micronaut e il linguaggio di programmazione Apache Groovy.

Obiettivi didattici

  • Come creare un pacchetto di una semplice applicazione Java come container Docker utilizzando Jib
  • Come creare il cluster Kubernetes su Kubernetes Engine.
  • Come eseguire il deployment del servizio Micronaut in Kubernetes su Kubernetes Engine
  • Come scalare il servizio ed eseguire il rollout di un upgrade.
  • Come accedere alla dashboard grafica di Kubernetes.

Che cosa ti serve

  • Un progetto Google Cloud
  • Un browser, ad esempio Chrome o Firefox
  • Familiarità con gli editor di testo standard di Linux, ad esempio Vim, EMAC o Nano

Come utilizzerai questo tutorial?

Leggilo e basta Leggilo e completa gli esercizi

Come valuti la tua esperienza di creazione di app web HTML/CSS?

Principiante Intermedio Avanzato

Come valuti la tua esperienza di utilizzo dei servizi Google Cloud Platform?

Principiante Intermedio Avanzato

2. Configurazione e requisiti

Configurazione dell'ambiente autonomo

  1. Accedi alla console Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai già un account Gmail o G Suite, devi crearne uno.

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Ricorda l'ID progetto, un nome univoco tra tutti i progetti Google Cloud (il nome sopra è già stato utilizzato e non funzionerà per te, mi dispiace). In questo codelab verrà chiamato PROJECT_ID.

  1. Successivamente, dovrai abilitare la fatturazione in Cloud Console per utilizzare le risorse Google Cloud.

L'esecuzione di questo codelab non dovrebbe costare molto, se non nulla. Assicurati di seguire le istruzioni riportate nella sezione "Pulizia", che ti consiglia come arrestare le risorse in modo da non incorrere in addebiti oltre questo tutorial. I nuovi utenti di Google Cloud possono beneficiare del programma prova senza costi di 300$.

3. Recupera il codice sorgente di esempio di Micronaut

Dopo l'avvio di Cloud Shell, puoi utilizzare la riga di comando per clonare il codice sorgente di esempio nella home directory e passare alla directory contenente il nostro servizio di esempio:

$ git clone https://github.com/GoogleContainerTools/jib.git
$ cd jib/examples/micronaut/

4. Un'occhiata rapida al codice

Il nostro servizio semplice Micronaut è costituito da un controller che restituisce il famoso messaggio Hello World:

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello World"
    }
}

Il controller HelloController risponde alle richieste nel percorso /hello e il metodo index() accetta le richieste HTTP GET.

È disponibile anche una classe di test Spock per verificare che nell'output venga visualizzato il messaggio corretto.

class HelloControllerSpec extends Specification {
    @Shared
    @AutoCleanup
    EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer)

    @Shared
    @AutoCleanup
    RxHttpClient client = embeddedServer.applicationContext.createBean(RxHttpClient, embeddedServer.getURL()) 

    void "test hello world response"() {
        when:
        HttpRequest request = HttpRequest.GET('/hello')
        String rsp  = client.toBlocking().retrieve(request)

        then:
        rsp == "Hello World"
    }
}

Più di un semplice test unitario, questo test esegue la stessa stack del server Micronaut (basata sul framework Netty) che viene eseguita in produzione. Pertanto, il comportamento del codice sarà lo stesso nel prodotto e nei test.

Per eseguire i test, puoi eseguire questo comando per verificare che tutto funzioni correttamente:

./gradlew test

5. Esegui l'applicazione in locale

Puoi avviare normalmente il servizio Micronaut con il seguente comando Gradle:

$ ./gradlew run

Una volta avviata l'applicazione, puoi aprire un'istanza di Cloud Shell aggiuntiva grazie alla piccola icona +, quindi controllare con curl di ottenere l'output previsto:

$ curl localhost:8080/hello

Dovresti visualizzare un semplice messaggio "Hello World".

6. Pacchettizza l'applicazione come container Docker con Jib

Successivamente, prepara l'app per l'esecuzione su Kubernetes. A questo scopo, sfrutteremo Jib per fare il lavoro più difficile, in quanto non dovremo toccare un Dockerfile.

Eseguiamo il comando per creare il nostro container:

$ ./gradlew jibDockerBuild

Ecco l'output che dovresti visualizzare:

Tagging image with generated image reference micronaut-jib:0.1. If you'd like to specify a different tag, you can set the jib.to.image parameter in your build.gradle, or use the --im
age=<MY IMAGE> commandline flag.

Containerizing application to Docker daemon as micronaut-jib:0.1...
warning: Base image 'gcr.io/distroless/java' does not use a specific image digest - build may not be reproducible
Getting base image gcr.io/distroless/java...
Building dependencies layer...
Building resources layer...
Building classes layer...
Finalizing...

Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, example.micronaut.Application]
Loading to Docker daemon...

Built image to Docker daemon as micronaut-jib:0.1

Ora che l'immagine è stata creata, controlliamo se riusciamo a visualizzare il nostro messaggio di saluto eseguendo l'immagine Docker nella prima scheda di Cloud Shell:

$ docker run -it -p 8080:8080 micronaut-jib:0.1
16:57:20.255 [main] INFO  i.m.context.env.DefaultEnvironment - Established active environments: [cloud, gcp]
16:57:23.203 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 2926ms. Server Running: http://97b7d76ccf3f:8080

Il nostro servizio è in esecuzione, quindi ora possiamo avviare il comando curl nella seconda scheda di Cloud Shell per verificare se funziona come previsto:

$ curl localhost:8080/hello
Hello World

Puoi arrestare il container premendo Ctrl+C in Cloud Shell.

7. Eseguire il push del servizio containerizzato nel registro

Ora che l'immagine funziona come previsto, puoi eseguirne il push in Google Container Registry, un repository privato per le tue immagini Docker accessibile da ogni progetto Google Cloud (ma anche dall'esterno della piattaforma Google Cloud).

Prima di poter eseguire il push nel registro, assicuriamoci che Container Registry sia abilitato per il nostro progetto andando su Strumenti > Container Registry. Se non è abilitata, dovresti visualizzare la seguente finestra di dialogo, quindi fai clic su "Abilita API Container Registry" per abilitarla:

ac812e6260ac7dfb.png

Una volta pronto il registro, per eseguire il push dell'immagine nel registro, esegui i seguenti comandi:

$ gcloud auth configure-docker
$ docker tag micronaut-jib:0.1 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

I comandi precedenti consentono a gcloud SDK di configurare e autorizzare Docker a eseguire il push delle immagini nell'istanza di Container Registry, di taggare l'immagine in modo che punti alla sua posizione nel registro e di eseguirne il push nel registro.

Se tutto va bene, dopo un po' dovresti essere in grado di vedere l'immagine container elencata nella console: Strumenti > Container Registry. A questo punto, hai a disposizione un'immagine Docker a livello di progetto a cui Kubernetes può accedere e che può orchestrare, come vedrai tra qualche minuto.

12224c4e42183b4e.png

8. Crea il cluster

Ok, ora puoi creare il tuo cluster Kubernetes Engine, ma prima vai alla sezione Google Kubernetes Engine della console web e attendi l'inizializzazione del sistema (dovrebbe richiedere solo pochi secondi).

20c0587c0108b8ba.png

Un cluster è costituito da un server API master Kubernetes gestito da Google e da un insieme di nodi worker. I nodi worker sono macchine virtuali Compute Engine. Utilizziamo la CLI gcloud dalla sessione Cloud Shell per creare un cluster con due nodi n1-standard-1 (il completamento dell'operazione richiederà alcuni minuti):

$ gcloud container clusters create hello-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

Alla fine, dovresti vedere il cluster creato.

Creating cluster hello-cluster in us-central1-c...done.
Created [https://container.googleapis.com/v1/projects/mn-gke-test/zones/us-central1-c/clusters/hello-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-c/hello-cluster?project=mn-gke-test
kubeconfig entry generated for hello-cluster.
NAME           LOCATION       MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
hello-cluster  us-central1-c  1.9.7-gke.7     35.239.224.115  n1-standard-1  1.9.7-gke.7   2          RUNNING

Ora dovresti avere un cluster Kubernetes completamente funzionante basato su Google Kubernetes Engine:

d9e1e314769753e7.png

Ora è il momento di eseguire il deployment della tua applicazione containerizzata nel cluster Kubernetes. D'ora in poi utilizzerai la riga di comando kubectl (già configurata nel tuo ambiente Cloud Shell). Il resto di questo codelab richiede che sia la versione client che quella server di Kubernetes siano 1.2 o successive. kubectl version mostrerà la versione attuale del comando.

9. Esegui il deployment dell'applicazione in Kubernetes

Un deployment Kubernetes può creare, gestire e scalare più istanze della tua applicazione utilizzando l'immagine container che hai appena creato. Creiamo un deployment della tua applicazione in Kubernetes utilizzando il comando kubectl create deployment:

$ kubectl create deployment hello-micronaut \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

Per visualizzare il deployment che hai appena creato, esegui:

$ kubectl get deployments
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   1         1         1            1           5m

Per visualizzare le istanze dell'applicazione create dal deployment, esegui questo comando:

$ kubectl get pods
NAME                               READY     STATUS    RESTARTS   AGE
hello-micronaut-5647fb98c5-lh5h7   1/1       Running   0          5m

A questo punto il container dovrebbe essere in esecuzione sotto il controllo di Kubernetes, ma devi ancora renderlo accessibile al mondo esterno.

10. Consenti traffico esterno

Per impostazione predefinita, il pod è accessibile solo tramite il suo IP interno all'interno del cluster. Per rendere accessibile il container hello-micronaut dall'esterno della rete virtuale Kubernetes, devi esporre il pod come servizio Kubernetes.

Da Cloud Shell puoi esporre il pod a internet pubblico con il comando kubectl expose combinato con il flag --type=LoadBalancer. Questo flag è obbligatorio per la creazione di un IP accessibile esternamente :

$ kubectl expose deployment hello-micronaut --type=LoadBalancer --port=8080

Il flag utilizzato in questo comando specifica che utilizzerai il bilanciatore del carico fornito dall'infrastruttura sottostante (in questo caso il bilanciatore del carico Compute Engine). Tieni presente che esponi il deployment e non il pod direttamente. In questo modo, il servizio risultante bilancerà il carico del traffico su tutti i pod gestiti dal deployment (in questo caso solo un pod, ma in seguito aggiungerai altre repliche).

Il master Kubernetes crea il bilanciatore del carico e le regole di forwarding, i pool di destinazione e le regole firewall di Compute Engine correlate per rendere il servizio completamente accessibile dall'esterno di Google Cloud.

Per trovare l'indirizzo IP accessibile pubblicamente del servizio, richiedi semplicemente kubectl per elencare tutti i servizi del cluster:

$ kubectl get services
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
hello-micronaut   LoadBalancer   10.39.243.251   aaa.bbb.ccc.ddd 8080:30354/TCP   1m
kubernetes        ClusterIP      10.39.240.1     <none>          443/TCP          31m

Tieni presente che per il tuo servizio sono elencati due indirizzi IP, entrambi che gestiscono la porta 8080. Uno è l'IP interno, visibile solo all'interno della rete virtuale cloud, l'altro è l'IP esterno bilanciato del carico. In questo esempio, l'indirizzo IP esterno è aaa.bbb.ccc.ddd.

Ora dovresti essere in grado di raggiungere il servizio indirizzando il browser a questo indirizzo: http://<EXTERNAL_IP>:8080/hello

11. Aumentare le dimensioni del servizio

Una delle potenti funzionalità offerte da Kubernetes è la facilità di scalare l'applicazione. Supponiamo che tu abbia improvvisamente bisogno di più capacità per la tua applicazione. Puoi semplicemente chiedere al controller di replica di gestire un nuovo numero di repliche per le istanze dell'applicazione:

$ kubectl scale deployment hello-micronaut --replicas=3
deployment.extensions "hello-micronaut" scaled

$ kubectl get deployment
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   3         3         3            3           16m

Tieni presente l'approccio dichiarativo: anziché avviare o arrestare nuove istanze, dichiari quante istanze devono essere in esecuzione in ogni momento. I cicli di riconciliazione di Kubernetes si limitano a verificare che la realtà corrisponda a ciò che hai richiesto e a intervenire se necessario.

12. Implementa ed esegui l'upgrade del servizio

A un certo punto, l'applicazione che hai implementato in produzione richiederà correzioni di bug o funzionalità aggiuntive. Kubernetes ti aiuta a eseguire il deployment di una nuova versione in produzione senza influire sugli utenti.

Innanzitutto, modifichiamo l'applicazione. Apri l'editor di codice da Cloud Shell.

5aee8f3d1e003571.png

Vai a /jib/examples/micronaut/src/main/groovy/example/micronaut/HelloController.groovy e aggiorna il valore della risposta:

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello Kubernetes World"
    }
}

In /jib/examples/micronaut/build.gradle, eseguiremo l'upgrade della versione della nostra immagine da 0.1 a 0.2 aggiornando questa riga:

version '0.2'

Quindi, ricompila e crea il pacchetto dell'applicazione con le ultime modifiche:

$ ./gradlew jibDockerBuild

Tagga l'immagine ed eseguine il push nel registro delle immagini container:

$ docker tag micronaut-jib:0.2 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

Ora Kubernetes è pronto per aggiornare senza problemi il controller di replica alla nuova versione dell'applicazione. Per modificare l'etichetta dell'immagine del container in esecuzione, devi modificare il hello-micronaut deployment esistente e cambiare l'immagine da gcr.io/PROJECT_ID/micronaut-jib:0.1 a gcr.io/PROJECT_ID/micronaut-jib:0.2.

Puoi utilizzare il comando kubectl set image per chiedere a Kubernetes di eseguire il deployment della nuova versione dell'applicazione nell'intero cluster un'istanza alla volta con l'aggiornamento in sequenza:

$ kubectl set image deployment/hello-micronaut \
          micronaut-jib=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

deployment.apps "hello-micronaut" image updated

Controlla di nuovo http://EXTERNAL_IP:8080 per verificare che restituisca la nuova risposta.

13. Rollback

Ops, hai commesso un errore con una nuova versione dell'applicazione? Forse la nuova versione conteneva un errore e devi eseguire rapidamente il rollback. Con Kubernetes, puoi eseguire facilmente il rollback allo stato precedente. Eseguiamo il rollback dell'applicazione eseguendo:

$ kubectl rollout undo deployment/hello-micronaut

Se dai un'occhiata all'output del servizio, torneremo al messaggio iniziale "Hello World".

14. Riepilogo

In questo passaggio, hai configurato un semplice servizio Micronaut Hello World basato su Apache Groovy e lo hai eseguito direttamente da Cloud Shell, lo hai pacchettizzato come container con Jib e ne hai eseguito il deployment su Google Kubernetes Engine.

15. Complimenti!

Hai imparato a creare ed eseguire il deployment di un nuovo microservizio basato sul web Apache Groovy / Micronaut in Kubernetes su Google Kubernetes Engine.

Scopri di più

Licenza

Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.