Servizi


In questa pagina vengono descritti i servizi Kubernetes e il loro utilizzo in Google Kubernetes Engine (GKE). Esistono diversi tipi di servizi, che puoi usare per raggruppare un insieme di endpoint dei pod in un'unica risorsa. Per scoprire come creare un servizio, vedi Esposizione di applicazioni mediante servizi.

Che cos'è un servizio Kubernetes?

L'idea di un servizio è raggruppare un insieme di endpoint dei pod in un'unica risorsa. Puoi configurare vari modi per accedere al raggruppamento. Per impostazione predefinita, ottieni un indirizzo IP del cluster stabile che i client all'interno del cluster possono utilizzare per contattare i pod nel servizio. Un client invia una richiesta all'indirizzo IP stabile, che viene instradata a uno dei pod nel servizio.

Un Service identifica i propri pod membri con un selettore. Affinché un pod sia membro del servizio, deve avere tutte le etichette specificate nel selettore. Un'etichetta è una coppia chiave/valore arbitraria collegata a un oggetto.

Il seguente manifest del servizio ha un selettore che specifica due etichette. Il campo selector indica che qualsiasi pod con etichetta app: metrics e etichetta department:engineering fa parte di questo servizio.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Perché utilizzare un servizio Kubernetes?

In un cluster Kubernetes, ogni pod ha un indirizzo IP interno. ma i pod in un deployment vanno e vengono e i loro indirizzi IP cambiano. Quindi non ha senso usare direttamente gli indirizzi IP dei pod. Con un servizio, si ottiene un indirizzo IP stabile che dura per tutta la durata del servizio, anche se gli indirizzi IP dei pod membri cambiano.

Un Service fornisce anche il bilanciamento del carico. I client chiamano un singolo indirizzo IP stabile e le loro richieste vengono bilanciate tra i pod membri del servizio.

Tipi di servizi Kubernetes

Esistono cinque tipi di servizi:

  • ClusterIP (predefinito): i client interni inviano le richieste a un indirizzo IP interno stabile.

  • NodePort: i client inviano le richieste all'indirizzo IP di un nodo su uno o più valori nodePort specificati dal servizio.

  • LoadBalancer: i client inviano le richieste all'indirizzo IP di un bilanciatore del carico di rete.

  • ExternalName::i client interni utilizzano il nome DNS di un servizio come alias per un nome DNS esterno.

  • Headless: puoi utilizzare un servizio headless quando vuoi un raggruppamento di pod, ma non hai bisogno di un indirizzo IP stabile.

Il tipo NodePort è un'estensione del tipo ClusterIP. Un servizio di tipo NodePort ha quindi un indirizzo IP cluster.

Il tipo LoadBalancer è un'estensione del tipo NodePort. Un servizio di tipo LoadBalancer ha quindi un indirizzo IP cluster e uno o più valori nodePort.

Servizi di tipo ClusterIP

Quando crei un servizio di tipo ClusterIP, Kubernetes crea un indirizzo IP stabile accessibile dai nodi nel cluster.

Di seguito è riportato un manifest per un servizio di tipo ClusterIP:

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  selector:
    app: metrics
    department: sales
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Puoi creare il servizio utilizzando kubectl apply -f [MANIFEST_FILE]. Dopo aver creato il servizio, puoi utilizzare kubectl get service per vedere l'indirizzo IP stabile:

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
my-cip-service   ClusterIP   10.11.247.213   none          80/TCP

I client del cluster chiamano il servizio utilizzando l'indirizzo IP del cluster e la porta TCP specificata nel campo port del manifest del servizio. La richiesta viene inoltrata a uno dei pod membro sulla porta TCP specificata nel campo targetPort. Nell'esempio precedente, un client chiama il servizio alla porta 10.11.247.213 sulla porta TCP 80. La richiesta viene inoltrata a uno dei pod membri sulla porta TCP 8080. Il pod membro deve avere un container in ascolto sulla porta TCP 8080. Se sulla porta 8080 non è presente alcun container in ascolto, i client visualizzeranno un messaggio come "Connessione non riuscita" o "Impossibile raggiungere il sito".

Servizio di tipo NodePort

Quando crei un servizio di tipo NodePort, Kubernetes ti fornisce un valore nodePort. Quindi il servizio è accessibile utilizzando l'indirizzo IP di qualsiasi nodo insieme al valore nodePort.

Di seguito è riportato il file manifest per un servizio di tipo NodePort:

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  selector:
    app: products
    department: sales
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Dopo aver creato il servizio, puoi utilizzare kubectl get service -o yaml per visualizzarne la specifica e vedere il valore nodePort.

spec:
  clusterIP: 10.11.254.114
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32675
    port: 80
    protocol: TCP
    targetPort: 8080

I client esterni chiamano il servizio utilizzando l'indirizzo IP esterno di un nodo insieme alla porta TCP specificata da nodePort. La richiesta viene inoltrata a uno dei pod membro sulla porta TCP specificata nel campo targetPort.

Ad esempio, supponiamo che l'indirizzo IP esterno di uno dei nodi del cluster sia 203.0.113.2. Quindi, per l'esempio precedente, il client esterno chiama il servizio in 203.0.113.2 sulla porta TCP 32675. La richiesta viene inoltrata a uno dei pod membro sulla porta TCP 8080. Il pod membro deve avere un ascolto di container sulla porta TCP 8080.

Il tipo di servizio NodePort è un'estensione del tipo di servizio ClusterIP. I clienti interni possono chiamare il servizio in due modi:

  • Usa i criteri clusterIP e port.
  • Utilizza l'indirizzo IP di un nodo e nodePort.

Per alcune configurazioni di cluster, il bilanciatore del carico delle applicazioni esterno utilizza un servizio di tipo NodePort.

Per ulteriori informazioni, consulta Configurare un bilanciatore del carico delle applicazioni esterno con Ingress.

Un bilanciatore del carico delle applicazioni esterno è un server proxy ed è fondamentalmente diverso dal bilanciatore del carico di rete passthrough esterno descritto in questo argomento in Servizio di tipo LoadBalancer.

Servizi di tipo LoadBalancer

Per scoprire di più sui servizi di tipo LoadBalancer, consulta i concetti del servizio LoadBalancer.

Servizio di tipo ExternalName

Un servizio di tipo ExternalName fornisce un alias interno per un nome DNS esterno. I client interni effettuano le richieste utilizzando il nome DNS interno e le richieste vengono reindirizzate al nome esterno.

Di seguito è riportato il file manifest per un servizio di tipo ExternalName:

apiVersion: v1
kind: Service
metadata:
  name: my-xn-service
spec:
  type: ExternalName
  externalName: example.com

Quando crei un servizio, Kubernetes crea un nome DNS che i client interni possono utilizzare per chiamare il servizio. Per l'esempio precedente, il nome DNS è my-xn-service.default.svc.cluster.local. Quando un client interno invia una richiesta a my-xn-service.default.svc.cluster.local, la richiesta viene reindirizzata a example.com.

Il tipo di servizio ExternalName è fondamentalmente diverso dagli altri tipi di servizio. Infatti, un Service di tipo ExternalName non rientra nella definizione di Service fornita all'inizio di questo argomento. Un servizio di tipo ExternalName non è associato a un insieme di pod e non ha un indirizzo IP stabile. Un servizio di tipo ExternalName è invece una mappatura da un nome DNS interno a un nome DNS esterno.

Servizio headless

Un servizio headless è un tipo di servizio Kubernetes che non alloca un indirizzo IP cluster. Un servizio headless utilizza invece il DNS per esporre gli indirizzi IP dei pod associati al servizio. Ciò ti consente di connetterti direttamente ai pod, invece di passare attraverso un proxy.

I servizi headless sono utili in diversi scenari, tra cui:

  • Bilanciamento del carico tra pod: puoi utilizzare servizi headless per bilanciare il carico tra i pod. Per implementarlo, crea un Service con un selettore che corrisponda ai pod che vuoi bilanciare. Il servizio distribuirà quindi il traffico in modo uniforme tra tutti i pod che corrispondono al selettore.

  • Service Discovery: puoi utilizzare un servizio headless per implementare il Service Discovery. Per implementarlo, crea un servizio con un nome e un selettore. Il record DNS per il servizio headless contiene tutti gli IP dei pod dietro il servizio corrispondenti al selettore. I client possono utilizzare questi record DNS per trovare gli indirizzi IP dei pod associati al servizio.

  • Accesso diretto ai pod: i client possono connettersi direttamente ai pod associati a un servizio headless, il che può essere utile per i servizi che richiedono l'accesso diretto ai pod sottostanti, come i bilanciatori del carico e i server DNS.

  • Flessibilità: i servizi headless possono essere utilizzati per creare una varietà di topologie diverse, come bilanciatori del carico, server DNS e database distribuiti.

Se hai requisiti di rete speciali per i tuoi carichi di lavoro che non possono essere risolti utilizzando servizi headless con selettori, c'è anche la possibilità di utilizzare servizi headless senza selettori. I servizi headless sono uno strumento utile per accedere ai servizi che non si trovano all'interno del cluster Kubernetes stesso, poiché il piano di controllo non crea oggetti EndpointSlice. Per saperne di più, consulta Servizio senza selettori

L'esempio seguente è un manifest per un servizio headless:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
  - name: http
    port: 80
    targetPort: 80

Una volta creato un servizio headless, puoi trovare gli indirizzi IP dei pod associati al servizio eseguendo una query sul DNS. Ad esempio, il comando seguente elenca gli indirizzi IP dei pod associati al servizio nginx:

dig +short nginx.default.svc.cluster.local

Ecco un altro esempio che utilizza l'espansione della query di Kubernetes:

dig +short +search nginx

Puoi creare un servizio headless con un solo comando, che è semplice da aggiornare e scalare.

kubectl create service clusterip my-svc --clusterip="None" --dry-run=client -o yaml > [file.yaml]

Astrazione del servizio

Un servizio è un'astrazione, nel senso che non è un processo in ascolto su alcune interfacce di rete. Parte dell'astrazione è implementata nelle regole iptables dei nodi del cluster. A seconda del tipo di servizio, altre parti dell'astrazione vengono implementate da un bilanciatore del carico di rete passthrough esterno o da un bilanciatore del carico delle applicazioni esterno.

Porte di servizio arbitrario

Il valore del campo port in un file manifest del servizio è arbitrario. Tuttavia, il valore di targetPort non è arbitrario. Ogni pod membro deve avere un container in ascolto su targetPort.

Ecco un servizio di tipo LoadBalancer che ha un valore di port pari a 50.000:

apiVersion: v1
kind: Service
metadata:
  name: my-ap-service
spec:
  clusterIP: 10.11.241.93
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30641
    port: 50000
    protocol: TCP
    targetPort: 8080
  selector:
    app: parts
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.200

Un client chiama il servizio alla porta 203.0.113.200 sulla porta TCP 50.000. La richiesta viene inoltrata a uno dei pod membri sulla porta TCP 8080.

Più porte

Il campo ports di un servizio è un array di oggetti ServicePort. L'oggetto ServicePort ha i seguenti campi:

  • name
  • protocol
  • port
  • targetPort
  • nodePort

Se disponi di più di una ServicePort, ciascuna deve avere un nome univoco.

Ecco un servizio, di tipo LoadBalancer, che ha due oggetti ServicePort:

apiVersion: v1
kind: Service
metadata:
  name: my-tp-service
spec:
  clusterIP: 10.11.242.196
  externalTrafficPolicy: Cluster
  ports:
  - name: my-first-service-port
    nodePort: 31233
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: my-second-service-port
    nodePort: 31081
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    app: tests
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.201

Nell'esempio precedente, se un client chiama il servizio alla porta 203.0.113.201 sulla porta TCP 60000, la richiesta viene inoltrata al pod di un membro sulla porta TCP 50000. Ma se un client chiama il servizio alla 203.0.113.201 sulla porta TCP 60001, la richiesta viene inoltrata al pod di un membro sulla porta TCP 8080.

Ogni pod membro deve disporre di un container in ascolto sulla porta TCP 50000 e di un container in ascolto sulla porta TCP 8080. Può trattarsi di un singolo container con due thread o di due container in esecuzione nello stesso pod.

Endpoint di servizio

Quando crei un servizio, Kubernetes crea un oggetto Endpoints con lo stesso nome del servizio. Kubernetes usa l'oggetto Endpoints per tenere traccia dei pod che sono membri del servizio.

Servizi a stack singolo e doppio

Puoi creare un servizio IPv6 di tipo ClusterIP o NodePort. GKE supporta servizi a doppio stack di tipo LoadBalancer durante l'anteprima, che non offrono SLA (accordi sul livello del servizio) o assistenza tecnica.

Per ognuno di questi tipi di servizi, puoi definire i campi ipFamilies e ipFamilyPolicy come servizio IPv4, IPv6 o a doppio stack.

Passaggi successivi