Что вызывает аннулирование кэша при сборке Dockerfile? - PullRequest
3 голосов
/ 11 декабря 2019

Я читал документы Рекомендации по написанию Dockerfiles . Я обнаружил небольшую некорректность (IMHO), значение которой стало ясно после прочтения далее:

Использование только обновления apt-get в операторе RUN вызывает проблемы с кэшированием и последующие инструкции по установке apt-get fail .

Почему терпеть неудачу я задавался вопросом. Позже пришло объяснение того, что они имели в виду под словом «fail»:

Поскольку обновление apt-get не запускается, ваша сборка может потенциально получить устаревшую версию пакетов curl и nginx.

Тем не менее, для следующего я все еще не могу понять, что они подразумевают под "Если нет, кеш становится недействительным.":

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

Эта часть упоминается в некоторых ответах на SO, например Как Docker узнает, когда использовать кеш во время сборки, а когда нет? иВ целом концепция аннулирования кэша мне ясна, я прочитал ниже:

Когда происходит аннулирование кэша изображений Docker? Какой алгоритм Docker использует для аннулирования кэша?

Но что означает "если нет"? Сначала я был уверен, что эта фраза означает, что такое изображение не найдено. Это было бы излишним - сделать кеш недействительным, что может пригодиться позже для других сборок. И действительно, он не будет признан недействительным, если не было найдено никакого изображения, когда я попробовал ниже:

$ docker build -t alpine:test1 - <<HITTT
> FROM apline
> RUN echo "test1"
> RUN echo "test1-2"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM apline
pull access denied for apline, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
(base) nb0408:docker a.martianov$ docker build -t alpine:test1 - <<HITTT
> FROM alpine
> RUN echo "test1"
> RUN echo "test1-2"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test1"
 ---> Running in 928453d33c7c
test1
Removing intermediate container 928453d33c7c
 ---> 0e93df31058d
Step 3/3 : RUN echo "test1-2"
 ---> Running in b068bbaf8a75
test1-2
Removing intermediate container b068bbaf8a75
 ---> daeaef910f21
Successfully built daeaef910f21
Successfully tagged alpine:test1

$ docker build -t alpine:test1-1 - <<HITTT
> FROM alpine
> RUN echo "test1"
> RUN echo "test1-3"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test1"
 ---> Using cache
 ---> 0e93df31058d
Step 3/3 : RUN echo "test1-3"
 ---> Running in 74aa60a78ae1
test1-3
Removing intermediate container 74aa60a78ae1
 ---> 266bcc6933a8
Successfully built 266bcc6933a8
Successfully tagged alpine:test1-1

$ docker build -t alpine:test1-2 - <<HITTT
> FROM alpine
> RUN "test2"
> RUN 
(base) nb0408:docker a.martianov$ docker build -t alpine:test2 - <<HITTT
> FROM alpine
> RUN echo "test2"
> RUN echo "test1-3"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test2"
 ---> Running in 1a058ddf901c
test2
Removing intermediate container 1a058ddf901c
 ---> cdc31ac27a45
Step 3/3 : RUN echo "test1-3"
 ---> Running in 96ddd5b0f3bf
test1-3
Removing intermediate container 96ddd5b0f3bf
 ---> 7d8b901f3939
Successfully built 7d8b901f3939
Successfully tagged alpine:test2

$ docker build -t alpine:test1-3 - <<HITTT
> FROM alpine
> RUN echo "test1"
> RUN echo "test1-3"
> HITTT
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
 ---> 965ea09ff2eb
Step 2/3 : RUN echo "test1"
 ---> Using cache
 ---> 0e93df31058d
Step 3/3 : RUN echo "test1-3"
 ---> Using cache
 ---> 266bcc6933a8
Successfully built 266bcc6933a8
Successfully tagged alpine:test1-3

Кэш снова использовался для последней сборки. Что означает документ "если нет"?

1 Ответ

3 голосов
/ 11 декабря 2019

Давайте сосредоточимся на вашей первоначальной проблеме (касающейся apt-get update), чтобы упростить задачу. Следующий пример не основан на каких-либо передовых практиках. Это просто иллюстрирует точку, которую вы пытаетесь понять.

Предположим, у вас есть следующий Dockerfile:

FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y nginx

Вы создаете первое изображение, используя docker build -t myimage:latest .

Что происходитis:

  • Образ Ubuntu извлекается, если он не существует
  • Слой создается и кэшируется для запуска apt-get update
  • Слой создается в кэшедля запуска apt install -y nginx

Теперь предположим, что вы изменили свой файл Docker на

FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y nginx openssl

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

  • Локально уже есть образ ubuntu, поэтому он не будет вытягиваться (если только вы не нажмете --pull)
  • Слой уже был создан с помощью команды apt-get update по сравнению с существующим локальным образом, поэтому он использует кэшированный
  • Следующая команда была изменена, поэтому для установки nginx и openssl создан новый слой. Поскольку база данных apt была создана в предыдущем слое и извлечена из кэша, если с тех пор была выпущена новая версия nginx и / или openssl, вы их не увидите и установите устаревшие.

Помогает ли это вам понять концепцию кэшированных слоев?

В этом конкретном примере лучше всего делать все в одном слое, следя за тем, чтобы вы очищались после себя:

FROM ubuntu:18.04

RUN apt-get update  \
    && apt-get install -y nginx openssl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...