Dockerfile: как создать новый образ из последнего слоя другого образа

Я не совсем понимаю официальное руководство «Использовать предыдущий этап как новый этап» на Используйте многоэтапные сборки.

Вот пример:

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=0FROM пространство имен«), и я копирую это в контекст сборки второго изображения. .. Но как мне узнать эту папку или что нужно скопировать, чтобы запустить в ней полностью рабочий контейнер? Я ожидал, что смогу скопировать слой, а не папку.

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

  • чтобы избавиться от закрытого ключа, который используется на предыдущем уровне, следуя советам Использование ключей SSH внутри контейнера докеров + комментарии;
  • а также потому, что мое изображение слишком велико, если я сохраню в нем все «данные сборки».

Для ответа не обязательно придерживаться примера Dockerfile.

ИЗМЕНИТЬ после первого ответа:

Мне нужно знать каталоги, в которых я хочу перейти к следующему изображению. И это довольно сложно, если вы установили множество пакетов Python и ROS, которые касаются довольно многих каталогов, а не только каталога проекта git. И мне нужно скопировать .bashrc. Правильно ли, что я должен копировать все это по своему выбору, и было бы интересно скопировать все? Поскольку я не уверен, сохраняются ли вообще «данные сборки» в каталогах, возможно, они просто в слоях? И если копирование всего — это трюк, как бы я это сделал, просто

COPY --from=0 . .

возможно?

1 ответ
1

Когда ты сказал

COPY --from=something /source /target

Вы меняете контекст этой копии с контекста сборки на другое изображение. В приведенном выше случае изображение something, это может быть имя изображения, номер этапа или предыдущий этап может назвать свое имя этапа с FROM base as something и тогда результат этого этапа будет известен как something.

С этим изменением контекста вы копируете определенные файлы, /source из этого контекста, чтобы /target в качестве нового слоя в итоговом изображении. Ничего другого не копируется, включая историю сборки на более ранних этапах, и никаких других файлов из файловой системы.

Однако если something это внешний образ, который вам нужно вытащить из реестра, этот образ нужно вытащить полностью, чтобы найти /source в этом изображении, которое может быть распределено по нескольким слоям.

Это один из несколько способов ввести учетные данные. Однако имейте в виду, что на хосте сборки эти учетные данные будут храниться в виде слоев для более ранних этапов, которые вы, надеюсь, не продвигаете. Другие варианты ввода учетных данных включают в себя не делать этого в сборке вообще (вытащить репозиторий git перед запуском сборки) или использовать buildkit’s --mount синтаксис.

  • 1

    @ questionto42, если на предыдущем этапе файлы разбросаны по всей файловой системе, вероятно, это из-за установщика, который изменяет свое поведение в зависимости от того, что уже находится в файловой системе, и не является хорошим вариантом использования для многоэтапных сборок. Многоступенчатые сборки перемещают внешний процесс создания артефакта, такого как jar, и перемещают его в сборку докеров для повторения в различных средах, что позволяет отправлять образ без компилятора. Интерпретируемые языки, такие как Python, не подходят для этой модели.

    — BMitch
    8 часов назад

  • 1

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

    — 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 часов назад

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *