С помощью контейнеров вы можете упаковать свое приложение и сделать его, таким образом, переносимым. В результате оно сможет работать в разных средах. Самая популярная платформа управления контейнерами – это Docker.
Кэш сборки
Процесс создания образов должен быть быстрым, эффективным и надежным. Сама по себе идея образов Docker предполагает неизменность слоев. Каждая команда, которую вы выполняете, приводит к созданию нового слоя, содержащего изменения, которые отличают его от предыдущих слоев.
Все предыдущие слои кэшируются, и вы можете использовать их повторно. Однако если ваша система зависит от внешних ресурсов, то кэш Docker может вызвать некоторые проблемы.
Как оптимизировать кэш сборки
Для того, чтобы понять, в чем заключаются проблемы, связанные с кэшем сборки Docker, давайте создадим собственное простенькое приложение Docker для ngnix. Прежде чем мы приступим к созданию образа, нам нужно создать Dockerfile, который отвечает за обновление библиотек и добавление пользовательской начальной страницы:
FROM nginx:1.21.6
# Update all packages { // Обновляем все пакеты }
RUN apt-get update && apt-get -y upgrade
# Use a custom startpage { // Используем пользовательскую начальную страницу }
RUN echo '<html><bod>My Custom Startpage</body></html>' > /usr/share/nginx/html/index.html
Теперь мы можем создать образ Docker:
$ docker build -t my-custom-nginx .
=> [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e12... 5.8s
=> [2/3] RUN apt-get update && apt-get -y upgrade 3.6s
=> [3/3] RUN echo '<html><bod>My Custom Startpage... 0.2s
=> exporting to image 0.1s
=> exporting layers 0.1s
=> writing image 0.0s
=> naming to docker.io/library/my-custom-nginx
[+] Building 11.3s (7/7) FINISHED
В данном примере я удалил часть вывода для того, чтобы его было проще читать. Если вы создаете образ впервые, то вы могли заметить, что этот процесс занимает довольно много времени – в данном случае 11.3s.
Самый долгий шаг - apt-get update && apt-get -y upgrade. Время его выполнения зависит от того, сколько зависимостей обновляется и насколько высока скорость вашего интернета. Эта команда проверяет наличие обновлений пакетов в операционной системе и устанавливает их при их наличии.
А теперь вы можете выполнить эту команду снова и выиграть время, воспользовавшись кэшем сборки:
$ docker build -t my-custom-nginx .
=> [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e1211ac1… 0.0s
=> CACHED [2/3] RUN apt-get update && apt-get -y upgrade 0.0s
=> CACHED [3/3] RUN echo '<html><bod>My Custom Startpage... 0.0s
=> exporting to image 0.0s
=> exporting layers 0.0s
=> writing image 0.0s
=> naming to docker.io/library/my-custom-nginx
Building 1.1s (7/7) FINISHED
На этот раз процесс создания образа был быстрее, так как были повторно использованы образы, созданные до этого. Когда вы будете настраивать свою начальную страницу в Dockerfile, вы увидите, как на это повлияет режим кэширования:
FROM nginx:1.21.6
# Update all packages { // Обновляем все пакеты }
RUN apt-get update && apt-get -y upgrade
# Use a custom startpage { // Используем пользовательскую начальную страницу }
RUN echo '<html><bod>New Startpage</body></html>' > /usr/share/nginx/html/index.html
А теперь снова создадим образ:
$ docker build -t my-custom-nginx .
=> [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e1211ac1… 0.0s
=> CACHED [2/3] RUN apt-get update && apt-get -y upgrade 0.0s
=> [3/3] RUN echo '<html><bod>My Custom Startpage... 0.2s
=> exporting to image 0.0s
=> exporting layers 0.0s
=> writing image 0.0s
=> naming to docker.io/library/my-custom-nginx
Building 2.1s (7/7) FINISHED
На этот раз мы видим, что был перестоен только последний слой, так как команда обнаружила, что изменилась команда RUN. Но она повторно использовала второй этап сборки и не обновляла зависимости операционной системы.
В данном случае режим кэширования является вполне разумным. Как только вам необходимо перестроить первый шаг, каждый последующий будет строиться заново. Именно поэтому лучше всего помещать постоянно меняющиеся части в конец Dockerfile, чтобы повторно использовать предыдущие уровни сборки.
И все же, вы можете захотеть принудительно перестроить кэшированный слой, чтобы принудительно выполнить обновление пакета. А так как вы хотите обеспечить безопасность своего приложения и использовать самые новые обновления, принудительная повторная сборка вам определенно потребуется.
Как использовать параметр --no-cache для сборки Docker
Причины отключения кэширования сборки могут быть самые разные. Вы можете повторно произвести сборку образа на базе основного образа, не используя при этом кэшированные слои, но используя при этом параметр --no-cache.
$ docker build -t my-custom-nginx .
=> CACHED [1/3] FROM docker.io/library/nginx:1.21.6@sha256:... 0.0s
=> [2/3] RUN apt-get update && apt-get -y upgrade 3.5s
=> [3/3] RUN echo '<html><bod>My Custom Startpage... 0.2s
=> exporting to image 0.1s
=> exporting layers 0.0s
=> writing image 0.0s
=> naming to docker.io/library/my-custom-nginx
Building 5.5s (7/7) FINISHED
Здесь были построены и созданы новые слои. docker build запустила в этот раз обе команды, то есть применила подход «все или ничего». Либо вы указываете параметр --no-cache, который позволит выполнить все команды, либо вы кэшируете по максимуму.
Как применить аргументы Docker для очистки кэша
Другой вариант позволяет создать некую отправную точку в Dockerfile. Для этого вам нужно изменить Dockerfile следующим образом:
FROM nginx:1.21.6
# Update all packages { // Обновляем все пакеты }
RUN apt-get update && apt-get -y upgrade
# Custom cache invalidation { // Обновление пользовательского кэша }
ARG CACHEBUST=1
# Use a custom startpage { // Используем пользовательскую начальную страницу }
RUN echo '<html><bod>New Startpage</body></html>' > /usr/share/nginx/html/index.html
Вы должны добавить в свой Dockerfile аргумент там, где вы хотите выполнить принудительную повторную сборку. Теперь вы сможете создать образ Docker и всегда указывать новое значение, что приведет к тому, что все следующие команды запустятся повторно:
$ docker build -t my-custom-nginx --build-arg CACHEBUST=$(date +%s) .
=> [1/3] FROM docker.io/library/nginx:1.21.6@sha256:e1211ac1... 0.0s
=> CACHED [2/3] RUN apt-get update && apt-get -y upgrade 0.0s
=> [3/3] RUN echo '<html><bod>My Custom Startpage... 0.3s
=> exporting to image 0.0s
=> exporting layers 0.0s
=> writing image 0.0s
=> naming to docker.io/library/my-custom-nginx
Building 1.0s (7/7) FINISHED
Указав --build-arg CACHEBUST=$(date +%s), вы постоянно будете устанавливать для параметра новой значение, что будет приводить к повторной сборке всех последующих слоев.
Заключение
Кэширование сборок в Docker – довольно полезная функция. Она ускоряет процесс сборки образов Docker за счет повторного использования слоев, которые были созданы ранее.
Для того, чтобы отключить функцию кэширования или использовать свой собственный аргумент сборки Docker, чтобы принудительно выполнить повторную сборку с какого-то определенного шага, вы можете воспользоваться параметром --no-cache.
Понимание того, как работает сборка в Docker, крайне важно, так как это может сделать процесс создания контейнеров Docker более эффективным.