Docker & Kubernetes

Guia Completo de Services em Kubernetes: ClusterIP, NodePort, LoadBalancer e ExternalName

11 min de leitura

Guia Completo de Services em Kubernetes: ClusterIP, NodePort, LoadBalancer e ExternalName

O que é um Service no Kubernetes Um Service no Kubernetes é um objeto que expõe um conjunto de Pods como um serviço de rede. Diferentemente de um Pod, que é efêmero e pode ser criado ou destruído a qualquer momento, um Service fornece um ponto de acesso estável e previsível para sua aplicação. Ele atua como um intermediário entre clientes (internos ou externos) e os Pods que executam sua aplicação, abstraindo a complexidade de descoberta e roteamento de tráfego. O Kubernetes oferece quatro tipos principais de Services, cada um com um propósito específico. Cada tipo determina como o tráfego chega aos seus Pods e quem pode acessá-los. Escolher o tipo correto é fundamental para uma arquitetura bem-planejada, pois afeta segurança, performance e usabilidade. Neste artigo, vamos explorar em profundidade cada um desses tipos e quando utilizá-los. ClusterIP: Comunicação Interna O que é ClusterIP ClusterIP é o tipo de Service padrão no Kubernetes. Ele cria um IP virtual (VIP) interno

<h2>O que é um Service no Kubernetes</h2>

<p>Um Service no Kubernetes é um objeto que expõe um conjunto de Pods como um serviço de rede. Diferentemente de um Pod, que é efêmero e pode ser criado ou destruído a qualquer momento, um Service fornece um ponto de acesso estável e previsível para sua aplicação. Ele atua como um intermediário entre clientes (internos ou externos) e os Pods que executam sua aplicação, abstraindo a complexidade de descoberta e roteamento de tráfego.</p>

<p>O Kubernetes oferece quatro tipos principais de Services, cada um com um propósito específico. Cada tipo determina como o tráfego chega aos seus Pods e quem pode acessá-los. Escolher o tipo correto é fundamental para uma arquitetura bem-planejada, pois afeta segurança, performance e usabilidade. Neste artigo, vamos explorar em profundidade cada um desses tipos e quando utilizá-los.</p>

<h2>ClusterIP: Comunicação Interna</h2>

<h3>O que é ClusterIP</h3>

<p>ClusterIP é o tipo de Service padrão no Kubernetes. Ele cria um IP virtual (VIP) interno que é acessível apenas dentro do cluster. Qualquer Pod dentro do cluster pode alcançar esse Service usando o seu nome DNS ou o IP do cluster. Este tipo é ideal para comunicação entre serviços internos da sua aplicação, como um frontend comunicando com um backend.</p>

<p>Quando você cria um Service ClusterIP, o Kubernetes aloca um IP de um intervalo específico (geralmente 10.0.0.0/24) e registra esse IP no servidor DNS interno do cluster (CoreDNS). Isso significa que os Pods podem fazer requisições usando simplesmente o nome do Service, como <code>meu-backend:8080</code>, sem precisar conhecer o IP real dos Pods subjacentes.</p>

<h3>Exemplo Prático de ClusterIP</h3>

<p>Vamos criar um exemplo real: um serviço de backend que será acessado apenas por Pods dentro do cluster. Primeiro, crie uma aplicação simples em Python:</p>

<pre><code class="language-python"># app.py

from flask import Flask

app = Flask(__name__)

@app.route(&#039;/api/dados&#039;)

def dados():

return {&#039;mensagem&#039;: &#039;Olá do backend&#039;, &#039;status&#039;: &#039;ativo&#039;}

if __name__ == &#039;__main__&#039;:

app.run(host=&#039;0.0.0.0&#039;, port=5000)</code></pre>

<p>Agora, crie o manifesto Kubernetes:</p>

<pre><code class="language-yaml">apiVersion: apps/v1

kind: Deployment

metadata:

name: backend-app

namespace: default

spec:

replicas: 3

selector:

matchLabels:

app: backend

template:

metadata:

labels:

app: backend

spec:

containers:

  • name: backend

image: backend-app:latest

ports:

  • containerPort: 5000

---

apiVersion: v1

kind: Service

metadata:

name: backend-service

namespace: default

spec:

type: ClusterIP

selector:

app: backend

ports:

  • protocol: TCP

port: 80

targetPort: 5000</code></pre>

<p>Aplicando esse manifesto, os Pods dentro do cluster podem acessar o backend usando <code>http://backend-service:80/api/dados</code>. O ClusterIP automaticamente distribui as requisições entre as três réplicas do Deployment.</p>

<h2>NodePort: Acesso Externo via Porta do Node</h2>

<h3>O que é NodePort</h3>

<p>NodePort estende o conceito do ClusterIP adicionando a capacidade de acessar o Service através de uma porta aberta em cada Node do cluster. Quando você cria um Service NodePort, o Kubernetes aloca uma porta no intervalo 30000-32767 em todos os Nodes e roteia o tráfego dessa porta para o Service. Isso permite que clientes externos acessem sua aplicação através de qualquer IP de Node e a porta designada.</p>

<p>NodePort é útil para desenvolvimento, testes e ambientes menores. Contudo, não é recomendado para produção em larga escala, pois a gestão de portas pode ficar complexa e cada Node expõe a mesma porta, criando possíveis conflitos. Além disso, a experiência do usuário é pior (ter que digitar uma porta específica em uma URL) comparada a soluções como LoadBalancer.</p>

<h3>Exemplo Prático de NodePort</h3>

<p>Vamos expor uma aplicação web simples usando NodePort:</p>

<pre><code class="language-yaml">apiVersion: apps/v1

kind: Deployment

metadata:

name: web-app

namespace: default

spec:

replicas: 2

selector:

matchLabels:

app: web

template:

metadata:

labels:

app: web

spec:

containers:

  • name: web

image: nginx:latest

ports:

  • containerPort: 80

---

apiVersion: v1

kind: Service

metadata:

name: web-service

namespace: default

spec:

type: NodePort

selector:

app: web

ports:

  • protocol: TCP

port: 80

targetPort: 80

nodePort: 30080</code></pre>

<p>Após aplicar esse manifesto, você pode acessar sua aplicação em <code>http://&lt;IP_DO_NODE&gt;:30080</code>. Se o seu cluster possui três Nodes com IPs 192.168.1.10, 192.168.1.11 e 192.168.1.12, todos os três endereços funcionarão: <code>http://192.168.1.10:30080</code>, <code>http://192.168.1.11:30080</code> e <code>http://192.168.1.12:30080</code>. O Kubernetes cuida do roteamento para os Pods corretos automaticamente.</p>

<h2>LoadBalancer: Balanceamento de Carga Externo</h2>

<h3>O que é LoadBalancer</h3>

<p>LoadBalancer é o tipo de Service que integra-se com o provedor de nuvem para provisionar um balanceador de carga externo. Quando você cria um Service LoadBalancer, o Kubernetes solicita ao provedor (AWS, Azure, Google Cloud, etc.) que crie um load balancer real, que então roteia o tráfego para seu cluster. Esse é o tipo preferido para expor serviços em produção, pois oferece uma solução robusta, escalável e gerenciada automaticamente.</p>

<p>O LoadBalancer é essencialmente um NodePort com uma camada adicional gerenciada pelo provedor de nuvem. Isso significa que você também consegue acessar o Service através da porta NodePort, mas o acesso primário é através do IP ou nome DNS do load balancer. O provedor de nuvem se encarrega de distribuir o tráfego entre os Nodes, monitorar saúde e escalar conforme necessário.</p>

<h3>Exemplo Prático de LoadBalancer</h3>

<p>Imagine que você quer expor uma API REST em produção na AWS. O manifesto seria:</p>

<pre><code class="language-yaml">apiVersion: apps/v1

kind: Deployment

metadata:

name: api-server

namespace: production

spec:

replicas: 3

selector:

matchLabels:

app: api

template:

metadata:

labels:

app: api

spec:

containers:

  • name: api

image: minha-api:v1.0

ports:

  • containerPort: 8080

resources:

requests:

memory: &quot;256Mi&quot;

cpu: &quot;250m&quot;

limits:

memory: &quot;512Mi&quot;

cpu: &quot;500m&quot;

---

apiVersion: v1

kind: Service

metadata:

name: api-service

namespace: production

annotations:

service.beta.kubernetes.io/aws-load-balancer-type: &quot;nlb&quot;

spec:

type: LoadBalancer

selector:

app: api

ports:

  • protocol: TCP

port: 443

targetPort: 8080

sessionAffinity: ClientIP

sessionAffinityConfig:

clientIP:

timeoutSeconds: 10800</code></pre>

<p>Após aplicar esse manifesto na AWS, o Kubernetes criará um Network Load Balancer e retornará um nome DNS externo (algo como <code>a1b2c3d4-e5f6g7h8.us-east-1.elb.amazonaws.com</code>). Você pode acessar sua API através desse endereço. A anotação <code>aws-load-balancer-type: &quot;nlb&quot;</code> especifica que queremos um Network Load Balancer em vez de um Classic Load Balancer, oferecendo melhor performance.</p>

<h2>ExternalName: Redirecionamento para Serviços Externos</h2>

<h3>O que é ExternalName</h3>

<p>ExternalName é um tipo de Service especial que não cria um load balancer ou expõe Pods. Em vez disso, ele funciona como um alias DNS que redireciona requisições para um serviço externo (fora do cluster). Isso é útil quando você precisa manter aplicações dentro do Kubernetes que dependem de serviços legados ou gerenciados externamente, como um banco de dados em um servidor dedicado ou uma API de terceiros.</p>

<p>Tecnicamente, um Service ExternalName cria um registro CNAME no DNS interno do cluster que aponta para o hostname externo fornecido. Quando um Pod tenta acessar o Service, ele é redirecionado transparentemente para o servidor externo. Isso oferece uma camada de abstração que facilita mudanças futuras (por exemplo, migrar o banco de dados para dentro do cluster sem alterar o código da aplicação).</p>

<h3>Exemplo Prático de ExternalName</h3>

<p>Suponha que você tenha um banco de dados PostgreSQL rodando em um servidor externo em <code>db.empresa.com</code> na porta 5432, e você quer que suas aplicações Kubernetes acessem-no através de um Service. Crie um Service ExternalName:</p>

<pre><code class="language-yaml">apiVersion: v1

kind: Service

metadata:

name: postgres-db

namespace: default

spec:

type: ExternalName

externalName: db.empresa.com

ports:

  • port: 5432

targetPort: 5432

protocol: TCP</code></pre>

<p>Agora, qualquer aplicação dentro do cluster pode conectar ao banco de dados usando <code>postgres-db:5432</code> em vez de precisar conhecer o hostname e gerenciar configurações externas. Uma aplicação Python que usa psycopg2 seria assim:</p>

<pre><code class="language-python"># database.py

import psycopg2

def conectar_banco():

conn = psycopg2.connect(

host=&quot;postgres-db&quot;, # Nome do Service ExternalName

port=5432,

user=&quot;usuario&quot;,

password=&quot;senha&quot;,

database=&quot;meu_banco&quot;

)

return conn

if __name__ == &#039;__main__&#039;:

conn = conectar_banco()

print(&quot;Conectado ao banco com sucesso!&quot;)

conn.close()</code></pre>

<p>A vantagem é que se no futuro você migrar o banco de dados para dentro do cluster, basta atualizar o Service para um ClusterIP apontando para o Deployment do banco, sem precisar alterar nenhum código das aplicações.</p>

<h2>Comparação e Casos de Uso</h2>

<p>Cada tipo de Service atende a necessidades diferentes, e a escolha adequada depende do contexto de sua aplicação. <strong>ClusterIP</strong> é usado para comunicação entre Pods internos, oferecendo segurança e eficiência máximas. <strong>NodePort</strong> é adequado para desenvolvimento e testes, quando você precisa acessar uma aplicação de fora do cluster, mas não quer a complexidade de um load balancer gerenciado. <strong>LoadBalancer</strong> é a escolha padrão para produção, oferecendo uma experiência de usuário polida com DNS e distribuição de carga automática. <strong>ExternalName</strong> resolve um caso de uso específico: permitir que aplicações Kubernetes acessem serviços legados ou terceirizados de forma transparente.</p>

<p>Uma aplicação típica em produção usaria uma combinação desses tipos: services ClusterIP para componentes internos que conversam entre si, um LoadBalancer para a API ou frontend exposta ao público, e talvez um ExternalName para conectar com um banco de dados gerenciado. Entender quando usar cada um é essencial para projetar uma arquitetura Kubernetes robusta e eficiente.</p>

<h2>Conclusão</h2>

<p>Aprendemos que Services no Kubernetes são abstrações fundamentais que resolvem o problema de descoberta de serviços e roteamento de tráfego. ClusterIP fornece acesso interno seguro, NodePort expõe serviços via portas nos Nodes para desenvolvimento, LoadBalancer oferece uma solução de produção gerenciada pelo provedor de nuvem, e ExternalName permite integração transparente com serviços externos. A chave é reconhecer que cada tipo tem um propósito específico: não existe um tipo &quot;melhor&quot;, mas sim o tipo correto para cada situação. Na prática, você combinará esses tipos conforme sua arquitetura exigir, construindo sistemas distribuídos resilientes e escaláveis.</p>

<h2>Referências</h2>

<ul>

<li>https://kubernetes.io/docs/concepts/services-networking/service/</li>

<li>https://kubernetes.io/docs/concepts/services-networking/service-types/</li>

<li>https://learn.microsoft.com/pt-br/azure/aks/concepts-network-services</li>

<li>https://aws.amazon.com/pt/blogs/containers/kubernetes-service-types/</li>

<li>https://www.oreilly.com/library/view/kubernetes-in-action/9781617293726/</li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Docker & Kubernetes

Como Usar Pod Disruption Budgets e Topology Spread Constraints em Produção
Como Usar Pod Disruption Budgets e Topology Spread Constraints em Produção

Pod Disruption Budgets (PDB): Garantindo Alta Disponibilidade Pod Disruption...

O que Todo Dev Deve Saber sobre Progressive Delivery com Argo Rollouts: Canary e Blue-Green Automatizados
O que Todo Dev Deve Saber sobre Progressive Delivery com Argo Rollouts: Canary e Blue-Green Automatizados

O que é Progressive Delivery? Progressive Delivery é um modelo de implantação...

O que Todo Dev Deve Saber sobre Docker Compose para Desenvolvimento: Hot Reload e Ambientes Reproduzíveis
O que Todo Dev Deve Saber sobre Docker Compose para Desenvolvimento: Hot Reload e Ambientes Reproduzíveis

Docker Compose para Desenvolvimento: Hot Reload e Ambientes Reproduzíveis O D...