Рубрики
Uncategorized

21 лучшие практики в 2021 году для DockerFile

«Это куриный длинный список из 20+ лучших практик для DockerFile за 2020 год». Так как INCEP. … с меткой докера, Кубернаны, Opensource, DevOps.

» Это куриный длинный список из 20+ лучших практик для DockerFile за 2020 год ».

С момента создания докера 20 марта 2013 года он уже взял мир во время шторма, путем революции, как легко приложения могут быть упакованы и доставлены на несколько платформ с легкостью. Все, хотя контейнеры существовали даже до эпохи Докеров, что сделало Докер выделяться из толпы и заставить ее всемирно сочувствовать, был тот факт, что он легко загрузил большую часть основной сложности, связанной с контейнерами в целом, что делает его справедливо доступным на всех Основные операционные системы и платформы с мощностью сообщества с открытым исходным кодом всегда поддерживаются для лучшей поддержки.

Docker всегда был моим личным фаворитом с точки зрения технологического сдвига, которая произошла в последние годы. Из перехода голых металлических машин до виртуальных машин в большинстве уважения. Точно так же Docker заменяет виртуальные машины контейнерами по всем велам. Docker, в двух словах, содержит некоторые основные компоненты, которые начинаются с простым докерфилом, который является простой текстовым файлом, где мы пишем (код), который содержит простые набор шагов или инструкций, которые определяют, что нужно сделать в простом Условия и то, что вы хотите, чтобы ваше приложение содержать и как она будет работать. После записи документа Docker мы создаем изображение из него (рассмотрим это как исполняемый файл), который создается после составления какого-то кода (Dockerfile). После того, как изображение построено, нам нужно запустить это изображение. Запуск изображения создает контейнер, который является запущенным экземпляром изображения, который аналогичен запуску исполняемого исполнения, который является запущенным экземпляром исполняемого файла.

Выберите минимальные базовые изображения

Каждое пользовательское изображение, которое мы строим в Docker, должны быть построены сверху существующего базового изображения, нам нужно CherryPick и выбирать изображения, которые более минимально и компактны. Существуют различные вкусы, которые предлагают светлые изображения. К ним относятся Alpine, Bitebox и другие специфические изображения для распределения, такие как Debian, Ubuntu, Centos, которые имеют -стройное * или * -Минимал версия их на выбор.

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

FROM alpine

WORKDIR /app

COPY package.json /app

RUN npm install

CMD ["node","index.js"]

Удалить пакеты кэширования

Для нашего приложения для запуска внутри контейнера часто требуется среда выполнения, зависимости и двоичных файлов. При попытке установить пакеты из пакета-менеджера, такого как (APT, APK, yum), он часто сначала загружает пакеты с удаленного исходных репозиторов на локальную машину, а затем устанавливает пакет. После установки пакетов часто порой файлы пакета Cache, которые были загружены, получите хранимые и потреблять дополнительное ненужное пространство. Лучшая рекомендация состоит в том, чтобы удалить эти файлы кэшированных/пакетов после установки пакета, это дополнительно оптимизирует изображение Docker.

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

** Изображение/дистрибутив: ** Debian/Ubuntu

** Менеджер пакета: ** APT

* Расположение кэша: * /var/cache/apt/архивы

** Изображение/дистрибутив: * * Alpine

** Менеджер пакета: ** apk

* Расположение кэша: * /var/cache/apk

** Изображение/дистрибутив: ** centos

** Менеджер пакетов: ** yum

* Расположение кэша: * /var/cache/

В приведенном ниже примере мы будем устанавливать Nginx WebServer на сервер статических HTML веб-страниц. Когда мы устанавливаем пакет Nginx рядом с наряду, мы также удалим пакеты кеша, которые были сохранены в определенном пути каталога кэша. В этом случае, как мы используем Alpine, мы указали каталог, который содержит кеш для пакетов.

FROM alpine

RUN apk add nginx && **rm -rf /var/cache/apt/***

COPY index.html /var/www/html/

EXPOSE 80

CMD ["nginx","-g","daemon off;"]

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

FROM alpine

RUN apk add –no-cache nginx

COPY index.html /var/www/html/

EXPOSE 80

CMD ["nginx","-g","daemon off;"]

Избегайте нескольких слоев

Ух ты! Этот бургер — это глазная конфета с этими дополнительными слоями Пэтти и сыра, что делает его действительно вкусным и тяжелый Отказ Docker Images аналогичны этому бургеру с каждым дополнением, который добавляется в файл DockerFile, одновременно создавая изображение, это делает его больше тяжелее . Всегда рекомендуется убедиться, что количество слоев как можно ниже.

Ниже представляет собой DockerFile, который содержит инструкцию, где мы устанавливаем Nginx вместе с другими необходимыми утилитами. В случае DockerFile каждая новая линия обучения формирует отдельный слой.

FROM alpine

RUN apk update

RUN apk add curl

RUN apk add nodejs

RUN apk add nginx-1.16.1-r6

RUN apk add nginx-mod-http-geoip2-1.16.1-r6

COPY index.html /var/www/html/

EXPOSE 80

CMD ["nginx","-g","daemon off;"]

Приведенный выше DockerFile можно оптимизировать с помощью цепочки и эффективного использования && и * * Где когда-либо необходимость уменьшить количество слоев, созданных для DockerFile.

FROM alpine

RUN apk update && apk add curl nginx nginx-mod-http-geoip2-1.16.1-r6 \

rm -rf /var/cache/apt/*

COPY index.html /var/www/html/

EXPOSE 80

CMD ["nginx","-g","daemon off;"]

С помощью цепочки мы выдвинули большую часть слоев и избегали создания нескольких слоев, которые в целом помогают оптимизировать DockerFile, чтобы сделать бургер еще больше Вкусный Отказ

Не игнорируйте .Dockerignore

.dockerignore. * Как следует из названия, является быстрым и легким способом игнорировать файлы, которые не должны находиться в отдельности образа докера. Похож на * .gitignore ** Файл, который игнорирует файлы от отслеживания под контролем версии. Прежде чем идти дальше, давайте понять ** Контекст сборки Отказ При создании DockerFile все файлы/папки в текущем рабочем каталоге копируются и используются в качестве контекста сборки. Съемки здесь состоит в том, что если нынешний рабочий каталог от того, где мы строим DockerFile, содержит гигабайты данных, в этом случае он часто увеличивает ненужное время сборки, ну это проблема, это означает, что именно мы должны перемещать гигабайты данных Для отделения каталога во время строительства Dockerfile, Naah !!, Но тогда как мы решаем это?

.Dockerignore К вашей спасению, его можно использовать для нескольких случаев использования, некоторые из которых я упоминал ниже:

  1. Игнорировать файлы и каталоги которые не нужно быть частью изображения, которое будет построен.

  2. Избегайте случайно копирования Конфиденциальные данные Отказ

Давайте постараемся понять это немного лучше с примером DockerFile, в котором мы будем подключать к применению и использование Nodejs. Dockerignore. Чтобы игнорировать файлы/каталоги, которые не обязаны копировать на момент создания этого изображения.

  1. Игнорировать безрученные файлы и каталоги

    Из узла: 10

    Workdir/NodeApp.

    Скопировать Package.json ./

    Запустите NPM Install

    Копировать. Отказ

    Выставлять 8888

    CMD [«Узел», «index.js»]

В этом случае мы выбираем Узел: 10 В качестве базового изображения установить приложение в качестве рабочего каталога для нашего образа докера, выставляя порт 8888 Для внешнего доступа, после чего мы копируем Package.json, а затем установить все зависимости, упомянутые в Package.json, используя NPM, который создаст каталог Node_Modules, который будет содержать все последние зависимости, установленные под ним, после чего приходит решающая часть, в которой мы копируем Все содержимое из нашего текущего рабочего каталога в образе докера. Часто иногда копируя все содержимое из текущего рабочего каталога, есть определенные файлы/каталог, который не требуется, в этом случае его Node_Modules Поскольку мы уже установили последние двоичные файлы, используя NPM Install. Так что с этим в виду мы можем добавить Node_Modules в .Dockerignore, чтобы избежать его скопирования, пока изображение получает сборку.

2. Избегайте копирования конфиденциальных деталей.

Разработчики не могут отрицать факт хранения .env, ssh ключей, сертификатов и файлов, которые содержат конфиденциальные детали в их локальной среде разработки (были сделаны это), в то время как это делает все возможное, чтобы получить доступ к тому, что она прогреется на целом в целом уязвимостей и защитных петель-дырок. Однако эти методы следует избегать всех средств, а также для того, чтобы предотвратить дальнейшее ущерб в среде разработки, которая содержит Docker, лучшее, что можно сделать, — избегать этих файлов, которые можно копировать в документе Docker, что мы строительство. Этого можно легко сделать с помощью .Dockerignore Указав файлы, которые необходимо избегать, от случайно скопированных.

Так что идеально вот как наш .Dockerignore файл должно понравиться

node_modules

.env

secrets/

*pem

*.md

В этом случае мы добавили, Node_Modules который не нужен, как упомянуто выше, .env.env. Поскольку он может содержать конфиденциальные детали или переменные, специфичные для местной среды развития, которые не должны создавать конфликт в других средах, таких как постановка, производство. Мы также исключили все конфиденциальные данные, хранящиеся в . * PEM * Файлы, а также файлы, которые присутствуют в секретной папке вместе с файлами Markdown/Documentation, которые часто не нужны внутри докера

Выберите тонкие варианты

При выборе базового изображения следует предпочесть выбрать много тонкого и минимального базового изображения. Они часто помечены как -Слим или -Минимал Отказ Эти изображения легче и имеют гораздо менее след по сравнению с их аналогами по умолчанию.

Вот пара примеров стройная версия против По умолчанию коллеги.

Порезать корень

Каждое изображение, которое мы построили с помощью Docker, имеют пользователь по умолчанию в качестве root, ну это охранное зло, следовательно, мы ссылаемся на него как « порезать корню» Отказ В большинстве случаев нам не нужен пользователь, чтобы изображения были root, поскольку мы можем указать пользователь по умолчанию со всеми минимальными разрешения, необходимыми для приложения для функции внутри контейнера

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

FROM node:10

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

EXPOSE 8888

CMD [ "node", "index.js" ]

Теперь, поскольку мы осознаем тот факт, что имел значение пользователя по умолчанию ROOT, чтобы избежать этого, мы можем указать пользователь по умолчанию, кроме root.

FROM node:10

RUN user add -m nodeapp

USER nodeappuser

RUN whoami

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

EXPOSE 8888

CMD [ "node", "index.js" ]

Удалить нежелать

При попытке подключить приложение наша основная цель — убедиться, что приложение успешно работает внутри контейнера Docker. Часто бывает, что после выбора базового изображения есть много инструментов и пакетов, утилит, которые приходят вместе с изображением его либо что мы можем выбрать использовать -slim/-minimal Версия изображения или предпочитаемая для удаления инструментов и утилит, которые могут не понадобиться.

Тег мудро

Теги — это уникальный способ для определения изображения. Помечая изображение, мы можем использовать любую специфическую конвенцию именования нашего выбора, но ее будет очень оптимально, чтобы выбрать тег изображения на основе функций, Commit, или что-то более значимое. Теги для конечного пользователя, чтобы выбрать, какую версию изображения использовать

Пример метки включает в себя метку их с помощью инкрементной версии изображения или использовать HIT-версию HASH для использования, все это может быть интегрировано в ваши трубопроводы CI/CD для автоматизации цели помечения изображений

Так что нет для последнего тега

Было сделано, что Хейден столкнулся с большим количеством вопросов с меткой Docker Images * : Последние * Вот несколько причин, по которым я предпочитаю больше не использовать последний тег.

MyImage: последние похоже, что это не помечено ничем, или скажем, по умолчанию MyImage (который не имеет тегов)

Избегайте использования последних тегов для Kubernetes в производстве, так как это делает его намного сложно для отладки и выяснить, какая версия может вызвать проблему. Вот почему часто рекомендуется осмысленно помещать изображения с определенной версией, которая изображает изменения, которые возникают и откат, если это необходимо. Он нарушает всю философию за уникальными тегами, которые изображают разные версии.

Государственный или частный реестр

Вопрос здесь — выбирать между публичным имиджем или частным изображением?

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

Частные изображения, хранящиеся с добавленным слоем безопасности и убедитесь, что только авторизованный персонал может получить доступ к этим изображениям. Docker Hub, а также пару других инструментов реестра контейнеров, предоставляют возможность выбирать между публичными или частными изображениями (хотя в корпусе Docker Hub вы можете выбрать только 1 изображение как личное в плане без по умолчанию)

Держите это одиноким

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

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

Использовать Линтер

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

  1. HADOLINT.

  2. Docker Linter (VSCode)

Мой личный любимый — Docker Linter, который является расширением VSCode, что указывает на предупреждения или синтаксические ошибки прямо, как вы идете.

Не храните секреты

Только то, как это в реальной жизни, никогда не раскрывайте свои секреты. То же самое, когда дело доходит до Dockerfile, никогда не хранит открытое пространство имени пользователя, пароля или другого чувствительного, так что его выявлено. Чтобы избежать хранения секретов с использованием .Dockerignore Чтобы предотвратить случайное копирование файлов, которые могут содержать конфиденциальную информацию.

Избегайте жесткого кодирования

Хотя этот принцип не только применится к DockerFile, но и проектирование программного обеспечения в целом, часто не рекомендуется ценностями из жестких кодов внутри докерафила. Лучшим примером может быть вместо того, чтобы жесткодирующая конкретная версия программного обеспечения, которая может обновлять или необходимость менять, мы можем динамически передавать значения для них при сборке ARGS.

* Args. * — это ключевое слово в DockerFile, которое позволяет нам динамически пропускать значения до DockerFile в Time Time.

Чтобы лучше понять это, давайте приведем пример.

ARG VERSION

FROM node:$VERSION

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

EXPOSE 8888

CMD [ "node", "index.js" ]

Использование динамических значений для передачи и создания изображений.

docker build -t testimage –build-arg VERSION=10 .

docker build -t testimage –build-arg VERSION=9 .

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

Избегайте отладки инструментов

Строив изображение их часто иногда мы добавляем инструменты отладки, такие как CURL, PING, NETSTAT, TELNET и другие сетевые утилиты, которые дополнительно повышают общий размер изображения. Это может быть хорошим выбором, чтобы избежать добавления этих инструментов отладки в DockerFile и устанавливать их только при фактическом необходимости во время выполнения.

Добавление метаданных

Этикетка Это ключевое слово в DockerFile, который добавляет детали метаданных о DockerFile.

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

FROM node:10

**LABEL version="1.0" maintainer="Chris Rego "**

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

EXPOSE 8888

CMD [ "node", "index.js" ]

Используя проверку уязвимости

Проверка уязвимости!

Благодаря недавней атаке на инфраструктуре Tesla’s Kubernetes, она заставила все понимать, что переход от голых металлов на виртуальные машины до конца до контейнеров никогда не фиксирует лазейки безопасности, которые часто остаются позади. Что ж, есть пара лучших практик с точки зрения безопасности, которая может сопровождаться при подключении и приложении, таковых, как уход за секретами/учетными данными, избегайте использования пользователей root в качестве пользователя по умолчанию для контейнера и нескольких других. Лучший подход к уязвимости безопасности контр-атаки в сфере контейнера в контейнерной сфере заключается в том, чтобы включать в себя инструменты/технологии, направленные на выполнение надежных проверок безопасности к контейнеру, присутствующему в вашей среде. Есть пара присутствия инструментов, которые могут быть добавлены в ваш арсенал безопасности.

  1. Яица

  2. Докл

  3. Falco.

  4. Приманки

Избегайте копирования всего

Всегда хорошо копировать, но это мудро копирует выборочно. В случае докера рекомендуется пытаться избежать использования Копировать. Отказ который имеет тенденцию скопировать все из вашего текущего рабочего каталога для вашего изображения Docker. Рекомендуется выбрать только файлы, которые необходимо скопировать, а также указать файлы в. Dockerignore от случайного копирования (нежелательных или файлов, которые содержат конфиденциальные данные)

FROM node:10

WORKDIR /app

COPY package.json ./

RUN npm install

COPY . .

EXPOSE 8888

CMD [ "node", "index.js" ]

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

FROM node:10

WORKDIR /app

COPY package.json ./

RUN npm install

COPY index.js src ./

EXPOSE 8888

CMD [ "node", "index.js" ]

Используйте Workdir. ПРИ НЕОБХОДИМОСТИ

Workdir Это еще одно важное ключевое слово в DockerFile, которое помогает сделать большую часть тяжелого подъема и избежать дополнительного использования создания и навигации к определенному рабочему каталогу при необходимости.

Workdir Может быть широко использоваться в конкретном использовании, где мы включаем написание дополнительного шага в DockerFile, которое включает в себя навигацию на определенный каталог. В этом случае мы благополучно удаляем эти ссылки на навигацию I.e. CD, просто используя Рабочий

FROM node:10

RUN mkdir -p /app/mynodejsapp

COPY package.json /app/mynodejsapp

RUN cd /app/mynodejsapp && npm install

COPY . ./app/mynodejsapp

EXPOSE 8888

CMD [ "node", "index.js" ]

В этом случае мы должны создать папку, использующую ** mkdir **, а затем для каждой дополнительной справки, мы должны упомянуть весь путь для этой конкретной папки, а также он включает в себя навигацию к папке с помощью CD, все это дополнительное эталон присутствует может быть заменена простым рабочим

FROM node:10

WORKDIR /app/mynodejsapp

COPY package.json ./

RUN npm install

COPY . .

EXPOSE 8888

CMD [ "node", "index.js" ]

В этом случае Workdir автоматически создает папку, если оно не существует, а не дополнительная потребность в навигации на текущий рабочий каталог как Workdir, как уже сделано то, что он должен делать.

Многоступенчатые сборки

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

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

# STAGE ONE: INVOLVES BUILDING THE APPLICATION

FROM node:10 AS build

WORKDIR /myapp

COPY package.json index.js ./

RUN npm install ./

# STAGE TWO: COPYING THE ONLY CONTENTS

# NEEDED TO RUN THE APPLICATION WHILE

# LEAVING BEHIND THE REST

FROM node:10-prod

WORKDIR /myapp

COPY –from=build /app/package.json /app/index.js ./

COPY –from=build /app/node_modules /app/node_modules ./

EXPOSE 8080

CMD ["node", "/app/index.js"]

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

Наконец-то кеш

Давайте поговорим о чем-то, что действительно важно сейчас, это кэш.

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

Кэширование доказывает, что эффективно помогает при обновлении изменений в DockerFile, а также, когда DockerFile содержит часто серию инструкций, которые включают загрузку определенных пакетов, по всей сети часто занимает больше времени, а также потребляет дополнительную пропускную способность сети, это может быть значительно снижена с помощью кэширование. Хотя Docker обеспечивает кэш по умолчанию, есть шансы, что кэш может нарушить из-за изменений, которые обнаруживаются, что ожидаемое поведение. Таким образом, это обязанность конечной пользователей, чтобы гарантировать, что инструкция, которая присутствует в DockerFile, разыгрывается в определенном порядке, чтобы избежать разрыва кэширования в качестве порядка кэширования.

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

Docker — это довольно гибкий инструмент, который позволяет нам полностью игнорировать кеш при создании изображения, которое можно сделать с помощью -NO-кэша. Это гарантирует, что при создании механизма кэширования изображения не работает, но это приводит к увеличению общего времени сборки.

Это не КОНЕЦ

Как я обещал, это 20+ Список лучших практик для DockerFile на 2020 Я буду добавлять больше в список, когда я иду на этот темный, неизвестный Endeavor в строительстве отличных контейнеров докеров. Если вы сделали

Оригинал: «https://dev.to/chrisedrego/21-best-practise-in-2021-for-dockerfile-1dji»