Nesta aula, vamos explorar como o Kubernetes gerencia a comunicação entre pods e com o mundo externo através do conceito de Serviços. Serviços são abstrações que definem uma política de acesso a um conjunto de pods, fornecendo um endpoint estável (IP e porta) mesmo quando os pods subjacentes mudam. Compreender os diferentes tipos de serviços e como eles interagem com o DNS interno e o Ingress é essencial para projetar aplicações resilientes e escaláveis no Kubernetes.

Vamos detalhar os três principais tipos de serviços: ClusterIP, NodePort e LoadBalancer, além de abordar a descoberta de serviços, o recurso Ingress (que atua como um roteador HTTP) e o DNS interno baseado no CoreDNS. Ao final, você terá uma visão clara de como conectar seus pods entre si e expô-los de forma controlada.

ClusterIP, NodePort, LoadBalancer

O tipo de serviço define como o tráfego é roteado para os pods. O ClusterIP é o tipo padrão: ele cria um IP virtual interno ao cluster, acessível apenas de dentro do cluster. Esse IP balanceia a carga entre os pods selecionados pelo serviço. É ideal para comunicação interna entre microsserviços, como um backend conversando com um banco de dados.

O NodePort expande o ClusterIP, expondo o serviço em uma porta estática (30000-32767) em cada nó do cluster. Assim, o tráfego externo pode chegar a qualquer nó na porta especificada e ser redirecionado para o ClusterIP. É útil para testes rápidos ou ambientes de desenvolvimento, mas não é recomendado para produção devido à exposição direta de portas altas.

O LoadBalancer é o tipo mais avançado: ele provisiona um balanceador de carga externo (como um ELB na AWS ou um LB no GCP) que encaminha o tráfego para o NodePort ou diretamente para os pods. É a forma mais comum de expor serviços em nuvens públicas, pois fornece um IP público e gerencia a distribuição de tráfego.

Abaixo, um exemplo de definição de um serviço do tipo LoadBalancer:

apiVersion: v1
kind: Service
metadata:
  name: meu-servico
spec:
  type: LoadBalancer
  selector:
    app: meu-app
  ports:
    - port: 80
      targetPort: 8080

Para criar o serviço, use kubectl apply -f servico.yaml. O Kubernetes criará automaticamente um ClusterIP e um NodePort subjacentes, e o provedor de nuvem configurará o balanceador externo.

Descoberta de serviços

A descoberta de serviços é o mecanismo pelo qual os pods encontram outros serviços no cluster. No Kubernetes, isso é feito principalmente através do DNS interno e das variáveis de ambiente. Quando um serviço é criado, o Kubernetes registra um nome DNS no formato <serviço>.<namespace>.svc.cluster.local. Outros pods podem usar esse nome para acessar o serviço, independentemente de sua localização no cluster.

Além do DNS, o kubelet também injeta variáveis de ambiente nos pods, como MEU_SERVICO_SERVICE_HOST e MEU_SERVICO_SERVICE_PORT, contendo o IP e a porta do serviço. No entanto, essas variáveis são definidas na criação do pod, então não são atualizadas se o serviço for recriado. Por isso, o DNS é a abordagem recomendada.

Para testar a descoberta, você pode executar um pod temporário e usar o comando nslookup ou curl:

kubectl run teste --rm -it --image=busybox -- sh
/ # nslookup meu-servico
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      meu-servico
Address 1: 10.108.123.45 meu-servico.default.svc.cluster.local

Isso mostra que o pod consegue resolver o nome do serviço para o IP ClusterIP. A descoberta funciona para serviços em qualquer namespace, desde que você use o nome completo ou o nome curto dentro do mesmo namespace.

Ingress (visão geral)

O Ingress é um recurso que gerencia o acesso externo aos serviços, geralmente HTTP/HTTPS. Ele atua como um proxy reverso, roteando requisições para diferentes serviços com base em regras de host e caminho. Por exemplo, você pode direcionar api.exemplo.com para um serviço backend e site.exemplo.com para um serviço frontend.

Para que o Ingress funcione, é necessário ter um Ingress Controller instalado no cluster, como o NGINX Ingress Controller ou o Traefik. O controller observa os recursos Ingress e configura o proxy de acordo. O Ingress oferece vantagens como TLS/SSL, balanceamento de carga e roteamento baseado em caminho, sem a necessidade de criar múltiplos LoadBalancers.

Um exemplo simples de Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: exemplo-ingress
spec:
  rules:
  - host: meuapp.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-svc
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

Esse Ingress encaminha as requisições para meuapp.com/api ao serviço api-svc e as demais para web-svc. O Ingress Controller aplicará as regras e atualizará seu proxy.

DNS interno

O DNS interno do Kubernetes é fornecido pelo CoreDNS, que roda como um conjunto de pods no namespace kube-system. Ele é automaticamente configurado como o servidor DNS para todos os pods, resolvendo nomes de serviços, pods e registros personalizados.

O domínio base é cluster.local. Para um serviço chamado meu-servico no namespace default, o FQDN é meu-servico.default.svc.cluster.local. Dentro do mesmo namespace, você pode usar apenas meu-servico. O CoreDNS também oferece suporte a headless services (sem ClusterIP), que retornam os IPs de todos os pods selecionados, permitindo descoberta de pods individuais.

Você pode verificar a configuração do CoreDNS com:

kubectl get configmap -n kube-system coredns -o yaml

O arquivo de configuração contém as zonas e os plugins. Por padrão, ele inclui o plugin kubernetes que integra o DNS com a API do Kubernetes.

Para testar a resolução de um nome de serviço, você pode usar o comando dig ou nslookup de dentro de um pod:

kubectl run dns-teste --rm -it --image=busybox -- nslookup meu-servico.default.svc.cluster.local

Isso deve retornar o IP do serviço. O DNS interno é fundamental para a comunicação entre serviços e para o funcionamento de aplicações distribuídas.

Boas práticas e observações finais

Ao trabalhar com serviços e networking, algumas práticas recomendadas incluem:

  • Use ClusterIP para comunicação interna entre serviços, evitando exposição desnecessária.
  • Prefira LoadBalancer para exposição externa em nuvem, mas esteja ciente dos custos.
  • Utilize Ingress para roteamento HTTP, centralizando a configuração de TLS e regras de caminho.
  • Sempre defina requests e limits para os pods, pois isso afeta a alocação de recursos e o balanceamento.
  • Monitore o CoreDNS e o Ingress Controller para garantir alta disponibilidade.

Com esses conceitos, você está pronto para projetar a comunicação da sua aplicação no Kubernetes de forma robusta e escalável.

Referências

Exercícios

  1. Explique a diferença entre ClusterIP, NodePort e LoadBalancer e em quais cenários cada um é mais adequado.

    ✓ Resposta: ClusterIP é o tipo padrão, criando um IP virtual acessível apenas dentro do cluster, ideal para comunicação interna entre serviços. NodePort expõe o serviço em uma porta estática em todos os nós, permitindo acesso externo, mas é menos seguro e usado para testes. LoadBalancer provisiona um balanceador de carga externo (em nuvem), fornecendo um IP público e gerenciando o tráfego, sendo o mais adequado para produção.
  2. Como funciona a descoberta de serviços no Kubernetes? Cite duas formas e indique a mais recomendada.

    ✓ Resposta: A descoberta de serviços funciona através do DNS interno (CoreDNS) e de variáveis de ambiente injetadas pelo kubelet. O DNS é a forma recomendada porque é dinâmico e atualizado automaticamente, enquanto as variáveis de ambiente são definidas na criação do pod e não refletem mudanças futuras.
  3. Escreva um manifesto YAML para um serviço do tipo NodePort que seleciona pods com o label app: web e expõe a porta 80 no pod, com porta do serviço 80 e nodePort 30080.

    ✓ Resposta:
    apiVersion: v1
    kind: Service
    metadata:
      name: web-service
    spec:
      type: NodePort
      selector:
        app: web
      ports:
        - port: 80
          targetPort: 80
          nodePort: 30080
  4. O que é um Ingress Controller e por que é necessário para usar recursos Ingress?

    ✓ Resposta: O Ingress Controller é um componente que implementa a lógica de roteamento definida nos recursos Ingress. Ele observa a API do Kubernetes e configura um proxy reverso (como NGINX) para encaminhar o tráfego conforme as regras. Sem um controller, o recurso Ingress não tem efeito, pois não há nada para processar as regras.
  5. Qual é o FQDN (nome totalmente qualificado) de um serviço chamado api no namespace prod? Como você acessaria esse serviço a partir de um pod no mesmo namespace?

    ✓ Resposta: O FQDN é api.prod.svc.cluster.local. Dentro do mesmo namespace, você pode usar apenas api como nome do host.