Я надеюсь использовать 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, что из следующего произойдет?
make.Dockerfile не был изменен.Если произойдет второе или третье, есть ли лучший вариант, чем поместить команду make внутри Dockerfile? Должен ли я выполнить его как часть docker run и смонтировать каталог исходного кода в контейнер Docker?
Спасибо.


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 создаете образ Докера.
Большое спасибо за все ответы.
Итак, после того, как я провел несколько экспериментов. Ниже приведен вывод, который у меня есть
COPY Docker использует механизм контрольной суммы, чтобы проверить, были ли изменены файлы или нет. Следовательно, Docker может точно определить, необходима ли повторная копия, и аннулировать все кешированные слои (включая make сборку) после COPY слоя.