Esempio di Architettura a microservizi su Kubernetes [PARTE1]

E

italiancoders vs microservizi episodio 1

Ciao ragazzi,

questo e’ il primo articolo di una serie che avra’ l obbiettivo di esplorare il mondo dei microservizi.

il nostro primo deploy sy k8s

Ciao a tutti coders,

inizio con la citazione di un amico

Kubernetes e’ come il sesso tra adolescenti, tutti ne

parlano ma pochi lo fanno

Scherzi a parte Kubernetes e’ oramai il presente da un po di tempo e sara’ sempre di più il futuro che sembra remare in maniera decisa sul mondo dei software cloud ready.

scopo dell articolo

Lo scopo di questo articolo non e’ spiegare Kubernetes ( abbreviato successivamente con l acronimo K8s) in quanto pure io sono alle prime armi su K8s  e trovo comunque veramente riduttivi gli articoli che tentano di spiegare K8s in poche righe. Kubernetes e’ una piattaforma che ha bisogno di essere studiata con attenzione. Segnalo le seguenti fonti su cui sto studiando Kubernetes magari vi possono essere d aiuto

Lo scopo di questo articolo e’ un esercizio che ha il fine di deployare una architettura  a microservizi in versione semplificata su un cluster Kubernetes di sviluppo. Andremo infatti a deployare i microservizi sotto descritti su un cluster mono-nodo  che gira in locale. 

prerequisti

Per poter comprendere questo articolo occorre:

  • avere le basi di Kubernetes e Docker.
  • avere un cluster kubernetes configurato in locale (puoi utilizzare minikube o docker desktop)
  • avere le basi di Spring Boot
  • conoscenza dei principi di un architettura a microservizi

tutorial Post e Commenti

L’ esercizio che andremo a realizzare e’ una versione molto semplificata di un social network basato su una architettura a microservizi. L obbiettivo e’ quello di realizzare delle API per pubblicare e gestire Post e Commenti come in un social network. Di seguito le API che offriremo ai nostri client:

  • GET /posts: Ritorna una lista di Post
  • GET /posts/{id}: Ritorna il Post con id specificato
  • POST /posts: Aggiunge un post come da richiesta nel body
  • PUT/posts/{id}: Aggiorna il Post con id specificato come da richiesta nel body
  • DELETE /posts/{id}: Elimina il Post con id specificato
  • GET /posts/{id}/comments: Ritorna i commenti del Post con id specificato
  • POST /posts/{id}/comments: Aggiunge il commento al Post con id specificato come da commento riportato nel body

La soluzione implementata e’ molto banale e non gestisci autenticazione/autorizzazione. Il motivo e’ quello di posizionare il focus dell articolo sul deploy su kubernetes di due semplici  microservizi. Siete liberi di raffinare la soluzione forkando il mio repository.

architettura SOFTWARE

Andremo a sviluppare un architettura con le seguenti caratteristiche

  • Infrastruttura su Kubernetes: Deployeremo i nostri microservizi su un cluster K8s con un singolo nodo e cercheremo di risolvere i problemi di service discovery e load balancing lato server/infrastruttura con K8s anziché’ Spring Cloud. Questa e’ veramente una grossa novità’ per gli sviluppatori Spring, i quali si potranno concentrare  esclusivamente sulla logica business del microservizio che stanno sviluppando, poiche’ service discovery, load balancing, circuit breaker saranno realizzati in maniera trasparente configurando opportunamente  l’infrastruttura di K8s. In questo modo:
    • il codice del singolo microservizio e’ più semplice
    • l architettura e’ più facilmente scalabile
    • l architettura e’ finalmente poliglotta e quindi per lo sviluppo di un singolo microservizio non siamo piu’ obbligati ad utilizzare Java e Spring ma bensi’ il team sceglierà’ lo stack che ritiene più opportuno a risolvere i problemi di un microservizio
  • Servizi sviluppati: divideremo il dominio in due microservizi: post-ws e comment-ws . Trattasi di una scelta puramente didattica, in un contesto reale con quasi certezza implementerei post e commenti all’interno del solito microservizio.
  • ogni microservizio avrà’  un database mysql dedicato per lo storage dei dati del proprio dominio
  • scaleremo il carico dei due microservizi tirando su istanze del microservizio e bilanciando il carico in maniera round robin
  •  Il microservizio Post-ws oltre a gestire  in autonomia le richieste inerenti ai Post, fara’ da orchestratore del microservizio Comment-ws andando a contattare il microservizio comment-ws quando ha bisogno  dei dati relativi ai commenti e aggregando quindi i dati di propria competenza con quelli dei commenti. Non e’ una soluzione pulitissima; di solito in letteratura si risolve questo problema sviluppando un terzo microservizio ( aggregator pattern) o aggregando i dati di diversi microservizi sul gateway.

Ecco una anteprima dell architettura che tireremo sul nostro cluster kubernetes che per semplicità’ sara’ composto da un solo nodo.

 

 

step 0: codice sorgente

Trovate il codice sorgente di questo esercizio sul mio REPO

All’interno del repo trovate le seguenti cartelle:

  • post-ws: codice sorgente microservizio post
  • comment-ws: codice sorgente microservizio comment
  • k8s: file yaml contenenti le dichiarazioni per creare gli object kubernetes che compongono la nostra architettura.

POST-WS

Il codice sorgente del microservice Post lo trovate al seguente URL

Analizziamo le properties del microservizio post-ws e la  sua immagine docker.

Ho due profili di application properties: dev e docker. Dev lo utilizzo quando sviluppo in locale mentre docker e’ quello che utilizzo per buildare la mia immagine docker.

application.properties

Carico a runtime le properties del profilo passato come variabile d ambiente SPRING_PROFILE  o se non presente carico il profilo dev ( profilo utilizzato per sviluppare in locale con puntamenti statici al db e agli altri servizi che girano in locale)

spring.profiles.active=${SPRING_PROFILE:dev} 

application.docker

server.port = 8080
spring.application.name= post-ws
instance.instance-id=${spring.application.name}:${spring.application.istance_id:${random.value}}

logging.level.org.springframework=INFO
logging.level.it.italiancoders.postws=INFO
logging.level.com.zaxxer=DEBUG
logging.level.root=ERROR
#show sql statement
logging.level.org.hibernate.SQL=debug
#show sql values
logging.level.org.hibernate.type.descriptor.sql=trace

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#$  docker run -p 3307:3306 --name hb-mysql-example -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=post_db -d mysql
spring.datasource.url=jdbc:mysql://${MYSQL_HOST_POST_DB}:${MYSQL_PORT_POST_DB}/post_db
spring.datasource.username=${MYSQL_ROOT_USERNAME_POST_DB}
spring.datasource.password=${MYSQL_ROOT_PASSWORD_POST_DB}
spring.jpa.hibernate.ddl-auto=create

#service discovery info
comments_ws.ip=${COMMENT_WS_IP}
comments_ws.port=${COMMENT_WS_PORT}

Come si evince dal file di properties, utilizziamo le Environment variables  per gestire i valori delle configurazioni come indirizzi e porte dei servizi che utilizzerà’ il nostro microservizio:

  • configurazione e indirizzi del db mysql utilizzato per storage dei dati relativi ad un Post.
  • indirizzo e porta del microservizio Comment-ws: Abbiamo seguito il principio di singola responsabilita’: il servizio post-ws gestisce in autonomia solo i Post; Quando sono richiesti i commenti sara’ necessario invocare il microservizio comment-ws. Servirà’ quindi conoscere l IP e la porta del microservizio comment-ws. I più’ attenti si staranno già chiedendo come mai un singolo IP? Se ho 4 istanze running  del microservizio Comment-ws come faccio a gestire il tutto con un unico indirizzo IP? Abbiate un attimo pazienza. Nella sezione dedicata ai service kubernetes vi spieghero’ come risolveremo il problema di service discovery e load balancing  in questo esercizio.

Infine riportiamo l immagine docker del microservizio Post-ws.

FROM openjdk:8-jdk-alpine
EXPOSE 8080
COPY target/post-ws.jar post-ws.jar
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=docker", "post-ws.jar"]

 

COMMENT WS

Il codice sorgente del microservice Comment lo trovate al seguente URL

Vale quanto detto dal microservizio Comment-ws. Riporto per completezza l application properties e il Dockerfile.

application.properties

application.docker.properties

Dockerfile

spring.profiles.active=${SPRING_PROFILE:dev} 
server.port = 8081
spring.application.name= comment-ws
instance.instance-id=${spring.application.name}:${spring.application.istance_id:${random.value}}

logging.level.org.springframework=INFO
logging.level.it.italiancoders.postws=INFO
logging.level.com.zaxxer=DEBUG
logging.level.root=ERROR
#show sql statement
logging.level.org.hibernate.SQL=debug
#show sql values
logging.level.org.hibernate.type.descriptor.sql=trace

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#$  docker run -p 3307:3306 --name hb-mysql-example -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=comment_db -d mysql
spring.datasource.url=jdbc:mysql://${MYSQL_HOST_COMMENT_DB}:${MYSQL_PORT_COMMENT_DB}/comment_db
spring.datasource.username=${MYSQL_ROOT_USERNAME_COMMENT_DB}
spring.datasource.password=${MYSQL_ROOT_PASSWORD_COMMENT_DB}
spring.jpa.hibernate.ddl-auto=create
FROM openjdk:8-jdk-alpine
EXPOSE 8081
COPY target/comment-ws.jar comment-ws.jar
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=docker", "comment-ws.jar"]

CONFIGURAZIONE K8S

Prima di passare alla configurazione di Kubernetes (pod, controller, ecc.), È importante comprendere il modello dichiarativo di Kubernetes. Kubernetes ha anche modalità imperative, ma ci concentreremo sul modello dichiarativo e sugli stati desiderati. Se vuoi saperne di più ti suggerisco il seguente articolo. In breve andremo a scrivere dei file YAML  che descriveranno lo stato desiderato dell’applicazione: quale immagine Docker dovrebbe essere eseguita, quale strategia di ridimensionamento usare e quali porte / servizi esporre. Queste informazioni vengono inviate al server kube-api attraverso il comando

kubectl apply -f <fileconfig>

e il master node distribuisce il lavoro per garantire che il cluster corrisponda allo stato desiderato. Questa configurazione viene archiviata in etcd e il carico di lavoro viene distribuito nel cluster. Infine, Kubernetes verificherà costantemente se lo stato corrente del cluster corrisponde al comportamento desiderato definito dal programmatore. Quindi, se un pod muore, Kubernetes ne fara’ partire un altro per garantire lo stato desiderato nel cluster.

Anche se tutto ciò sembra semplice, è un potente schema che rende Kubernetes molto utile. Tu (il programmatore) devi solo specificare lo stato desiderato, e Kubernetes si prenderà cura di tutto il resto (invece di aver eseguito comandi specifici per raggiungere questo obiettivo come nei modelli imperativi).

Nella soluzione di questo articolo utilizzeremo i seguenti tipi di oggetti kubernetes:

  • pod
  • service
  • persitent volume e persitent volume claim
  • secret
  • ingress

Faro’ una brevissima panoramica degli object di K8s che utilizzeremo

POD

Iniziamo con l analizzare il componente POD.

I pod sono le unità distribuibili più piccole che possono essere create e gestite in Kubernetes.

Un Pod è un gruppo di uno o più container con memoria / rete condivisa e una specifica su come eseguire i container. Nessun pod può esistere senza un container. Ma ci possono essere pod a container singolo o pod a container multiplo a seconda dell’applicazione che implementiamo. Un’altra piccola cosa da ricordare sui Pod è che sono “mortali” o meglio hanno un ciclo di vita a 3 fasi
In attesa → In esecuzione → Riuscito / Non riuscito
Questo è simile a Born → Living → Dead. Non ci sarà risurrezione; nessuna rinascita. Se un Pod è morto senza aver completato il suo compito, verrà creato un nuovo Pod per sostituire il Pod morto. La cosa più importante è che l’IP di questo nuovo pod saranno diversi dal pod morto. In aggiunta possiamo configurare Kubernates per creare piu’ di un istanza replica di un Pod per poter scalar orizzontalmente la nostra architettura.

service

Come ho detto prima, i pod sono mortali. Quando un pod muore, ne nasce uno nuovo per prendere il suo posto. Non ha pero’ lo stesso indirizzo IP di quello morto.
Pensa quindi allo scenario del nostro tutorial. Dal microservizio Post-ws per chiamare il servizio  Comment-ws abbiamo bisogno dell IP e porta di quest’ultimo. Supponiamo di aver utilizzato l’IP del Comment-ws all’interno del codice del servizio Post-ws. Ci troviamo di fronte a tre problemi:

  • Dobbiamo prima deployare il micro servizio comment-ws e prendere il suo IP.
  • Non siamo in grado di gestire piu’ istanze del microservizio comment-ws
  • Se il pod Commen-ws muore, K8s ri-creera’ il Pod con un nuovo IP

Insomma la gestione diventa parecchio problematica; per questo abbiamo bisogno di un nuovo Object i service.

esempio servizio frontend che deve contattare il pod backend configurato per avere diverse repliche ( https://medium.com/javarevisited/kubernetes-step-by-step-with-spring-boot-docker-gke-35e9481f6d5f). Medesima situazione di quella proposta in questo articolo

Come si evince dal immagine sopra il service ha un proprio indirizzo IP e DNS che sono stabili. Quindi utilizzeremo questa soluzione anche per il nostro esercizio per permettere ad un Pod di collegarsi ad un altro Pod (quindi sia per invocare i microservizi tra loro che per il collegamento al db). Il singolo pod Post-ws utilizzerà come indirizzo IP dei Commenti il DNS del servizio che gestisce i Pod del Comment-ws. Quando una richiesta arriva al Servizio di comment-ws, esso bilancerà’ le richieste tra le diverse repliche del comment-ws. Concludo dicendo che l’uso dell object Service ci offre altri molti vantaggi, come l’inoltro di richieste solo a pod sani, il bilanciamento del carico, il rollback delle versioni, ecc. Ma il vantaggio più importante di un servizio è il disaccoppiamento  dei componenti del sistema.

Andiamo a leggere i file yaml contenenti le configurazione dei pod e service per i nostri due microservizi post-ws e comment-ws

comment-ws

comment-ws-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: comment-ws-deployment
spec:
  replicas: 4
  selector:
    matchLabels:
      component: comment-ws
  template:
    metadata:
      labels:
        component: comment-ws
    spec:
      containers:
      - name: comment-ws
        image: dariofrongillo/comment-ws:1.0.1
        ports:
        - containerPort: 8081
        env:
          - name: MYSQL_ROOT_USERNAME_COMMENT_DB
            value: root
          - name: MYSQL_ROOT_PASSWORD_COMMENT_DB
            valueFrom:
                secretKeyRef:
                  name: dbpassword
                  key: MYSQL_ROOT_PASSWORD_COMMENT_DB
          - name: MYSQL_HOST_COMMENT_DB
            value: mysql-comment-cluster-ip-service
          - name: MYSQL_PORT_COMMENT_DB
            value: '3306'
          - name: SPRING_PROFILE
            value: docker

Il nostro deployment dichiara a K8s

  • di volere 4 repliche del pod comment-ws
  • il pod conterra al suo interno un solo container con immagine dariofrongillo/comment-ws:1.0.1
  • per le label vi consiglio di leggere il seguente LINK. Le labels sono dei metadata che possono essere associati a qualsiasi oggetto Kubernates. Consentono di etichettare oggetti, in modo da poterli facilmente recuperare, ricercare ed interrogare. In un ambiente composto da numersosi pods, le label sono sicuramente un ottimo strumento per poter raggruppare e individuare facilmente un’insieme di pods. In pratica, sono un ottimo strumento per organizzare i pods.

comment-ws-cluster-ip-services.yaml

apiVersion: v1
kind: Service
metadata:
  name: comment-ws-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: comment-ws
  ports:
  - port: 8081
    targetPort: 8081

 

Lo yaml definisce il servizio che gestisce i pod che hanno labels comment-ws. Grazie a label e selector K8s riesce quindi a realizzare la service discovery.

Abbiamo utilizzato un tipo specifico di servizio kubernetes, ClusterIp: questo tipo espone il servizio su un IP interno al cluster. La scelta di questo valore rende il servizio raggiungibile solo all’interno del cluster. Questo è il tipo di servizio predefinito. I nostri servizi non saranno raggiungibili direttamente da fuori del cluster perciò’ abbiamo utilizzato questo tipo.

Quindi il microservizio post-ws potra interrogare uno dei pod running sparando una richiesta al service di comment ws al seguente indirizzo http://comment-ws-cluster-ip-service:8081 . Sara’ compito del servizio bilanciare le richieste ai pod running di comment-ws.

post-ws

Il concetto per configurare post-ws e il suo service e’ il medesimo.

Al seguente URL trovate il deployment file del pod post-ws mentre a questo URL la configurazione del suo servizio.

database

Configurare un database su un cluster con repliche e alta affidabilità’ e’ sempre un operazione ardua. Se non si ha le giuste competenze nel team valutare sempre la possibilità’ di utilizzare un database as service come ad esempio RDS di AWS o Cloud Sql di Google Cloud per l ambiente di produzione.

L’ esempio di questo articolo e’ un deploy su un cluster K8S di un solo nodo adatta ad un ambiente di sviluppo e test. Pertanto ci faremo alcuni “sconti” nella configurazione degli storage. Prima di creare i Pod dei nostri due database mysql e i loro relativi volumi andremo a creare un Secret per salvare le due password dei nostri db mysql.

secret

Un secret è un oggetto che contiene una piccola quantità di dati sensibili come una password, un token o una chiave. Tali informazioni possono essere lette dai nostri Pod. Nel nostro esempio con la cli di kubectl andremo a creare il secret con il seguente comando

kubectl create secret generic dbpassword --from-literal MYSQL_ROOT_PASSWORD_POST_DB=password123 --from-literal MYSQL_ROOT_PASSWORD_COMMENT_DB=password123

Ad esempio, come visto sopra, il pod comment-ws e’ stato definito con una env MYSQL_ROOT_COMMENT-DB presa dal secret dbpassword appena creato

- name: MYSQL_ROOT_PASSWORD_COMMENT_DB
  valueFrom:
      secretKeyRef:
        name: dbpassword
        key: MYSQL_ROOT_PASSWORD_COMMENT_DB

persistent volume e persistent volume claim

Lo storage dei container tramite il file system root  di un contenitore è effimera e può scomparire dopo la cancellazione e la creazione del contenitore. Per fornire una posizione “durabile” in cui archiviare i dati e prevenirne la perdita, è possibile creare e utilizzare volumi persistenti per archiviare i dati all’esterno dei contenitori. Per risolvere questi problemi introduciamo due nuovi oggetti di K8S: Persitent Volume e Persistent Volume Claim.

Un PersistentVolume (PV) è un pezzo di storage nel cluster che è stato fornito da un administrator o dinamicamente fornito  usando le Storage Classes. È quindi una risorsa nel cluster proprio come un nodo è una risorsa cluster. I PV hanno un ciclo di vita indipendente da ogni singolo Pod che utilizza il PV. Questo oggetto acquisisce i dettagli dell’implementazione dell’archiviazione, che sia NFS, iSCSI o un sistema di archiviazione specifico del provider cloud.

Un PersistentVolumeClaim (PVC) è una richiesta di archiviazione da parte di un utente. È simile ad un Pod. Infatti come i pod consumano risorse di un nodo, i PVC consumano PV. I pod possono richiedere livelli specifici di risorse (CPU e memoria). I Claims possono richiedere dimensioni e modalità di accesso specifiche (ad es. Possono essere montati una volta in lettura / scrittura o molte volte in sola lettura).
I concetti attorno ai volumi persistenti sono sicuramente uno dei topic più complessi da apprendere quindi vi rimando al LINK per una spiegazione dettagliata.

Nel nostro esercizio abbiamo creato:

  • due volumi persistenti hostPath. Kubernetes supporta hostPath per lo sviluppo e il test su un cluster a nodo singolo. Un hostPath PersistentVolume utilizza un file o una directory sul nodo per emulare l’archiviazione collegata alla rete. Essendo il nostro cluster composto da un nodo questa configurazione é  sufficiente.
  • due persistent volume claim che utilizzeranno i pod utilizzano per richiedere l’archiviazione fisica.

mysql-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv-volume-1
  labels:
    type: local-1
spec:
  storageClassName: manual
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data-pv1"
---    
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv-volume-2
  labels:
    type: local-2
spec:
  storageClassName: manual
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data-pv2"    
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim-post-ws
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---      
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim-comment-ws
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

 

Una nota: In un cluster di produzione, non utilizzare hostPath come volumi. Un administrator in produzione dovrebbe eseguire il provisioning di una risorsa di rete come un disco persistente di Google Compute Engine, una condivisione NFS o un volume di Amazon Elastic Block Store.

pod database

A questo punto, possiamo dichiarare i deployment file dei due database utilizzati dai microservice post e comment e i service necessari per poter accedere ai database tramire il loro DNS. Riporto solo la configurazione del pod del database dei post; il deployment yaml del database dei commenti e il relativo service li trovate nel repository del progetto.

mysql-post-db-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-post-db-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: mysql-post
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        component: mysql-post
    spec:
      volumes:
        - name: mysql-persistent-storage
          persistentVolumeClaim:
              claimName: mysql-pv-claim-post-ws
      containers:
      - name: mysql
        image: mysql:5.6
        ports:
        - containerPort: 3306
        volumeMounts:
          - name: mysql-persistent-storage
            mountPath: /var/lib/mysql
        env:
          - name: MYSQL_ROOT_PASSWORD
            valueFrom:
                secretKeyRef:
                  name: dbpassword
                  key: MYSQL_ROOT_PASSWORD_POST_DB
          - name: MYSQL_DATABASE
            value: post_db

mysql-post-db-cluster-ip-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql-post-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: mysql-post
  ports:
  - port: 3306
    targetPort: 3306

ingress

I service di tipo ClusterIp espongono il servizio su un IP interno al cluster e pertanto i nostri microservizi, come giusto che sia, non sono raggiungibili al di fuori del cluster. Date un occhio di nuovo all immagine dell architettura del nostro esercizio. Abbiamo bisogno di rendere accessibili all’ esterno le API del microservizio Post-ws. Per fare questo abbiamo bisogno di configurare Ingress: un object di K8s che gestisce gli accessi esterni al cluster ai servizi interni al cluster come nel nostro caso il service dei Post.

   internet
        |
   [ Ingress ]
   --|-----|--
   [ Services ]

Nel nostro esempio abbiamo utilizzato Nginx Ingress. Esistono diversi modi per installare Nginx Ingress nel proprio cluster e alcuni di questi dipendono dal vostro OS. Trovate le istruzioni di setup a questo LINK. La mia macchina di sviluppo ha Windows come OS e ho installato il cluster K8s con Docker for Desktop e pertanto mi e’ bastato eseguire il seguente comando

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.32.0/deploy/static/provider/cloud/deploy.yaml

Una volta installato ingress potete verificare se tutto e’ andato a buon fine eseguendo

kubectl get pods -n ingress-nginx  -l app.kubernetes.io/name=ingress-nginx --watch

Una volta installato ingress occorre configurare le route da applicare inviando a K8s lo yaml di configurazione

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - http:
        paths:
          - path: /post-ws/?(.*)
            backend:
              serviceName: post-ws-cluster-ip-service
              servicePort: 8080

In questo modo abbiamo configurato ingress per redirigere tutte le richieste http che iniziano con /post-ws al service di post-ws e a rimuovere infine tale prefisso. Pertanto nel mio esempio la seguente richiesta

http://localhost/post-ws/posts verra’ gestita all interno del cluster con il seguente URL http://post-ws-cluster-ip-service:8080/posts

applichiamo le configurazioni e testiamo il tutto

Abbiamo descritto tutti i file yaml da applicare sul nostro cluster K8S. Li trovate cmq disponibili al seguente URL. Dopo aver installato Ingress Nginx e creato il secret dei database potete comunque inviare tutte le configurazioni in un colpo solo passando al comando apply la folder contente i file yaml

kubectl apply -f k8s/

Potrete verificare i deployments e service applicati a k8s

PS C:\Users\Dario> kubectl get deployments
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
comment-ws-deployment         4/4     4            4           8d
mysql-comment-db-deployment   1/1     1            1           8d
mysql-post-db-deployment      1/1     1            1           8d
post-ws-deployment            3/3     3            3           8d
PS C:\Users\Dario> kubectl get services
NAME                               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
comment-ws-cluster-ip-service      ClusterIP   10.106.126.10    <none>        8081/TCP   8d
kubernetes                         ClusterIP   10.96.0.1        <none>        443/TCP    8d
mysql-comment-cluster-ip-service   ClusterIP   10.108.191.13    <none>        3306/TCP   8d
mysql-post-cluster-ip-service      ClusterIP   10.106.147.220   <none>        3306/TCP   8d
post-ws-cluster-ip-service         ClusterIP   10.107.179.55    <none>        8080/TCP   8d

e potrete verificare lo stato dei vostri Pod in modo da assicurarvi che siano tutti Running

PS C:\Users\Dario> kubectl get pods
NAME                                           READY   STATUS    RESTARTS   AGE
comment-ws-deployment-6fbd48c545-78cgh         1/1     Running   0          8d
comment-ws-deployment-6fbd48c545-9tfzh         1/1     Running   0          8d
comment-ws-deployment-6fbd48c545-m6rfg         1/1     Running   0          8d
comment-ws-deployment-6fbd48c545-v46gl         1/1     Running   0          8d
mysql-comment-db-deployment-5bd584f666-vjggt   1/1     Running   0          8d
mysql-post-db-deployment-686cd9d966-j8x2s      1/1     Running   0          8d
post-ws-deployment-589864f477-6fx8q            1/1     Running   0          8d
post-ws-deployment-589864f477-md5zq            1/1     Running   0          8d
post-ws-deployment-589864f477-qd47z            1/1     Running   0          8d

Se per caso un Pod non e’ Running ed e’ in errore, potrete consulare i log di quest ultimo in modo da capire la causa del malfunzionamento con il comando

kubectl logs <podname>

Una volta assicurato che tutto sia Running potrete iniziare ad inviare Richieste Http alla nostra applicazione che gira su K8s ricordandoci che abbiamo configurato Ingress con il prefisso /post-ws. Ad esempio

GET localhost/post-ws/posts

response

200 []

conclusioni

In questo articolo abbiamo configurato un cluster con un singolo nodo utile per sviluppare e testare la nostra applicazione Social di esempio. La soluzione proposta va’ sicuramente migliorata ed estesa in quanto non abbiamo gestito:

  • monitoring
  • tracing
  • circuit breaker
  • autenticazione e autorizzazione

Raffineremo con queste features la nostra soluzione nei prossimi articoli.

 

A proposito di me

Dario Frongillo

Uno degli admin di Italiancoders e dell iniziativa devtalks.
Dario Frongillo è un software engineer e architect, specializzato in Web API, Middleware e Backend in ambito cloud native. Attualmente lavora presso NTT DATA, realtà di consulenza internazionale.
E' membro e contributor in diverse community italiane per developers; Nel 2017 fonda italiancoders.it, una community di blogger italiani che divulga articoli, video e contenuti per developers.

Gli articoli più letti

Articoli recenti

Commenti recenti