Os contedores responden na LAN da oficina e deixan de responder no momento en que se conecta a VPN da empresa. Nada do contedor cambiou: nin reinicio, nin actualización de imaxe, nin edición de configuración. O que cambiou é a táboa de enrutamento do host, onde unha ruta que engadiu o túnel agora cobre o enderezo que Docker asignou. Antes de editar unha subrede ou pedir unha exclusión da VPN, poña os dous plans de enderezos un ao lado do outro, porque as reparacións custan cantidades de tempo moi distintas.

Lea a ruta antes de cambiar a configuración

Comece pola rede que Docker construíu realmente. O bloque IPAM é o plan de enderezos, e a subrede é a liña que importa:

docker network inspect project_default --format '{{json .IPAM.Config}}'
# [{"Subnet":"172.18.0.0/16","Gateway":"172.18.0.1"}]

Compose asigna por defecto unha /16 a cada proxecto novo, así que dous servizos poden caber dentro dun rango de 65,536 enderezos. Esa anchura é a razón de que os solapamentos sexan habituais: unha /16 escollida ao azar é abondo grande para tragar un sitio ao que chega polo túnel, e ninguén o nota ata que o túnel se levanta.

Despois compare a selección de ruta para un enderezo de contedor, unha vez co túnel baixado e outra co túnel subido:

ip route get 172.18.0.7
# 172.18.0.7 dev br-3f2a9c src 172.18.0.1

Dúas formas de resposta levan a lugares distintos. Se a saída nomea tun0, wg0 ou outro dispositivo de túnel, un prefixo de VPN é polo menos tan específico como a ruta da ponte e o paquete nunca chega ao contedor. Se segue nomeando a ponte, o host pode alcanzar o contedor, e o seu fallo é filtrado, DNS ou unha ruta de retorno que falla só nunha dirección.

Por que unha colisión de /16 é fácil de atopar

Docker toma as redes de ponte dos grupos privados, e o grupo por defecto sae do bloque 172.16.0.0/12 en porcións de /16. As redes corporativas adoitan usar o mesmo espazo privado, e unha VPN de acceso remoto empurra eses prefixos a cada cliente que se conecta. Cando ambos os lados cren que posúen 172.18.0.0/16, unha táboa de enrutamento sostén dúas afirmacións contraditorias.

A lonxitude do prefixo decide o gañador, non a orde en que aparecen as rutas. Un túnel que empurra 10.0.0.0/8 non vence unha ruta de ponte 172.18.0.0/16, porque /8 é menos específico. Un túnel que empurra 172.18.0.0/16, ou 172.18.5.0/24 dentro del, si vence. Por iso un portátil funciona na rede da oficina e falla no Wi-Fi do hotel coa mesma VPN: o cliente recibe prefixos distintos.

A mesma táboa goberna a dirección contraria. Un contedor que precisa un host interno en 10.8.4.20 envía o paquete á súa porta de enlace de ponte, e o host encamíñao despois cara ao túnel. Esa ruta normalmente funciona porque o host fai o NAT, pero falla cando o lado corporativo acepta só o enderezo VPN do portátil, ou cando o filtrado de ruta inversa descarta a resposta asimétrica.

Compare as tres reparacións

Só hai tres saídas, e difiren en quen debe aprobalas e que se rompe mentres aplica unha.

RepairWho owns itWhat it costs
Renumber the container networkYouRecreates the network, restarts services, invalidates literal addresses in configs and scripts
Exclude your range from the tunnelNetwork teamChanges what every laptop sees, needs a change request and a client profile update
Reach the service through a published portYou and the clientOne port only, no direct container-to-container routing across the tunnel

Renumerar é a única reparación que pode rematar sen un ticket, e por iso a maioría dos artigos detéñense aí. É barata nun proxecto novo e cara en canto unha ferramenta de migración ou unha cadea de conexión gardada apunta a un enderezo literal. Conte esas referencias antes de editar o YAML, non despois.

Unha exclusión do túnel é a resposta máis limpa cando o solapamento está nun rango que a súa empresa posúe de verdade. Tamén é a máis lenta, e é inútil para un contratista que non pode cambiar o perfil do cliente. Un porto publicado ou un pequeno proxy inverso evitan a discusión: o cliente fala cun enderezo que o túnel xa encamiña correctamente, e só ese porto ten que ser accesible.

Fixe un rango a propósito

Para un só proxecto, declare a subrede no ficheiro compose para que o proxecto deixe de tomar do grupo compartido:

networks:
  default:
    ipam:
      config:
        - subnet: 10.201.7.0/24

Tome ese rango dun rexistro que manteña o seu equipo, non dun exemplo que atopou buscando. Compruébeo contra os prefixos que empurra a VPN, as LAN domésticas desde as que traballa a xente e as demais redes de contedores do mesmo host. Logo planifique a recreación, porque unha rede existente conserva a súa subrede antiga: docker compose down, logo up -d. docker network rm négaose mentres haxa puntos finais conectados, e calquera ipv4_address entrada do ficheiro ten que caer dentro do rango novo.

Para as redes que Docker crea por si mesmo, fixe un grupo de daemon en /etc/docker/daemon.json:

{
  "default-address-pools": [
    { "base": "10.201.0.0/16", "size": 24 },
    { "base": "10.202.0.0/16", "size": 24 }
  ]
}

O grupo aplícase ás redes creadas despois de que o daemon se reinicie, e as pontes que xa existen conservan os seus enderezos. Iso é cómodo e fácil de esquecer, así que trate un proxecto antigo como aínda solapado ata que alguén recree a súa rede. A documentación de Docker sobre redes do motor describe as regras de asignación se precisa defender o grupo nunha revisión.

A ponte de Linux e Docker Desktop fallan de forma distinta

Nun host Linux, os contedores séntanse en pontes dentro do espazo de nomes do host. Unha táboa decide todo, así que a comparación anterior é toda a historia: lea a ruta da ponte, lea a ruta do túnel e vexa cal gaña para un enderezo real de contedor.

Docker Desktop pon os contedores detrás dunha VM co seu propio NAT. O host non ten ningunha ruta ao enderezo do contedor; chega ao servizo por un porto publicado, normalmente vinculado a 127.0.0.1. Un cliente de VPN pode, xa que logo, romper o servizo sen ningún solapamento de subredes, sexa instalando unha ruta para o rango interno da VM ou bloqueando o tráfico de loopback mentres o túnel está conectado. Se ip route get no host informa de que non hai ruta para o enderezo do contedor, iso é o esperado e non o fallo.

A consecuencia práctica é onde mira primeiro. En Linux, comece pola táboa de enrutamento. En Desktop, comece polo porto publicado e as regras de firewall do cliente de VPN, e logo comprobe se a subrede interna da VM choca con algo que empurra o túnel.

Verifique co túnel subido

Reconecte a VPN dúas veces antes de dalo por arranxado, porque un perfil que empurra rutas ao conectar e as retira ao desconectar pode parecer correcto tras o primeiro intento. Logo execute as comprobacións que o cliente executa de verdade:

  1. ip route get desde o host, usando o enderezo real do contedor.
  2. Unha petición desde outro contedor, para demostrar que o servizo en si está san.
  3. curl -sv http://127.0.0.1:8080/ desde o cliente co túnel subido, logo traceroute -n ao enderezo do contedor desde unha máquina da LAN.
  4. sysctl net.ipv4.conf.all.rp_filter se a petición chega ao host pero a resposta desaparece.

Por último, escriba o rango escollido no mesmo rexistro que usou para escollelo, coa data e o proxecto que o posúe. O seguinte solapamento virá dun proxecto que ninguén documentou, e a única defensa é que o rango se reservou a propósito en lugar de sacalo ao azar.

Artigos relacionados