Services e networking
Esta aula aborda os conceitos fundamentais de serviços e networking no Kubernetes, incluindo os tipos de Service ClusterIP, NodePort e LoadBalancer, a descoberta de serviços, uma visão geral do Ingress e o DNS interno. O conteúdo inclui explicações detalhadas, exemplos práticos com YAML e comandos kubectl, além de exercícios para fixação.
Nesta aula, vamos explorar um dos pilares do Kubernetes: os Services e o networking que permite que os pods se comuniquem entre si e com o mundo externo. Entender como os serviços funcionam é essencial para projetar aplicações resilientes e escaláveis no Kubernetes.
Vamos começar com os três tipos principais de Service (ClusterIP, NodePort e LoadBalancer), depois veremos como a descoberta de serviços acontece, uma visão geral do Ingress e, por fim, o DNS interno que o Kubernetes fornece automaticamente.
ClusterIP, NodePort, LoadBalancer
Um Service no Kubernetes é uma abstração que define um conjunto lógico de pods e uma política para acessá-los. Ele fornece um endereço IP estável e um nome DNS para um conjunto de pods que podem ser criados e destruídos dinamicamente. Existem três tipos principais de Service, cada um com um escopo de exposição diferente.
ClusterIP é o tipo padrão. Ele cria um IP virtual dentro do cluster (no intervalo configurado para serviços) que só é acessível de dentro do cluster. Esse é o tipo mais comum para comunicação interna entre serviços. Por exemplo, um backend que só precisa ser acessado por outros pods internamente.
NodePort expõe o serviço em cada nó do cluster em uma porta estática (entre 30000-32767). Isso permite que o serviço seja acessado de fora do cluster usando <IP-do-nó>:<porta-do-nó>. NodePort é útil para testes simples ou quando você não tem um balanceador de carga externo.
LoadBalancer é o tipo que integra com o balanceador de carga do provedor de nuvem (como AWS ELB, GCP LB, etc.). Ele cria um balanceador de carga externo que encaminha tráfego para os nós, e de lá para os pods. Esse é o tipo mais comum para expor serviços para o mundo externo em produção.
Vamos ver um exemplo de cada tipo. Primeiro, um Service ClusterIP para uma aplicação web simples:
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
selector:
app: web
ports:
- protocol: TCP
port: 80 # porta do serviço
targetPort: 8080 # porta do podEsse Service seleciona pods com o label app: web e encaminha o tráfego da porta 80 do serviço para a porta 8080 dos pods.
Para criar um NodePort, basta adicionar type: NodePort e especificar uma porta no intervalo permitido:
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30080 # opcional, se omitido o Kubernetes escolheE para um LoadBalancer, usamos type: LoadBalancer:
apiVersion: v1
kind: Service
metadata:
name: web-lb
spec:
type: LoadBalancer
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 8080No caso do LoadBalancer, o Kubernetes provisiona um balanceador de carga externo (se o ambiente suportar) e retorna o endereço IP externo.
Descoberta de serviços
A descoberta de serviços é o mecanismo pelo qual um pod encontra o endereço de outro serviço. No Kubernetes, isso é feito principalmente por duas vias: variáveis de ambiente e DNS.
Quando um Service é criado, o Kubernetes injeta automaticamente um conjunto de variáveis de ambiente nos pods (se eles foram criados depois do Service). Essas variáveis seguem o padrão <SERVICE_NAME>_SERVICE_HOST e <SERVICE_NAME>_SERVICE_PORT. Por exemplo, para um serviço chamado web-service, o pod terá WEB_SERVICE_SERVICE_HOST e WEB_SERVICE_SERVICE_PORT.
No entanto, o método mais recomendado e moderno é usar o DNS interno do cluster. O Kubernetes roda um serviço DNS (geralmente o CoreDNS) que cria registros DNS para cada Service. O nome DNS é o nome do Service no namespace, então um pod pode simplesmente usar http://web-service para acessar o serviço. Isso é muito mais limpo e não depende da ordem de criação.
Vamos ver um exemplo prático. Suponha que temos um Deployment para um backend e um Service chamado backend. Um frontend pode acessar o backend usando a URL http://backend:8080 (onde 8080 é a porta do Service).
Para testar a descoberta de serviços, podemos executar um pod temporário e fazer uma requisição:
kubectl run test-pod --image=busybox --rm -it --restart=Never -- wget -qO- http://backend:8080Isso demonstra que o pod consegue resolver o nome do serviço e se conectar a ele.
Ingress (visão geral)
O Ingress é um recurso do Kubernetes que gerencia o acesso externo aos serviços, geralmente HTTP e HTTPS. Ele fornece roteamento baseado em regras, balanceamento de carga, TLS/SSL e virtual hosting. O Ingress não é um Service, mas sim um controlador que implementa as regras definidas.
Para usar Ingress, você precisa instalar um controlador de Ingress, como o NGINX Ingress Controller, Traefik, ou o controlador do seu provedor de nuvem. O controlador observa os recursos Ingress e configura o proxy de acordo.
Um exemplo de Ingress que roteia o tráfego para dois serviços diferentes com base no caminho:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: meuapp.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80Nesse exemplo, requisições para meuapp.com/api são encaminhadas para o serviço api-service, e as demais para web-service. O Ingress também pode configurar TLS com certificados, usando um Secret.
É importante notar que o Ingress só é útil para tráfego HTTP/HTTPS. Para outros protocolos, você precisará de LoadBalancer ou NodePort.
DNS interno
O DNS interno do Kubernetes é um componente essencial para a descoberta de serviços. Ele é implementado pelo CoreDNS (ou kube-dns em versões antigas) e roda como um conjunto de pods no namespace kube-system. O DNS resolve nomes de serviços para os IPs de ClusterIP correspondentes.
Cada Service recebe um registro DNS no formato <nome-do-serviço>.<namespace>.svc.cluster.local. Dentro do mesmo namespace, você pode usar apenas o nome do serviço (ex: backend). De outro namespace, use <nome>.<namespace> (ex: backend.producao).
Além de serviços, o DNS também resolve pods (se habilitado) e pode ser configurado para domínios personalizados. Vamos ver como testar a resolução DNS:
kubectl exec -it meu-pod -- nslookup backendou usando o busybox:
kubectl exec -it meu-pod -- nslookup backend.default.svc.cluster.localO CoreDNS também suporta políticas de DNS (como ClusterFirst, que é o padrão), que definem como as consultas DNS são encaminhadas para o DNS externo.
Entender o DNS interno é crucial para configurar a comunicação entre serviços de forma confiável.
Boas práticas e observações finais
Ao trabalhar com Services e networking no Kubernetes, siga estas boas práticas:
- Use Services ClusterIP para comunicação interna, evitando expor desnecessariamente seus serviços.
- Prefira Ingress para exposição HTTP/HTTPS em produção, pois oferece controle mais fino e economia de IPs públicos.
- Use LoadBalancer apenas quando precisar de balanceamento externo para protocolos não HTTP.
- Nomeie seus Services de forma clara e consistente, pois eles são usados como nomes DNS.
- Aproveite o DNS interno para descoberta de serviços, em vez de variáveis de ambiente, pois é mais flexível.
- Monitore o CoreDNS e os endpoints dos Services para garantir que o tráfego está sendo roteado corretamente.
Com esses conceitos, você está pronto para projetar a rede da sua aplicação no Kubernetes de forma eficiente.
Exercícios
- Crie um Service ClusterIP para um deployment chamado
appque escuta na porta 80 do pod, usando a porta 8080 no Service. Escreva o YAML. - Qual é a diferença entre ClusterIP e NodePort? Em que situação você usaria NodePort?
- Explique como funciona a descoberta de serviços usando DNS interno. Dê um exemplo de como um pod pode acessar um serviço chamado
dbno namespaceproducao. - O que é um Ingress? Quais são os benefícios de usar Ingress em vez de expor cada serviço com LoadBalancer?
- Como você verifica se o DNS interno está resolvendo corretamente um serviço? Dê um comando exemplo.
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: app
ports:
- protocol: TCP
port: 8080
targetPort: 80<nome-do-serviço>.<namespace>.svc.cluster.local. Um pod pode acessar o serviço db no namespace producao usando o nome db.producao (ou o FQDN completo). Por exemplo, um pod pode conectar-se a db.producao:5432.nslookup ou wget para testar a resolução. Por exemplo:kubectl run test-pod --image=busybox --rm -it --restart=Never -- nslookup nome-do-serviçoReferências
- Kubernetes Documentation: Service
- Kubernetes Documentation: DNS for Services and Pods
- Kubernetes Documentation: Ingress
- Kubernetes Documentation: Ingress Minikube
- Kubernetes Documentation: Network Policies
- Kubernetes Documentation: DNS Debugging
- Kubernetes Documentation: Connecting Applications with Services