This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Serviços, balanceamento de carga e conectividade

Conceitos e recursos por trás da conectividade no Kubernetes.

A conectividade do Kubernetes trata quatro preocupações:

  • Contêineres em um Pod se comunicam via interface loopback.
  • A conectividade do cluster provê a comunicação entre diferentes Pods.
  • O recurso de Service permite a você expor uma aplicação executando em um Pod, de forma a ser alcançável de fora de seu cluster.
  • Você também pode usar os Services para publicar serviços de consumo interno do seu cluster.

1 - Service

Exponha uma aplicação em execução no seu cluster por trás de um único endpoint voltado para o exterior, mesmo quando a carga de trabalho está dividida entre vários backends.

No Kubernetes, um Service é uma forma abstrata de expor uma aplicação que está executando em um conjunto de Pods como um serviço de rede.

Um objetivo fundamental dos Services no Kubernetes é que você não precise modificar sua aplicação existente para usar um mecanismo de descoberta de serviços desconhecido. Você pode executar código em Pods, seja um código projetado para um mundo nativo em nuvem, ou uma aplicação mais antiga que você containerizou. Você usa um Service para tornar esse conjunto de Pods disponível na rede para que os clientes possam interagir com ele.

Se você usa um Deployment para executar sua aplicação, esse Deployment pode criar e destruir Pods dinamicamente. De um momento para o outro, você não sabe quantos desses Pods estão funcionando e íntegros; você pode nem mesmo saber como esses Pods íntegros são nomeados. Os Pods do Kubernetes são criados e destruídos para corresponder ao estado desejado do seu cluster. Pods são recursos efêmeros (você não deve esperar que um Pod individual seja confiável e durável).

Cada Pod obtém seu próprio endereço IP (o Kubernetes espera que os plugins de rede garantam isso). Para um determinado Deployment no seu cluster, o conjunto de Pods em execução em um momento no tempo pode ser diferente do conjunto de Pods executando essa aplicação um momento depois.

Isso leva a um problema: se algum conjunto de Pods (chame-os de "backends") fornece funcionalidade para outros Pods (chame-os de "frontends") dentro do seu cluster, como os frontends descobrem e mantêm o controle de qual endereço IP conectar, para que o frontend possa usar a parte backend da carga de trabalho?

Entram os Services.

Services no Kubernetes

A API Service, parte do Kubernetes, é uma abstração para ajudá-lo a expor grupos de Pods em uma rede. Cada objeto Service define um conjunto lógico de endpoints (geralmente esses endpoints são Pods) junto com uma política sobre como tornar esses pods acessíveis.

Por exemplo, considere um backend de processamento de imagens sem estado que está em execução com 3 réplicas. Essas réplicas são fungíveis—os frontends não se importam com qual backend eles usam. Embora os Pods reais que compõem o conjunto de backend possam mudar, os clientes frontend não devem precisar estar cientes disso, nem devem precisar manter o controle do conjunto de backends por conta própria.

A abstração Service permite esse desacoplamento.

O conjunto de Pods direcionado por um Service geralmente é determinado por um seletor que você define. Para aprender sobre outras maneiras de definir endpoints de Service, consulte Services sem seletores.

Se sua carga de trabalho fala HTTP, você pode optar por usar um Ingress para controlar como o tráfego web alcança essa carga de trabalho. Ingress não é um tipo de Service, mas atua como o ponto de entrada para o seu cluster. Um Ingress permite que você consolide suas regras de roteamento em um único recurso, para que você possa expor múltiplos componentes da sua carga de trabalho, executando separadamente no seu cluster, atrás de um único ponto de entrada.

O Gateway API para Kubernetes fornece capacidades extras além de Ingress e Service. Você pode adicionar Gateway ao seu cluster - é uma família de APIs de extensão, implementadas usando CustomResourceDefinitions - e então usá-las para configurar o acesso a serviços de rede que estão em execução no seu cluster.

Descoberta de serviços nativos em nuvem

Se você puder usar as APIs do Kubernetes para descoberta de serviços na sua aplicação, você pode consultar o servidor de API para EndpointSlices correspondentes. O Kubernetes atualiza os EndpointSlices para um Service sempre que o conjunto de Pods em um Service muda.

Para aplicações não nativas, o Kubernetes oferece maneiras de colocar uma porta de rede ou balanceador de carga entre sua aplicação e os Pods de backend.

De qualquer forma, sua carga de trabalho pode usar esses mecanismos de descoberta de Services para encontrar o destino ao qual deseja se conectar.

Definindo um Service

Um Service é um objeto (da mesma forma que um Pod ou um ConfigMap é um objeto). Você pode criar, visualizar ou modificar definições de Service usando a API do Kubernetes. Normalmente você usa uma ferramenta como kubectl para fazer essas chamadas para a API.

Por exemplo, suponha que você tenha um conjunto de Pods que escutam na porta TCP 9376 e são rotulados como app.kubernetes.io/name=MyApp. Você pode definir um Service para publicar esse ponto de entrada TCP:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

Aplicar esse manifesto cria um novo Service chamado "my-service" com o tipo de Service ClusterIP padrão. O Service direciona para a porta TCP 9376 em qualquer Pod com o rótulo app.kubernetes.io/name: MyApp.

O Kubernetes atribui a este Service um endereço IP (o IP do cluster), que é usado pelo mecanismo de endereço IP virtual. Para mais detalhes sobre esse mecanismo, leia IPs Virtuais e Proxies de Service.

O controlador para esse Service verifica continuamente por Pods que correspondam ao seu seletor, e então faz quaisquer atualizações necessárias ao conjunto de EndpointSlices para o Service.

O nome de um objeto Service deve ser um nome de rótulo RFC 1035 válido.

Requisitos de nomenclatura relaxados para objetos Service

ESTADO DA FUNCIONALIDADE: Kubernetes v1.34 [alpha](disabled by default)

O feature gate RelaxedServiceNameValidation permite que nomes de objetos Service comecem com um dígito. Quando este feature gate está habilitado, os nomes de objetos Service devem ser nomes de rótulo RFC 1123 válidos.

Definições de porta

Definições de porta em Pods têm nomes, e você pode referenciar esses nomes no atributo targetPort de um Service. Por exemplo, podemos vincular a targetPort do Service à porta do Pod da seguinte maneira:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80
        name: http-web-svc

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 80
    targetPort: http-web-svc

Isso funciona mesmo se houver uma mistura de Pods no Service usando um único nome configurado, com o mesmo protocolo de rede disponível através de diferentes números de porta. Isso oferece muita flexibilidade para implantar e evoluir seus Services. Por exemplo, você pode alterar os números de porta que os Pods expõem na próxima versão do seu software de backend, sem quebrar os clientes.

O protocolo padrão para Services é TCP; você também pode usar qualquer outro protocolo suportado.

Como muitos Services precisam expor mais de uma porta, o Kubernetes suporta múltiplas definições de porta para um único Service. Cada definição de porta pode ter o mesmo protocol, ou um diferente.

Services sem seletores

Services mais comumente abstraem o acesso a Pods do Kubernetes graças ao seletor, mas quando usados com um conjunto correspondente de objetos EndpointSlices e sem um seletor, o Service pode abstrair outros tipos de backends, incluindo aqueles que são executados fora do cluster.

Por exemplo:

  • Você quer ter um cluster de banco de dados externo em produção, mas no seu ambiente de teste você usa seus próprios bancos de dados.
  • Você quer apontar seu Service para um Service em um Namespace diferente ou em outro cluster.
  • Você está migrando uma carga de trabalho para o Kubernetes. Ao avaliar a abordagem, você executa apenas uma parte dos seus backends no Kubernetes.

Em qualquer um desses cenários, você pode definir um Service sem especificar um seletor para corresponder aos Pods. Por exemplo:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376

Como este Service não tem seletor, os objetos EndpointSlice correspondentes não são criados automaticamente. Você pode mapear o Service para o endereço de rede e porta onde ele está sendo executado, adicionando um objeto EndpointSlice manualmente. Por exemplo:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: my-service-1 # por convenção, use o nome do Service
                     # como um prefixo para o nome do EndpointSlice
  labels:
    # Você deve definir o rótulo "kubernetes.io/service-name".
    # Defina seu valor para corresponder ao nome do Service
    kubernetes.io/service-name: my-service
addressType: IPv4
ports:
  - name: http # deve corresponder ao nome da porta do service definida acima
    appProtocol: http
    protocol: TCP
    port: 9376
endpoints:
  - addresses:
      - "10.4.5.6"
  - addresses:
      - "10.1.2.3"

EndpointSlices personalizados

Quando você cria um objeto EndpointSlice para um Service, você pode usar qualquer nome para o EndpointSlice. Cada EndpointSlice em um namespace deve ter um nome único. Você vincula um EndpointSlice a um Service definindo o rótulo kubernetes.io/service-name nesse EndpointSlice.

Para um EndpointSlice que você criar por conta própria, ou no seu próprio código, você também deve escolher um valor para usar no rótulo endpointslice.kubernetes.io/managed-by. Se você criar seu próprio código de controlador para gerenciar EndpointSlices, considere usar um valor similar a "my-domain.example/name-of-controller". Se você estiver usando uma ferramenta de terceiros, use o nome da ferramenta em letras minúsculas e altere espaços e outras pontuações para traços (-). Se as pessoas estiverem usando diretamente uma ferramenta como kubectl para gerenciar EndpointSlices, use um nome que descreva esse gerenciamento manual, como "staff" ou "cluster-admins". Você deve evitar usar o valor reservado "controller", que identifica EndpointSlices gerenciados pela própria camada de gerenciamento do Kubernetes.

Acessando um Service sem seletor

Acessar um Service sem seletor funciona da mesma forma que se tivesse um seletor. No exemplo de um Service sem seletor, o tráfego é roteado para um dos dois endpoints definidos no manifesto EndpointSlice: uma conexão TCP para 10.1.2.3 ou 10.4.5.6, na porta 9376.

Um Service ExternalName é um caso especial de Service que não possui seletores e usa nomes DNS em vez disso. Para mais informações, consulte a seção ExternalName.

EndpointSlices

ESTADO DA FUNCIONALIDADE: Kubernetes v1.21 [stable]

EndpointSlices são objetos que representam um subconjunto (uma fatia) dos endpoints de rede de suporte para um Service.

Seu cluster Kubernetes rastreia quantos endpoints cada EndpointSlice representa. Se houver tantos endpoints para um Service que um limite seja atingido, então o Kubernetes adiciona outro EndpointSlice vazio e armazena novas informações de endpoint lá. Por padrão, o Kubernetes cria um novo EndpointSlice assim que os EndpointSlices existentes contêm pelo menos 100 endpoints. O Kubernetes não cria o novo EndpointSlice até que um endpoint extra precise ser adicionado.

Consulte EndpointSlices para mais informações sobre esta API.

Endpoints (descontinuado)

ESTADO DA FUNCIONALIDADE: Kubernetes v1.33 [deprecated]

A API EndpointSlice é a evolução da antiga API Endpoints. A API Endpoints descontinuada tem vários problemas em relação ao EndpointSlice:

  • Ela não suporta clusters dual-stack.
  • Ela não contém informações necessárias para suportar funcionalidades mais recentes, como trafficDistribution.
  • Ela truncará a lista de endpoints se for muito longa para caber em um único objeto.

Devido a isso, é recomendado que todos os clientes usem a API EndpointSlice em vez de Endpoints.

Endpoints com capacidade excedida

O Kubernetes limita o número de endpoints que podem caber em um único objeto Endpoints. Quando há mais de 1000 endpoints de suporte para um Service, o Kubernetes trunca os dados no objeto Endpoints. Como um Service pode ser vinculado a mais de um EndpointSlice, o limite de 1000 endpoints de suporte afeta apenas a API Endpoints legada.

Nesse caso, o Kubernetes seleciona no máximo 1000 endpoints de backend possíveis para armazenar no objeto Endpoints, e define uma anotação no Endpoints: endpoints.kubernetes.io/over-capacity: truncated. A camada de gerenciamento também remove essa anotação se o número de Pods de backend cair abaixo de 1000.

O tráfego ainda é enviado para os backends, mas qualquer mecanismo de balanceamento de carga que dependa da API Endpoints legada envia tráfego apenas para no máximo 1000 dos endpoints de suporte disponíveis.

O mesmo limite da API significa que você não pode atualizar manualmente um Endpoints para ter mais de 1000 endpoints.

Protocolo de aplicação

ESTADO DA FUNCIONALIDADE: Kubernetes v1.20 [stable]

O campo appProtocol fornece uma maneira de especificar um protocolo de aplicação para cada porta do Service. Isso é usado como uma dica para implementações oferecerem comportamento mais rico para protocolos que elas entendem. O valor deste campo é espelhado pelos objetos Endpoints e EndpointSlice correspondentes.

Este campo segue a sintaxe de rótulo padrão do Kubernetes. Valores válidos são um dos seguintes:

  • Nomes de serviço padrão IANA.

  • Nomes prefixados definidos pela implementação, como mycompany.com/my-custom-protocol.

  • Nomes prefixados definidos pelo Kubernetes:

Protocolo Descrição
kubernetes.io/h2c HTTP/2 sobre cleartext conforme descrito na RFC 7540
kubernetes.io/ws WebSocket sobre cleartext conforme descrito na RFC 6455
kubernetes.io/wss WebSocket sobre TLS conforme descrito na RFC 6455

Services multi-porta

Para alguns Services, você precisa expor mais de uma porta. O Kubernetes permite que você configure múltiplas definições de porta em um objeto Service. Ao usar múltiplas portas para um Service, você deve dar nomes a todas as suas portas para que estas sejam inequívocas. Por exemplo:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377

Tipo de Service

Para algumas partes da sua aplicação (por exemplo, frontends) você pode querer expor um Service em um endereço IP externo, acessível de fora do seu cluster.

Os tipos de Service do Kubernetes permitem que você especifique que tipo de Service você deseja.

Os valores de type disponíveis e seus comportamentos são:

ClusterIP
Expõe o Service em um IP interno do cluster. Escolher este valor torna o Service acessível apenas de dentro do cluster. Este é o padrão usado se você não especificar explicitamente um type para um Service. Você pode expor o Service para a internet pública usando um Ingress ou um Gateway.
NodePort
Expõe o Service no IP de cada Node em uma porta estática (a NodePort). Para disponibilizar a porta do nó, o Kubernetes configura um endereço IP do cluster, o mesmo que se você tivesse solicitado um Service do type: ClusterIP.
LoadBalancer
Expõe o Service externamente usando um balanceador de carga externo. O Kubernetes não oferece diretamente um componente de balanceamento de carga; você deve fornecer um, ou pode integrar seu cluster Kubernetes com um provedor de nuvem.
ExternalName
Mapeia o Service para o conteúdo do campo externalName (por exemplo, para o nome de host api.foo.bar.example). O mapeamento configura o servidor DNS do seu cluster para retornar um registro CNAME com esse valor de nome de host externo. Nenhum tipo de proxy é configurado.

O campo type na API Service é projetado como funcionalidade aninhada - cada nível adiciona ao anterior. No entanto, há uma exceção a este design aninhado. Você pode definir um Service LoadBalancer desabilitando a alocação de NodePort do balanceador de carga.

type: ClusterIP

Este tipo de Service padrão atribui um endereço IP de um pool de endereços IP que seu cluster reservou para esse propósito.

Vários dos outros tipos de Service são construídos sobre o tipo ClusterIP como fundação.

Se você definir um Service que tenha o .spec.clusterIP definido como "None", então o Kubernetes não atribui um endereço IP. Consulte headless Services para mais informações.

Escolhendo seu próprio endereço IP

Você pode especificar seu próprio endereço IP do cluster como parte de uma requisição de criação de Service. Para fazer isso, defina o campo .spec.clusterIP. Por exemplo, se você já tem uma entrada DNS existente que deseja reutilizar, ou sistemas legados que estão configurados para um endereço IP específico e difíceis de reconfigurar.

O endereço IP que você escolher deve ser um endereço IPv4 ou IPv6 válido dentro do intervalo CIDR service-cluster-ip-range que está configurado para o servidor de API. Se você tentar criar um Service com um valor de clusterIP inválido, o servidor de API retornará um código de status HTTP 422 para indicar que há um problema.

Leia evitando conflitos para aprender como o Kubernetes ajuda a reduzir o risco e o impacto de dois Services diferentes tentando usar o mesmo endereço IP.

type: NodePort

Se você definir o campo type como NodePort, a camada de gerenciamento do Kubernetes aloca uma porta de um intervalo especificado pela flag --service-node-port-range (padrão: 30000-32767). Cada nó faz proxy dessa porta (o mesmo número de porta em cada Node) para o seu Service. Seu Service reporta a porta alocada no campo .spec.ports[*].nodePort.

Usar um NodePort lhe dá a liberdade de configurar sua própria solução de balanceamento de carga, configurar ambientes que não são totalmente suportados pelo Kubernetes, ou até mesmo expor diretamente os endereços IP de um ou mais nós.

Para um Service do tipo node port, o Kubernetes aloca adicionalmente uma porta (TCP, UDP ou SCTP para corresponder ao protocolo do Service). Cada nó no cluster se configura para escutar nessa porta atribuída e encaminhar o tráfego para um dos endpoints prontos associados a esse Service. Você poderá contatar o Service type: NodePort de fora do cluster, conectando-se a qualquer nó usando o protocolo apropriado (por exemplo: TCP), e a porta apropriada (conforme atribuída a esse Service).

Escolhendo sua própria porta

Se você deseja um número de porta específico, pode especificar um valor no campo nodePort. A camada de gerenciamento alocará essa porta para você ou reportará que a transação da API falhou. Isso significa que você precisa cuidar de possíveis conflitos de porta por conta própria. Você também precisa usar um número de porta válido, que esteja dentro do intervalo configurado para uso de NodePort.

Aqui está um exemplo de manifesto para um Service do type: NodePort que especifica um valor NodePort (30007, neste exemplo):

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - port: 80
      # Por padrão e por conveniência, a `targetPort` é definida com
      # o mesmo valor do campo `port`.
      targetPort: 80
      # Campo opcional
      # Por padrão e por conveniência, a camada de gerenciamento do Kubernetes
      # alocará uma porta de um intervalo (padrão: 30000-32767)
      nodePort: 30007

Reserve intervalos de Nodeport para evitar conflitos

A política para atribuir portas a services NodePort se aplica tanto aos cenários de atribuição automática quanto de atribuição manual. Quando um usuário deseja criar um service NodePort que usa uma porta específica, a porta de destino pode entrar em conflito com outra porta que já foi atribuída.

Para evitar este problema, o intervalo de portas para services NodePort é dividido em duas faixas. A atribuição dinâmica de portas usa a faixa superior por padrão, e pode usar a faixa inferior uma vez que a faixa superior tenha sido esgotada. Os usuários podem então alocar da faixa inferior com menor risco de conflito de porta.

Configuração de endereço IP personalizado para Services type: NodePort

Você pode configurar nós no seu cluster para usar um endereço IP específico para servir services de node port. Você pode querer fazer isso se cada nó estiver conectado a múltiplas redes (por exemplo: uma rede para tráfego de aplicação, e outra rede para tráfego entre nós e a camada de gerenciamento).

Se você deseja especificar endereço(s) IP particular(es) para fazer proxy da porta, você pode definir a flag --nodeport-addresses para o kube-proxy ou o campo equivalente nodePortAddresses do arquivo de configuração do kube-proxy para bloco(s) de IP particular(es).

Esta flag recebe uma lista delimitada por vírgulas de blocos de IP (por exemplo, 10.0.0.0/8, 192.0.2.0/25) para especificar intervalos de endereços IP que o kube-proxy deve considerar como locais para este nó.

Por exemplo, se você iniciar o kube-proxy com a flag --nodeport-addresses=127.0.0.0/8, o kube-proxy seleciona apenas a interface de loopback para Services NodePort. O padrão para --nodeport-addresses é uma lista vazia. Isso significa que o kube-proxy deve considerar todas as interfaces de rede disponíveis para NodePort. (Isso também é compatível com versões anteriores do Kubernetes.)

type: LoadBalancer

Em provedores de nuvem que suportam balanceadores de carga externos, definir o campo type como LoadBalancer provisiona um balanceador de carga para o seu Service. A criação real do balanceador de carga acontece de forma assíncrona, e informações sobre o balanceador provisionado são publicadas no campo .status.loadBalancer do Service. Por exemplo:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

O tráfego do balanceador de carga externo é direcionado aos Pods de backend. O provedor de nuvem decide como é feito o balanceamento de carga.

Para implementar um Service do type: LoadBalancer, o Kubernetes normalmente começa fazendo as alterações que são equivalentes a você solicitar um Service com type: NodePort. O componente cloud-controller-manager então configura o balanceador de carga externo para encaminhar o tráfego para essa porta de nó atribuída.

Você pode configurar um Service com balanceamento de carga para omitir a atribuição de uma porta de nó, desde que a implementação do provedor de nuvem suporte isso.

Alguns provedores de nuvem permitem que você especifique o loadBalancerIP. Nesses casos, o balanceador de carga é criado com o loadBalancerIP especificado pelo usuário. Se o campo loadBalancerIP não for especificado, o balanceador de carga é configurado com um endereço IP efêmero. Se você especificar um loadBalancerIP mas seu provedor de nuvem não suportar a funcionalidade, o campo loadbalancerIP que você definiu é ignorado.

Impacto da operacionalidade do nó no tráfego do balanceador de carga

As verificações de integridade do balanceador de carga são críticas para aplicações modernas. Elas são usadas para determinar para qual servidor (máquina virtual ou endereço IP) o balanceador de carga deve despachar o tráfego. As APIs do Kubernetes não definem como as verificações de integridade devem ser implementadas para balanceadores de carga gerenciados pelo Kubernetes, em vez disso, são os provedores de nuvem (e as pessoas implementando código de integração) que decidem sobre o comportamento. As verificações de integridade do balanceador de carga são extensivamente usadas no contexto de suportar o campo externalTrafficPolicy para Services.

Balanceadores de carga com tipos de protocolo mistos

ESTADO DA FUNCIONALIDADE: Kubernetes v1.26 [stable](habilitado por padrão: <no value>)

Por padrão, para Services do tipo LoadBalancer, quando há mais de uma porta definida, todas as portas devem ter o mesmo protocolo, e o protocolo deve ser um que seja suportado pelo provedor de nuvem.

O feature gate MixedProtocolLBService (habilitado por padrão para o kube-apiserver a partir da v1.24) permite o uso de protocolos diferentes para Services do tipo LoadBalancer, quando há mais de uma porta definida.

Desabilitando a alocação de NodePort do balanceador de carga

ESTADO DA FUNCIONALIDADE: Kubernetes v1.24 [stable]

Você pode opcionalmente desabilitar a alocação de node port para um Service do type: LoadBalancer, definindo o campo spec.allocateLoadBalancerNodePorts como false. Isso deve ser usado apenas para implementações de balanceador de carga que roteiam tráfego diretamente para Pods em vez de usar node ports. Por padrão, spec.allocateLoadBalancerNodePorts é true e Services do tipo LoadBalancer continuarão a alocar node ports. Se spec.allocateLoadBalancerNodePorts for definido como false em um Service existente com node ports alocados, esses node ports não serão desalocados automaticamente. Você deve remover explicitamente a entrada nodePorts em cada porta do Service para desalocar esses node ports.

Especificando a classe de implementação do balanceador de carga

ESTADO DA FUNCIONALIDADE: Kubernetes v1.24 [stable]

Para um Service com type definido como LoadBalancer, o campo .spec.loadBalancerClass permite que você use uma implementação de balanceador de carga diferente do padrão do provedor de nuvem.

Por padrão, .spec.loadBalancerClass não está definido e um Service do tipo LoadBalancer usa a implementação de balanceador de carga padrão do provedor de nuvem se o cluster estiver configurado com um provedor de nuvem usando a flag de componente --cloud-provider.

Se você especificar .spec.loadBalancerClass, presume-se que uma implementação de balanceador de carga que corresponda à classe especificada esteja observando os Services. Qualquer implementação de balanceador de carga padrão (por exemplo, a fornecida pelo provedor de nuvem) ignorará Services que tenham este campo definido. spec.loadBalancerClass pode ser definido apenas em um Service do tipo LoadBalancer. Uma vez definido, não pode ser alterado. O valor de spec.loadBalancerClass deve ser um identificador no estilo de rótulo, com um prefixo opcional como "internal-vip" ou "example.com/internal-vip". Nomes sem prefixo são reservados para usuários finais.

Modo do endereço IP do balanceador de carga

ESTADO DA FUNCIONALIDADE: Kubernetes v1.32 [stable](habilitado por padrão: <no value>)

Para um Service do type: LoadBalancer, um controlador pode definir .status.loadBalancer.ingress.ipMode. O .status.loadBalancer.ingress.ipMode especifica como o IP do balanceador de carga se comporta. Ele pode ser especificado apenas quando o campo .status.loadBalancer.ingress.ip também estiver especificado.

Existem dois valores possíveis para .status.loadBalancer.ingress.ipMode: "VIP" e "Proxy". O valor padrão é "VIP", significando que o tráfego é entregue ao nó com o destino definido para o IP e porta do balanceador de carga. Existem dois casos ao definir isso como "Proxy", dependendo de como o balanceador de carga do provedor de nuvem entrega o tráfego:

  • Se o tráfego é entregue ao nó e então sofre DNAT para o Pod, o destino seria definido para o IP do nó e a node port;
  • Se o tráfego é entregue diretamente ao Pod, o destino seria definido para o IP e porta do Pod.

Implementações de Service podem usar esta informação para ajustar o roteamento de tráfego.

Balanceador de carga interno

Em um ambiente misto, às vezes é necessário rotear o tráfego de Services dentro do mesmo bloco de endereço de rede (virtual).

Em um ambiente DNS split-horizon, você precisaria de dois Services para poder rotear tanto o tráfego externo quanto o interno para seus endpoints.

Para definir um balanceador de carga interno, adicione uma das seguintes anotações ao seu Service dependendo do provedor de serviço de nuvem que você está usando:

Select one of the tabs.

metadata:
  name: my-service
  annotations:
    networking.gke.io/load-balancer-type: "Internal"

metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"

metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"

metadata:
  name: my-service
  annotations:
    service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: "private"

metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/openstack-internal-load-balancer: "true"

metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"

metadata:
  annotations:
    service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx

metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet"

metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/oci-load-balancer-internal: true

type: ExternalName

Services do tipo ExternalName mapeiam um Service para um nome DNS, não para um seletor típico como my-service ou cassandra. Você especifica esses Services com o parâmetro spec.externalName.

Esta definição de Service, por exemplo, mapeia o Service my-service no namespace prod para my.database.example.com:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

Ao procurar o host my-service.prod.svc.cluster.local, o Service DNS do cluster retorna um registro CNAME com o valor my.database.example.com. Acessar my-service funciona da mesma forma que outros Services, mas com a diferença crucial de que o redirecionamento acontece no nível DNS em vez de via proxy ou encaminhamento. Se você decidir posteriormente mover seu banco de dados para dentro do seu cluster, você pode iniciar seus Pods, adicionar seletores ou endpoints apropriados, e alterar o type do Service.

Headless Services

Às vezes você não precisa de balanceamento de carga e um único IP de Service. Neste caso, você pode criar o que são chamados de headless Services, especificando explicitamente "None" para o endereço IP do cluster (.spec.clusterIP).

Você pode usar um headless Service para fazer interface com outros mecanismos de descoberta de serviços, sem estar vinculado à implementação do Kubernetes.

Para headless Services, um IP de cluster não é alocado, o kube-proxy não manipula esses Services, e não há balanceamento de carga ou proxy feito pela plataforma para eles.

Um headless Service permite que um cliente se conecte a qualquer Pod que preferir, diretamente. Headless Services não configuram rotas e encaminhamento de pacotes usando endereços IP virtuais e proxies; em vez disso, Headless Services reportam os endereços IP de endpoint dos Pods individuais via registros DNS internos, servidos através do serviço DNS do cluster. Para definir um headless Service, você cria um Service com .spec.type definido como ClusterIP (que também é o padrão para type), e você adicionalmente define .spec.clusterIP como None.

O valor de string None é um caso especial e não é o mesmo que deixar o campo .spec.clusterIP não definido.

Como o DNS é configurado automaticamente depende se o Service tem seletores definidos:

Com seletores

Para headless Services que definem seletores, o controlador de endpoints cria EndpointSlices na API do Kubernetes, e modifica a configuração DNS para retornar registros A ou AAAA (endereços IPv4 ou IPv6) que apontam diretamente para os Pods que sustentam o Service.

Sem seletores

Para headless Services que não definem seletores, a camada de gerenciamento não cria objetos EndpointSlice. No entanto, o sistema DNS procura e configura um dos seguintes:

  • Registros DNS CNAME para Services type: ExternalName.
  • Registros DNS A / AAAA para todos os endereços IP dos endpoints prontos do Service, para todos os tipos de Service diferentes de ExternalName.
    • Para endpoints IPv4, o sistema DNS cria registros A.
    • Para endpoints IPv6, o sistema DNS cria registros AAAA.

Quando você define um headless Service sem seletor, a port deve corresponder à targetPort.

Descobrindo Services

Para clientes em execução dentro do seu cluster, o Kubernetes suporta dois modos principais de encontrar um Service: variáveis de ambiente e DNS.

Variáveis de ambiente

Quando um Pod é executado em um Node, o kubelet adiciona um conjunto de variáveis de ambiente para cada Service ativo. Ele adiciona as variáveis {SVCNAME}_SERVICE_HOST e {SVCNAME}_SERVICE_PORT, onde o nome do Service está em maiúsculas e os traços são convertidos em sublinhados.

Por exemplo, o Service redis-primary que expõe a porta TCP 6379 e recebeu o endereço IP de cluster 10.0.0.11, produz as seguintes variáveis de ambiente:

REDIS_PRIMARY_SERVICE_HOST=10.0.0.11
REDIS_PRIMARY_SERVICE_PORT=6379
REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcp
REDIS_PRIMARY_PORT_6379_TCP_PORT=6379
REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11

O Kubernetes também suporta e fornece variáveis que são compatíveis com a funcionalidade "legacy container links" do Docker Engine. Você pode ler makeLinkVariables para ver como isso é implementado no Kubernetes.

DNS

Você pode (e quase sempre deveria) configurar um serviço DNS para o seu cluster Kubernetes usando um complemento.

Um servidor DNS com reconhecimento de cluster, como o CoreDNS, observa a API do Kubernetes em busca de novos Services e cria um conjunto de registros DNS para cada um. Se o DNS foi habilitado em todo o seu cluster, então todos os Pods devem ser capazes automaticamente de resolver Services por seu nome DNS.

Por exemplo, se você tem um Service chamado my-service em um namespace my-ns do Kubernetes, a camada de gerenciamento e o Service DNS atuando juntos criam um registro DNS para my-service.my-ns. Os Pods no namespace my-ns devem ser capazes de encontrar o service fazendo uma busca de nome por my-service (my-service.my-ns também funcionaria).

Pods em outros namespaces devem qualificar o nome como my-service.my-ns. Esses nomes resolverão para o IP do cluster atribuído ao Service.

O Kubernetes também suporta registros DNS SRV (Service) para portas nomeadas. Se o Service my-service.my-ns tiver uma porta chamada http com o protocolo definido como TCP, você pode fazer uma consulta DNS SRV para _http._tcp.my-service.my-ns para descobrir o número da porta para http, bem como o endereço IP.

O servidor DNS do Kubernetes é a única maneira de acessar Services ExternalName. Você pode encontrar mais informações sobre resolução ExternalName em DNS para Services e Pods.

Mecanismo de endereçamento de IP virtual

Leia IPs Virtuais e Proxies de Service que explica o mecanismo que o Kubernetes fornece para expor um Service com um endereço IP virtual.

Políticas de tráfego

Você pode definir os campos .spec.internalTrafficPolicy e .spec.externalTrafficPolicy para controlar como o Kubernetes roteia o tráfego para backends íntegros ("prontos").

Consulte Políticas de Tráfego para mais detalhes.

Distribuição de tráfego

ESTADO DA FUNCIONALIDADE: Kubernetes v1.33 [stable](habilitado por padrão: <no value>)

O campo .spec.trafficDistribution fornece outra maneira de influenciar o roteamento de tráfego dentro de um Service do Kubernetes. Enquanto as políticas de tráfego focam em garantias semânticas estritas, a distribuição de tráfego permite que você expresse preferências (como rotear para endpoints topologicamente mais próximos). Isso pode ajudar a otimizar desempenho, custo ou confiabilidade. No Kubernetes 1.34, o seguinte valor de campo é suportado:

PreferClose
Indica uma preferência por rotear o tráfego para endpoints que estão na mesma zona que o cliente.
ESTADO DA FUNCIONALIDADE: Kubernetes v1.34 [beta](habilitado por padrão: <no value>)

No Kubernetes 1.34, dois valores adicionais estão disponíveis (a menos que o feature gate PreferSameTrafficDistribution esteja desabilitado):

PreferSameZone
Este é um alias para PreferClose que é mais claro sobre a semântica pretendida.
PreferSameNode
Indica uma preferência por rotear o tráfego para endpoints que estão no mesmo nó que o cliente.

Se o campo não for definido, a implementação aplicará sua estratégia de roteamento padrão.

Consulte Distribuição de Tráfego para mais detalhes.

Persistência de sessão

Se você quiser garantir que as conexões de um cliente específico sejam passadas para o mesmo Pod a cada vez, você pode configurar afinidade de sessão baseada no endereço IP do cliente. Leia afinidade de sessão para saber mais.

IPs externos

Se houver IPs externos que roteiam para um ou mais nós do cluster, os Services do Kubernetes podem ser expostos nesses externalIPs. Quando o tráfego de rede chega ao cluster, com o IP externo (como IP de destino) e a porta correspondente a esse Service, regras e rotas que o Kubernetes configurou garantem que o tráfego seja roteado para um dos endpoints desse Service.

Quando você define um Service, você pode especificar externalIPs para qualquer tipo de Service. No exemplo abaixo, o Service chamado "my-service" pode ser acessado por clientes usando TCP, em "198.51.100.32:80" (calculado a partir de .spec.externalIPs[] e .spec.ports[].port).

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 49152
  externalIPs:
    - 198.51.100.32

Objeto da API

Service é um recurso de nível superior na API REST do Kubernetes. Você pode encontrar mais detalhes sobre o objeto da API Service.

Próximos passos

Saiba mais sobre Services e como eles se encaixam no Kubernetes:

  • Siga o tutorial Conectando Aplicações com Services.
  • Leia sobre Ingress, que expõe rotas HTTP e HTTPS de fora do cluster para Services dentro do seu cluster.
  • Leia sobre Gateway, uma extensão do Kubernetes que fornece mais flexibilidade do que o Ingress.

Para mais contexto, leia o seguinte:

2 - Ingress

Disponibilize seu serviço de rede HTTP ou HTTPS usando um mecanismo de configuração com reconhecimento de protocolo, que entende conceitos da Web como URIs, nomes de host, caminhos e muito mais. O conceito Ingress permite mapear o tráfego para diferentes backends com base nas regras definidas por meio da API do Kubernetes.

ESTADO DA FUNCIONALIDADE: Kubernetes v1.19 [stable]

Um objeto da API (do inglês "Application Programming Interface") que gerencia o acesso externo aos serviços em um cluster, normalmente HTTP.

Um Ingress pode fornecer balanceamento de carga, terminação SSL e hospedagem virtual baseada em nomes.

Terminologia

Para fins de clareza, este guia define os seguintes termos:

  • Nó: Uma máquina de trabalho no Kubernetes, parte de um cluster.
  • Cluster: Um conjunto de nós que executam aplicações em contêiner gerenciado pelo Kubernetes. Para este exemplo, e nas instalações mais comuns do Kubernetes, os nós no cluster não fazem parte da Internet pública.
  • Roteador de borda: Um roteador que impõe a política de firewall para o seu cluster. Isso pode ser um gateway gerenciado por um provedor de nuvem ou um hardware físico.
  • Rede do cluster: Um conjunto de links, lógicos ou físicos, que facilitam a comunicação dentro de um cluster de acordo com o modelo de rede do Kubernetes.
  • Serviço: Um objeto serviço do Kubernetes que identifica um conjunto de Pods usando seletores de label. Salvo indicação em contrário, assume-se que os Serviços tenham IPs virtuais apenas roteáveis dentro da rede de cluster.

O que é o Ingress?

O Ingress expõe rotas HTTP e HTTPS de fora do cluster para um serviço dentro do cluster. O roteamento do tráfego é controlado por regras definidas no recurso Ingress.

Aqui está um exemplo simples em que o Ingress envia todo o seu tráfego para um serviço:

 diagrama do Ingress

Figura. Ingress

Um Ingress pode ser configurado para fornecer URLs acessíveis externamente aos serviços, balanceamento de carga de tráfego, terminação SSL/TLS e oferecer hospedagem virtual baseada em nome. Um controlador Ingress é responsável por atender o Ingress, geralmente com um balanceador de carga, embora também possa configurar seu roteador de borda ou frontends adicionais para ajudar a lidar com o tráfego.

Um Ingress não expõe portas ou protocolos arbitrários. Normalmente se usa um serviço do tipo Service.Type=NodePort ou Service.Type=LoadBalancer para expor serviços à Internet que não sejam HTTP e HTTPS.

Pré-requisitos

Você deve ter um controlador Ingress para satisfazer um Ingress. Apenas a criação de um recurso Ingress não tem efeito.

Você pode precisar instalar um controlador Ingress, como ingress-nginx. Você pode escolher entre vários controladores Ingress.

Idealmente, todos os controladores Ingress devem se encaixar na especificação de referência. Na realidade, os vários controladores Ingress operam de forma ligeiramente diferente.

O recurso Ingress

Um exemplo mínimo do recurso Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

Um Ingress precisa dos campos apiVersion, kind, metadata e spec. O nome de um objeto Ingress deve ser um nome de subdomínio DNS válido. Para obter informações gerais sobre como trabalhar com arquivos de configuração, consulte como instalar aplicações, como configurar contêineres e como gerenciar recursos. O Ingress frequentemente usa anotações para configurar opções dependendo do controlador Ingress. Um exemplo deste uso é a anotação rewrite-target. Diferentes controladores Ingress suportam diferentes anotações. Revise a documentação do seu controlador Ingress escolhido para saber quais anotações são suportadas.

A especificação Ingress tem todas as informações necessárias para configurar um balanceador de carga ou servidor proxy. Mais importante ainda, ele contém uma lista de regras correspondentes a todas as solicitações recebidas. O recurso Ingress suporta apenas regras para direcionar o tráfego HTTP(S).

Se o ingressClassName for omitido, uma classe Ingress padrão deve ser definida.

Existem alguns controladores Ingress que funcionam sem a definição de uma IngressClass padrão. Por exemplo, o controlador Ingress-NGINX pode ser configurado com uma flag --watch-ingress-without-class. No entanto, recomenda-se especificar a IngressClass padrão, conforme mostrado abaixo.

Regras do Ingress

Cada regra HTTP contém as seguintes informações:

  • Um host opcional. Neste exemplo, nenhum host é especificado, portanto, a regra se aplica a todo o tráfego HTTP de entrada através do endereço IP especificado. Se um host for fornecido (por exemplo, foo.bar.com), as regras se aplicam a esse host.
  • Uma lista de caminhos (por exemplo, /testpath), cada um com um backend associado definido com um service.name e um service.port.name ou service.port.number. Tanto o host quanto o caminho devem corresponder ao conteúdo de uma solicitação recebida antes que o balanceador de carga direcione o tráfego para o serviço referenciado.
  • Um backend é uma combinação de nomes de serviço e porta, conforme descrito na documentação de Services ou um backend de recursos personalizados por meio de um CRD. As solicitações HTTP e HTTPS para o Ingress que correspondem ao host e ao caminho da regra são enviadas para o backend listado.

Um defaultBackend geralmente é configurado em um controlador Ingress para atender a quaisquer solicitações que não correspondam a um caminho na especificação.

DefaultBackend

Um Ingress sem regras envia todo o tráfego para um único backend padrão e .spec.defaultBackend é o backend que deve lidar com as solicitações nesse caso. O defaultBackend é convencionalmente uma opção de configuração do controlador Ingress e não é especificado em seus recursos Ingress. Se nenhum .spec.rules for especificado, o .spec.defaultBackend deve ser especificado. Se o defaultBackend não for definido, o tratamento de solicitações que não correspondem a nenhuma das regras ficará a cargo do controlador de Ingress (consulte a documentação do seu controlador de Ingress para descobrir como ele lida com esse caso).

Se nenhum dos hosts ou caminhos corresponder à solicitação HTTP nos objetos Ingress, o tráfego será roteado para o seu backend padrão.

Resource backends

Um Resource backend é um ObjectRef para outro recurso Kubernetes dentro do mesmo namespace que o objeto Ingress. Um Resource é uma configuração mutuamente exclusiva com o serviço, e a validação irá falhar se ambos forem especificados. Um uso comum para um Resource backend é inserir dados em um backend de armazenamento de objetos com ativos estáticos.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource-backend
spec:
  defaultBackend:
    resource:
      apiGroup: k8s.example.com
      kind: StorageBucket
      name: static-assets
  rules:
    - http:
        paths:
          - path: /icons
            pathType: ImplementationSpecific
            backend:
              resource:
                apiGroup: k8s.example.com
                kind: StorageBucket
                name: icon-assets

Depois de criar o Ingress acima, você pode visualizá-lo com o seguinte comando:

kubectl describe ingress ingress-resource-backend
Name:             ingress-resource-backend
Namespace:        default
Address:
Default backend:  APIGroup: k8s.example.com, Kind: StorageBucket, Name: static-assets
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /icons   APIGroup: k8s.example.com, Kind: StorageBucket, Name: icon-assets
Annotations:  <none>
Events:       <none>

Tipos de path HTTP

Cada caminho no Ingress deve ter um tipo de caminho correspondente. Os caminhos que não incluem um pathType explícito falharão na validação. Existem três tipos de caminho suportados:

  • ImplementationSpecific: Com esse tipo de caminho, a correspondência depende da IngressClass. As implementações podem tratar isso como um pathType separado ou tratá-lo de forma idêntica aos tipos de caminho Prefix ou Exact.
  • Exact: Corresponde exatamente ao caminho da URL podendo ser case-sensitive.
  • Prefix: Corresponde com base em um prefixo de caminho de URL dividido por /. A correspondência faz distinção entre maiúsculas e minúsculas e é feita em um caminho, elemento por elemento. Um elemento de caminho refere-se à lista de labels no caminho dividido pelo separador /. Uma solicitação é uma correspondência para o caminho p se cada p for um prefixo elementar de p do caminho da solicitação.

Exemplos

Tipos Caminho(s) Caminho(s) de solicitação Correspondências?
Prefix / (todos os caminhos) Sim
Exact /foo /foo Sim
Exact /foo /bar Não
Exact /foo /foo/ Não
Exact /foo/ /foo Não
Prefix /foo /foo, /foo/ Sim
Prefix /foo/ /foo, /foo/ Sim
Prefix /aaa/bb /aaa/bbb Não
Prefix /aaa/bbb /aaa/bbb Sim
Prefix /aaa/bbb/ /aaa/bbb Sim, ignora a barra final
Prefix /aaa/bbb /aaa/bbb/ Sim, combina com a barra final
Prefix /aaa/bbb /aaa/bbb/ccc Sim, corresponde ao subcaminho
Prefix /aaa/bbb /aaa/bbbxyz Não, não corresponde ao prefixo da string
Prefix /, /aaa /aaa/ccc Sim, corresponde ao prefixo /aaa
Prefix /, /aaa, /aaa/bbb /aaa/bbb Sim, corresponde ao prefixo /aaa/bbb
Prefix /, /aaa, /aaa/bbb /ccc Sim, corresponde ao prefixo /
Prefix /aaa /ccc Não, usa o backend padrão
Mixed /foo (Prefix), /foo (Exact) /foo Sim, prefere o exact

Várias correspondências

Em alguns casos, vários caminhos dentro de uma entrada corresponderão a uma solicitação. Nesses casos, a precedência será dada primeiro ao caminho correspondente mais longo. Se dois caminhos ainda estiverem iguais, a precedência será dada aos caminhos com um tipo de caminho exato sobre o tipo de caminho de prefixo.

Hostname curingas

Os hosts podem ter correspondências precisas (por exemplo, “foo.bar.com”) ou um curinga (por exemplo, “*.foo.com”). Correspondências precisas exigem que o cabeçalho do host HTTP corresponda ao campo host. As correspondências curinga exigem que o cabeçalho do host HTTP seja igual ao sufixo da regra curinga.

Host Host header Corresponde?
*.foo.com bar.foo.com Correspondências baseadas no sufixo compartilhado
*.foo.com baz.bar.foo.com Sem correspondência, o curinga cobre apenas um único rótulo DNS
*.foo.com foo.com Sem correspondência, o curinga cobre apenas um único rótulo DNS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

Classe Ingress

Os Ingress podem ser implementados por diferentes controladores, muitas vezes com diferentes configurações. Cada Ingress deve especificar uma classe, uma referência a um recurso IngressClass que contém uma configuração adicional, incluindo o nome do controlador que deve implementar a classe.

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

O campo .spec.parameters de uma classe Ingress permite que você faça referência a outro recurso que fornece a configuração relacionada a essa classe Ingress.

O tipo específico de parâmetros a serem usados depende do controlador Ingress que você especificar no campo .spec.controller da classe Ingress.

Escopo da classe Ingress

Dependendo do seu controlador Ingress, os parâmetros definidos em todo o cluster ou apenas para um namespace poderão ser utilizados.

O escopo padrão para os parâmetros da classe Ingress é em todo o cluster.

Se você definir o campo .spec.parameters e não definir .spec.parameters.scope, ou se você definir .spec.parameters.scope como Cluster, então a classe Ingress se refere a um recurso com escopo de cluster. O kind (em combinação com o apiGroup) dos parâmetros refere-se a uma API com escopo de cluster (possivelmente um recurso personalizado), e o name dos parâmetros identifica um recurso específico com escopo de cluster para essa API.

Por exemplo:

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-1
spec:
  controller: example.com/ingress-controller
  parameters:
    # Os parâmetros para esta classe Ingress são especificados em um
    # ClusterIngressParameter (grupo de API k8s.example.net) nomeado
    # "external-config-1". Esta definição diz ao Kubernetes para
    # procurar um recurso de parâmetro com escopo de cluster.    
    scope: Cluster
    apiGroup: k8s.example.net
    kind: ClusterIngressParameter
    name: external-config-1

ESTADO DA FUNCIONALIDADE: Kubernetes v1.23 [stable]

Se você definir o campo .spec.parameters e definir .spec.parameters.scope como Namespace, a classe Ingress terá como referência um recurso com escopo de namespace. Você também deve definir o campo namespace dentro de .spec.parameters para o namespace que contém os parâmetros que deseja usar.

O campo kind (em combinação com o campo apiGroup) dos parâmetros refere-se a uma API com namespace (por exemplo: ConfigMap), e o campo name dos parâmetros identifica um recurso específico no namespace que você especificou no campo namespace.

Os parâmetros com escopo de namespace ajudam o operador de cluster a delegar o controle sobre a configuração (por exemplo: configurações do balanceador de carga, definição de gateway API) que é usada para uma carga de trabalho. Se você usou um parâmetro com escopo de cluster, então:

  • A equipe do operador do cluster precisa aprovar as alterações de uma equipe diferente toda vez que houver uma nova alteração de configuração sendo aplicada.
  • O operador de cluster deve definir controles de acesso específicos, como funções e vínculos RBAC, que permitem que a equipe do aplicativo faça alterações no recurso de parâmetros do escopo do cluster.

A própria API do IngressClass é sempre com escopo de cluster.

Aqui está um exemplo de uma classe Ingress que se refere a parâmetros com namespace:

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-2
spec:
  controller: example.com/ingress-controller
  parameters:
    # The parameters for this IngressClass are specified in an
    # IngressParameter (API group k8s.example.com) named "external-config",
    # that's in the "external-configuration" namespace.
    scope: Namespace
    apiGroup: k8s.example.com
    kind: IngressParameter
    namespace: external-configuration
    name: external-config

Anotação obsoleta

Antes que o recurso IngressClass e o campo ingressClassName fossem adicionados no Kubernetes 1.18, as classes Ingress foram especificadas com uma anotação kubernetes.io/ingress.class no Ingress. Esta anotação nunca foi formalmente definida, mas foi amplamente apoiada pelos controladores Ingress.

O campo ingressClassName mais recente no Ingress é um substituto para essa anotação, mas não é um equivalente direto. Embora a anotação tenha sido geralmente usada para fazer referência ao nome do controlador Ingress que deve implementar o Ingress, o campo é uma referência a um recurso IngressClass que contém a configuração Ingress adicional, incluindo o nome do controlador Ingress.

Classe Ingress Padrão

Você pode marcar uma classe Ingress específica como padrão para o seu cluster. Definir a anotação ingressclass.kubernetes.io/is-default-class como true em um recurso IngressClass garantirá que novos Ingress sem um campo ingressClassName especificado sejam atribuídos a esta ingressClassName padrão.

Existem alguns controladores Ingress que funcionam sem a definição de uma IngressClass padrão. Por exemplo, o controlador Ingress-NGINX pode ser configurado com uma flag --watch-ingress-without-class. No entanto, é recomendável especificar a IngressClass padrão:

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    app.kubernetes.io/component: controller
  name: nginx-example
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
spec:
  controller: k8s.io/ingress-nginx

Tipos de Ingress

Ingress fornecidos por um único serviço

No Kubernetes existem conceitos que permitem expor um único serviço (veja alternativas). Você também pode fazer isso com um Ingress especificando um backend padrão sem regras.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80

Se você criá-lo usando kubectl apply -f, você deve ser capaz de visualizar o estado do Ingress que você adicionou:

kubectl get ingress test-ingress
NAME           CLASS         HOSTS   ADDRESS         PORTS   AGE
test-ingress   external-lb   *       203.0.113.123   80      59s

Onde 203.0.113.123 é o IP alocado pelo controlador Ingress para satisfazer o Ingress.

Simples fanout

Uma configuração de fanout roteia o tráfego de um único endereço IP para mais de um serviço, com base na URI HTTP que está sendo solicitada. Um Ingress permite que você mantenha o número de balanceadores de carga no mínimo. Por exemplo, uma configuração como:

ingress-fanout-diagram

Figura. Ingress Fan Out

exigiria um Ingress como:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

Quando você cria o Ingress com kubectl apply -f:

kubectl describe ingress simple-fanout-example
Name:             simple-fanout-example
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:4200 (10.8.0.90:4200)
               /bar   service2:8080 (10.8.0.91:8080)
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     22s                loadbalancer-controller  default/test

O controlador Ingress fornece um balanceador de carga específico de implementação que satisfaz o Ingress, desde que os serviços (service1, service2) existam. Quando tiver feito isso, você pode ver o endereço do balanceador de carga no campo Address.

Hospedagem virtual baseada em nome

Os hosts virtuais baseados em nomes suportam o roteamento de tráfego HTTP para vários nomes de host no mesmo endereço IP.

ingress-namebase-diagram

Figura. Hospedagem de host virtual baseado em nome

O Ingress a seguir diz ao balanceador de carga de apoio para rotear solicitações com base no Host header.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

Se você criar um recurso de Ingress sem nenhum host definido nas regras, qualquer tráfego da web para o endereço IP do seu controlador de Ingress pode ser correspondido sem que seja necessário um host virtual baseado em nome.

Por exemplo, o Ingress a seguir roteia o tráfego solicitado para first.bar.com para service1, second.bar.com para service2 e qualquer tráfego cujo cabeçalho de host de solicitação não corresponda a first.bar.com e second.bar.com para service3.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: first.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: second.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service3
            port:
              number: 80

TLS

Você pode configurar o uso de TLS no Ingress especificando um Secret que contém uma chave privada e um certificado TLS. O recurso Ingress suporta apenas uma única porta TLS, 443, e assume a terminação TLS no ponto de entrada (o tráfego para o Serviço e seus Pods não está criptografado o que é inseguro). Se a seção de configuração TLS em um Ingress especificar hosts diferentes, eles serão multiplexados na mesma porta de acordo com o nome do host especificado através da extensão SNI TLS (desde que o controlador Ingress suporte SNI). O objeto Secret do tipo TLS deve conter chaves chamadas tls.crt e tls.key que contêm o certificado e a chave privada a ser usada para TLS.

Por exemplo:

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

Fazer referência a esse segredo em um Ingress diz ao controlador Ingress para proteger o canal do cliente para o balanceador de carga usando TLS. Você precisa ter certeza de que o objeto Secret do tipo TLS que você criou é originário de um certificado que contém um Nome Comum (Common Name, CN), também conhecido como Nome de Domínio Totalmente Qualificado (Fully Qualified Domain Name, FQDN), tal como https-example.foo.com.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80

Balanceador de carga

Um controlador Ingress é inicializado com algumas configurações de política de balanceamento de carga que se aplicam a todos os Ingress, como o algoritmo de balanceamento de carga, esquema de peso de backend e outros. Conceitos mais avançados de balanceamento de carga (por exemplo, sessões persistentes, pesos dinâmicos) ainda não estão expostos através do Ingress. Em vez disso, você pode obter esses recursos através do balanceador de carga usado para um serviço.

Também vale a pena notar que, embora as verificações de integridade não sejam expostas diretamente através do Ingress, existem conceitos paralelos no Kubernetes, como readiness probes, que permitem alcançar o mesmo resultado final. Revise a documentação específica do controlador para ver como eles lidam com as verificações de integridade (por exemplo: nginx ou GCE).

Atualizando um Ingress

Para atualizar um Ingress existente para adicionar um novo Host, você pode atualizá-lo editando o recurso:

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     35s                loadbalancer-controller  default/test
kubectl edit ingress test

Isso abre um editor com a configuração existente no formato YAML. Para incluir o novo host modifique:

spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          service:
            name: service1
            port:
              number: 80
        path: /foo
        pathType: Prefix
  - host: bar.baz.com
    http:
      paths:
      - backend:
          service:
            name: service2
            port:
              number: 80
        path: /foo
        pathType: Prefix
..

Depois de salvar suas alterações, o kubectl atualizará o recurso no servidor API, que diz ao controlador Ingress para reconfigurar o balanceador de carga.

Verifique isso:

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
  bar.baz.com
               /foo   service2:80 (10.8.0.91:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     45s                loadbalancer-controller  default/test

Você pode alcançar o mesmo resultado invocando kubectl replace -f em um arquivo Ingress YAML modificado.

Falha nas zonas de disponibilidade

Técnicas para distribuir o tráfego entre domínios de falha diferem entre os provedores de nuvem. Verifique a documentação do controlador Ingress para obter detalhes relevantes.

Alternativas

Você pode expor um serviço de várias maneiras que não envolve diretamente o recurso Ingress:

Próximos passos

3 - Políticas de rede

Se você deseja controlar o fluxo do tráfego de rede no nível do endereço IP ou de portas TCP e UDP (camadas OSI 3 e 4) então você deve considerar usar Políticas de rede (NetworkPolicies) do Kubernetes para aplicações no seu cluster. NetworkPolicy é um objeto focado em aplicações/experiência do desenvolvedor que permite especificar como é permitido a um pod comunicar-se com várias "entidades" de rede.

As entidades que um Pod pode se comunicar são identificadas através de uma combinação dos 3 identificadores à seguir:

  1. Outros pods que são permitidos (exceção: um pod não pode bloquear a si próprio)
  2. Namespaces que são permitidos
  3. Blocos de IP (exceção: o tráfego de e para o nó que um Pod está executando sempre é permitido, independentemente do endereço IP do Pod ou do Nó)

Quando definimos uma política de rede baseada em pod ou namespace, utiliza-se um selector para especificar qual tráfego é permitido de e para o(s) Pod(s) que correspondem ao seletor.

Quando uma política de redes baseada em IP é criada, nós definimos a política baseada em blocos de IP (faixas CIDR).

Pré requisitos

As políticas de rede são implementadas pelo plugin de redes. Para usar uma política de redes, você deve usar uma solução de redes que suporte o objeto NetworkPolicy. A criação de um objeto NetworkPolicy sem um controlador que implemente essas regras não tem efeito.

Pods isolados e não isolados

Por padrão, pods não são isolados; eles aceitam tráfego de qualquer origem.

Os pods tornam-se isolados ao existir uma NetworkPolicy que selecione eles. Uma vez que exista qualquer NetworkPolicy no namespace selecionando um pod em específico, aquele pod irá rejeitar qualquer conexão não permitida por qualquer NetworkPolicy. (Outros pod no mesmo namespace que não são selecionados por nenhuma outra NetworkPolicy irão continuar aceitando todo tráfego de rede.)

As políticas de rede não conflitam; elas são aditivas. Se qualquer política selecionar um pod, o pod torna-se restrito ao que é permitido pela união das regras de entrada/saída de tráfego definidas nas políticas. Assim, a ordem de avaliação não afeta o resultado da política.

Para o fluxo de rede entre dois pods ser permitido, tanto a política de saída no pod de origem e a política de entrada no pod de destino devem permitir o tráfego. Se a política de saída na origem, ou a política de entrada no destino negar o tráfego, o tráfego será bloqueado.

O recurso NetworkPolicy

Veja a referência NetworkPolicy para uma definição completa do recurso.

Uma NetworkPolicy de exemplo é similar ao abaixo:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Campos obrigatórios: Assim como todas as outras configurações do Kubernetes, uma NetworkPolicy necessita dos campos apiVersion, kind e metadata. Para maiores informações sobre trabalhar com arquivos de configuração, veja Configurando contêineres usando ConfigMap, e Gerenciamento de objetos.

spec: A spec contém todas as informações necessárias para definir uma política de redes em um namespace.

podSelector: Cada NetworkPolicy inclui um podSelector que seleciona o grupo de pods que a política se aplica. A política acima seleciona os pods com a label "role=db". Um podSelector vazio seleciona todos os pods no namespace.

policyTypes: Cada NetworkPolicy inclui uma lista de policyTypes que pode incluir Ingress, Egress ou ambos. O campo policyTypes indica se a política se aplica ao tráfego de entrada com destino aos pods selecionados, o tráfego de saída com origem dos pods selecionados ou ambos. Se nenhum policyType for definido então por padrão o tipo Ingress será sempre utilizado, e o tipo Egress será configurado apenas se o objeto contiver alguma regra de saída. (campo egress a seguir).

ingress: Cada NetworkPolicy pode incluir uma lista de regras de entrada permitidas através do campo ingress. Cada regra permite o tráfego que corresponde simultaneamente às sessões from (de) e ports (portas). A política de exemplo acima contém uma regra simples, que corresponde ao tráfego em uma única porta, de uma das três origens definidas, sendo a primeira definida via ipBlock, a segunda via namespaceSelector e a terceira via podSelector.

egress: Cada política pode incluir uma lista de regras de regras de saída permitidas através do campo egress. Cada regra permite o tráfego que corresponde simultaneamente às sessões to (para) e ports (portas). A política de exemplo acima contém uma regra simples, que corresponde ao tráfego destinado a uma porta em qualquer destino pertencente à faixa de IPs em 10.0.0.0/24.

Então a NetworkPolicy acima:

  1. Isola os pods no namespace "default" com a label "role=db" para ambos os tráfegos de entrada e saída (se eles ainda não estavam isolados)

  2. (Regras de entrada/ingress) permite conexões para todos os pods no namespace "default" com a label "role=db" na porta TCP 6379 de:

    • qualquer pod no namespace "default" com a label "role=frontend"
    • qualquer pod em um namespace que tenha a label "project=myproject" (aqui cabe ressaltar que o namespace que deve ter a label e não os pods dentro desse namespace)
    • IPs dentro das faixas 172.17.0.0–172.17.0.255 e 172.17.2.0–172.17.255.255 (ex.:, toda 172.17.0.0/16 exceto 172.17.1.0/24)
  3. (Regras de saída/egress) permite conexões de qualquer pod no namespace "default" com a label "role=db" para a faixa de destino 10.0.0.0/24 na porta TCP 5978.

Veja o tutorial Declarando uma política de redes para mais exemplos.

Comportamento dos seletores to e from

Existem quatro tipos de seletores que podem ser especificados nas sessões ingress.from ou egress.to:

podSelector: Seleciona Pods no mesmo namespace que a política de rede foi criada, e que deve ser permitido origens no tráfego de entrada ou destinos no tráfego de saída.

namespaceSelector: Seleciona namespaces para o qual todos os Pods devem ser permitidos como origens no caso de tráfego de entrada ou destino no tráfego de saída.

namespaceSelector e podSelector: Uma entrada to/from única que permite especificar ambos namespaceSelector e podSelector e seleciona um conjunto de Pods dentro de um namespace. Seja cuidadoso em utilizar a sintaxe YAML correta; essa política:

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
      podSelector:
        matchLabels:
          role: client
  ...

contém um único elemento from permitindo conexões de Pods com a label role=client em namespaces com a label user=alice. Mas essa política:

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
    - podSelector:
        matchLabels:
          role: client
  ...

contém dois elementos no conjunto from e permite conexões de Pods no namespace local com a label role=client, OU de qualquer outro Pod em qualquer outro namespace que tenha a label user=alice.

Quando estiver em dúvida, utilize o comando kubectl describe para verificar como o Kubernetes interpretou a política.

ipBlock: Isso seleciona um conjunto particular de faixas de IP a serem permitidos como origens no caso de entrada ou destinos no caso de saída. Devem ser considerados IPs externos ao cluster, uma vez que os IPs dos Pods são efêmeros e imprevisíveis.

Os mecanismos de entrada e saída do cluster geralmente requerem que os IPs de origem ou destino sejam reescritos. Em casos em que isso aconteça, não é definido se deve acontecer antes ou depois do processamento da NetworkPolicy que corresponde a esse tráfego, e o comportamento pode ser diferente para cada plugin de rede, provedor de nuvem, implementação de Service, etc.

No caso de tráfego de entrada, isso significa que em alguns casos você pode filtrar os pacotes de entrada baseado no IP de origem atual, enquanto que em outros casos o IP de origem que a NetworkPolicy atua pode ser o IP de um LoadBalancer ou do Nó em que o Pod está executando.

No caso de tráfego de saída, isso significa que conexões de Pods para Services que são reescritos para IPs externos ao cluster podem ou não estar sujeitos a políticas baseadas no campo ipBlock.

Políticas padrão

Por padrão, se nenhuma política existir no namespace, então todo o tráfego de entrada e saída é permitido de e para os pods nesse namespace. Os exemplos a seguir permitem a você mudar o comportamento padrão nesse namespace.

Bloqueio padrão de todo tráfego de entrada

Você pode criar uma política padrão de isolamento para um namespace criando um objeto NetworkPolicy que seleciona todos os pods mas não permite o tráfego de entrada para esses pods.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Isso garante que mesmo pods que não são selecionados por nenhuma outra política de rede ainda serão isolados. Essa política não muda o comportamento padrão de isolamento de tráfego de saída nesse namespace.

Permitir por padrão todo tráfego de entrada

Se você deseja permitir todo o tráfego de todos os pods em um namespace (mesmo que políticas que sejam adicionadas faça com que alguns pods sejam tratados como "isolados"), você pode criar uma política que permite explicitamente todo o tráfego naquele namespace.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

Bloqueio padrão de todo tráfego de saída

Você pode criar uma política de isolamento de saída padrão para um namespace criando uma política de redes que selecione todos os pods, mas não permita o tráfego de saída a partir de nenhum desses pods.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes:
  - Egress

Isso garante que mesmo pods que não são selecionados por outra política de rede não seja permitido tráfego de saída. Essa política não muda o comportamento padrão de tráfego de entrada.

Permitir por padrão todo tráfego de saída

Caso você queira permitir todo o tráfego de todos os pods em um namespace (mesmo que políticas sejam adicionadas e cause com que alguns pods sejam tratados como "isolados"), você pode criar uma política explicita que permite todo o tráfego de saída no namespace.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-egress
spec:
  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

Bloqueio padrão de todo tráfego de entrada e saída

Você pode criar uma política padrão em um namespace que previne todo o tráfego de entrada E saída criando a política a seguir no namespace.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Isso garante que mesmo pods que não são selecionados por nenhuma outra política de redes não possuam permissão de tráfego de entrada ou saída.

Selecionando uma faixa de portas

ESTADO DA FUNCIONALIDADE: Kubernetes v1.21 [alpha]

Ao escrever uma política de redes, você pode selecionar uma faixa de portas ao invés de uma porta única, utilizando-se do campo endPort conforme a seguir:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: multi-port-egress
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 32000
      endPort: 32768

A regra acima permite a qualquer Pod com a label "role=db" no namespace default de se comunicar com qualquer IP na faixa 10.0.0.0/24 através de protocolo TCP, desde que a porta de destino esteja na faixa entre 32000 e 32768.

As seguintes restrições aplicam-se ao se utilizar esse campo:

  • Por ser uma funcionalidade "alpha", ela é desativada por padrão. Para habilitar o campo endPort no cluster, você (ou o seu administrador do cluster) deve habilitar o feature gate NetworkPolicyEndPort no kube-apiserver com a flag --feature-gates=NetworkPolicyEndPort=true,....
  • O valor de endPort deve ser igual ou maior ao valor do campo port.
  • O campo endPort só pode ser definido se o campo port também for definido.
  • Ambos os campos port e endPort devem ser números.

Selecionando um Namespace pelo seu nome

ESTADO DA FUNCIONALIDADE: Kubernetes 1.21 [beta]

A camada de gerenciamento do Kubernetes configura uma label imutável kubernetes.io/metadata.name em todos os namespaces, uma vez que o feature gate esteja habilitado por padrão. O valor dessa label é o nome do namespace.

Enquanto que um objeto NetworkPolicy não pode selecionar um namespace pelo seu nome através de um campo específico, você pode utilizar essa label padrão para selecionar um namespace pelo seu nome.

O que você não pode fazer com NetworkPolicies (ao menos por enquanto!)

Por enquanto no Kubernetes 1.34 as funcionalidades a seguir não existem mas você pode conseguir implementar de forma alternativa utilizando componentes do Sistema Operacional (como SELinux, OpenVSwitch, IPtables, etc) ou tecnologias da camada 7 OSI (Ingress controllers, implementações de service mesh) ou ainda admission controllers. No caso do assunto "segurança de redes no Kubernetes" ser novo para você, vale notar que as histórias de usuário a seguir ainda não podem ser implementadas:

  • Forçar o tráfego interno do cluster passar por um gateway comum (pode ser implementado via service mesh ou outros proxies)
  • Qualquer coisa relacionada a TLS/mTLS (use um service mesh ou ingress controller para isso)
  • Políticas específicas a nível do nó kubernetes (você pode utilizar as notações de IP CIDR para isso, mas não pode selecionar nós Kubernetes por suas identidades)
  • Selecionar Services pelo seu nome (você pode, contudo, selecionar pods e namespaces por seus labels o que torna-se uma solução de contorno viável).
  • Criação ou gerenciamento
  • Políticas padrão que são aplicadas a todos os namespaces e pods (existem alguns plugins externos do Kubernetes e projetos que podem fazer isso, e a comunidade está trabalhando nessa especificação).
  • Ferramental de testes para validação de políticas de redes.
  • Possibilidade de logar eventos de segurança de redes (conexões bloqueadas, aceitas). Existem plugins CNI que conseguem fazer isso à parte.
  • Possibilidade de explicitamente negar políticas de rede (o modelo das NetworkPolicies são "negar por padrão e conforme a necessidade, deve-se adicionar regras que permitam o tráfego).
  • Bloquear o tráfego que venha da interface de loopback/localhost ou que venham do nó em que o Pod se encontre.

Próximos passos