Я не совсем понимаю официальное руководство «Использовать предыдущий этап как новый этап» на Используйте многоэтапные сборки.
Вот пример:
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
В моем случае я хочу взять последний слой, это будет RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
в примере, как единственное, что нужно сохранить. Верно ли, что я могу отбросить все предыдущие слои, то есть последний слой содержит все, что мне нужно? И как тогда мне взять на себя последний слой? В этом примере мне нужно выбрать папку /go/src/github.com/alexellis/href-counter/app
на первом изображении --from=0
(«FROM пространство имен«), и я копирую это в контекст сборки второго изображения. .
. Но как мне узнать эту папку или что нужно скопировать, чтобы запустить в ней полностью рабочий контейнер? Я ожидал, что смогу скопировать слой, а не папку.
Я пробую эту идею, чтобы получить второе изображение меньшего размера и безопасное:
- чтобы избавиться от закрытого ключа, который используется на предыдущем уровне, следуя советам Использование ключей SSH внутри контейнера докеров + комментарии;
- а также потому, что мое изображение слишком велико, если я сохраню в нем все «данные сборки».
Для ответа не обязательно придерживаться примера Dockerfile.
ИЗМЕНИТЬ после первого ответа:
Мне нужно знать каталоги, в которых я хочу перейти к следующему изображению. И это довольно сложно, если вы установили множество пакетов Python и ROS, которые касаются довольно многих каталогов, а не только каталога проекта git. И мне нужно скопировать .bashrc. Правильно ли, что я должен копировать все это по своему выбору, и было бы интересно скопировать все? Поскольку я не уверен, сохраняются ли вообще «данные сборки» в каталогах, возможно, они просто в слоях? И если копирование всего — это трюк, как бы я это сделал, просто
COPY --from=0 . .
возможно?
1 ответ
Когда ты сказал
COPY --from=something /source /target
Вы меняете контекст этой копии с контекста сборки на другое изображение. В приведенном выше случае изображение something
, это может быть имя изображения, номер этапа или предыдущий этап может назвать свое имя этапа с FROM base as something
и тогда результат этого этапа будет известен как something
.
С этим изменением контекста вы копируете определенные файлы, /source
из этого контекста, чтобы /target
в качестве нового слоя в итоговом изображении. Ничего другого не копируется, включая историю сборки на более ранних этапах, и никаких других файлов из файловой системы.
Однако если something
это внешний образ, который вам нужно вытащить из реестра, этот образ нужно вытащить полностью, чтобы найти /source
в этом изображении, которое может быть распределено по нескольким слоям.
Это один из несколько способов ввести учетные данные. Однако имейте в виду, что на хосте сборки эти учетные данные будут храниться в виде слоев для более ранних этапов, которые вы, надеюсь, не продвигаете. Другие варианты ввода учетных данных включают в себя не делать этого в сборке вообще (вытащить репозиторий git перед запуском сборки) или использовать buildkit’s --mount
синтаксис.
@ questionto42, если на предыдущем этапе файлы разбросаны по всей файловой системе, вероятно, это из-за установщика, который изменяет свое поведение в зависимости от того, что уже находится в файловой системе, и не является хорошим вариантом использования для многоэтапных сборок. Многоступенчатые сборки перемещают внешний процесс создания артефакта, такого как jar, и перемещают его в сборку докеров для повторения в различных средах, что позволяет отправлять образ без компилятора. Интерпретируемые языки, такие как Python, не подходят для этой модели.
— BMitch
8 часов назад
(вышеприведенный ответ отвечает на теперь удаленный комментарий, но я оставляю его, так как считаю, что он предоставляет некоторый полезный дополнительный контекст)
— BMitch
8 часов назад
Понятно, тогда понятно, почему я не смог разобраться в официальном гайде. Это могло произойти только тогда, когда я впервые загрузил репозиторий git перед установкой чего-либо еще и скопировал полную папку проекта git на второй образ без закрытого ключа. Ваш ответ помогает мне не столько в отношении размера изображения, поскольку git и openssh не такие большие, сколько в отношении проблемы с закрытым ключом. (Я удалил первый комментарий, так как мне нужно как можно больше поговорить с вами по этому вопросу, я добавил его туда.)
— questionto42
8 часов назад
Я только что нашел его, используя
docker history --no-trunc <Image ID>
:RUN /bin/sh -c apt-get -yqq install openssh-client
вызывает почти 1 ГБ пространства изображения, что не так мало, как предполагалось, поэтому ваш ответ также помогает уменьшить размер второго изображения, если оставить в стороне программы git и ssh.— questionto42
8 часов назад
Оно работает. Тем не менее, это сэкономило мне всего 0,02 ГБ размера образа, с 6,2 ГБ до 6,18 ГБ :), вероятно, потому, что мой второй образ снова установил git в его базовом образе или в одном из двух «полных» установщиков. В любом случае закрытого ключа на изображении больше нет. Я использовал базовый образ «alpine» для клонирования репозитория git, результат можно посмотреть на Использование ключей SSH внутри контейнера докеров.
— questionto42
5 часов назад