LinuxRuLinux без лишней теории
WSL2 и Docker

Docker в WSL2 медленный: что реально ускоряет работу

Редакция LinuxRu7 мин чтенияИнструкции

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

Docker в WSL2 медленный: что реально ускоряет работу
Фото: Karacehennem, Public domain, Wikimedia Commons
Содержание
  1. Причина
  2. Проект в ext4
  3. Desktop или Engine
  4. Память и CPU
  5. Кэш сборки
  6. Диск VHDX
  7. Сеть и антивирус
  8. Compose
  9. Частые вопросы

Почему 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 с WSL2Docker 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.

Документация и источники

Читайте также

Команды проверены на актуальных версиях дистрибутивов на момент обновления. Перед изменением системных настроек сделайте резервную копию.