разборnixdockerdevops

Docker-образы без Dockerfile: dockerTools в Nix

· 2 мин · BadRabbit

В посте про VoiceLM я пообещал объяснить, почему мой контейнер собирается через Nix, а не через Dockerfile. Объясняю по официальному туториалу nix.dev и своему опыту.

Что не так с Dockerfile

Типичный Dockerfile выглядит так:

FROM python:3.12
RUN apt-get update && apt-get install -y ffmpeg
RUN pip install -r requirements.txt

Проблема в том, что результат зависит от момента сборки. Сегодня apt-get update даст одну версию ffmpeg, через месяц другую. Два человека, собравшие «один и тот же» Dockerfile, получат разные образы. Плюс в образ попадает весь базовый Debian с shell, пакетным менеджером и кучей ненужных утилит.

Как это делает Nix

В Nix образ — это просто ещё одна сборка, описанная декларативно:

pkgs.dockerTools.buildImage {
  name = "hello-docker";
  config.Cmd = [ "${pkgs.hello}/bin/hello" ];
}

Обратите внимание: здесь нет базового образа. Nix сам знает точное замыкание зависимостей программы: какие библиотеки ей нужны, вплоть до хешей. В образ попадает ровно это и больше ничего.

Сборка и запуск:

nix-build hello-docker.nix          # получаем tar.gz с образом
docker load < result                # загружаем в Docker
docker run hello-docker:<тег>

buildLayeredImage

Для реальных проектов лучше buildLayeredImage: он раскладывает зависимости по отдельным слоям. Если поменялся только код приложения, а Python и ffmpeg остались прежними, Docker перекачает один маленький слой вместо всего образа.

Нюанс

Образ Docker — это Linux. На macOS придётся настроить удалённую сборку на Linux-машине или кросс-компиляцию. На NixOS этой проблемы нет.

Мой комментарий

Для меня главный плюс даже не размер, а честность. Если nix build прошёл у меня, он пройдёт и на сервере, и через год, потому что все версии закреплены в flake.lock. Образ VoiceLM — distroless по сути: внутри нет shell, нет apt, только Python, ffmpeg, CUDA-библиотеки и мой код. Злоумышленнику, попавшему в такой контейнер, даже ls запустить нечем.

Этот блог, кстати, собирается так же: nix build выдаёт папку с HTML.