Лаптоп с Docker контейнери, излизащи от екрана, и Linux пингвин на клавиатурата

WSL — практическо ръководство

Част 4: Docker в WSL 2 — контейнери без компромиси

Дълго време мислех за WSL като за „терминал до Windows”. После направих нещо просто: инсталирах нативен Docker Engine вътре в дистрото и разбрах, че лаптопът ми е станал пълноценна Linux dev машина. Контейнерите тичат на истинско Linux ядро, кодът е в Linux файлова система, а портът се отваря директно в Windows браузъра.

ℹ Бележка Тук говоря за нативен Docker Engine в дистрото, не за Docker Desktop. Разликата не е козметична — това са два различни модела на работа и ще обясня защо аз избрах нативния. Всички команди са тествани в Debian на WSL 2.

1. Защо нативен Engine, а не Docker Desktop?

Docker Desktop е отличен продукт и нищо не му има. Но за моя начин на работа нативният Engine в WSL печели по три причини:

  • Контрол. Моят сървър вкъщи тича с docker и docker compose от терминала. Когато dev средата ми е същата, командите са идентични — не уча два инструмента, а един.
  • Ресурси. Docker Desktop носи собствена VM и собствена система за услуги. В WSL 2 дистрото вече е лека VM — втори слой VM за контейнери ми се струва загуба на RAM.
  • Лиценз. Docker Desktop изисква платен абонамент за по-големи компании. Нативният Engine е с отворен код и това не е тема.

Схемата, в която всичко се побира, е следната:

Архитектурна схема: Windows 11 домакин → лека WSL 2 виртуална машина с Linux ядро и Debian → Docker Engine с контейнерите. Долният ред показва моста /mnt/c, \wsl$, wsl.conf и wsl --export.

2. Предусловие: systemd в дистрото

Docker daemon-ът иска init система. В по-новите WSL версии systemd се включва с три реда:

Включвам systemd в /etc/wsl.conf
[boot]
systemd=true

После от PowerShell рестартирам дистрото, за да влезе настройката в сила:

wsl --shutdown
wsl

Проверявам дали systemd е активен:

Проверка на init системата
ps -p 1 -o comm=

Ако отговорът е systemd, сме готови. Ако е init или sh, WSL версията е стара — wsl --update от PowerShell решава проблема в девет от десет случая.

3. Инсталирам Docker Engine по официалния път

Ползвам официалния apt repository на Docker, не пакетите от дистрибуцията — там версията изостава:

Официален Docker repository за Debian
sudo apt-get update && sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

⚠ Предупреждение Ако дистрото е Ubuntu, редът с репото е .../linux/ubuntu/..., не debian. Копиране на сляпо между дистрибуции тук си струва точно една счупена инсталация, за да се научиш.

4. Docker без sudo на всяка команда

Добавям потребителя си в docker групата:

Права на потребителя
sudo usermod -aG docker $USER

Излизам от сесията, влизам пак (или newgrp docker) и проверявам:

docker run hello-world

Ако виждам „Hello from Docker!”, всичко е на място. Групата docker е еквивалент на root над daemon-а — на dev машина ми е удобно, на споделен сървър щях да помисля два пъти.

5. Автостарт — Docker се събужда сам

С включен systemd остава една команда:

Услугата да тръгва при стартиране на WSL
sudo systemctl enable --now docker

Оттук нататък образът на работа е следният: отварям Windows Terminal, пиша wsl, и docker е вече вдигнат. При wsl --shutdown VM-ът гасне и при следващата команда всичко тръгва наново.

За да имам и самото дистро готово още при логване в Windows, добавям един Task Scheduler задача с действие wsl.exe -d Debian -e true — втора фаза на стартиране, която не ме накара нито веднъж да чакам.

6. Порти: от WSL до Windows браузъра без нищо да настройвам

localhost forwarding е най-приятната изненада на WSL 2. Когато в дистрото вдигна:

Пробен web сървър в контейнер
docker run -d -p 8080:80 nginx:alpine

…отварям http://localhost:8080 в Windows и виждам Nginx страницата. Няма bridge мрежи за настройка, няма firewall танци за локалния развой. Същото важи и в обратна посока при mirrored networking — но за всекидневната работа класическият forwarding напълно ми стига.

✓ Успех Моят навик: един docker compose файл в репото на всеки проект. docker compose up -d в дистрото, браузър в Windows — независимо дали е локален сайт или тестова база.

7. Къде държа кода — и защо това е половината от производителността

Това е урокът, който всички получаваме по трудния път. Bind mount от /mnt/c (Windows NTFS през 9P протокола) е драстично по-бавен за файлови операции от ext4 на Linux файловата система. Разлика от порядъка на 10–20 пъти при npm install и composer заявки не е грешка при измерването — това е архитектура.

Затова моето правило е просто:

  • Код на проекта → в дистрото (~/src/...), отвътре в Linux.
  • Достъп от Windows → \\wsl$\Debian\home\fedya\src или VS Code с extension-а WSL — отваря папката в Linux, а редакторът тича в Windows.
  • Обмен на еднократни файлове → /mnt/c е ок. За четене и копиране, не за build.

И още нещо, което често се пропуска: volumes на Docker също живеят в Linux FS. Мястото на vhdx диска може да порасне с данните — wsl --manage Debian --set-sparse true помага vhdx да се смалява обратно при изтриване на контент.

8. Капаните, които обходих

Кратък списък, за да не ги срещате всички:

  • DNS умря след sleep. WSL понякога генерира resolv.conf с адрес, който не работи на дадена мрежа. Решение: в /etc/wsl.conf [network] generateResolvConf = false и ръчен запис с реален DNS (напр. 1.1.1.1).
  • Мястото на vhdx расте, но не смалява. Изтриване на образи ≠ по-малко място в Windows. wsl --shutdown + Optimize-VHD (или sparse vhdx, виж по-горе).
  • Прекалено много RAM. По подразбиране WSL 2 взема до половината от паметта на компютъра. В %UserProfile%\.wslconfig пиша memory=6GB и спя спокоен.
  • docker compose version разлики. С plugin-ът (docker compose) вече няма специалното docker-compose с тире — командите в стари tutorial-и могат да объркат.

9. Командите накратко

КомандаЗа какво я използвам
wsl --updateОбновява WSL слота (и системата).
wsl --shutdownГаси всички WSL VM-и — рестарт на целия слой.
ps -p 1 -o comm=Проверявам дали systemd е init.
sudo systemctl enable --now dockerАвтостарт на Docker в дистрото.
docker run -d -p 8080:80 nginx:alpineТест, който свързва WSL порта с Windows.
\\wsl$\Debian\home\...Път до Linux файловете от Windows Explorer.
wsl --manage Debian --set-sparse truevhdx да се смалява сам при освобождаване.
wsl --export Debian backup.tarЦялото дистро в един файл — виж Част 3.

10. Заключение

С нативен Docker Engine в WSL 2 лаптопът с Windows ми работи като Linux dev сървър, който се събужда за секунди и ползва същите команди като производствената среда. Не е гъвкавата комбинация „Docker Desktop с GUI”, а именно онази проста, която ми позволява да мисля за кода, не за средата.

✓ Успех Моят принцип: dev средата трябва да прилича на production колкото е възможно — а с WSL 2 и нативен Docker приликата е почти пълна, без да напускам Windows.