Docker в WSL2 медленный: что реально ускоряет работу
Docker в WSL2 почти всегда тормозит из-за того, что проект лежит на диске Windows в /mnt/c. Перенесите код в домашний каталог WSL, затем настройте память в .wslconfig и кэш BuildKit, и сборка станет сопоставимой с обычным Linux.

Содержание
Почему Docker в WSL2 тормозит
В девяти случаях из десяти виновато расположение проекта. WSL2 работает как лёгкая виртуальная машина со своим диском ext4 внутри файла VHDX. Диски Windows видны в ней как /mnt/c, /mnt/d, но каждый доступ к ним проходит через сетевой протокол между Linux и Windows. Для одного файла задержка незаметна. Для npm install с десятками тысяч мелких файлов или для сборки образа, где Docker читает весь контекст, она превращается в минуты.
Вторая особенность: изменения файлов на дисках Windows не генерируют событий inotify внутри Linux. Горячая перезагрузка в webpack, Vite, Django или nodemon либо не срабатывает, либо переходит на опрос файлов и грузит процессор.
Остальные причины встречаются реже: виртуальной машине не хватает памяти и она уходит в swap, кэш сборки сбрасывается из-за неудачного Dockerfile, антивирус проверяет каждый файл, который Docker отправляет в контекст. Ниже по порядку, от самого действенного к мелочам.
Перенесите проект в файловую систему Linux
Документация Docker прямо рекомендует держать исходники и данные для bind-монтирования внутри файловой системы Linux. Переезд занимает пять минут:
# внутри WSL
mkdir -p ~/projects
cd ~/projects
git clone git@github.com:user/app.git
# или перенести существующий каталог
cp -a /mnt/c/Users/имя/source/app ~/projects/
cd ~/projects/app
docker compose up --build
В compose.yaml и командах docker run монтируйте относительные пути от проекта или пути вида ~/projects/app, а не /mnt/c/.... Из Windows эти файлы открываются по адресу \\wsl.localhost\Ubuntu\home\имя\projects, а команда explorer.exe . откроет текущий каталог в Проводнике.
Редактор тоже должен работать изнутри WSL. VS Code с расширением WSL запускается командой code . из каталога проекта: интерфейс остаётся в Windows, а файловые операции, git и терминал идут в Linux. JetBrains IDE умеют то же через Remote Development. Если открыть проект из WSL в редакторе Windows напрямую по сетевому пути, тормоза переедут из Docker в редактор.
Общая настройка WSL под разработку, включая выбор дистрибутива и интеграцию с IDE, разобрана в статье WSL2 для разработки в 2026 году.
Docker Desktop или Docker Engine внутри WSL
Есть два способа запускать контейнеры. Docker Desktop ставится в Windows и использует WSL2 как движок, а Docker Engine можно поставить прямо в дистрибутив, как на обычный сервер с Linux.
| Критерий | Docker Desktop с WSL2 | Docker Engine в дистрибутиве |
|---|---|---|
| Установка | Установщик Windows, графический интерфейс | Пакеты apt или dnf внутри WSL |
| Лицензия | Платная подписка для крупных компаний | Свободная, без ограничений |
| Доступ из PowerShell | Команда docker работает и в Windows | Только внутри WSL |
| Память | Отдельный служебный дистрибутив плюс сам Desktop | Только ваш дистрибутив |
| Скорость bind-монтирования | Высокая для путей в ext4 | Такая же |
По скорости сборки разница небольшая, если проект лежит в ext4. Docker Engine экономит память и избавляет от лишнего слоя. Для его работы включите systemd в /etc/wsl.conf:
[boot]
systemd=true
Затем в PowerShell выполните wsl --shutdown, откройте дистрибутив и поставьте пакеты. В Ubuntu 26.04 проще всего взять пакеты из репозитория дистрибутива:
sudo apt update
sudo apt install docker.io docker-compose-v2 docker-buildx
sudo usermod -aG docker $USER
# выйти из сеанса WSL и зайти снова, затем
docker run --rm hello-world
Для самых свежих версий подключите официальный репозиторий Docker по инструкции для Ubuntu или Debian. Одновременно держать Docker Desktop с интеграцией в этот дистрибутив и свой Engine не стоит: два демона будут спорить за один сокет. Вариант без прав root описан в статье Docker Rootless.
Ресурсы виртуальной машины в .wslconfig
По умолчанию WSL2 получает половину оперативной памяти Windows и все логические процессоры, а swap равен четверти объёма памяти. При сборке тяжёлых образов на машине с 16 ГБ этого бывает мало, и всё упирается в swap на файле VHDX. Глобальные настройки задаются в файле %UserProfile%\.wslconfig на стороне Windows:
[wsl2]
memory=10GB
processors=8
swap=8GB
[experimental]
autoMemoryReclaim=gradual
sparseVhd=true
Параметр autoMemoryReclaim управляет тем, как виртуальная машина отдаёт Windows память из кэша. Значение gradual возвращает её постепенно, dropCache сразу, disabled отключает возврат. Для долгих сборок gradual мягче: кэш, нужный компилятору, не выбрасывается каждую минуту. Параметр sparseVhd делает новые виртуальные диски разреженными, чтобы они не раздувались навсегда.
Изменения применяются только после полной остановки WSL:
wsl --shutdown
wsl --list --running
Вторая команда должна ответить, что запущенных дистрибутивов нет. В свежих версиях WSL те же параметры можно поменять в приложении "Параметры WSL" из меню Пуск. Полный список ключей с умолчаниями приведён в документации Microsoft по wsl.conf и .wslconfig.
Кэш BuildKit и правильный Dockerfile
Даже на быстром диске сборка будет долгой, если каждый раз пересобираются все слои. Три правила дают больше, чем любые настройки WSL.
Файл .dockerignore
Всё, что не исключено, отправляется демону как контекст сборки. Каталоги node_modules, .git, .venv, dist и логи легко весят гигабайт:
node_modules
.git
.venv
dist
*.log
Сначала зависимости, потом код
Копируйте файлы манифестов отдельно и ставьте зависимости до копирования исходников. Тогда правка кода не сбросит слой с npm ci или pip install.
Кэш-монтирования
BuildKit включён по умолчанию в современных версиях Docker. Он умеет сохранять кэш пакетных менеджеров между сборками:
# syntax=docker/dockerfile:1
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
COPY . .
Тот же приём работает для /root/.npm, /root/.cache/go-build, /var/cache/apt. Сколько места занимает кэш, показывает docker buildx du, а очистить старое можно командой docker builder prune.
Разросшийся диск VHDX
Файл виртуального диска WSL растёт по мере записи, но сам не уменьшается, когда вы удаляете образы. Через полгода активной работы с Docker он легко доходит до сотни гигабайт на диске C. Сначала почистите данные внутри:
docker system df
docker image prune -a
docker builder prune
Затем включите разреженный режим для уже существующего дистрибутива, чтобы освобождённое место возвращалось Windows. Команда выполняется в PowerShell при остановленном WSL:
wsl --shutdown
wsl --manage Ubuntu --set-sparse true
Имя дистрибутива покажет wsl --list --verbose. Подробнее о том, что ещё съедает место внутри Linux, читайте в статье о том, как освободить место на диске.
Сеть, антивирус и прочие мелочи
- Обновите WSL. Команда
wsl --updateв PowerShell, текущую версию покажетwsl --version. Docker Desktop требует WSL не ниже 2.1.5, а старые версии известны утечками памяти процесса vmmem. - Зеркальный режим сети. Если контейнер доступен из WSL, но не открывается из браузера Windows или наоборот, попробуйте
networkingMode=mirroredв разделе[wsl2]файла .wslconfig. В этом режиме у Linux и Windows общие сетевые интерфейсы и localhost. - Антивирус. Если по какой-то причине проект остаётся на диске Windows, Defender проверяет каждый файл при чтении. Вынесите такие проекты на Dev Drive в Windows 11, где для антивируса включён режим производительности.
- Время сборки. Замеряйте до и после изменений:
time docker build --no-cache .и обычная сборка с кэшем. Так видно, что помогло, а что было самовнушением.
Самая быстрая проверка, в файловой системе ли дело: скопируйте проект в ~/ внутри WSL и запустите ту же сборку там. Если время упало в разы, дальше можно ничего не трогать, кроме привычки хранить код в /mnt/c.
Docker Compose в WSL2 без сюрпризов
Современный Compose работает как плагин: команда docker compose через пробел, файл compose.yaml. Старый docker-compose на Python не нужен. Для WSL полезны две опции. Режим develop.watch синхронизирует изменённые файлы в контейнер без bind-монтирования и пересобирает образ при изменении зависимостей, это снимает проблему inotify. Лимиты deploy.resources.limits не дают одной базе данных съесть всю память виртуальной машины.
docker compose watch
docker compose stats
Подробно про формат файла и переход со старого Compose рассказано в статье о Docker Compose plugin.
Частые вопросы
Почему docker build в WSL2 медленнее, чем на Linux?
Чаще всего проект лежит на диске Windows в /mnt/c, и каждое чтение файла идёт через межсистемный протокол. Перенесите проект в домашний каталог WSL, и разница с обычным Linux станет небольшой.
Сколько памяти выделить WSL2 под Docker?
По умолчанию берётся половина памяти Windows. Для сборок обычно хватает 8-12 ГБ на машине с 16-32 ГБ, лимит задаётся параметром memory в .wslconfig.
Нужен ли Docker Desktop для WSL2?
Нет. Docker Engine ставится прямо в дистрибутив WSL как на обычный Linux, нужно только включить systemd в /etc/wsl.conf. Docker Desktop удобен, если нужен docker в PowerShell и графический интерфейс.
Как уменьшить файл ext4.vhdx?
Удалите ненужные образы и кэш сборки внутри WSL, затем выполните wsl --shutdown и wsl --manage имя_дистрибутива --set-sparse true, чтобы место возвращалось Windows.
Почему не работает горячая перезагрузка в контейнере?
Изменения файлов на дисках Windows не порождают событий inotify в Linux. Храните код в файловой системе WSL или используйте docker compose watch.
Документация и источники
- Advanced settings configuration in WSL, Microsoft Learn, 2026
- Best practices: Docker Desktop WSL 2 backend, Docker Docs, 2026
- Optimize cache usage in builds, Docker Docs, 2026
Читайте также
Команды проверены на актуальных версиях дистрибутивов на момент обновления. Перед изменением системных настроек сделайте резервную копию.