Kubernetes è una potente piattaforma di orchestrazione dei container, ma per sfruttarne appieno il potenziale, è importante comprendere i suoi componenti principali, con i pod e i servizi che svolgono ruoli fondamentali. In questo articolo, esploreremo cosa sono e come lavorano insieme per esporre e gestire l’accesso alle applicazioni in esecuzione all’interno di un cluster Kubernetes.
Cosa è un Pod?
Pod sono le unità di calcolo più piccole che puoi creare e gestire in Kubernetes.
Prima di creare un pod, controlliamo le risorse API disponibili nel tuo cluster Kubernetes; puoi utilizzare il comando kubectl api-resources
. Questo comando elenca le risorse API supportate dal server API di Kubernetes, inclusi i loro nomi abbreviati, i gruppi API e se sono o meno namespace. Questo è utile per comprendere le capacità del tuo cluster, specialmente quando si lavora con risorse personalizzate o si esplorano nuove funzionalità di Kubernetes. Il comando kubectl explain
completa questo fornendo informazioni dettagliate sulle singole risorse.
Creiamo un file di configurazione di base per un pod che esegue un semplice container Nginx.
Crea un file denominato nginx-pod.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Ecco una breve spiegazione dei termini utilizzati:
- apiVersion: v1: Specifica la versione API.
- kind: Pod: Indica che questa configurazione è per un pod.
- metadata:name: Il nome del pod.
- metadati: etichette: Coppie chiave-valore che possono essere utilizzate per organizzare e selezionare il pod.
- spec:contenitori: Un elenco di contenitori che verranno eseguiti nel pod.
- spec:contenitori:nome: Il nome del contenitore.
- spec:contenitori:immagine: L’immagine del contenitore da utilizzare (in questo caso, l’ultima immagine di Nginx).
- spec:contenitori:porte: Le porte da esporre dal contenitore.
Usa kubectl
per applicare il file di configurazione e creare il pod:
kubectl apply -f nginx-pod.yaml
Controlla lo stato del pod per assicurarti che sia stato creato e sia in esecuzione:
kubectl get pods
Dovresti vedere un output simile a questo:
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 10s
Successivamente, elimina il pod:
kubectl delete pod nginx-pod
L’output dovrebbe assomigliare al seguente:
kubectl get pod
No resources found in default namespace.
Cos’è un Servizio?
Creare un servizio per un pod Nginx in Kubernetes ti consente di esporre l’applicazione Nginx e renderla accessibile all’interno o all’esterno del cluster. Ecco una guida passo dopo passo per creare un Servizio per un pod Nginx.
Per assicurarti di avere un pod Nginx in esecuzione, se non ne hai già uno, crea un file YAML chiamato nginx-pod.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Applica la configurazione del Pod:
kubectl apply -f nginx-pod.yaml
Crea un file YAML chiamato nginx-service.yaml
per definire il Servizio:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Qui ci sono alcune cose da notare:
- selector: Un selettore di etichette per abbinare il pod Nginx.
- app: nginx: Questo dovrebbe corrispondere all’etichetta nel pod Nginx.
- type: ClusterIP: Il tipo del Servizio. ClusterIP rende il Servizio accessibile solo all’interno del cluster. Puoi anche usare NodePort o LoadBalancer per esporre il Servizio esternamente.
Applica la configurazione del Servizio utilizzando kubectl
:
kubectl apply -f nginx-service.yaml
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP 10.96.0.1 <none> 80/TCP 10s
Poiché il Servizio è di tipo ClusterIP, è accessibile solo all’interno del cluster. Per accedervi dall’esterno del cluster, puoi cambiare il tipo di Servizio in NodePort o LoadBalancer.
Per esporre il Servizio esternamente utilizzando NodePort
, modifica il file nginx-service.yaml
:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30007 # Specify a node port in the range 30000-32767 (optional)
type: NodePort
Applica la configurazione aggiornata del Servizio:
kubectl apply -f nginx-service.yaml
Ora puoi accedere all’applicazione Nginx utilizzando l’indirizzo IP del nodo e la porta del nodo (ad esempio, http://<node-ip>:30007).
Pod Multi-Container
L’utilizzo di un singolo contenitore per pod fornisce la massima granularità e disaccoppiamento. Tuttavia, ci sono scenari in cui il deployment di più contenitori, talvolta definiti come contenitori compositi, all’interno di un singolo pod risulta vantaggioso. Questi contenitori secondari possono svolgere diverse funzioni: gestire i log o potenziare il contenitore primario (concetto di sidecar), agire come proxy per sistemi esterni (concetto di ambasciatore) o modificare i dati per adattarli a un formato esterno (concetto di adattatore). Questi contenitori secondari complementano il contenitore primario eseguendo compiti che quest’ultimo non gestisce.
Di seguito è riportato un esempio di configurazione del pod Kubernetes che include un contenitore primario in esecuzione di un server Nginx e un contenitore secondario che funge da sidecar per gestire i log. Il contenitore sidecar utilizza un semplice contenitore di log come BusyBox per dimostrare come è possibile visualizzare i log di accesso di Nginx.
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-logging-sidecar
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
- name: log-sidecar
image: busybox:latest
command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
volumes:
- name: shared-logs
emptyDir: {}
In seguito, eseguirai le seguenti operazioni:
- Salva la configurazione YAML in un file, ad esempio
nginx-with-logging-sidecar.yaml
. - Applica la configurazione utilizzando
kubectl:kubectl apply -f nginx-with-logging-sidecar.yaml
. - Verifica che il pod sia in esecuzione:
kubectl get pods
. - Controlla i log del contenitore sidecar per visualizzare i log di accesso di Nginx:
kubectl logs -f <nome-pod> -c log-sidecar
.
Seguendo questi passaggi, eliminerai il Pod esistente e applicherai la nuova configurazione, impostando un Pod con un container Nginx e un container sidecar per il logging. Ciò garantirà che la nuova configurazione sia attiva ed in esecuzione nel tuo cluster Kubernetes.
I Pod multi-container in Kubernetes offrono diversi vantaggi, consentendo un deployment e una gestione delle applicazioni più flessibili ed efficienti.
Pattern di Pod Multi-Container
Pattern Sidecar
I container sidecar possono potenziare l’applicazione principale fornendo funzioni ausiliarie come il logging, la gestione delle configurazioni o il proxying. Questo pattern aiuta ad estendere la funzionalità senza modificare il container principale. Un container sidecar può gestire il logging raccogliendo e inoltrando i log dal container dell’applicazione principale.
Pattern Ambassador
I container ambassador fungono da proxy, gestendo la comunicazione tra l’applicazione principale e i servizi esterni. Ciò può semplificare l’integrazione e la configurazione. Un container ambassador potrebbe gestire la terminazione SSL o le funzioni di API gateway.
Il pattern Ambassador coinvolge l’utilizzo di un container sidecar per gestire la comunicazione tra l’applicazione principale e i servizi esterni. Questo pattern può gestire compiti come il proxying, il bilanciamento del carico o la gestione delle connessioni sicure, astrayendo la complessità dal container dell’applicazione principale.
- Container Applicazione Principale: Un semplice server web che effettua richieste HTTP
- Container Ambassador: Proxy Envoy configurato per gestire le richieste all’API esterna
apiVersion: v1
kind: Pod
metadata:
name: app-with-ambassador
spec:
containers:
- name: web-app
image: python:3.8-slim
command: ["python", "-m", "http.server", "8000"]
volumeMounts:
- name: config-volume
mountPath: /etc/envoy
- name: envoy-proxy
image: envoyproxy/envoy:v1.18.3
args: ["-c", "/etc/envoy/envoy.yaml"]
ports:
- containerPort: 8080
volumeMounts:
- name: config-volume
mountPath: /etc/envoy
volumes:
- name: config-volume
configMap:
name: envoy-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: envoy-config
data:
envoy.yaml: |
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: external_service
http_filters:
- name: envoy.filters.http.router
clusters:
- name: external_service
connect_timeout: 0.25s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: external_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: api.example.com
port_value: 80
Questo esempio dimostra il pattern Ambassador in Kubernetes, in cui un proxy Envoy funge da intermediario per gestire la comunicazione esterna per il container dell’applicazione principale. Questo pattern aiuta ad astrarre le complessità della comunicazione e migliora la modularità e la manutenibilità.
Pattern Adattatore
I container Adattatore possono modificare o trasformare i dati tra l’applicazione principale e i sistemi esterni, garantendo compatibilità e integrazione. Ad esempio, un container adattatore può riformattare i dati di log per soddisfare i requisiti di un servizio di logging esterno.
Il pattern Adattatore in Kubernetes coinvolge l’uso di un container sidecar per trasformare i dati tra il container dell’applicazione principale e i sistemi esterni. Questo può essere utile quando l’applicazione principale richiede dati in un formato specifico diverso da quello fornito o richiesto dai sistemi esterni.
Supponiamo di avere un container di applicazione principale che genera log in un formato personalizzato. È necessario inviare questi log a un servizio di logging esterno che richiede log in un formato standard specifico. Un container adattatore può essere utilizzato per trasformare i dati di log nel formato richiesto prima di inviarli al servizio esterno.
- Container Applicazione Principale: Un’applicazione semplice che scrive log in un formato personalizzato.
- Container Adattatore: Un container che legge i log personalizzati, li trasforma in formato JSON e li invia a un servizio di logging esterno.
apiVersion: v1
kind: Pod
metadata:
name: app-with-adapter
spec:
containers:
- name: log-writer
image: busybox
command: ["sh", "-c", "while true; do echo \"$(date) - Custom log entry\" >> /var/log/custom/app.log; sleep 5; done"]
volumeMounts:
- name: shared-logs
mountPath: /var/log/custom
- name: log-adapter
image: busybox
command: ["sh", "-c", "tail -f /var/log/custom/app.log | while read line; do echo \"$(echo $line | sed 's/ - / - {\"timestamp\": \"/;s/$/\"}/')\" >> /var/log/json/app.json; done"]
volumeMounts:
- name: shared-logs
mountPath: /var/log/custom
- name: json-logs
mountPath: /var/log/json
- name: log-sender
image: busybox
command: ["sh", "-c", "while true; do cat /var/log/json/app.json | grep -v '^$' | while read line; do echo \"Sending log to external service: $line\"; done; sleep 10; done"]
volumeMounts:
- name: json-logs
mountPath: /var/log/json
volumes:
- name: shared-logs
emptyDir: {}
- name: json-logs
emptyDir: {}
Questo esempio illustra il pattern Adapter in Kubernetes, in cui un contenitore adattatore trasforma i dati dal contenitore dell’applicazione primaria nel formato richiesto prima di inviarli a un sistema esterno. Questo pattern aiuta ad integrare le applicazioni con i servizi esterni gestendo le trasformazioni dei formati dei dati all’interno del contenitore sidecar.
Riepilogo
In sintesi, i pods:
- Sono le unità più piccole distribuibili in Kubernetes.
- Rappresentano un’istanza singola di un processo in esecuzione.
- Possono contenere uno o più contenitori.
I servizi:
- Forniscono un indirizzo IP stabile e un nome DNS per accedere ai pods.
- Abilitano il bilanciamento del carico tra un insieme di pods.
- Agevolano la scoperta dei servizi all’interno del cluster.
Source:
https://dzone.com/articles/the-ultimate-guide-to-kubernetes-pods-and-services