Налаштування WSL2, що не ламає Docker (так — є правильний спосіб)

Було корисно?

Більшість гайдів «WSL2 + Docker» написані так, ніби ніхто ніколи не відправляв реліз під тиском дедлайну. Вони пропускають ті моменти, коли контейнери повзають повільно через те, що ви клонували репозиторій у не те місце, або Docker Desktop вирішує, що ваші образи «зникли», бо ви «почистили» WSL. А потім настає понеділок.

Це підхід, зорієнтований на продакшн: як налаштувати WSL2 так, щоб Docker залишався швидким, передбачуваним і відновлюваним. Він має думку, бо реальність теж має думку.

Правильний підхід: що ви насправді будуєте

Ви не «встановлюєте Linux на Windows». Ви будуєте невеликий, керований стек віртуалізації:

  • Windows хостить інфраструктуру, суміжну з ядром (компоненти Hyper-V), які використовує WSL2.
  • WSL2 запускає один або кілька дистрибутивів Linux всередині легкого VM. Кожен дистро має свій віртуальний диск (VHDX).
  • Docker запускається або:
    • Docker Desktop, який запускає власний Linux-VM і може інтегруватися з дистро WSL2, або
    • Docker Engine всередині дистро WSL2 (без Docker Desktop), з systemd і нативною поведінкою Linux.

Налаштування, яке «не ламає», зводиться до трьох тем:

  1. Кладіть потрібні файли на потрібну файлову систему. Linux-на-Linux для збірок, node_modules і шарів образів. Windows-шляхи лише коли вам справді потрібні Windows-інструменти.
  2. Керуйте ресурсами свідомо. WSL2 охоче з’їсть RAM і диск, поки ваш ноутбук не перетвориться на обігрівач з клавіатурою.
  3. Виберіть одну модель володіння Docker. Або Docker Desktop володіє Docker, або ваш дистро володіє ним. Змішування без наміру — шлях до «вчора все працювало».

Цитата, яку варто тримати над монітором: Надія — не стратегія. — General Gordon R. Sullivan

Цікаві факти та контекст (щоб ви перестали робити помилки 2019 року)

  • WSL1 не був VM. Він транслював виклики системи Linux у виклики ядра Windows. Гарний трюк, але це не був «реальний Linux», і Docker у WSL1 був радше науковим проєктом.
  • WSL2 перейшов на справжнє ядро Linux. Ось чому Docker став практичним. Це також причина наявності справжнього віртуального диска, який може заповнюватися й фрагментуватися.
  • Ранні збірки WSL2 мали відомі проблеми з I/O на /mnt/c. Саме тому «клонуйте в Linux home» стало стандартною порадою — і для більшості робочих навантажень це досі правильно.
  • Docker Desktop переміщував бекенд кілька разів. Бекенд на Hyper-V, потім на WSL2, плюс зміни інтеграції між версіями. Старі блог-пости випадково вводять в оману.
  • Мережа WSL2 використовує NAT. Тому WSL2 VM має власний IP і деякі VPN/DNS-настройки поводяться так, ніби їх переслідують привиди.
  • «Стиснення» VHDX не відбувається автоматично. Видалення файлів у Linux не обов’язково повертає простір у Windows. Потрібні явні кроки з компактування.
  • Підтримка systemd у WSL нещодавня. Багато років її не було, що впливало на сервіси й Docker. Зараз можна ввімкнути systemd, але багато гайдів все ще припускають, що його немає.
  • Проблема різниці чутливості до регістру реальна. Файлові системи Windows зазвичай нечутливі до регістру; Linux — чутливий. Це проявляється дивними Git-diff, зламаними збірками або дублікатами файлів.

WSL2 + Docker: архітектура та гострі кути

Дві підтримувані моделі (виберіть одну)

Модель A: Docker Desktop + інтеграція з WSL2. Docker Desktop володіє демоном. Ваше дистро WSL отримує доступ до Docker CLI і може запускати контейнери, але «реальний» стан Docker живе в керованому середовищі Docker Desktop.

Модель B: Docker Engine всередині дистро WSL2. Ваше дистро володіє демоном і сховищем. Це більше схоже на Linux-сервер. Чудово, якщо ви хочете нативної поведінки Linux і менше сюрпризів від GUI-програми.

Реальність зберігання: звідки приходить або зникає продуктивність

Файлова система Linux у WSL2 (ext4 всередині VHDX вашого дистро) швидка для Linux-інструментів. Файли Windows, змонтовані під /mnt/c, повільніші й мають накладні витрати на трансляцію метаданих. Bind-монти Docker і контексти збірки підсилюють ці витрати.

Якщо ви робите збірки на Windows-шляхах і монтуєте їх у Linux-контейнери, ви підписуєтесь на проблеми продуктивності. Ви також ризикуєте проблемами з file watcher (особливо для Node, Python або будь-якого інструменту, що орієнтується на inotify).

Мережа: «localhost працює» — поки не перестане

WSL2 має власний віртуальний мережевий інтерфейс. Windows і WSL2 співпрацюють так, що «localhost» часто працює з обох сторін, але шлях несиметричний і не гарантований при VPN, фаєрволах або кастомних DNS.

Docker додає свої простори імен мережі та містові мережі всередині Linux-середовища. Шари трансляції накладаються, і кожен шар — ще одне місце, де може з’явитися затримка, проблеми з MTU або розв’язанням імен.

Жарт №1: NAT — як середній менеджмент: теоретично корисний, але іноді ваші пакети виходять із наради більш збитими з пантелику, ніж заходили.

Негайно обов’язкові правила, що рятують Docker від поломок

Правило 1: Тримайте код у файловій системі Linux, якщо немає сильної причини інакше

За замовчуванням: клонувати в ~/src всередині WSL. Збирати там. Запускати Docker звідти. Життя покращиться.

Є винятки (робочі процеси лише в Windows IDE, корпоративні сканери кінцевих точок), але винятки слід трактувати як запити на зміну в продакшні: документовані, обґрунтовані, зворотні.

Правило 2: Не давайте даним Docker «дрейфувати» через межі володіння

Якщо ви використовуєте Docker Desktop, дозвольте йому володіти енжином і сховищем. Не запускайте окремий dockerd всередині дистро, якщо ви навмисно не запускаєте два демони (більшість людей цього не робить).

Правило 3: Керуйте ресурсами WSL за допомогою .wslconfig

Без меж WSL може висмоктати Windows. Це виглядає як «Docker повільний», «VS Code пригальмовує» або «мій вентилятор тепер основний пристрій введення». Встановіть обмеження, а потім налаштовуйте.

Правило 4: Тримайте дистро WSL як «чащу худоби», але експортуйте перед операцією

WSL полегшує видалення й відтворення дистро. Це фіча. Але образи Docker, томи і бази даних всередині WSL — це стан. Експортуйте або зробіть снапшот перед тим, як «просто швиденько перевстановити Ubuntu».

Правило 5: Ніколи не відлагоджуйте продуктивність, не вимірявши межу файлової системи

Коли Docker здається повільним, ви повинні відповісти: ми маємо повільний I/O на /mnt/c, чи це CPU/пам’ять/мережа? Вгадування — це спосіб витратити післяобідню порцію часу даремно.

Практичні завдання (команди, виводи, рішення)

Це повсякденні команди, що роблять WSL2 + Docker нецікавими. Кожне завдання включає: команду, що означає вивід, і яке рішення прийняти далі.

Завдання 1: Підтвердити версії WSL і дистро за замовчуванням

cr0x@server:~$ wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu-22.04           Running         2
  docker-desktop         Running         2
  docker-desktop-data    Running         2

Значення: У вас Ubuntu на WSL2, а також внутрішні дистро Docker Desktop. Це нормально для Моделі A.

Рішення: Якщо ви не хочете Docker Desktop, ви не повинні бачити docker-desktop дистро. Якщо бачите — ви в Моделі A, навіть якщо цього не визнаєте.

Завдання 2: Перевірити версію ядра WSL (санітарна перевірка + контекст багів)

cr0x@server:~$ wsl --status
Default Distribution: Ubuntu-22.04
Default Version: 2
WSL version: 2.1.5.0
Kernel version: 5.15.133.1-1
WSLg version: 1.0.59
MSRDC version: 1.2.4677
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26091.1-240325-1447.ge-release
Windows version: 10.0.22631.3085

Значення: Сучасний WSL з ядром на базі 5.15. Багато старих проблем з мережею й systemd залежать від версії ядра/WSL.

Рішення: Якщо у вас значно старіша версія WSL, оновіть перед тим, як переслідувати привидів. Дебаг старих збірок WSL — це платити відсотки за технічний борг.

Завдання 3: Перевірити, хто володіє Docker (Desktop або в дистро)

cr0x@server:~$ docker context ls
NAME                DESCRIPTION                               DOCKER ENDPOINT                  ERROR
default *           Current DOCKER_HOST based configuration   unix:///var/run/docker.sock
desktop-linux       Docker Desktop                            unix:///var/run/docker.sock

Значення: Існують контексти; у WSL обидва можуть вказувати на Unix-сокет залежно від інтеграції.

Рішення: Виберіть контекст і дотримуйтеся його в робочому процесі. Якщо контексти перемикаються під вами — це проблема конфігурації, а не «Docker нестабільний».

Завдання 4: Перевірити, чи ввімкнено systemd у дистро WSL (попередня умова для Моделі B)

cr0x@server:~$ cat /etc/wsl.conf
[boot]
systemd=true

Значення: systemd увімкнено. Ви можете коректно запускати docker.service всередині WSL (Модель B).

Рішення: Якщо ви хочете Модель B і це відсутнє — додайте і перезапустіть WSL. Якщо ви обираєте Модель A (Docker Desktop), зазвичай вам не потрібен dockerd всередині дистро.

Завдання 5: Чисто перезапустити WSL після змін конфігурації

cr0x@server:~$ wsl --shutdown
The operation completed successfully.

Значення: Усі WSL VM зупинено. Наступний запуск перечитає конфіг.

Рішення: Зробіть це після зміни .wslconfig або /etc/wsl.conf. Якщо не зробите — ви дебагуєте конфіг, яку фактично не застосували.

Завдання 6: Виміряти, де живе ваш репо (Linux чи Windows-монтування)

cr0x@server:~$ pwd
/home/cr0x/src/myapp

Значення: Репозиторій у файловій системі Linux. Добре для контекстів збірки Docker і bind-монтів.

Рішення: Якщо ви під /mnt/c/..., очікуйте повільніший I/O. Перенесіть репо, якщо немає жорсткої потреби тримати його в Windows.

Завдання 7: Швидко показати межу продуктивності (fio)

cr0x@server:~$ fio --name=randread --filename=/home/cr0x/fio.test --size=256M --bs=4k --rw=randread --iodepth=32 --numjobs=1 --runtime=10 --time_based --direct=1
randread: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=32
fio-3.33
Starting 1 process
randread: Laying out IO file (1 file / 256MiB)
randread: (groupid=0, jobs=1): err= 0: pid=221: Fri Feb  2 10:01:16 2026
  read: IOPS=21.4k, BW=83.5MiB/s (87.6MB/s)(835MiB/10000msec)

Значення: Ви отримуєте здорові випадкові IOPS читання на файловій системі Linux.

Рішення: Запустіть той самий тест на /mnt/c. Якщо IOPS падають — припиніть звинувачувати Docker і перестаньте збирати на Windows-монтах.

Завдання 8: Перевірити драйвер зберігання Docker і кореневу папку (де насправді зберігаються шари)

cr0x@server:~$ docker info --format 'RootDir={{.DockerRootDir}} Driver={{.Driver}} Cgroup={{.CgroupDriver}}'
RootDir=/var/lib/docker Driver=overlay2 Cgroup=systemd

Значення: Docker використовує overlay2 і зберігає дані в /var/lib/docker всередині Linux-середовища, що володіє демоном.

Рішення: Якщо ви бачите несподіваний RootDir або драйвер, якого ви не планували, — ви не той демон, про який думаєте.

Завдання 9: Знайти, де на Windows лежить VHDX (планування ємності)

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-ChildItem -Recurse $env:LOCALAPPDATA\Packages\*Ubuntu*\LocalState\ext4.vhdx | Select-Object FullName,Length"
FullName                                                             Length
--------                                                             ------
C:\Users\cr0x\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx  64424509440

Значення: Віртуальний диск вашого дистро Ubuntu займає ~60 GiB на C:. Саме там живе файлова система Linux.

Рішення: Якщо C: маленький або під корпоративними політиками, плануйте контрольований переміщення через export/import (див. пізніші завдання). Рандомне «перемістити папки» — шлях до нерековеровних станів WSL.

Завдання 10: Перевірити використання диска WSL зсередини Linux (перед тим, як «чистити»)

cr0x@server:~$ df -hT /
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sdb       ext4   251G   96G  143G  41% /

Значення: Коренева файлова система Linux має вільне місце. Це всередині VHDX.

Рішення: Якщо Use% високий, чистіть всередині Linux спочатку (docker prune, очищення логів). Не припускайте, що Windows автоматично побачить звільнений простір.

Завдання 11: Визначити найбільших споживачів простору Docker (образи/томи)

cr0x@server:~$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          24        6         18.3GB    12.7GB (69%)
Containers      11        2         1.4GB     1.1GB (78%)
Local Volumes   13        5         22.9GB    9.6GB (41%)
Build Cache     0         0         0B        0B

Значення: Томи — головні «важковаговики». Образи теж можна звільнити.

Рішення: Якщо треба звільнити диск — prune образи/контейнери спочатку, потім аудит томів. Бездумне очищення томів — шлях випадково видалити чиюсь локальну базу даних.

Завдання 12: Достатньо безпечне очищення (prune з наміром)

cr0x@server:~$ docker image prune -a
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:3f1e2a0f7c8d...
Total reclaimed space: 9.8GB

Значення: Невикористані образи видалено, ~10 GB вільно в сховищі Docker.

Рішення: Якщо ваші збірки повільні, pruning не допоможе. Якщо диск повний — pruning допоможе. Різні проблеми — різні важелі.

Завдання 13: Перевірити ризик продуктивності при bind-монтах (чи монтуєте ви Windows-шляхи?)

cr0x@server:~$ docker run --rm -v /mnt/c/Users/cr0x/src:/src alpine ls -la /src | head
total 64
drwxrwxrwx    1 root     root          4096 Feb  2 10:22 .
drwxr-xr-x    1 root     root          4096 Feb  2 10:22 ..
-rwxrwxrwx    1 root     root          1962 Feb  1 19:04 README.md
-rwxrwxrwx    1 root     root           372 Feb  1 19:04 docker-compose.yml

Значення: Ви робите bind-mount Windows-шляху. Це працює, але це пастка продуктивності для інтенсивних I/O навантажень.

Рішення: Якщо ваш стек читає багато файлів (Node, PHP, webpack, Python), перемістіть репо в Linux і монтуйте з /home замість цього.

Завдання 14: Підтвердити доступність портів з Windows до WSL-контейнерів

cr0x@server:~$ docker run --rm -d -p 8080:80 nginx:alpine
c7c51d1c65b98a0c2a5c2b9d9a3a9b10f1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
cr0x@server:~$ powershell.exe -NoProfile -Command "Test-NetConnection -ComputerName 127.0.0.1 -Port 8080 | Select-Object TcpTestSucceeded"
TcpTestSucceeded
----------------
True

Значення: Публікація портів працює і Windows може дістатися до нього на localhost.

Рішення: Якщо це не працює під VPN, зазвичай проблема в розв’язанні імен, правилах файрвола або поведінці NAT WSL — а не в «nginx зламався».

Завдання 15: Діагностика DNS всередині WSL (мовчазний вбивця продуктивності)

cr0x@server:~$ cat /etc/resolv.conf
nameserver 172.22.48.1
search corp.example
cr0x@server:~$ getent hosts registry-1.docker.io | head -n 1
2600:1f18:2148:bc02:7fd3:1c63:6f57:fc3a registry-1.docker.io

Значення: WSL використовує резолвер, що надається NAT; DNS-запити працюють.

Рішення: Якщо запити зависають або повертають неправильні результати під VPN, можливо потрібно вимкнути авто-генерований resolv.conf і вказати DNS явно (обережно — див. типові помилки).

Завдання 16: Експортувати дистро перед ризикованими змінами (ваша кнопка «відмінити»)

cr0x@server:~$ wsl --export Ubuntu-22.04 D:\wsl-backups\Ubuntu-22.04.tar
The operation completed successfully.

Значення: У вас тепер офлайн-резервна копія, яку можна імпортувати в інше місце.

Рішення: Зробіть це перед переміщенням дисків, перевстановленням або «чисткою» WSL. Якщо не зробите — ви ставите свою роботу на удачу.

Завдання 17: Перемістити дистро на інший диск (правильний спосіб)

cr0x@server:~$ wsl --unregister Ubuntu-22.04
The operation completed successfully.
cr0x@server:~$ wsl --import Ubuntu-22.04 D:\wsl\Ubuntu-22.04 D:\wsl-backups\Ubuntu-22.04.tar --version 2
The operation completed successfully.

Значення: Дистро тепер зберігається під D:\wsl\Ubuntu-22.04 (включаючи новий VHDX). Так ви коректно переміщуєте зберігання WSL без корупції.

Рішення: Робіть це, якщо C: обмежений або корпоративні політики шифрування роблять роботу WSL на системному диску нестерпною.

Завдання 18: Перевірити, що Docker все ще вказує туди, куди ви думаєте, після переміщень

cr0x@server:~$ wsl -d Ubuntu-22.04 -- bash -lc "docker ps"
CONTAINER ID   IMAGE           COMMAND                  CREATED       STATUS       PORTS                  NAMES
c7c51d1c65b9   nginx:alpine    "/docker-entrypoint.…"   2 min ago     Up 2 min     0.0.0.0:8080->80/tcp   nostalgic_borg

Значення: Docker CLI все ще може спілкуватися з демоном і ваші контейнери існують.

Рішення: Якщо контейнери/образи «зникли», ви перемкнули демони або контексти. Діагностуйте дрейф моделі володіння в першу чергу, а не думайте, що «Docker з’їв моє домашнє завдання».

Швидкий план діагностики

Порядок, що швидко знаходить вузьке місце, без переслідування фольклору.

1) Визначте модель володіння за 30 секунд

  • Перевірка: wsl -l -v на наявність docker-desktop дистро; docker info для кореневої папки і драйвера.
  • Чому: Якщо ви не знаєте, з яким демоном говорите, кожне інше спостереження під питанням.
  • Рішення: Приберіться на Модель A або Модель B для цієї машини і команди. «Обидві» — податок на дебаг.

2) Виміряйте межу файлової системи (Linux vs /mnt/c)

  • Перевірка: Де живе репо (pwd), куди вказують bind-монти, і швидкий fio-тест в обох місцях.
  • Чому: Більшість скарг «Docker у WSL повільний» насправді — «я роблю Linux-збірки на Windows-монтуванні».
  • Рішення: Якщо /mnt/c — гаряча точка, перемістіть код у файлову систему Linux і налаштуйте робоче середовище редактора.

3) Підтвердіть ліміти ресурсів (RAM/swap) та сигнали тиску

  • Перевірка: Використання пам’яті WSL, поведінка swap і чи Windows активно пейджить.
  • Чому: При тиску пам’яті все здається I/O-повільним.
  • Рішення: Встановіть ліміти в .wslconfig; збільшіть пам’ять для важких збірок; тримайте swap у розумних межах.

4) Перевірте DNS і проксі (особливо під VPN)

  • Перевірка: getent hosts, pull-операції з реєстрів і чи /etc/resolv.conf авто-генерується.
  • Чому: Кроки збірки часто витягують залежності; зламаний DNS виглядає як «Docker build зависає».
  • Рішення: Виправте генерацію DNS або встановіть статичний DNS за контрольованою політикою.

5) І тільки потім: Docker-специфічна продуктивність (buildkit, cache, overlay2)

  • Перевірка: Логи збірки, промахи кешу, шаблони інвалідації шарів та чи bind-монти викликають повторні збірки.
  • Чому: Налаштування Docker марне, якщо базова файлова система неправильна.
  • Рішення: Оптимізуйте порядок у Dockerfile, використовуйте BuildKit і зменшіть хвилювання від bind-монтів.

Типові помилки: симптом → корінь → виправлення

1) «Docker неймовірно повільний»

Симптом: npm install, composer install, pip install або webpack-збірки займають у 5–20× більше часу, ніж очікується.

Корінь: Репозиторій живе під /mnt/c і ви монтуєте його в контейнери; операції з метаданими дорогі через кордон Windows↔Linux.

Виправлення: Перенесіть репо у файлову систему Linux (/home/.../src). Якщо потрібен доступ редактора у Windows, використовуйте VS Code Remote / WSL або доступ через \\wsl$\\ з Windows.

2) «Мої образи/контейнери зникли після перезавантаження»

Симптом: Вчорашні образи зникли; docker ps порожній; томи відсутні.

Корінь: Ви говорите з іншим Docker-демоном/контекстом (Desktop vs in-distro), або Docker Desktop скинув свій data дистро.

Виправлення: Запустіть docker context ls, потім docker info, щоб підтвердити RootDir. Визначте Модель A або B і видаліть інший демон, щоб уникнути дрейфу.

3) «Docker build зависає на ‘Downloading…’»

Симптом: Збірки зависають при завантаженні базових образів або залежностей; іноді повтор працює.

Корінь: Проблеми з DNS під VPN або налаштування проксі не застосовані всередині WSL/Docker середовища.

Виправлення: Тестуйте розв’язання імен за допомогою getent hosts. Якщо потрібно, вимкніть авто-генерований resolv.conf і вкажіть відомі резолвери; узгодьте змінні проксі для WSL і Docker.

4) «Опубліковані порти раптово перестали працювати»

Симптом: -p 8080:80 раніше працював; тепер Windows не може дістатися до нього на localhost.

Корінь: NAT WSL і зміни фаєрвола після переходу у сплячий режим/включення VPN; іноді віртуальний свіч WSL у поганому стані.

Виправлення: Перезапустіть WSL (wsl --shutdown). Якщо ви використовуєте Docker Desktop, перезапустіть і його. Повторно тестуйте з Test-NetConnection.

5) «Диск заповнений, хоча я багато видалив»

Симптом: Місце на диску Windows не збільшується після видалення Docker-образів або файлів у Linux.

Корінь: VHDX не стискається автоматично; простір залишається зарезервованим у віртуальному диску.

Виправлення: Почистіть всередині Linux, потім компактніть VHDX за допомогою підтримуваних інструментів. Якщо компакт підтяжний складний — export/import у новий VHDX як практичний скидання.

6) «File watching не працює (hot reload зламався)»

Симптом: Додаток не перезавантажується при зміні файлів; watcher пропускає події або навантажує CPU.

Корінь: Спостереження за файловою системою Windows з Linux-контейнерів погіршує семантику inotify; або занадто багато файлів перевантажують watcher.

Виправлення: Тримайте код у файловій системі Linux; для великих монорепозиторіїв налаштуйте polling з розумними інтервалами як запасний варіант, але ставте це як останній засіб.

7) «Git показує дивні перейменування лише по регістру або дублі»

Симптом: CI проходить на Linux, але локально поведінка дивна; файли відрізняються лише регістром.

Корінь: Невідповідність чутливості до регістру при роботі на файловій системі Windows.

Виправлення: Працюйте в файловій системі Linux для репозиторіїв, що припускають Linux-семантику; дотримуйтеся консистентного іменування в репо.

Три корпоративні міні-історії з передової

Інцидент: неправильне припущення («WSL — це просто папка»)

Команда продукту розгорнула WSL2, щоб стандартизувати середовища розробки. Мандат був розумний: Docker, Linux-інструменти, стабільні збірки. Реалізація — ні. Хтось припустив, що дистро WSL — це просто каталоги, які можна пересувати як кеш.

Отже інженер «заощадив місце», скопіювавши LocalState дистро WSL на D: і видаливши оригінал з C:. Це працювало день, переважно. Потім Docker Desktop оновився, зареєстрований стан WSL більше не відповідав вмісту диска, і дистро відмовилося запускатись. Негайний симптом був «Docker не запускається», але справжня проблема — «диск VM більше не там, де WSL думає».

Відновлення було неприємним. Довелося unregister і реімпортувати з того, що ще залишалось. Дехто втратив локальні бази в томах, бо не було політики експорту стану WSL перед операцією.

Урок не в тому, «не використовуйте WSL». Він у тому, щоб ставитись до дистро WSL як до керованих VM-ресурсів. Якщо хочете перенести їх на інший диск — використовуйте export/import. Якщо хочете зменшити простір — prune і compact, а не файлову рулетку.

Оптимізація, що відбилася бумерангом: «Покладемо все на /mnt/c щоб Windows-інструменти бачили все»

Інша організація хотіла гладкого досвіду для Windows-перших розробників. Ідея: тримати репозиторії на C:\ щоб Windows security tools і IDE «бачили все», а потім запускати збірки в WSL2 і контейнерах, прив’язавши ті самі Windows-шляхи.

На малих проєктах це виглядало нормально. На головному монорепо це перетворилось на повільний інцидент. Інкрементні збірки перестали бути інкрементними. Кроки сканування файлів (лінтери, виявлення тестів, компіляція TypeScript) стали новим вузьким місцем. Люди компенсували, відключаючи перевірки локально — бо дедлайн не цікавиться вашою діаграмою архітектури.

Потім настала справжня фіаско: Docker збірки почали таймаутитись у скриптах, схожих на CI. Не тому, що CPU слабкий, а тому що tar контексту збірки та операції overlay витрачали час на трансляцію Windows↔Linux. Розробники назвали це «накладними витратами Docker». Насправді це було розміщення сховища.

Вони врешті переключились на нативні розташування репозиторіїв у Linux і використали інтеграції редактора, щоб зберегти Windows-UX. Прискорення було миттєвим і нудним — саме такий успіх вам і потрібен у операціях.

Нудна але правильна практика, що врятувала день: «Експортуй перед змінами»

Платформна команда підтримувала стандартний образ WSL2 для розробників, що працюють з кількома сервісами в контейнерах. У них було правило: будь-яка зміна, що може зачіпати зберігання дистро WSL, вимагає експорту перед початком. Без винятків, без «це буде ок», без геройських вчинків.

Одного кварталу оновлення Windows плюс оновлення агента безпеки спричинили затримки дискових I/O на C:. Розробники повідомляли про повільні Docker-збірки й часом таймаути WSL. Вирішення — перемістити дистро на інший диск, де політика сканування агента менш агресивна. Це негарна фраза, але таке трапляється.

Оскільки у них був останній експорт, переміщення стало процедурним: вимкнути WSL, експортувати, unregister, імпортувати в нове місце, перевірити. Не довелось дебажити пошкоджені VHDX о 2 ранку. І не довелось просити сотні інженерів заново налаштовувати середовища.

Це не було гламурно. Це було дисципліновано. І це перетворило потенційно хаотичну міграцію на контрольоване технічне обслуговування.

Чеклісти / покроковий план

Крок 0: Визначте вашу модель Docker (не імпровізуйте потім)

  • Виберіть Модель A, якщо хочете найменше тертя на Windows, GUI-управління і не потребуєте нативного контролю демона.
  • Виберіть Модель B, якщо хочете поведінку як на Linux-сервері, явний контроль /var/lib/docker і менше сюрпризів від Docker Desktop.

Крок 1: Чисто встановіть WSL2 і перевірте

  • Встановіть WSL і дистро.
  • Запустіть wsl -l -v і підтвердіть VERSION=2.
  • Запустіть wsl --status і підтвердіть, що у вас сучасна версія WSL.

Крок 2: Налаштуйте ресурси WSL (нудні запобіжні рамки)

Створіть або відредагуйте %UserProfile%\.wslconfig у Windows. Приклад політики (підлаштуйте під машину):

  • Memory: обмежте до розумної величини (наприклад, 8–16 GB на ноутбуці для розробки).
  • Swap: не виставляйте 0, якщо не хочете OOM під час збірок.
  • Processors: обмежте, якщо хочете, щоб вентилятори перестали домагатися надбавки за ризик.

Потім wsl --shutdown, щоб застосувати.

Крок 3: Кладіть код у потрібне місце

  • Створіть ~/src всередині WSL.
  • Клонуйте репозиторії туди.
  • Запускайте Docker-збірки звідти.

Крок 4: Налаштування Docker по моделі

Модель A: Docker Desktop + інтеграція WSL2

  • Увімкніть бекенд WSL2 в налаштуваннях Docker Desktop.
  • Увімкніть інтеграцію для обраного дистро.
  • Переконайтеся, що docker ps працює всередині дистро.
  • Не встановлюйте і не запускайте окремий dockerd всередині WSL, якщо ви навмисно не хочете двох демонів.

Модель B: Docker Engine всередині WSL2

  • Увімкніть systemd у /etc/wsl.conf.
  • Перезапустіть WSL.
  • Встановіть пакети Docker Engine всередині дистро.
  • Запустіть і увімкніть docker через systemd; переконайтеся, що docker info показує overlay2 і коректний root dir.

Крок 5: Зробіть відновлення дрібницею

  • Перед важливими змінами експортуйте дистро: wsl --export.
  • Для переміщення диска: export → unregister → import.
  • Майте політику щодо того, що може жити в Docker-томах локально (бази даних, кеші) та як це бекапити, якщо це важливо.

Жарт №2: Якщо ваш єдиний план резервного копіювання — «я згадаю, що робив», вітаємо — ви винайшли єдину точку відмови пам’яті.

Питання й відповіді

1) Чи використовувати Docker Desktop чи Docker Engine всередині WSL?

Якщо хочете найменше тертя на Windows — використовуйте Docker Desktop (Модель A). Якщо хочете нативний контроль Linux і передбачувану поведінку демона — запускайте Docker Engine всередині WSL (Модель B). Вибирайте одну модель на машину.

2) Чому збірки з /mnt/c набагато повільніші?

Бо ви перетинаєте межу файлової системи з трансляцією метаданих. Збірки роблять багато дрібних файлових операцій. Саме в дрібних операціях проявляються витрати цієї межі.

3) Де насправді зберігаються мої Docker-образи?

Запустіть docker info і подивіться DockerRootDir. В Docker Desktop бекенд зберігає дані у керованому середовищі; в Docker всередині дистро зазвичай це /var/lib/docker всередині VHDX відповідного дистро.

4) Чи можна безпечно перемістити WSL на інший диск?

Так: експортуйте дистро в tar, unregister, потім імпортуйте в директорію на цільовому диску. Не копіюйте вручну LocalState VHDX і не сподівайтеся.

5) Чому місце на диску Windows не повертається після видалення файлів у WSL?

Бо VHDX не стискається автоматично. Ви звільнили місце всередині ext4, але Windows все ще бачить алокацію VHDX. Використовуйте workflow компактування або export/import щоб отримати менший VHDX.

6) Як зрозуміти, чи «Docker повільний» через DNS?

Якщо pull-операції/кроки збірки зависають при мережевих запитах, протестуйте getent hosts і простий pull образу. Якщо розв’язання імен повільне або неправильне — виправте DNS перед тим, як чіпати Dockerfile.

7) Чи безпечно запускати два Docker-демони (Desktop + in-distro)?

Технічно можна, але зазвичай це самоінфікована авіарія. Ви заплутаєте контексти, порти й місця зберігання образів. Якщо мусите — документуйте контексти й фіксуйте їх під проєкт.

8) Чому порти іноді працюють лише з Windows або лише з WSL?

Тому що правила NAT і форвардингу відрізняються за напрямком. Також VPN/фаєрвол можуть порушити «хімічну» зв’язку. Перезапустіть WSL і Docker Desktop, потім протестуйте з відомим контейнером і Test-NetConnection.

9) Який найкращий підхід для баз даних у локальних Docker-томах?

Вважайте томи тимчасовими, якщо ви їх явно не бекапите. Для будь-чого важливого скриптуйте експорт (наприклад, pg_dump) у відоме місце всередині файлової системи Linux і/або на Windows-шлях для резервного копіювання.

10) Чи важливо ввімкнення systemd у WSL для Docker?

Для Моделі B — так: systemd робить Docker поведінкою як на реальному Linux, включно з життєвим циклом сервісів і узгодженням драйвера cgroup. Для Моделі A це опціонально.

Наступні кроки (робіть це, а не «відчуття»)

  1. Визначте вашу модель Docker і усуньте двозначність: інтеграція Desktop або демон в дистро.
  2. Перенесіть активні репозиторії в файлову систему Linux і припиніть bind-монтувати Windows-шляхи для важких збірок.
  3. Додайте обмеження ресурсів WSL щоб Windows залишалася чутливою під навантаженням.
  4. Експортуйте дистро перед змінами як-от переміщення диска, перевстановлення або «прибирання».
  5. Використовуйте швидкий план діагностики наступного разу, коли продуктивність впаде: ownership → filesystem boundary → resources → DNS → Docker tuning.

Коли WSL2 і Docker налаштовані правильно, вони не відчуваються як «стек». Вони відчуваються так, ніби ваша машина нарешті співпрацює. Мета — нудно, швидко і відновлювано.

← Попередня
RDP працює, файловий ресурс — ні: правильно налаштуйте правила брандмауера
Наступна →
TLS електронної пошти: чому «дійсний сертифікат» усе ще не працює (і справжнє рішення)

Залишити коментар