A VPN está ativa, o navegador alcança sites internos, e o contêiner continua sem resolver os mesmos nomes. Uma instalação de pacote morre com um erro de resolução de nomes como EAI_AGAIN, ou uma aplicação não encontra um host de banco de dados que a máquina host resolve sem qualquer reclamação. O contêiner não usa o resolvedor que a VPN instalou. O Docker copiou a configuração do resolvedor do host quando o contêiner foi criado, e nada a copiou de novo depois disso.

Duas visões do resolvedor numa mesma máquina

No Linux, o Docker dá a cada contêiner uma cópia de a configuração do resolvedor do host no momento da criação, filtra endereços de loopback e executa um servidor DNS embutido em 127.0.0.11 que encaminha as consultas para fora. Um cliente VPN que reescreva /etc/resolv.conf depois de o contêiner ter iniciado não muda nada dentro dele. Reiniciar o contêiner só ajuda se o resolvedor do host estiver correto naquele momento por acaso.

O Docker Desktop no macOS ou Windows acrescenta uma camada, porque o daemon vive numa máquina virtual. O resolvedor VPN do host pode nunca ser visível para essa VM, então reiniciar não muda absolutamente nada. Compare as duas visões antes de escolher uma correção: docker exec mycontainer cat /etc/resolv.conf ao lado da lista de resolvedores do host.

Um contêiner que lista um resolvedor público enquanto o host lista um interno resolverá os nomes públicos e falhará nos internos. Essa divisão é a assinatura deste problema.

Opção A: passar o resolvedor do túnel por contêiner

O Docker aceita definições de DNS por contêiner, e essa é a menor mudança que funciona. Primeiro leia os endereços do resolvedor da VPN: scutil --dns no macOS, resolvectl status ou a saída de estado do próprio cliente no Linux. Depois inicie o contêiner com eles, por exemplo docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage. No Compose a mesma definição é uma lista sob o serviço, onde vive no controle de versão em vez do histórico de shell de alguém.

Uma matriz dns em /etc/docker/daemon.json aplica-se a cada contêiner novo, o que soa mais arrumado e não é. Também se aplica quando o túnel está em baixo, e então um resolvedor acessível apenas pela VPN quebra os downloads normais de imagens. Definições por contêiner são mais fáceis de justificar e mais fáceis de desfazer.

Opção B: deixar o contêiner compartilhar a rede do host

A rede do host contorna a cópia por completo, porque o contêiner usa o resolvedor do host e o túnel do host. Também remove o isolamento de rede que você provavelmente queria, e não se comporta da mesma forma no Docker Desktop. No Linux é a escolha pragmática para uma ferramenta ocasional que precisa resolver nomes internos.

Para builds nenhuma das duas opções se aplica, já que os passos de build não herdam sinalizadores de tempo de execução. Compile com a rede do host onde a plataforma permitir, ou mantenha a instalação de dependências numa etapa que não precise do túnel.

O que nenhuma das duas opções corrige

Um endereço DNS é inútil se o contêiner não tem rota até ele. O resolvedor da VPN costuma ficar dentro do espaço de endereçamento do túnel, então o contêiner precisa de um caminho até esse prefixo. A ponte padrão do Docker normalmente encaminha para fora através do host, e isso basta quando o host tem a rota do túnel e o encaminhamento está ativado. Redes de ponte personalizadas com os seus próprios intervalos de endereços podem colidir com a sub-rede da VPN, e então as consultas vão para um lugar completamente diferente.

Verifique a sub-rede da rede Docker contra a sub-rede da VPN antes de depurar o próprio resolvedor. A sobreposição produz uma falha que parece exatamente um servidor DNS avariado.

Verifique dentro do contêiner

Teste com getent hosts db.internal dentro do contêiner em vez de com um navegador ou um ambiente de execução de linguagem, porque esses aplicam a sua própria política de DNS e a sua própria cache. Se o getent resolver o nome e a aplicação continuar a falhar, o resolvedor agora está correto e o problema restante está no nível da aplicação. Se não o resolver, a etapa de DNS não está concluída.

Recrie o contêiner depois de mudar as definições de DNS. Editar /etc/resolv.conf dentro de um contêiner em execução desaparece com ele e esconde o problema de configuração exatamente pelo tempo que alguém leva a reiniciá-lo.

Artigos relacionados