Rede de pilha dupla IPv4/IPv6

Os clusters do Anthos em bare metal são compatíveis com a rede IPv4/IPv6 de pilha dupla. Isso significa que um cluster pode aceitar tráfego de dispositivos externos que usam a versão 4 do Protocolo de Internet (IPv4) ou a versão 6 do Protocolo de Internet (IPv6).

A rede de pilha dupla atribui endereços IPv4 e IPv6 a pods e nós. Um serviço do Kubernetes pode ter um endereço IPv4, um endereço IPv6 ou ambos.

Todos os clusters de pilha dupla usam o modo simples para IPv6. Por padrão, um cluster de pilha dupla usa o modo de ilha para IPv4, mas é possível configurá-lo para usar o modo simples para IPv4.

Para criar um cluster de pilha dupla, sua rede subjacente precisa estar ativada. Se a rede subjacente for IPv4 ou IPv6 de pilha única, não será possível iniciar um cluster de pilha dupla.

Antes de começar

Se os nós do cluster estiverem executando o CentOS ou RedHat Enterprise Linux e tiverem o SELinux ativado, em cada nó:

  • Em /etc/firewalld/firewalld.conf, defina IPv6_rpfilter=no.

  • Execute systemctl restart firewalld.

Visão geral da criação de um cluster de pilha dupla

É possível ativar a rede de pilha dupla ao criar um novo cluster, mas não é possível ativá-la em um cluster atual.

Siga as instruções em um dos documentos de criação de cluster.

No arquivo de configuração, inclua manifestos para:

  • um recurso de namespace;
  • um recurso de cluster;
  • um ou mais recursos do NodePool;
  • um ou mais recursos ClusterCIDRConfig.

Preencha o manifesto de namespace e os manifestos de NodePool como faria para um cluster de pilha única.

No manifesto do cluster, em clusterNetwork.services.cidrBlocks, especifique um intervalo CIDR IPv4 e um intervalo CIDR IPv6. Esse é o critério de ativação para um cluster de pilha dupla. Ou seja, se você fornecer intervalos CIDR de serviço para IPv4 e IPv6, o cluster terá uma rede de pilha dupla.

No manifesto do cluster, em clusterNetwork.pods.cidrBlocks, especifique um intervalo CIDR IPv4, mas não um intervalo CIDR IPv6. Os intervalos CIDR IPv6 para pods são especificados nos manifestos ClusterCIDRConfig.

Se você estiver usando o balanceamento de carga em pacote, forneça os endereços IPv4 e IPv6 na seção loadBalancer.addressPools do manifesto do cluster.

Os recursos de ClusterCIDRConfig são para especificar intervalos CIDR IPv4 e IPv6 para pods. É possível usar um único recurso ClusterCIDRConfig para especificar intervalos CIDR em todo o cluster. Ou seja, os endereços do pod IPv4 para todos os nós são tomados de um único intervalo CIDR, e os endereços do pod IPv6 para todos os nós são tomados de um único intervalo CIDR. Outra opção é usar vários recursos ClusterCIDRConfig para especificar intervalos CIDR que se aplicam a um determinado pool de nós ou a um nó específico.

Acessibilidade para endereços IP do pod

Um cluster de pilha dupla usa o modo plano para redes IPv6. O exemplo mostrado neste documento é para um cluster que usa rede estática de modo plano para IPv6. Ou seja, o cluster não está configurado para usar o protocolo de gateway de borda (BGP, na sigla em inglês).

Para um cluster que usa rede estática de modo plano, é necessário especificar os endereços IP do nó e do pod que fazem parte da mesma sub-rede. Isso possibilita que clientes fora do cluster, mas no mesmo domínio da camada 2 (L2) que os nós do cluster, enviem pacotes diretamente aos endereços IP do pod.

Por exemplo, suponha que os nós do cluster e algumas outras máquinas estejam no mesmo domínio L2. Veja uma maneira de especificar os intervalos de endereços:

MotivoIntervaloNúmero de endereços
Todo o domínio L2fd12::/1082^20
Podsfd12::1:0/1122^16
Nósfd12::2:0/1122^16
Outras máquinasfd12::3:0/1122^16
VIPsfd12::4:0/1122^16

Sobre o exemplo anterior, é importante entender os pontos abaixo:

  • Todos os endereços de nós, pods e máquinas estão no intervalo grande "fd12::/108".

  • Os endereços IP do pod estão em um subconjunto de um intervalo grande.

  • Os endereços IP do nó estão em um subconjunto diferente do intervalo grande.

  • Os endereços IP de outras máquinas estão em um subconjunto diferente do intervalo grande.

  • Todos os intervalos de subconjuntos são diferentes uns dos outros.

No exemplo anterior, cada máquina no domínio L2, incluindo os nós do cluster, precisa ter uma regra de encaminhamento para o intervalo maior. Exemplo:

inet fd12::/108 scope global eth0

Exemplo: criar um cluster de pilha dupla

Ao criar um cluster de pilha dupla, você tem várias opções. Por exemplo, é possível ter intervalos CIDR em todo o cluster ou aplicáveis a pools de nós específicos. É possível combinar uma rede plana IPv6 com uma rede no modo ilha IPv4. Ou suas redes IPv4 e IPv6 podem ser simples. É possível usar o balanceamento de carga em pacote ou manual.

Nesta seção, mostramos um exemplo de como criar um cluster de pilha dupla. O cluster neste exemplo tem as seguintes características:

  • Uma rede IPv4 no modo de ilha
  • Uma rede IPv6 no modo simples
  • Um intervalo de CIDR IPv4 para pods em todo o cluster
  • Um intervalo de CIDR IPv6 para pods em todo o cluster
  • Um intervalo CIDR de IPv4 para Serviços em todo o cluster
  • Um intervalo CIDR para IPv6 para serviços em todo o cluster
  • Um pool de endereços IPv4 a ser usado para serviços do tipo LoadBalancer
  • Um pool de endereços IPv6 a ser usado para serviços do tipo LoadBalancer
  • Balanceamento de carga em pacote

Para ver mais exemplos de configuração, consulte Variações no uso do Cluster CIDRConfig.

Preencher um arquivo de configuração

Siga as instruções em um dos documentos de criação de cluster.

No arquivo de configuração, no manifesto Cluster:

  • Para clusterNetwork.pods.cidrBlocks, forneça um único intervalo CIDR IPv4.

  • Para clusterNetwork.services.cidrBlocks, forneça dois intervalos CIDR: um para IPv4 e outro para IPv6.

  • Para loadBalancer.addressPools, forneça dois intervalos de endereços: um para IPv4 e outro para IPv6. Quando você cria um Serviço do tipo LoadBalancer, os endereços IP externos do Serviço são escolhidos nesses intervalos.

Veja um exemplo que mostra as partes relevantes de um manifesto de cluster:

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: "dual-stack"
  namespace: "cluster-dual-stack"

spec:
  clusterNetwork:
    pods:
      cidrBlocks:
      - "192.168.0.0/16"
    services
      cidrBlocks:
       - "172.16.0.0/20"
       - "fd12::5:0/116"
...
  loadBalancer:
    mode: "bundled"
    ...
    addressPools:
    - name: "pool-1"
      addresses:
       - "10.2.0.212-10.2.0.221"
       - "fd12::4:101-fd12::4:110"

No mesmo arquivo de configuração, inclua um manifesto para uma ClusterCIDRConfig.

  • Defina ipv4.cidr com o mesmo intervalo CIDR fornecido no manifesto Cluster. Esse é um requisito se o IPv4 estiver no modo Ilha.

  • Defina namespace com o mesmo valor fornecido no manifesto Cluster.

  • Defina ipv6.cidr como um intervalo CIDR IPv6 para pods.

  • Para cada intervalo CIDR, forneça um valor para perNodeMaskSize para especificar quantos endereços de pod serão atribuídos a cada nó. O número de endereços IPv4 atribuídos a cada nó precisa ser igual ao número de endereços IPv6 atribuídos a cada nó. Defina seus valores para perNodeMaskSize de acordo. Por exemplo, se você quiser 2^8 endereços por nó, defina seus valores de perNodeMaskSize da seguinte maneira:

    • ipv4.perNodeMaskSize: 24 # (32 - 8 = 24)
    • ipv6.perNodeMaskSize: 120 # (128 - 8 = 120)

Veja um exemplo de um manifesto ClusterCIDRConfig:

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "cluster-wide-ranges"
  namespace: "cluster-dual-stack"  # Must be the same as the Cluster namespace.
spec:
  ipv4:
    cidr: "192.168.0.0/16"  #  For island mode, must be the same as the Cluster CIDR.
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/112"
    perNodeMaskSize: 120

No exemplo anterior:

  • O intervalo de CIDR do pod IPv4 tem 2^(32-16) = 2^16 endereços. O tamanho da máscara por nó é 24, portanto, o número de endereços atribuídos a cada nó é 2^(32-24) = 2^8.

  • O intervalo CIDR de pod do IPv6 tem 2^(128-112) = 2^16 endereços. O tamanho da máscara por nó é 120. Portanto, o número de endereços atribuídos a cada nó é 2^(128-120) = 2^8.

Exemplo: arquivo de configuração

Concluir a criação do cluster

Conclua a criação do cluster conforme descrito no documento de criação do cluster.

Ver nós e pods do cluster

Liste os nós do cluster:

kubectl --kubeconfig CLUSTER_KUBECONFIG get nodes --output yaml

Substitua CLUSTER_KUBECONFIG pelo caminho do seu arquivo kubeconfig do cluster.

Na saída, é possível ver os endereços IPv4 e IPv6 de cada nó. Também é possível ver os intervalos de endereços IPv4 e IPv6 para pods no nó. Exemplo:

- apiVersion: v1
  kind: Node
  ...
  spec:
    podCIDR: 192.168.1.0/24
    podCIDRs:
    - 192.168.1.0/24
    - fd12::1:100/120
    providerID: baremetal://10.2.0.5
  status:
    addresses:
    - address: 10.2.0.5
      type: InternalIP
    - address: fd12::2:5
      type: InternalIP

Liste os pods no cluster:

kubectl --kubeconfig CLUSTER_KUBECONFIG get pods --all-namespaces

Escolha um pod e liste os detalhes. Exemplo:

kubectl --kubeconfig CLUSTER_KUBECONFIG get pod gke-metrics-agent-b9qrv \
  --namespace kube-system \
  -- output yaml

Na saída, é possível ver os endereços IPv4 e IPv6 do pod. Exemplo:

apiVersion: v1
kind: Pod
metadata:
  ...
  name: gke-metrics-agent-b9qrv
  namespace: kube-system
...
status:
  ...
  podIPs:
  - ip: 192.168.1.146
  - ip: fd12::1:11a

Variações no uso de ClusterCIDRConfig

O exemplo anterior usou um objeto ClusterCIDRConfig para especificar intervalos CIDR de pod em todo o cluster. Ou seja, um único intervalo CIDR IPv4 é usado para todos os pods no cluster. E um único intervalo CIDR IPv6 é usado para todos os pods no cluster.

Em determinadas situações, talvez você não queira usar um único intervalo CIDR para todos os pods em um cluster. Por exemplo, é possível especificar um intervalo CIDR separado para cada pool de nós ou um intervalo CIDR separado para cada nó.

Por exemplo, o ClusterCIDRConfig a seguir especifica um intervalo CIDR para um pool de nós chamado "workers".

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "worker-pool-ccc"
  namespace: "cluster-dual-stack"
spec:
  ipv4:
    cidr: "192.168.0.0/16"
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/112"
    perNodeMaskSize: 120
  nodeSelector:
    matchLabels:
      baremetal.cluster.gke.io/node-pool: "workers"

O ClusterCIDRConfig a seguir especifica um intervalo CIDR para um único nó que tem o endereço IP 10.2.0.5:

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "range-node1"
  namespace: "cluster-dual-stack"
spec:
  ipv4:
    cidr: "192.168.1.0/24"
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/120"
    perNodeMaskSize: 120
  nodeSelector:
    matchLabels:
      baremetal.cluster.gke.io/k8s-ip: "10.2.0.5"

Crie um serviço de pilha dupla do tipo ClusterIP

Veja o manifesto de uma implantação:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: "my-deployment"
spec:
  selector:
    matchLabels:
      app: "try-dual-stack"
  replicas: 3
  template:
    metadata:
      labels:
        app: "try-dual-stack"
    spec:
      containers:
      - name: "hello"
        image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"

Salve o manifesto em um arquivo denominado my-deployment.yaml e crie a implantação:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-deployment.yaml

Substitua CLUSTER_KUBECONFIG pelo caminho do seu arquivo kubeconfig do cluster.

Veja um manifesto para um Service do tipo ClusterIP:

apiVersion: v1
kind: Service
metadata:
  name: "my-service"
spec:
  selector:
    app: "try-dual-stack"
  type: "ClusterIP"
  ipFamilyPolicy: "RequireDualStack"
  ipFamilies:
  - "IPv6"
  - "IPv4"
  ports:
  - port: 80
    targetPort: 8080

No contexto deste exercício, estes são os pontos principais para entender sobre o manifesto de serviço anterior:

  • O campo ipFamilyPolicy está definido como RequireDualStack. Isso significa que os endereços ClusterIP e IPv6 são alocados para o serviço.

  • O campo ipFamilies especifica a família IPv6 primeiro e, em seguida, a segunda família de IPv4. Isso significa que spec.ClusterIP para o serviço será um endereço IPv6 escolhido de clusterNetwork.services.cidrBlocks no manifesto do cluster.

Salve o manifesto em um arquivo chamado my-cip-service.yaml e crie o Serviço:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-cip-service.yaml

Liste os detalhes do Serviço:

kubectl --kubeconfig CLUSTER_KUBECONFIG get service my-service --output yaml

Na saída, é possível ver os endereços IP do cluster do Serviço. Por exemplo:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  …
spec:
  clusterIP: fd12::5:9af
  clusterIPs:
  - fd12::5:9af
  - 172.16.12.197

Em um nó de cluster, chame o Serviço:

curl IPV4_CLUSTER_IP
curl [IPV6_CLUSTER_IP]

A saída vai mostrar a mensagem "Hello world":

Hello, world!
Version: 2.0.0
Hostname: my-deployment-xxx

Crie um serviço de pilha dupla do tipo LoadBalancer

Veja um manifesto para um Service do tipo LoadBalancer:

apiVersion: v1
kind: Service
metadata:
  name: "my-lb-service"
spec:
  selector:
    app: "try-dual-stack"
  type: "LoadBalancer"
  ipFamilyPolicy: "RequireDualStack"
  ipFamilies:
  - "IPv6"
  - "IPv4"
  ports:
  - port: 80
    targetPort: 8080

Salve o manifesto em um arquivo chamado my-lb-service.yaml e crie o Serviço:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-lb-service.yaml

Lembre-se de que, no manifesto do cluster, você especificou um intervalo de endereços IPv6 e um intervalo de endereços IPv4 a serem usados para serviços do tipo LoadBalancer:

  loadBalancer:
    mode: "bundled"
    ...
    addressPools:
    - name: "pool-1"
      addresses:
      - "10.2.0.112-10.2.0.221"
      - "fd12::4:101-fd12::4:110"

Seu serviço receberá um endereço IPv4 externo escolhido no intervalo IPv4 e um endereço IPv6 externo escolhido no intervalo IPv6.

Lista de detalhes do Serviço:

kubectl --kubeconfig CLUSTER_KUBECONFIG get service my-lb-service --output yaml

Na saída, é possível ver os endereços externos do Serviço. Exemplo:

apiVersion: v1
kind: Service
metadata:
  name: my-lb-service
...
status:
  loadBalancer:
    ingress:
    - ip: 10.2.0.213
    - ip: fd12::4:101

Valores possíveis para ipFamilyPolicy

Ao criar um serviço de pilha dupla, é possível definir ipFamilyPolicy como um destes valores:

  • SingleStack: o controlador aloca um endereço IP de cluster para o serviço escolhido no primeiro intervalo especificado pelo manifesto do cluster em clusterNetwork.services.cidrBlocks.

  • PreferDualStack: o controlador aloca endereços IP do cluster IPv4 e IPv6 para o serviço, escolhidos entre os intervalos especificados no manifesto do cluster em clusterNetwork.services.cidrBlocks. Se não for um cluster de pilha dupla, o comportamento será o mesmo de SingleStack.

  • RequireDualStack: o controlador aloca endereços IP do cluster IPv4 e IPv6 para o serviço, escolhidos nos intervalos especificados no manifesto do cluster em clusterNetwork.services.cidrBlocks. Ele define o valor de spec.clusterIP com base na primeira família de endereços especificada no manifesto do Serviço em ipFamilies.

Mais informações

Para mais informações sobre como criar serviços de pilha dupla, consulte Opções de pilha dupla em novos serviços.