Сборка Docker и Makefile

Я надеюсь использовать Dockerfile для создания довольно большой кодовой базы из исходного кода. Исходный код написан на C++, а система сборки написана на Makefile. В настоящее время мой Dockerfile выглядит следующим образом:

FROM ubuntu:16.04

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        vim g++ make && \
    rm -rf /var/lib/apt/lists/*

COPY src /srC# `src` folder contains the source code
WORKDIR /src
RUN make && make all

Меня больше всего беспокоит Dockerfile следующее: предположим, что позже, когда я изменю небольшую часть большой кодовой базы и повторно выполню команду docker build, что из следующего произойдет?

  1. Docker снова выполняет копирование и выясняет зависимость сборки make.
  2. Docker ничего не делает, потому что Dockerfile не был изменен.
  3. Docker создает всю кодовую базу с самого начала.

Если произойдет второе или третье, есть ли лучший вариант, чем поместить команду make внутри Dockerfile? Должен ли я выполнить его как часть docker run и смонтировать каталог исходного кода в контейнер Docker?

Спасибо.

Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Kubernetes - это портативная, расширяемая платформа с открытым исходным кодом для управления контейнерными рабочими нагрузками и сервисами, которая...
Как создать PHP Image с нуля
Как создать PHP Image с нуля
Сегодня мы создадим PHP Image from Scratch для того, чтобы легко развернуть базовые PHP-приложения. Пожалуйста, имейте в виду, что это разработка для...
4
0
4 357
3

Ответы 3

Docker does the copying once again and figure out the build dependency of make

да. Он скопирует ваш источник в указанное место назначения в контейнере.

Docker does nothing because the Dockerfile has not been changed.

Нет. Docker пересоберет ваш код, даже если вы не измените файл Dockerfile. Это потому, что вы изменили кодовую базу. Если вы не изменили кодовую базу, это может ничего не сделать, поскольку оно может просто получить последний созданный слой. (Обратите внимание, что порядок команд здесь может изменить логику кэширования)

Docker builds the entire codebase from the very beginning.

По умолчанию да. Если вы не скопировали предварительно скомпилированные артефакты в свой контейнер (чего делать не следует), то он пересоберет ваш код с нуля.

is there any better option than putting the make command inside the Dockerfile?

Поместите команду make в Dockerfileэто лучший вариант здесь. Одна из самых важных причин, по которым люди используют Docker (если не самая важная), — наличие предсказуемые сборки.

Примечание

Возможным "лучший способ" является использование многоэтапные сборки для разделения ваших "строительный контейнер" и ваших "контейнер, содержащий двоичный файл". Это также дает вам меньшие образы "окончательный", поскольку вы можете создавать их из альпийский или царапать. Таким образом, ваш контейнер "окончательный" не должен включать ненужные библиотеки/программное обеспечение.

На это есть два возможных ответа.

Если у вас есть файл .dockerignore, который включает *.o, или у вас настроено отдельное дерево сборки, то, когда вы дойдете до строки RUN make, образ будет содержать все исходные файлы и ни один из объектных файлов, и сборка запустится полностью. с нуля. Это самый «чистый» ответ — вы должны получить очень последовательный результат сборки — но на самом деле это может занять некоторое время.

Если у вас его нет, то все, что вы создали локально, будет скопировано в образ, включая временные метки, и вы получите инкрементную сборку. Но это означает, что разные люди, создающие одно и то же приложение из одного и того же частичного исходного дерева, получат разные результаты; в проекте на основе Autoconf все функции приложения могут быть ограничены в зависимости от того, установил ли конкретный разработчик какую-либо библиотеку на своем хосте или нет.

Если у вас уже есть система сборки, в основном основанная на Make, я мог бы придерживаться ее и предпочесть модель «все делать в Make», а не модель «все делать в Docker». В GNU Make вы можете написать такой фрагмент:

DOCKER_TAG := $(shell date +%Y%m%d)

.PHONY: docker

docker:
        $(MAKE) install DESTDIR=docker/dist
        cp Dockerfile docker
        docker build -t me/myapp:$(DOCKER_TAG) docker

Это также дает вам практические эффекты многоэтапной сборки (вы предварительно скомпилировали приложение, поэтому вам нигде не нужна цепочка инструментов в конвейере Docker. Точно так же, как вы sudo make install сейчас, вы sudo make docker создаете образ Докера.

Большое спасибо за все ответы.

Итак, после того, как я провел несколько экспериментов. Ниже приведен вывод, который у меня есть

  • Как ответил @molamk, Docker скопирует файлы и начнет сборку с самого начала. Причина в том, что для команды COPY Docker использует механизм контрольной суммы, чтобы проверить, были ли изменены файлы или нет. Следовательно, Docker может точно определить, необходима ли повторная копия, и аннулировать все кешированные слои (включая make сборку) после COPY слоя.
  • В моем случае, когда я хочу изменить часть большой кодовой базы, включая сборку внутри Dockerfile, это ужасная идея, поскольку это означает, что каждый раз мне нужно ждать несколько часов, пока изменения вступят в силу. Поэтому я включил только предварительную сборку в файл Dockerfile и смонтировал исходный каталог в контейнер, полученный путем запуска необходимого образа.

Другие вопросы по теме