Primeiro, minha pergunta é semelhante a Como configurar uma rede em ponte com máquina virtual e host com KVM (Virt-Manager)? mas a resposta marcada não funciona para mim, e como a questão está marcada como resolvida, achei melhor postar uma nova pergunta.
Vou tentar simplificar minha configuração.
- Eu tenho um
host
comeno1
(rodando Debian + KDE) - Eu removi todas
eno1
as interfaces - Eu criei uma interface em ponte
br0
e adicioneieno1
como escravo - Eu tenho o virt-manager instalado em
host
Agora:
host
está conectadobr0
e obtém um IP- um virt-manager
VM
está configurado para usarbr0
, mas não obtém um IP
Não importa o que eu tente, não consigo VM
obter um IP. Como posso consertar isso?
Aqui estão algumas capturas de tela. Ignore br1, pois era apenas eu jogando/testando.
A br0
conexão...
... com um escravo Ethernet ...
... vinculado a eno1
.
VM
configurado para dispositivo em pontebr0
Docker usa iptables para gerenciar seus contêineres, assim como libvirt também o usa. Mas geralmente o Docker não funciona bem com outras ferramentas relacionadas à rede em execução no mesmo sistema, por dois motivos:
O Docker carrega o
br_netfilter
módulo do kernel que faz com que os quadros em ponte atravessem iptables (em vez de apenas ebtables ).Docker também define a política padrão de filtro/FORWARD do iptables para DROP
A combinação destes, e o fato de
br_netfilter
fazer isso como comportamento padrão , qualquer ponte presente no sistema, seja ela relacionada ou não ao Docker, herda uma política de encaminhamento padrão de DROP através do iptables , além de tudo o que o ebtables possa fazer se também estiver presente : qualquer quadro encaminhado é descartado.Portanto, todas as pontes manipuladas pela libvirt são afetadas: as VMs ficam isoladas devido à execução do Docker. Conforme citado acima, exceções podem ser adicionadas (mas na verdade devem ser inseridas em vez de adicionadas) à
DOCKER-USER
regra de cadeia criada pelo Docker (mas que pode ser criada primeiro pelo administrador, se necessário). Apenas adicionar regras àFORWARD
cadeia pode não ser suficiente porque o Docker sempre insere suas regras antes (mas chamaDOCKER-USER
primeiro).Para permitir que qualquer ponte não Docker não seja filtrada por iptables , pode-se usar uma das seguintes opções:
combinar por endereço IP o que pode ser encaminhado. Não será mais fácil diferenciar do DHCP usando endereços como 0.0.0.0 e 255.255.255.255, eles também devem ser adicionados. Para o IP LAN 192.0.2.0/24 isso seria:
ou, em vez disso, combine por interface não Docker
A menos que sejam nomeados de forma personalizada, as interfaces do Docker são sempre nomeadas como
docker0
oubr-...
. Não use a mesma convenção de nomenclatura e adicione exceções para elas.Do ponto de vista do iptables , os quadros em ponte encaminhados das portas da ponte eno1 e, por exemplo, vnet0 (a interface tap para a VM) são apresentados como provenientes da interface br0 : a porta da ponte não será vista, então o pacote vem de br0 e é encaminhado para br0 .
A ordem é importante. A declaração do índice de inserção mantém uma ordem natural para as regras abaixo, como se elas tivessem sido adicionadas
-A
(mas elas precisam ser inseridas porque o Docker adicionou um final-j RETURN
).Permitir
br0
ebr1
:Vamos continuar com outros nomes comuns para libvirt e LXC (também uma vítima comum):
ou, em vez disso, faça com que o iptables obtenha algumas informações de ponte para tomar uma decisão
Mesmo que pareça mais genérico, deve ser evitado, porque o uso do
physdev
módulo match carrega obr_netfilter
módulo do kernel para funcionar se ainda não estiver carregado, portanto, ele estará presente mesmo quando não estiver usando o Docker, embora seu objetivo seja proteger-se do carregamento do Dockerbr_netfilter
. É um pouco mais poderoso porque permite distinguir quadros que foram interligados de pacotes que foram roteados (com um roteamento de um braço que usa uma ponte como interface de roteamento).Exceções para o Docker ainda são necessárias, pois o Docker faz sua própria filtragem de LAN em suas próprias cadeias. Qualquer coisa que não seja Docker e em ponte (em vez de roteada) é permitida.
As escolhas anteriores podem não funcionar em todos os casos possíveis, considerando que a própria libvirt possui regras na cadeia FORWARD que podem não funcionar corretamente ou podem sofrer curto-circuito pelas regras do Docker. Embora as regras nat , que também são afetadas, geralmente sejam tratadas de forma completamente correta neste caso pela libvirt (e pelo LXC).
Docker em uma VM
Não misture o Docker com nenhuma outra ferramenta de rede, pois isso atrapalhará seu comportamento na presença de uma ponte. Em vez disso, execute o próprio Docker em uma VM onde esteja devidamente isolado e não afete o host ou outras VMs e contêineres (por exemplo: LXC) no host. Então, se esta VM estiver conectada à rede principal, como a configuração do host atual já permite, isso não mudará muito nas configurações externas para alcançar seus contêineres: o Docker terá apenas seu próprio endereço IP separado na LAN física, em vez de os anfitriões.
outras possibilidades (requer kernel >= 5.3)
Pré-carregue
br_netfilter
para ter certeza de obter as configurações do sysctl disponíveis e desative a configuração de todo o sistema para iptables com:e ative-o novamente em pontes selecionadas do Docker (possivelmente usando um script executando comandos do Docker para recuperar seus nomes):
Isso exigirá ações em cada nova ponte criada.
Uma outra maneira poderia ser o Docker-in-Docker sendo executado em um contêiner com apenas a configuração global desabilitada (esta configuração ainda está habilitada por padrão em novos namespaces de rede...). Isso parece cada vez mais difícil devido à carga adicional de gerenciamento do que executar o Docker em uma VM.
Eu escolheria 4. (VM: evita todas as interferências possíveis do Docker) ou então 2. (mantenha-o simples, mas bom o suficiente)
Nota: tudo o que está escrito se aplica ao IPv6, substituindo
iptables
peloip6tables
acima (incluindo osysctl
). Para integração com nftables , consulte esta resposta específica do nftables .