Compreenda os serviços do Kubernetes


Esta página descreve os diferentes tipos de serviços do Kubernetes e como o Google Kubernetes Engine (GKE) usa os serviços para agrupar os pontos finais dos pods.

Aprende a criar serviços através de exemplos de YAML. Cada tipo de serviço usa o endereço IP estável do serviço para reduzir a complexidade de tarefas específicas de rede e comunicação. Por exemplo, vai aprender a usar várias portas e pontos finais, bem como a configurar opções de pilha única ou dupla que suportam IPv4 e IPv6.

Para saber como criar um serviço, consulte o artigo Expor aplicações através de serviços.

Esta página destina-se a operadores e programadores que preparam e configuram recursos na nuvem, e implementam apps e serviços. Para saber mais sobre as funções comuns e as tarefas de exemplo referenciadas no Google Cloud conteúdo, consulte o artigoFunções e tarefas comuns do utilizador do GKE.

O que é um serviço do Kubernetes?

A ideia de um serviço é agrupar um conjunto de pontos finais de pods num único recurso. Pode configurar várias formas de aceder ao agrupamento. Por predefinição, recebe um endereço IP de cluster estável que os clientes no interior do cluster podem usar para contactar os Pods no serviço. Um cliente envia um pedido para o endereço IP estável e o pedido é encaminhado para um dos agrupamentos no serviço.

Um serviço identifica os respetivos pods membros com um seletor. Para que um Pod seja membro do serviço, tem de ter todas as etiquetas especificadas no seletor. Uma etiqueta é um par de chave/valor arbitrário anexado a um objeto.

O manifesto de serviço seguinte tem um seletor que especifica duas etiquetas. O campo selector indica que qualquer agrupamento que tenha a etiqueta app: metrics e a etiqueta department:engineering é membro deste serviço.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  # Use labels to select the member Pods of the Service.
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Porquê usar um serviço Kubernetes?

Num cluster do Kubernetes, cada pod tem um endereço IP interno. No entanto, os pods numa implementação aparecem e desaparecem, e os respetivos endereços IP mudam. Por isso, não faz sentido usar diretamente os endereços IP dos pods. Com um serviço, recebe um endereço IP estável que dura durante a vida útil do serviço, mesmo que os endereços IP dos pods membros mudem.

Um serviço também oferece balanceamento de carga. Os clientes chamam um único endereço IP estável e os respetivos pedidos são equilibrados entre os pods que são membros do serviço.

Tipos de serviços do Kubernetes

Existem cinco tipos de serviços:

  • ClusterIP (predefinição): os clientes internos enviam pedidos para um endereço IP interno estável.

  • NodePort: os clientes enviam pedidos para o endereço IP de um nó num ou mais valores nodePort especificados pelo serviço.

  • LoadBalancer: os clientes enviam pedidos para o endereço IP de um equilibrador de carga de rede.

  • ExternalName: os clientes internos usam o nome DNS de um serviço como um alias para um nome DNS externo.

  • Sem interface: pode usar um serviço sem interface quando quiser um agrupamento de pods, mas não precisar de um endereço IP estável.

O tipo NodePort é uma extensão do tipo ClusterIP. Assim, um serviço do tipo NodePort tem um endereço IP do cluster.

O tipo LoadBalancer é uma extensão do tipo NodePort. Assim, um serviço do tipo LoadBalancer tem um endereço IP do cluster e um ou mais valores nodePort.

Serviços do tipo ClusterIP

Quando cria um serviço do tipo ClusterIP, o Kubernetes cria um endereço IP estável acessível a partir de nós no cluster.

Segue-se um manifesto para um serviço do tipo ClusterIP:

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  selector:
    app: metrics
    department: sales
  # Create a ClusterIP Service. Kubernetes dynamically allocates an IP address
  # to the Service.
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Pode criar o Serviço através de kubectl apply -f [MANIFEST_FILE]. Depois de criar o serviço, pode usar kubectl get service para ver o endereço IP estável:

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

Os clientes no cluster chamam o serviço através do endereço IP do cluster e da porta TCP especificada no campo port do manifesto do serviço. O pedido é encaminhado para um dos pods membros na porta TCP especificada no campo targetPort. Para o exemplo anterior, um cliente chama o serviço em 10.11.247.213 na porta TCP 80. O pedido é encaminhado para um dos pods membros na porta TCP 8080. O membro Pod tem de ter um contentor que esteja a ouvir na porta TCP 8080. Se não existir um contentor a ouvir na porta 8080, os clientes veem uma mensagem como "Falha ao estabelecer ligação" ou "Não é possível aceder a este site".

Serviço do tipo NodePort

Quando cria um serviço do tipo NodePort, o Kubernetes atribui-lhe um valor nodePort. Em seguida, o serviço fica acessível através do endereço IP de qualquer nó, juntamente com o valor nodePort.

Segue-se um manifesto para um serviço do tipo NodePort:

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  selector:
    app: products
    department: sales
  # Kubernetes allocates a nodePort between 30000 and 32767 for external traffic
  # that reaches the node IP address. Additionally, Kubernetes dynamically
  # allocates a clusterIP IP address for internal traffic.
  type: NodePort
  ports:
  - protocol: TCP
    port: 80 # Route internal traffic that reaches the clusterIP IP address on this port.
    targetPort: 8080

Depois de criar o serviço, pode usar kubectl get service -o yaml para ver a respetiva especificação e o valor nodePort.

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

Os clientes externos chamam o Serviço através do endereço IP externo de um nó, juntamente com a porta TCP especificada por nodePort. O pedido é encaminhado para um dos pods membros na porta TCP especificada pelo campo targetPort.

Por exemplo, suponhamos que o endereço IP externo de um dos nós do cluster é 203.0.113.2. Em seguida, para o exemplo anterior, o cliente externo chama o serviço em 203.0.113.2 na porta TCP 32675. O pedido é encaminhado para um dos pods membros na porta TCP 8080. O agrupamento de membros tem de ter um contentor a escutar na porta TCP 8080.

O tipo de serviço NodePort é uma extensão do tipo de serviço ClusterIP. Assim, os clientes internos têm duas formas de chamar o serviço:

  • Use clusterIP e port.
  • Use o endereço IP de um nó e nodePort.

Para algumas configurações de clusters, o balanceador de carga de aplicações externo usa um serviço do tipo NodePort.

Um Application Load Balancer externo é um servidor proxy e é fundamentalmente diferente do Network Load Balancer de passagem externo descrito neste tópico em Serviço do tipo LoadBalancer.

Serviços do tipo LoadBalancer

Para saber mais acerca dos serviços do tipo LoadBalancer, consulte os conceitos do serviço LoadBalancer.

Serviço do tipo ExternalName

Um serviço do tipo ExternalName fornece um alias interno para um nome DNS externo. Os clientes internos fazem pedidos através do nome DNS interno e os pedidos são redirecionados para o nome externo.

Segue-se um manifesto para um serviço do tipo ExternalName:

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

Quando cria um serviço, o Kubernetes cria um nome DNS que os clientes internos podem usar para chamar o serviço. Para o exemplo anterior, o nome DNS é my-xn-service.default.svc.cluster.local. Quando um cliente interno faz um pedido a my-xn-service.default.svc.cluster.local, o pedido é redirecionado para example.com.

O tipo de serviço ExternalName é fundamentalmente diferente dos outros tipos de serviço. Na verdade, um serviço do tipo ExternalName não se enquadra na definição de serviço apresentada no início deste tópico. Um serviço do tipo ExternalName não está associado a um conjunto de pods e não tem um endereço IP estável. Em alternativa, um serviço do tipo ExternalName é um mapeamento de um nome DNS interno para um nome DNS externo.

Serviço sem interface

Um serviço sem interface é um tipo de serviço do Kubernetes que não atribui um endereço IP do cluster. Em alternativa, um serviço sem interface usa o DNS para expor os endereços IP dos pods associados ao serviço. Isto permite-lhe ligar-se diretamente aos Pods, em vez de passar por um proxy.

Os serviços sem interface são úteis para vários cenários, incluindo:

  • Deteção de serviços: pode usar um serviço sem interface para implementar a deteção de serviços. Para implementar esta funcionalidade, crie um serviço com um nome e um seletor. O registo DNS do serviço sem cabeça contém todos os IPs dos pods atrás do serviço que correspondem ao seletor. Os clientes podem usar estes registos DNS para encontrar os endereços IP dos pods associados ao serviço.

  • Acesso direto ao Pod: os clientes podem ligar-se diretamente aos Pods associados a um serviço sem interface, o que pode ser útil para serviços que requerem acesso direto aos Pods subjacentes, como equilibradores de carga e servidores DNS.

  • Flexibilidade: os serviços sem interface podem ser usados para criar uma variedade de topologias diferentes, como balanceadores de carga, servidores DNS e bases de dados distribuídas.

Se tiver requisitos de rede especiais para as suas cargas de trabalho que não podem ser resolvidos através de serviços sem interface com seletores, também existe a possibilidade de usar serviços sem interface sem seletores. Os serviços sem interface são uma ferramenta útil para aceder a serviços que não estão localizados no próprio cluster do Kubernetes. Uma vez que o plano de controlo não cria objetos EndpointSlice, pode ler mais sobre o assunto em Serviço sem seletores

O exemplo seguinte é um manifesto para um serviço sem interface:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  # Prevent Kubernetes from allocating an IP address to the Service.
  clusterIP: None
  selector:
    app: nginx
  ports:
  - name: http
    port: 80
    targetPort: 80

Depois de criar um serviço sem interface, pode encontrar os endereços IP dos pods associados ao serviço consultando o DNS. Por exemplo, o comando seguinte lista os endereços IP dos pods associados ao serviço nginx:

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

Outro exemplo que usa a expansão de consultas do Kubernetes:

dig +short +search nginx

Pode criar um serviço sem interface com um único comando, e os serviços sem interface são fáceis de atualizar e dimensionar.

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

Abstração de serviços

Um serviço é uma abstração no sentido em que não é um processo que escuta numa determinada interface de rede. Parte da abstração é implementada nas regras iptables dos nós do cluster. Consoante o tipo de serviço, outras partes da abstração são implementadas por um balanceador de carga de rede de encaminhamento externo ou um balanceador de carga de aplicações externo.

Portas de serviço arbitrárias

O valor do campo port num manifesto de serviço é arbitrário. No entanto, o valor de targetPort não é arbitrário. Cada pod de membro tem de ter um contentor a ouvir em targetPort.

Segue-se um serviço, do tipo LoadBalancer, que tem um valor port de 50 000:

apiVersion: v1
kind: Service
metadata:
  name: my-ap-service
spec:
  # Set your own IP address for internal traffic instead of letting Kubernetes
  # select one for you.
  clusterIP: 10.11.241.93
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30641 # Set a port for external traffic that reaches the node IP address.
    port: 50000 # Set a port for internal traffic that reaches the clusterIP IP address.
    protocol: TCP
    targetPort: 8080
  selector:
    app: parts
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.200

Um cliente chama o serviço em 203.0.113.200 na porta TCP 50000. O pedido é encaminhado para um dos pods membros na porta TCP 8080.

Várias portas

O campo ports de um serviço é uma matriz de objetos ServicePort. O objeto ServicePort tem estes campos:

  • name
  • protocol
  • port
  • targetPort
  • nodePort

Se tiver mais do que um ServicePort, cada ServicePort tem de ter um nome exclusivo.

Segue-se um serviço, do tipo LoadBalancer, que tem dois objetos ServicePort:

apiVersion: v1
kind: Service
metadata:
  name: my-tp-service
spec:
  clusterIP: 10.11.242.196
  externalTrafficPolicy: Cluster
  ports:
  # Forward traffic that reaches port 31233 on the node IP address, or port
  # 60000 on the clusterIP IP address, to port 50000 on a member Pod.
  - name: my-first-service-port
    nodePort: 31233
    port: 60000
    protocol: TCP
    targetPort: 50000
  # Forward traffic that reaches port 31081 on the node IP address, or port
  # 60001 on the clusterIP IP address, to port 8080 on a member Pod.
  - 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

No exemplo anterior, se um cliente chamar o serviço em 203.0.113.201 na porta TCP 60000, o pedido é encaminhado para um pod membro na porta TCP 50000. No entanto, se um cliente chamar o serviço em 203.0.113.201 na porta TCP 60001, o pedido é encaminhado para um pod membro na porta TCP 8080.

Cada membro do Pod tem de ter um contentor a ouvir na porta TCP 50000 e um contentor a ouvir na porta TCP 8080. Pode ser um único contentor com dois threads ou dois contentores em execução no mesmo pod.

Pontos finais de serviço

Quando cria um serviço, o Kubernetes cria um objeto Endpoints com o mesmo nome do seu serviço. O Kubernetes usa o objeto Endpoints para monitorizar os pods que são membros do serviço.

Serviços de pilha única e pilha dupla

Pode criar um serviço IPv6 do tipo ClusterIP ou NodePort.

Para cada um destes tipos de serviço, pode definir os campos ipFamilies e ipFamilyPolicy como IPv4, IPv6 ou um serviço de duplo stack.

O que se segue?