Há um tempo eu venho tentando contruir um SaaS como forma de praticar meus estudos. Durante várias ideias e tentativas, eu me deparei com um problema relacionado ao docker: por algum motivo, o Docker Desktop não queria funcionar com Windows.
O que foi estranho e pareceu ser um problema simples de resolver, acabou se tornando uma dor de cabeça tremenda e me levou a buscar novas alternativas. O uso do WSL2 se mostrou como caminho, não só para resolver um problema, mas como um tópico de estudo para além da programação.
O WSL2 não é uma simples compatibilidade de comandos UNIX dentro do Windows. Ele roda um kernel Linux completo em uma máquina virtual leve baseada em Hyper-V. Quando o Docker Desktop é configurado para usar o WSL2 como backend, todos os containers são criados dentro desse kernel Linux, e não diretamente no Windows.
A comunicação entre o Windows e o ambiente Linux do WSL2 é feita via uma interface virtual criada pelo Windows: vEthernet (WSL). Ela é, na verdade, um Switch Virtual criado automaticamente pela plataforma de virtualização do Windows (chamada Virtual Machine Platform, um componente do Hyper-V) quando o WSL2 é iniciado pela primeira vez. Essa interface atua como única ponte de rede entre dois ambientes isolados:
- O sistema operacional Windows (Host).
- O kernel Linux/VM do WSL2 (Guest).
O principal mecanismo que ela gerencia é o NAT (Network Address Translation). O Linux (WSL2 VM) recebe um IP privado (por exemplo, 172.27.x.x ou 192.168.x.x) que muda a cada reinicialização do Windows. Esse IP funciona como Gateway Padrão e Servidor DNS dentro do ambiente Linux, permitindo que o tráfego de saída seja traduzido para a rede do host. No lado do Windows, a interface vEthernet (WSL) recebe o primeiro endereço desse bloco privado (por exemplo, 172.27.x.1) e atua como o roteador/NAT responsável por gerenciar todo o tráfego entre o Windows e a VM Linux.
Teoricamente, o Docker Desktop deveria configurar o proxy automático de portas por meio da interface vEthernet (WSL), permitindo que minha aplicação no Windows acessasse o container através do endereço localhost:1433. No entanto, como optei por rodar o Docker Engine nativo diretamente na minha distribuição WSL2, eu não contava com o serviço de encaminhamento automático de portas que o Docker Desktop injeta no host Windows.
Assim, minha aplicação .NET, executando no Windows, tentava se conectar a localhost:1433. Como não havia o serviço de port forwarding do Docker Desktop, o Windows não sabia que o tráfego dessa porta deveria ser redirecionado para o endereço IP dinâmico da VM WSL2 (geralmente algo como 172.x.x.x). Por isso, a conexão falhava.
Uma alternativa para contornar esse problema foi criar uma rede personalizada no Docker e expor a porta do container do SQL Server para o host Windows. Essa configuração permitiu que o tráfego de localhost:1433 fosse corretamente roteado até o container, mesmo sem o proxy de portas do Docker Desktop.
O primeiro passo foi criar uma rede bridge isolada com suporte a DNS interno:
docker network create mynetwork
Essa rede cria uma bridge virtual (por exemplo, br-2c7e9a5d7b45) com uma sub-rede dedicada (172.18.0.0/16) e um gateway interno (172.18.0.1).
Containers conectados a ela podem se comunicar diretamente por nome, sem precisar de IP fixo.
Em seguida, subi o container do SQL Server conectado a essa rede e expus a porta 1433:
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=YourStrong!Passw0rd" \
--name sqlserver \
--network mynetwork \
-p 1433:1433 \
-d mcr.microsoft.com/mssql/server:2022-latest
O parâmetro -p 1433:1433 faz o mapeamento de porta entre o host (Windows) e o container, permitindo que a aplicação fora do WSL2 acesse o serviço pelo localhost:1433.
O --network mynetwork garante que, se eu decidir rodar outros containers (por exemplo, uma API .NET) dentro do WSL2, eles poderão se conectar via DNS interno — usando apenas sqlserver como host.
Para confirmar a conectividade, testei o acesso diretamente do Windows:
Test-NetConnection localhost -Port 1433
E também validei de dentro da aplicação .NET, configurando a connection string da seguinte forma:
"Server=localhost,1433;Database=MyAppDb;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
Após isso, a aplicação passou a se conectar normalmente ao SQL Server rodando dentro do container, mesmo com o Docker Engine isolado dentro da VM WSL2.
Mas, por que essa solução funciona?
Ao expor a porta (-p 1433:1433), o Docker criou uma regra de DNAT (Destination NAT) na tabela iptables do Linux interno do WSL2. Essa regra instrui o kernel a redirecionar todo o tráfego recebido na porta 1433 do host (interface eth0) para o IP interno do container SQL Server.
Quando o Windows acessa localhost:1433, o pacote é enviado à interface vEthernet (WSL) → traduzido pelo NAT → entregue à bridge br-xxxxx → e finalmente roteado ao container. Com isso, o comportamento esperado do Docker Desktop foi restaurado manualmente, mas de forma controlada e previsível.
Top comments (0)