Ajuste fino da roteação para MetalLB em modo L2

Ajuste fino da roteação para MetalLB em modo L2
Recentemente, me deparei com uma tarefa bastante incomum de configuração de roteamento para o MetalLB. Não haveria problema, pois normalmente não são necessárias ações adicionais para o MetalLB, mas, no nosso caso, temos um cluster consideravelmente grande com uma configuração de rede simples.

Neste artigo, vou explicar como configurar roteamento baseado em origem e baseado em política para a rede externa do seu cluster.

Não vou entrar em detalhes sobre a instalação e configuração do MetalLB, pois presumo que você já tenha alguma experiência. Vamos direto ao ponto, ou seja, à configuração do roteamento. Portanto, temos quatro casos:

Caso 1: Quando a configuração não é necessária

Vamos analisar um caso simples.

Ajuste fino da roteação para MetalLB em modo L2

Configuração adicional de roteamento não é necessária quando os endereços fornecidos pelo MetalLB estão na mesma sub-rede que os endereços dos seus nós.

Por exemplo, você tem uma sub-rede 192.168.1.0/24, nela há um roteador 192.168.1.1, e seus nós recebem endereços: 192.168.1.10-30, então, para o MetalLB, você pode configurar o intervalo 192.168.1.100-120 e ter certeza de que eles funcionarão sem qualquer configuração adicional.

Por que isso acontece? Porque seus nós já têm rotas configuradas:

# ip route
default via 192.168.1.1 dev eth0 onlink 
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10

E os endereços do mesmo intervalo reutilizarão essas rotas sem qualquer esforço adicional.

Caso 2: Quando é necessária configuração adicional

Ajuste fino da roteação para MetalLB em modo L2

Você deve configurar rotas adicionais sempre que seus nós não tiverem configurado endereços IP ou uma rota na sub-rede para a qual o MetalLB está atribuindo endereços.

Vou explicar com mais detalhes. Sempre que o MetalLB atribuir um endereço, isso pode ser comparado a uma simples atribuição como:

ip addr add 10.9.8.7/32 dev lo

Preste atenção em:

  • a) O endereço é atribuído com um prefixo /32 ou seja, uma rota na sub-rede para ele não será adicionada automaticamente (é apenas um endereço)
  • b) O endereço é vinculado a qualquer interface do nó (por exemplo, loopback). Aqui, vale mencionar a particularidade da pilha de rede do Linux. Não importa a qual interface você adicione o endereço, o núcleo sempre processará as solicitações ARP e enviará respostas ARP em qualquer uma delas; esse comportamento é considerado correto e, além disso, é bastante utilizado em um ambiente dinâmico como o Kubernetes.

Esse comportamento pode ser configurado, por exemplo, ativando o arp strict:

echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

Neste caso, as respostas ARP serão enviadas apenas se a interface contiver explicitamente um endereço IP específico. Essa configuração é obrigatória se você planeja usar o MetalLB e o seu kube-proxy está operando no modo IPVS.

No entanto, o MetalLB não utiliza o kernel para processar solicitações ARP, mas faz isso por conta própria no user-space, assim essa opção não afetará o funcionamento do MetalLB.

Retornando à nossa tarefa. Se não houver rota para os endereços atribuídos nos seus nós, adicione-a antecipadamente em todos os nós:

ip route add 10.9.8.0/24 dev eth1

Caso 3: Quando será necessário o roteamento baseado em origem

Você precisará configurar o roteamento baseado em origem quando receber pacotes através de um gateway separado, diferente daquele que está configurado por padrão, assim as respostas também devem sair por esse mesmo gateway.

Por exemplo, você tem a mesma sub-rede 192.168.1.0/24 designada para seus nós, mas deseja atribuir endereços externos por meio do MetalLB. Suponha que você tenha alguns endereços da sub-rede 1.2.3.0/24 localizados na VLAN 100, e deseja usá-los para acessar serviços do Kubernetes externamente.

Ajuste fino da roteação para MetalLB em modo L2

Ao acessar 1.2.3.4 você estará fazendo solicitações de uma sub-rede diferente daquela de 1.2.3.0/24 e esperando a resposta. O nó que atualmente é mestre para o endereço atribuído pelo MetalLB 1.2.3.4, receberá o pacote do roteador 1.2.3.1, mas a resposta deve obrigatoriamente seguir o mesmo caminho, através de 1.2.3.1.

Como nosso nó já tem um gateway padrão configurado 192.168.1.1, a resposta por padrão irá para ele, e não para 1.2.3.1, através do qual recebemos o pacote.

Como lidar com essa situação?

Neste caso, você precisará preparar todos os seus nós para que eles possam atender endereços externos sem configuração adicional. Ou seja, para o exemplo acima, você precisará criar antecipadamente uma interface VLAN no nó:

ip link add link eth0 name eth0.100 type vlan id 100
ip link set eth0.100 up

E então adicionar as rotas:

ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100

Note que as rotas estão sendo adicionadas a uma tabela de rotas separada 100 ela conterá apenas duas rotas necessárias para enviar o pacote de resposta através do gateway 1.2.3.1, localizado atrás da interface eth0.100.

Agora precisamos adicionar uma regra simples:

ip rule add from 1.2.3.0/24 lookup 100

que diz explicitamente: se o endereço de origem do pacote estiver em 1.2.3.0/24, então deve-se usar a tabela de rotas 100. Nela, já descrevemos um caminho que o enviará através de 1.2.3.1

Caso 4: Quando o roteamento baseado em políticas for necessário

A topologia de rede é a mesma do exemplo anterior, mas suponha que você também queira ter a possibilidade de acessar endereços externos do pool 1.2.3.0/24 a partir dos seus pods:

Ajuste fino da roteação para MetalLB em modo L2

A característica é que, ao acessar qualquer endereço em 1.2.3.0/24, o pacote de resposta, ao chegar ao nó e tendo um endereço de origem na faixa 1.2.3.0/24 , será enviado obedientemente para eth0.100, mas queremos que o Kubernetes o redirecione para nosso primeiro pod, que gerou a solicitação original.

Resolver esse problema se revelou complicado, mas foi possível graças ao roteamento baseado em políticas:

Para entender melhor o processo, apresento o diagrama de bloco do netfilter:
Ajuste fino da roteação para MetalLB em modo L2

Para começar, como no exemplo anterior, vamos criar uma tabela de roteamento adicional:

ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100

Agora adicionamos algumas regras no iptables:

iptables -t mangle -A PREROUTING -i eth0.100 -j CONNMARK --set-mark 0x100
iptables -t mangle -A PREROUTING  -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j RETURN
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark

Essas regras marcarão as conexões de entrada na interface eth0.100, marcando todos os pacotes com a tag 0x100, essa mesma tag será usada nas respostas dentro da mesma conexão.

Agora podemos adicionar uma regra de roteamento:

ip rule add from 1.2.3.0/24 fwmark 0x100 lookup 100

Ou seja, todos os pacotes com um endereço de origem 1.2.3.0/24 e com a tag 0x100 devem ser roteados usando a tabela 100.

Assim, outros pacotes recebidos em outra interface não se enquadrarão nessa regra, permitindo que sejam roteados pelos meios padrões do Kubernetes.

Há um porém, no Linux existe o que é chamado de filtro de caminho reverso, que estraga tudo realizando uma simples verificação: para todos os pacotes de entrada, ele substitui o endereço de origem do pacote pelo endereço do remetente e verifica se o pacote pode sair pela mesma interface pela qual foi recebido; caso contrário, ele o filtra.

O problema é que, no nosso caso, ele não funcionará corretamente, mas podemos desativá-lo:

echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0.100/rp_filter

Observe que o primeiro comando controla o comportamento global do rp_filter; se não for desativado, o segundo comando não terá efeito. No entanto, as outras interfaces permanecerão com o rp_filter ativado.

Para não limitar completamente o funcionamento do filtro, podemos usar a implementação do rp_filter para o netfilter. Usando o rpfilter como um módulo do iptables, é possível configurar regras bastante flexíveis, por exemplo:

iptables -t raw -A PREROUTING -i eth0.100 -d 1.2.3.0/24 -j RETURN
iptables -t raw -A PREROUTING -i eth0.100 -m rpfilter --invert -j DROP

ativar o rp_filter na interface eth0.100 para todos os endereços, exceto 1.2.3.0/24.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster