Как добавить файл в образ в файл Docker без использования директивы ADD или COPY

Мне нужно содержимое большого файла *.zip (5 gb) в контейнере Docker для компиляции программы. Файл *.zip находится на моей локальной машине. Стратегия для этого будет:

COPY program.zip /tmp/
RUN cd /tmp \
&& unzip program.zip \
&& make

После этого я хотел бы удалить распакованный каталог и исходный файл *.zip, потому что они больше не нужны. Проблема в том, что директива COPY (а также директива ADD) добавит слой к изображению, который будет содержать файл program.zip, который является проблематичным, так как изображение может быть не менее 5 ГБ. Есть ли способ добавить файл в контейнер без использования директивы COPY или ADD? wget не будет работать, так как указанный файл *.zip находится на моем локальном компьютере, а curl file://localhost/home/user/program.zip -o /tmp/program.zip тоже не будет работать.

Ответ 1

Это не просто, но это можно сделать с помощью wget или curl с небольшой поддержкой от python. (Все три инструмента обычно должны быть доступны в системе *nix.)

wget не будет работать, если не указано url и

 curl file://localhost/home/user/program.zip -o /tmp/

не будет работать из инструкции Dockerfile RUN. Следовательно, нам понадобится сервер, с которого wget и curl могут получить доступ и загрузить program.zip из.

Для этого мы настроим небольшой сервер python, который обслуживает наши запросы http. Для этого мы будем использовать модуль http.server от python. (Вы можете использовать python или python 3. Он будет работать с обоими.).

python -m http.server --bind 192.168.178.20 8000

Сервер python будет обслуживать все файлы в каталоге, в котором он запущен. Поэтому вы должны убедиться, что вы запустите свой сервер либо в каталоге, в котором находится файл, который вы хотите загрузить во время сборки изображения, или создайте временную каталог, содержащий вашу программу. Для иллюстрации можно создать файл foo.txt, который мы позже скажем через wget в нашем Dockerfile:

echo "foo bar" > foo.txt

При запуске http-сервера важно указать IP-адрес нашего локального компьютера в локальной сети. Кроме того, мы откроем порт 8000. Сделав это, мы увидим следующий вывод:

python3 -m http.server --bind 192.168.178.20 8000
Serving HTTP on 192.168.178.20 port 8000 ...

Теперь мы построим a Dockerfile, чтобы проиллюстрировать, как это работает. (Мы предположим, что файл foo.txt должен быть загружен в /tmp):

FROM debian:latest
RUN apt-get update -qq \
&& apt-get install -y wget
RUN cd /tmp \
&& wget http://192.168.178.20:8000/foo.txt

Теперь мы начинаем сборку с помощью

docker build -t test .

Во время сборки вы увидите следующий вывод на нашем сервере python:

172.17.0.21 - - [01/Nov/2014 23:32:37] "GET /foo.txt HTTP/1.1" 200 -

и результат сборки нашего изображения будет:

Step 2 : RUN cd /tmp && wget http://192.168.178.20:8000/foo.txt
 ---> Running in 49c10e0057d5
--2014-11-01 22:56:15--  http://192.168.178.20:8000/foo.txt
Connecting to 192.168.178.20:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 25872 (25K) [text/plain]
Saving to: `foo.txt'

     0K .......... .......... .....                           100%  129M=0s

2014-11-01 22:56:15 (129 MB/s) - `foo.txt' saved [25872/25872]

 ---> 5228517c8641
Removing intermediate container 49c10e0057d5
Successfully built 5228517c8641

Затем вы можете проверить, действительно ли это работает, путем запуска и ввода контейнера из только что созданного образа:

docker run -i -t --rm test bash

Затем вы можете посмотреть /tmp для foo.txt.

Теперь мы можем добавить любой файл в наш image, не создавая новый слой. Предполагая, что вы хотите добавить программу размером около 5 гб, как упоминалось в вопросе, который мы могли бы сделать:

FROM debian:latest
RUN apt-get update -qq \
&& apt-get install -y wget
RUN cd /tmp \
&& wget http://conventiont:8000/program.zip \
&& unzip program.zip \
&& cd program \
&& make \
&& make install \
&& cd /tmp \
&& rm -f program.zip \
&& rm -rf program

Таким образом, мы не останемся с 10 gb трещины.

Ответ 2

Нельзя ли сопоставить локальную папку с контейнером при запуске, а затем скопировать нужные файлы.

sudo docker run -d -P --name myContainerName -v /localpath/zip_extract:/container/path/ yourContainerID

https://docs.docker.com/userguide/dockervolumes/

Ответ 4

Я опубликовал аналогичный ответ здесь: fooobar.com/info/496208/...

Вы можете использовать docker-squash, чтобы раздавить вновь созданные слои. Это существенно удалит архив из окончательного изображения, если вы удалите его в следующей инструкции RUN.