Serviço

Nesta página, descrevemos os Serviços do Kubernetes e como eles são usados no Google Kubernetes Engine. Para aprender a criar um Serviço, consulte Como exibir aplicativos usando Serviços.

O que é um Serviço?

Um Service (em inglês) agrupa um conjunto de endpoints do pod em um recurso. É possível configurar várias maneiras de acessar o agrupamento. Por padrão, você recebe um endereço IP de cluster estável que os clientes no cluster podem usar para contatar pods no Service. Um cliente envia uma solicitação ao endereço IP estável, e ela é encaminhada a um dos pods no Serviço.

Um Serviço identifica os pods membros com um seletor. Para que um pod seja membro do Serviço, ele precisa ter todos os rótulos especificados no seletor. Um rótulo é um par de chave-valor arbitrário anexado a um objeto.

O manifesto de Serviço a seguir tem um seletor que especifica dois rótulos. O campo selector diz que qualquer pod que tenha os rótulos app: metrics e department:engineering é membro desse Serviço.

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

Por que usar um Serviço?

Em um cluster do Kubernetes, cada pod tem um endereço IP interno. Mas, em uma implantação, os pods vêm e vão, e os endereços IP deles mudam. Portanto, não faz sentido usar os endereços IP do pod diretamente. Você recebe, com um Serviço, um endereço IP estável válido durante a vida útil do Serviço, mesmo quando os endereços IP dos pods membros são alterados.

Um Serviço também fornece balanceamento de carga. Os clientes chamam um endereço IP único e estável, e as solicitações deles são balanceadas nos pods que são membros do Serviço.

Tipos de Serviços

Há cinco tipos de Serviços:

  • ClusterIP (padrão): os clientes internos enviam solicitações para um endereço IP interno estável.

  • NodePort: os clientes enviam solicitações para o endereço IP de um nó em um ou mais valores nodePort especificados pelo Serviço.

  • LoadBalancer: os clientes enviam solicitações para o endereço IP de um balanceador 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 comando: use um Serviço sem comando quando você quiser agrupar um pod, mas não precisa de um endereço IP estável.

O tipo NodePort é uma extensão do tipo ClusterIP. Portanto, um Serviço do tipo NodePort tem um endereço IP de cluster.

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

Serviços do tipo ClusterIP

Quando você cria um Serviço do tipo ClusterIP, o Kubernetes cria um endereço IP estável que pode ser acessado pelos nós no cluster.

Veja aqui um manifesto de um Serviço do 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
    

É possível criar o Serviço usando kubectl apply -f [MANIFEST_FILE]. Depois de criar o Serviço, use 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 usando o endereço IP do cluster e a porta TCP especificada no campo port do manifesto do Serviço. A solicitação é encaminhada para um dos pods de membro na porta TCP especificada no campo targetPort. Portanto, no exemplo anterior, um cliente chama o Serviço em 10.11.247.213 na porta TCP 80. A solicitação é encaminhada a um dos pods membros na porta TCP 8080. Observe que o pod membro precisa ter um contêiner que esteja detectando a porta TCP 8080. Se nenhum contêiner estiver detectando a porta 8080, os clientes verão uma mensagem como "Falha ao conectar" ou "Não foi possível acessar este site".

Serviço do tipo NodePort

Quando você cria um Serviço do tipo NodePort, o Kubernetes fornece um valor nodePort. Em seguida, o Serviço pode ser acessado usando o endereço IP de qualquer nó junto com o valor nodePort.

Veja um manifesto para um Serviço do 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
    

Depois de criar o Serviço, use kubectl get service -o yaml para visualizar a especificação dele e ver o valor nodePort.

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

Clientes externos chamam o Serviço usando o endereço IP externo de um nó junto com a porta TCP especificada por nodePort. A solicitação é encaminhada para um dos pods membros na porta TCP especificada pelo campo targetPort.

Por exemplo, imagine que o endereço IP externo de um dos nós do cluster seja 203.0.113.2. Em seguida, no exemplo anterior, o cliente externo chama o Serviço em 203.0.113.2 na porta TCP 32675. A solicitação é encaminhada a um dos pods membros na porta TCP 8080. O pod membro precisa ter um contêiner detectando a porta TCP 8080.

O tipo de Serviço NodePort é uma extensão do tipo de Serviço ClusterIP. Portanto, os clientes internos têm duas maneiras de chamar o Serviço:

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

Para algumas configurações de cluster, o balanceador de carga HTTP(S) do Google Cloud usa um Serviço do tipo NodePort. Para mais informações, consulte Como configurar o balanceamento de carga HTTP com a entrada.

Observe que um balanceador de carga HTTP(S) é um servidor proxy e é fundamentalmente diferente do balanceador de carga de rede descrito neste tópico em Serviço do tipo LoadBalancer.

Serviços do tipo LoadBalancer

Quando você cria um Serviço do tipo LoadBalancer, um controlador do Google Cloud é reativado e configura um balanceador de carga de rede no projeto. Esse balanceador de carga tem um endereço IP estável que pode ser acessado de fora do seu projeto.

Observe que um balanceador de carga de rede não é um servidor proxy. Ele encaminha pacotes sem alterar os endereços IP de origem e destino.

Veja um manifesto para um Serviço do tipo LoadBalancer:

    apiVersion: v1
    kind: Service
    metadata:
      name: my-nlb-service
    spec:
      selector:
        app: metrics
        department: engineering
      type: LoadBalancer
      ports:
      - port: 80
        targetPort: 8080
    

Depois de criar o Serviço, use kubectl get service -o yaml para visualizar a especificação e ver o endereço IP externo estável:

    spec:
      clusterIP: 10.11.242.115
      externalTrafficPolicy: Cluster
      ports:
      - nodePort: 32676
        port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: metrics
        department: engineering
      sessionAffinity: None
      type: LoadBalancer
      status:
        loadBalancer:
          ingress:
          - ip: 203.0.113.100
    

Na saída, o endereço IP do balanceador de carga de rede aparece em loadBalancer:ingress:. Clientes externos chamam o Serviço usando o endereço IP do balanceador de carga e a porta TCP especificada por port. A solicitação é encaminhada para um dos pods membros na porta TCP especificada por targetPort. Portanto, no exemplo anterior, o cliente chama o Serviço em 203.0.113.100 na porta TCP 80. A solicitação é encaminhada a um dos pods membros na porta TCP 8080. O pod membro precisa ter um contêiner detectando a porta TCP 8080.

O tipo de Serviço LoadBalancer é uma extensão do tipo NodePort, que, por sua vez, é uma extensão do tipo ClusterIP.

Serviço do tipo ExternalName

Um Serviço do tipo ExternalName fornece um alias interno para um nome DNS externo. Os clientes internos fazem solicitações usando o nome DNS interno, e as solicitações são redirecionadas para o nome externo.

Veja 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 você cria um Serviço, o Kubernetes cria um nome DNS que os clientes internos podem usar para chamar o Serviço. No exemplo anterior, o nome DNS é my-xn-service.default.svc.cluster.local. Quando um cliente interno faz uma solicitação para esse DNS, ela é redirecionada 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 ajusta à definição de Serviço fornecida 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 vez disso, um Serviço do tipo ExternalName é um mapeamento de um nome DNS interno para um nome DNS externo.

Abstração de Serviço

Um Serviço é uma abstração no sentido de que não é um processo que detecta em alguma interface de rede. Parte da abstração é implementada nas regras do iptables dos nós do cluster. Dependendo do tipo do Serviço, outras partes da abstração são implementadas por balanceamento de carga de rede ou balanceamento de carga HTTP(S).

Portas de Serviço arbitrário

O valor do campo port em um manifesto de Serviço é arbitrário. No entanto, o valor de targetPort não é arbitrário. Cada pod membro precisa ter um contêiner detectando em targetPort.

Este é um Serviço do tipo LoadBalancer, que tem um valor de port de 50000:

    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
    

Um cliente chama o Serviço em 203.0.113.200 na porta TCP 50000. A solicitação é encaminhada a 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 você tiver mais de um ServicePort, cada um precisará ter um nome exclusivo.

Este é 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:
      - 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
    

No exemplo anterior, se um cliente chama o Serviço em 203.0.113.201 na porta TCP 60000, a solicitação é encaminhada a um pod membro na porta TCP 50000. Mas se um cliente chamar o Serviço em 203.0.113.201 na porta TCP 60001, a solicitação será encaminhada a um pod membro na porta TCP 8080.

Cada pod membro precisa ter um contêiner detectando a porta TCP 50000 e outro detectando a porta TCP 8080. É possível ter um contêiner único com duas linhas de execução ou dois contêineres em execução no mesmo pod.

Endpoints de Serviço

Ao criar um Serviço, o Kubernetes cria um objeto Endpoints com o mesmo nome. O Kubernetes usa o objeto Endpoints para rastrear quais pods são membros do Serviço.

A seguir