2 - Instância do Docker no WSL
🐳 docker.wsl.lab.local
Este procedimento descreve a instalação do Debian 12 como uma instância isolada no Windows Subsystem for Linux (WSL), com o nome Docker, localizada em D:\WSL\Docker. A separação do laboratório em outro disco é uma decisão assertiva, pensada para diversas finalidades que serão exploradas ao longo dos trabalhos. O objetivo é criar um ambiente dedicado exclusivamente a testes e à execução de containers Docker, separado da instância principal utilizada no ambiente wsl.lab.local. A instalação é realizada por meio da importação manual da imagem oficial do Debian, garantindo maior controle sobre a estrutura do sistema e evitando interferências entre ambientes.
💡 Nota
Embora este guia utilize o Docker instalado diretamente no WSL para maior leveza e controle, também é possível rodar contêineres no Windows usando o Docker Desktop. Ele oferece interface gráfica, integração com WSL 2 e Kubernetes, mas consome mais recursos e exige licença paga para uso empresarial. Alternativas como Rancher Desktop, Podman Desktop, Colima (via WSL) ou a instalação manual do Docker Engine no WSL podem ser mais adequadas conforme o cenário.
Utilizaremos o PowerShell em modo Administrador para executar todas as nossas atividades no Windows. Toda a configuração desse lab.local é suportada pelo Windows Terminal. A construção desse ambiente é uma jornada de aprendizado Hibrido entre os sistemas operacionais Debian Linux e Windows.
Instalar Debian 12 no WSL com o nome Docker
- Windows 11 com WSL2 habilitado
- PowerShell 7.5.2
- A pasta D:\WSL deve existir (ou será criada no processo)
Baixar a imagem oficial do Debian 12 (Bookworm)
Invoke-WebRequest `
-Uri https://github.com/debuerreotype/docker-debian-artifacts/raw/dist-amd64/bookworm/oci/blobs/rootfs.tar.gz `
-OutFile D:\WSL\debian-docker-rootfs.tar.gz
Criar o diretório da nova instância
New-Item -ItemType Directory `
-Path D:\WSL\Docker -Force
Importar a imagem como instância Docker
wsl --import Docker D:\WSL\Docker `
D:\WSL\debian-docker-rootfs.tar.gz --version 2
A imagem importada é extremamente minimalista. Comandos como ping, ip a e nano não estão disponíveis até que sejam instalados manualmente.
Criar a bridge no Hyper-V (wsl.lab.local)
No PowerShell (como administrador):
New-VMSwitch `
-Name "wsl.lab.local" `
-NetAdapterName (Get-NetAdapter |
Where {$_.Status -eq "Up" -and $_.HardwareInterface} |
Select-Object -First 1 -ExpandProperty Name) `
-AllowManagementOS $true
Configurar o WSL para usar a bridge wsl.lab.local
@"
[wsl2]
networkingMode=bridged
vmSwitch=wsl.lab.local
"@ | Out-File "$env:USERPROFILE\.wslconfig" -Encoding ASCII -Force
Esse comando faz:
Cria (ou sobrescreve) o arquivo wslconfig
Insere as configurações necessárias para o WSL2 usar modo bridge
Usa o switch virtual wsl.lab.local que você criou com o New-VMSwitch
🖥️ Hosts no Windows no PowerShell (Admin):
$hosts="$env:WINDIR\System32\drivers\etc\hosts"
Add-Content -Path $hosts -Value "`r`n192.168.2.100 wsl.lab.local portainer.wsl.lab.local"
ou manualmente com:
notepad C:\Windows\System32\drivers\etc\hosts
Iniciar a Instância no WSL
wsl -d Docker
Ajustar o SystemD no WSL
tee -a /etc/wsl.conf > /dev/null <<EOF
[boot]
systemd=true
EOF
Editar /etc/wsl.conf
tee -a /etc/wsl.conf > /dev/null <<EOF
[network]
generateHosts = false
hostname = docker
EOF
Isso edita o /etc/wsl.conf para que a configuração fique persistente
Configurar o DNS na Instância Docker (Debian)
echo "nameserver 1.1.1.1" > /etc/resolv.conf
Preparar a instância Docker (Debian) com o necessário
📦 Instalar pacotes essenciais
apt update
apt install -y iproute2 iputils-ping net-tools dnsutils \
curl wget nano procps systemd systemd-sysv dbus cron \
sudo tree locales dialog
Criar o usuário e adicionar sudo
Adicionar usuário
adduser mol
Adicionar usuário do grupo de sudo
usermod -aG sudo mol
newgrp sudo
Configurar o usuário default para a instância e entrar sem senha
tee -a /etc/wsl.conf > /dev/null <<EOF
[user]
default=mol
EOF
Atualizar o /etc/hosts
tee /etc/hosts > /dev/null <<'EOF'
# hosts definidos
127.0.0.1 localhost
127.0.1.1 docker.wsl.lab.local docker
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
Isso substitui totalmente o conteúdo atual do /etc/hosts
Fixar IP na Instância Docker do WSL
O WSL não tem recurso para fixar o IP na instância, com isso alguns serviços dependem de IP Fixo para as configurações.
Criar o script /usr/local/bin/set-static-ip.sh
Rede 192.168.2.0/24
tee /usr/local/bin/set-static-ip.sh > /dev/null <<'EOF'
#!/bin/bash
# Limpa IPs anteriores
ip addr flush dev eth0
# Define IP fixo e gateway
ip addr add 192.168.2.100/24 dev eth0
ip route add default via 192.168.2.1
# Define DNS fixo
echo "nameserver 1.1.1.1" > /etc/resolv.conf
EOF
Criar a unidade systemd /etc/systemd/system/set-static-ip.service
tee /etc/systemd/system/set-static-ip.service > /dev/null <<EOF
[Unit]
Description=Set static IP on eth0 for WSL
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/set-static-ip.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
Ativar e iniciar o serviço
chmod +x /usr/local/bin/set-static-ip.sh
systemctl daemon-reload
systemctl enable set-static-ip.service
Provavelmente vai dar um erro: "System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down". Não precisa se preocupar com ele.
Sair da instância do WSL
exit
# Ou Crtl + D para sair da instância
No PowerShell desligar o WSL para aplicar as configurações
wsl --shutdown
wsl -d Docker
Conferir se funcionou
Iniciar a instância novamente e dentro dela verificar se a rede tá ok!
ip a
Você deverá ver eth0 com um IP da sua rede local real (ex: 192.168.x.x), não da sub-rede 172.x.
Instalar o Docker
curl -fsSL https://get.docker.com | sh
Observar que o script oficial dá um aviso de recomendação para que preferencialmente do WSL seja utilizado o Docker Desktop, mas esse não é o objetivo do wsl.lab.local. Aguardar 20 segundos que ele inicia o processo normalmente.
Ativar o Docker na inicialização da Instância com systemd.
sudo systemctl enable --now docker
Adicionar o usuário no grupo docker
sudo usermod -aG docker mol
newgrp docker
Testar o Docker Engine
docker run hello-world
Docker Engine está OK, o container Hello World subiu com usuário criado, não precisando mas do root para operar o Docker e a configuração foi validada.
Inicializar o Swarm na instância Docker (como nó manager)
docker swarm init --advertise-addr eth0
🔎 --advertise-addr eth0 faz com que o Docker use o IP da sua interface real (útil no WSL bridge)
Guarde esse token para adicionar workers no futuro.
Se você preferir fixar o IP diretamente:
sudo docker swarm init --advertise-addr 192.168.2.100
Verificar o status do cluster
docker node ls
Você verá algo como:
Construir o esqueleto de diretórios
sudo mkdir -p \
"/srv/docker/.backup" \
"/srv/docker/apps" \
"/srv/docker/core/traefik/dynamic" \
"/srv/docker/core/portainer" \
"/srv/docker/shared/certs" \
"/srv/docker/.envs" \
"/srv/docker/volumes/portainer/data" \
"/srv/docker/volumes/traefik"
Resultado do comando tree /srv/docker, que exibe de forma hierárquica a estrutura de diretórios criada para organizar os serviços Docker no ambiente local.
/srv/docker/
├── .backup/ → Backups do lab (configs, envs, volumes)
├── apps/ → Serviços adicionais via Portainer
│ ├── nome-app-1/
│ ├── nome-app-2/
│ └── ...
├── core/ → Serviços essenciais do lab.local
│ ├── traefik/
│ │ └── dynamic/
│ └── portainer/
├── shared/
│ └── certs/
├── .envs/ → Arquivos de variáveis de ambiente
├── volumes/
│ ├── portainer/data/
│ └── traefik/
Nesta estrutura, temos:
.backup/: Diretório reservado para armazenar backups do laboratório, incluindo arquivos de configuração, variáveis de ambiente, exports do Portainer e dumps de volumes importantes.apps/: diretório reservado para os serviços que não são essenciais que serão ativados a partir do Portainercore/: diretório reservado para os serviços essenciais. Aqui colocamos o:portainer/: onde ficará odocker-compose.ymldo Portainer.traefik/: contendo a pastadynamic/com configurações dinâmicas do Traefik (como roteadores, middlewares, TLS, etc).
shared/certs/: onde serão armazenados os certificados TLS auto assinados ou importados manualmente. Isso permite o uso de HTTPS local mesmo sem domínio público.volumes/: diretório dedicado a volumes persistentes de cada serviço:volumes/portainer/data/: armazenará os dados de configuração da interface do Portainer.volumes/traefik/: poderá conter arquivos comoacme.json, se necessário, para persistência de certificados gerenciados pelo Traefik.
Essa organização facilita a separação de responsabilidades, torna o ambiente mais legível e permite escalar ou versionar os serviços de forma independente.
💡 A separação clara entre core, shared e volumes é especialmente útil quando lidamos com múltiplos serviços e stacks Docker, mesmo em ambientes locais como WSL.
Aplicar permissões nos diretórios
No Linux, cada arquivo ou diretório tem um usuário dono e um grupo dono (ownership). Definir corretamente quem é o dono evita acessos indevidos e permite que administradores trabalhem sem precisar usar sudo o tempo todo. Agora vamos aplicar permissões e ownership adequados para manter segurança e facilitar a colaboração entre administradores.
# Dono root, grupo docker
sudo chown -R root:docker /srv/docker
# Diretórios com setgid (2775) para herdar o grupo 'docker'
sudo find /srv/docker -type d -exec chmod 2775 {} \;
# Restringir pastas sensíveis (.envs e certs) para leitura apenas pelo dono e grupo
sudo chmod 2750 /srv/docker/.envs
sudo chmod 2750 /srv/docker/shared
sudo chmod 2750 /srv/docker/shared/certs
# Garantir que o arquivo acme.json do Traefik exista com permissão 600
sudo touch /srv/docker/volumes/traefik/acme.json
sudo chown root:docker /srv/docker/volumes/traefik/acme.json
sudo chmod 600 /srv/docker/volumes/traefik/acme.json
Explicação sobre os diretórios
Diretório | Função |
|---|---|
| Configurações dinâmicas do Traefik (middlewares, regras extras). |
| Arquivos de configuração do Portainer. |
| Certificados SSL/TLS locais. |
| Arquivos |
| Volume persistente de dados do Portainer. |
| Volume persistente do Traefik (inclui |
Por que configuramos ownership no laboratório?
Garantir que somente administradores (root e membros do grupo docker) possam modificar configs sensíveis.
Permitir que membros do grupo docker acessem e gerenciem os arquivos sem precisar ser root o tempo todo.
Evitar que “usuários comuns” do sistema (fora do grupo) leiam coisas como .env ou certificados.
Gerar o Certificado Auto Hospedado
sudo openssl req -x509 -newkey rsa:4096 -sha256 -days 825 -nodes \
-keyout /srv/docker/shared/certs/wsl.lab.local.key \
-out /srv/docker/shared/certs/wsl.lab.local.crt \
-subj "/CN=wsl.lab.local" \
-addext "subjectAltName=DNS:wsl.lab.local,DNS:painel.wsl.lab.local,DNS:*.wsl.lab.local" \
-addext "basicConstraints=CA:FALSE" \
-addext "keyUsage=digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage=serverAuth"
sudo chmod 600 /srv/docker/shared/certs/wsl.lab.local.key
sudo chmod 644 /srv/docker/shared/certs/wsl.lab.local.crt
Conferir o certificado pelo OpenSSL
echo | openssl s_client -servername wsl.lab.local -connect 192.168.2.100:443 2>/dev/null \
| openssl x509 -noout -subject -dates -ext subjectAltName
🧩 Confiar o certificado no Windows
Import-Certificate -FilePath "\\wsl$\Docker\srv\docker\shared\certs\wsl.lab.local.crt" -CertStoreLocation Cert:\LocalMachine\Root
Stacks de Serviços Básicos
Abaixo tem os guias para instalar o serviços do core que são Traefik e Portainer
Comandos Úteis
# PowerShell - Excluir Instância do WSL
wsl --unregister Docker
# Forçar Updade do Traefik
docker service update --force traefik_traefik
No comments to display
No comments to display