Configurar Serviços Públicos e Privados com Duas Instâncias do Traefik

Atualizado em 22 de May de 2026

Quando um cluster Kubernetes hospeda serviços voltados para a internet e serviços internos ao mesmo tempo, a abordagem mais limpa é dividir o tráfego de entrada no nível do ingress controller. Para isso, você pode implantar duas instâncias separadas do Traefik: uma para lidar com o ingress público e outra para o ingress privado.

Este guia apresenta essa configuração passo a passo. Você vai implantar dois releases Helm do Traefik com IngressClasses diferentes e, em seguida, rotear o tráfego para os serviços públicos e internos.

Como funciona

Duas instâncias independentes do Traefik são executadas no cluster:

  • traefik-public processa apenas recursos Ingress com ingressClassName: public
  • traefik-private processa apenas recursos Ingress com ingressClassName: private

Cada instância cria seu próprio serviço do tipo LoadBalancer com parâmetros diferentes:

  • O Traefik público recebe um IP externo e aceita tráfego da internet
  • O Traefik privado cria um load balancer interno sem IP público, acessível apenas dentro da rede privada

Dessa forma, você pode usar um único cluster tanto para aplicações externas quanto internas, sem misturar seus pontos de entrada.

Pré-requisitos

Antes de começar, certifique-se de que você tem:

  • helm instalado
  • Um cluster Kubernetes em execução
  • Acesso à rede privada do cluster para testar o ingress privado (por exemplo, via um servidor em nuvem separado na mesma rede)

Configurar o Traefik

As duas instâncias do Traefik são implantadas a partir do mesmo chart Helm, mas com arquivos de values separados. 

Configuração do Traefik público

Crie um arquivo chamado traefik-public-values.yaml com o seguinte conteúdo:

fullnameOverride: traefik-public
 
ingressClass:
  enabled: true
  isDefaultClass: false
  name: public
 
service:
  enabled: true
  type: LoadBalancer
 
providers:
  kubernetesCRD:
    enabled: true
    allowCrossNamespace: false
    ingressClass: public
  kubernetesIngress:
    enabled: true
    ingressClass: public
    publishedService:
      enabled: true

Esse arquivo configura a instância pública do Traefik para processar recursos ingress da classe public e criar um LoadBalancer padrão com IP externo.

Parâmetros importantes:

  • ingressClass.name: public define o nome da classe que os recursos Ingress públicos vão referenciar
  • providers.kubernetesCRD.ingressClass e providers.kubernetesIngress.ingressClass restringem o Traefik apenas aos recursos da sua própria classe
  • publishedService.enabled: true permite a publicação correta do endereço do serviço de ingress

Configuração do Traefik privado

Crie um arquivo chamado traefik-private-values.yaml com o seguinte conteúdo:

fullnameOverride: traefik-private
 
ingressClass:
  enabled: true
  isDefaultClass: false
  name: private
 
service:
  enabled: true
  type: LoadBalancer
  annotations:
    k8s.hostman.com/attached-loadbalancer-no-external-ip: "true"
 
providers:
  kubernetesCRD:
    enabled: true
    allowCrossNamespace: false
    ingressClass: private
  kubernetesIngress:
    enabled: true
    ingressClass: private
    publishedService:
      enabled: true

Esse arquivo configura a instância privada do Traefik para processar recursos ingress da classe private e criar um load balancer interno sem IP público.

O parâmetro principal aqui é k8s.hostman.com/attached-loadbalancer-no-external-ip: "true", que instrui a plataforma a provisionar um load balancer interno sem endereço IP público.

Instalar as duas instâncias do Traefik

Adicione o repositório Helm do Traefik:

helm repo add traefik https://helm.traefik.io/traefik
helm repo update

Implante a instância pública:

helm install traefik-public traefik/traefik \
  -n traefik-public --create-namespace \
  -f traefik-public-values.yaml

Implante a instância privada:

helm install traefik-public traefik/traefik \
  -n traefik-public --create-namespace \
  -f traefik-public-values.yaml

Após a instalação, verifique se os serviços do tipo LoadBalancer foram criados:

kubectl get svc -n traefik-public
kubectl get svc -n traefik-private

O provisionamento do load balancer pode levar até 10 minutos. A coluna EXTERNAL-IP pode exibir pending enquanto o recurso está sendo criado.

O comportamento esperado é diferente para cada instância:

  • traefik-public deve receber um endereço IP externo
  • traefik-private não receberá IP externo, pois utiliza um load balancer interno

Você também pode acompanhar o status dos load balancers pelo painel de controle da Hostman. Aguarde a conclusão do provisionamento antes de prosseguir.

Nessa etapa, confirme também que as duas classes de ingress estão registradas no cluster:

kubectl get ingressclass

A saída deve listar tanto public quanto private.

Rotear tráfego para serviços públicos e privados

Com as duas instâncias do Traefik em execução, basta definir o ingressClassName adequado em cada manifesto Ingress.

Para um serviço público:

spec:
  ingressClassName: public

Para um serviço privado:

spec:
  ingressClassName: private

Todo o tráfego será roteado automaticamente pelo ingress controller correspondente.

Exemplo prático

Os manifestos abaixo demonstram a configuração completa. O exemplo inclui:

  • Dois serviços públicos: service1 e service2
  • Um serviço privado: service3
  • Dois recursos Ingress com IngressClasses diferentes

ConfigMap com páginas HTML de teste

Crie config-map.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: service-config
  namespace: ingress-example
data:
  service1.html: |
    <html>
      <head><title>Service 1</title></head>
      <body><h1>Welcome to Service 1!</h1></body>
    </html>
  service2.html: |
    <html>
      <head><title>Service 2</title></head>
      <body><h1>Welcome to Service 2!</h1></body>
    </html>
  service3.html: |
    <html>
      <head><title>Service 3</title></head>
      <body><h1>Welcome to Service 3!</h1></body>
    </html>

Serviço público service1

Crie service1-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: service1
  namespace: ingress-example
spec:
  replicas: 2
  selector:
    matchLabels:
      app: service1
  template:
    metadata:
      labels:
        app: service1
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /usr/share/nginx/html
      volumes:
        - name: config-volume
          configMap:
            name: service-config
            items:
              - key: service1.html
                path: service1.html
---
apiVersion: v1
kind: Service
metadata:
  name: service1
  namespace: ingress-example
spec:
  selector:
    app: service1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Serviço público service2

Crie service2-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: service2
  namespace: ingress-example
spec:
  replicas: 2
  selector:
    matchLabels:
      app: service2
  template:
    metadata:
      labels:
        app: service2
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /usr/share/nginx/html
      volumes:
        - name: config-volume
          configMap:
            name: service-config
            items:
              - key: service2.html
                path: service2.html
---
apiVersion: v1
kind: Service
metadata:
  name: service2
  namespace: ingress-example
spec:
  selector:
    app: service2
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Serviço privado service3

Crie service3-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: service3
  namespace: ingress-example
spec:
  replicas: 2
  selector:
    matchLabels:
      app: service3
  template:
    metadata:
      labels:
        app: service3
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /usr/share/nginx/html
      volumes:
        - name: config-volume
          configMap:
            name: service-config
            items:
              - key: service3.html
                path: index.html
---
apiVersion: v1
kind: Service
metadata:
  name: service3
  namespace: ingress-example
spec:
  selector:
    app: service3
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Ingress público

Crie ingress-public.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-public-ingress
  namespace: ingress-example
spec:
  ingressClassName: public
  rules:
    - host: ingress1.example.com
      http:
        paths:
          - path: /service1
            pathType: Prefix
            backend:
              service:
                name: service1
                port:
                  number: 80
          - path: /service2
            pathType: Prefix
            backend:
              service:
                name: service2
                port:
                  number: 80

Observe que spec.ingressClassName está definido como public, o que significa que este Ingress será processado pelo ingress controller público.

Ingress privado

Crie ingress-private.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-private-ingress
  namespace: ingress-example
spec:
  ingressClassName: private
  rules:
    - host: ingress2.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: service3
                port:
                  number: 80

Aqui spec.ingressClassName está definido como private, portanto este Ingress será processado pelo ingress controller privado.

Aplicar os manifestos

Crie o namespace ingress-example:

kubectl create namespace ingress-example

Aplique todos os manifestos:

kubectl apply -f config-map.yaml
kubectl apply -f service1-deployment.yaml
kubectl apply -f service2-deployment.yaml
kubectl apply -f service3-deployment.yaml
kubectl apply -f ingress-public.yaml
kubectl apply -f ingress-private.yaml

Verifique se os deployments, serviços e recursos de ingress foram criados:

kubectl get deploy,svc,ingress -n ingress-example

Você deve ver três serviços, três deployments e dois recursos de ingress. Se algum estiver faltando, o manifesto correspondente não foi aplicado ou contém um erro.

Com essa configuração:

  • Requisições para ingress1.example.com/service1... são roteadas para o service1
  • Requisições para ingress1.example.com/service2... são roteadas para o service2
  • Requisições para ingress2.example.com/ são roteadas para o service3, acessível apenas dentro da rede privada via load balancer interno do Traefik

Verificar a configuração

Antes de enviar requisições de teste, confirme que cada ingress tem a classe correta atribuída:

kubectl describe ingress example-public-ingress -n ingress-example
kubectl describe ingress example-private-ingress -n ingress-example

Certifique-se de que example-public-ingress exibe Ingress Class: public e example-private-ingress exibe Ingress Class: private. Se a classe não corresponder, o Traefik não vai processar esse recurso.

O exemplo usa ingress1.example.com e ingress2.example.com como hostnames fictícios. Você pode utilizá-los com curl --resolve sem precisar configurar DNS real. Se quiser abrir o ingress público no navegador, substitua ingress1.example.com por um domínio real e configure um registro DNS apontando para o IP do load balancer público.

Quando o load balancer público tiver um IP externo, teste as rotas:

curl http://ingress1.example.com/service1.html \
  --resolve ingress1.example.com:80:PUBLIC_LB_EXTERNAL_IP
 
curl http://ingress1.example.com/service2.html \
  --resolve ingress1.example.com:80:PUBLIC_LB_EXTERNAL_IP

Onde PUBLIC_LB_EXTERNAL_IP é o IP externo atribuído ao load balancer público.

Se você receber um erro 404, verifique se está usando o hostname ingress1.example.com e os caminhos /service1 ou /service2.

Para testar o serviço privado, execute o comando abaixo a partir de uma máquina dentro da mesma rede privada do cluster:

curl http://ingress2.example.com/ \
  --resolve ingress2.example.com:80:PRIVATE_LB_IP

Onde PRIVATE_LB_IP é o IP privado do load balancer interno.

Você deve receber uma página HTML servida pelo service3.

Se a rota privada não responder, confirme que a requisição está partindo de dentro da rede privada. Tráfego externo não consegue alcançar esse ingress, mesmo que os recursos no cluster estejam configurados corretamente.

Esta página foi útil?
Atualizado em 22 de May de 2026

Tem perguntas,
comentários ou preocupações?

Nossos profissionais estão disponíveis para ajudá-lo a qualquer momento,
seja para assistência ou apenas se você não souber por onde começar.
Envie-nos um e-mail
Hostman's Support