Создание образов

Узнайте, как создавать собственные контейнерные образы на основе предварительно собранных образов, которые готовы помочь вам. Процесс включает изучение лучших практик написания образов, определение метаданных для образов, тестирование образов и использование пользовательского рабочего процесса сборки для создания образов, которые можно использовать с Alauda Container Platform Registry. После создания образа вы можете отправить его в Alauda Container Platform Registry.

Содержание

Изучение лучших практик для контейнеров

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

Общие рекомендации по контейнерным образам

Следующие рекомендации применимы при создании контейнерного образа в целом и не зависят от того, используются ли образы на Alauda Container Platform.

Повторное использование образов

По возможности базируйте свой образ на соответствующем upstream-образе, используя инструкцию FROM. Это гарантирует, что ваш образ сможет легко получить исправления безопасности из upstream-образа при его обновлении, вместо того чтобы вам самим обновлять зависимости напрямую.

Кроме того, используйте теги в инструкции FROM, например, alpine:3.20, чтобы пользователи точно знали, на какой версии образа основан ваш образ. Использование тега, отличного от latest, гарантирует, что ваш образ не подвергнется несовместимым изменениям, которые могут появиться в latest-версии upstream-образа.

Поддерживайте совместимость внутри тегов

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

Если позже вы выпустите несовместимое обновление, переключитесь на новый тег, например image:v2. Это позволит потребителям самостоятельно перейти на новую версию, не ломая их работу из-за несовместимых изменений. Любой потребитель, использующий image:latest, принимает на себя риск любых несовместимых изменений.

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

Не запускайте несколько сервисов, таких как база данных и SSHD, внутри одного контейнера. Это не нужно, так как контейнеры легковесны и их легко связать для оркестрации нескольких процессов. Alauda Container Platform позволяет легко размещать и совместно управлять связанными образами, группируя их в один pod.

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

Используйте exec в обёрточных скриптах

Многие образы используют обёрточные скрипты для подготовки перед запуском основного процесса. Если ваш образ использует такой скрипт, он должен использовать exec, чтобы процесс скрипта был заменён вашим программным обеспечением. Если не использовать exec, сигналы, посылаемые средой выполнения контейнера, будут направлены скрипту, а не процессу вашего ПО. Это нежелательно.

Например, если у вас есть обёрточный скрипт, который запускает серверный процесс. Вы запускаете контейнер, например, с помощью docker run -i, который запускает скрипт, а тот — процесс. Если вы хотите остановить контейнер с помощью CTRL+C, и если скрипт использует exec для запуска сервера, docker отправит SIGINT серверному процессу, и всё сработает как ожидается. Если exec не используется, SIGINT будет отправлен процессу скрипта, а серверный процесс продолжит работу.

Также учтите, что ваш процесс работает как PID 1 в контейнере. Это означает, что если основной процесс завершится, весь контейнер остановится, отменяя все дочерние процессы, запущенные из PID 1.

Очистка временных файлов

Удаляйте все временные файлы, созданные в процессе сборки. Это также касается файлов, добавленных с помощью команды ADD. Например, выполняйте команду yum clean после операций yum install.

Вы можете предотвратить попадание кэша yum в слой образа, создав команду RUN следующим образом:

RUN yum -y install mypackage && yum -y install myotherpackage && yum clean all -y

Обратите внимание, что если написать так:

RUN yum -y install mypackage
RUN yum -y install myotherpackage && yum clean all -y

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

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

Кроме того, выполнение нескольких команд в одном RUN уменьшает количество слоёв в образе, что улучшает время загрузки и распаковки.

Размещайте инструкции в правильном порядке

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

Например, если вы работаете с Dockerfile, который содержит команду ADD для установки файла, над которым вы работаете, и команду RUN для установки пакета через yum, лучше поместить ADD последним:

FROM foo
RUN yum -y install mypackage && yum clean all -y
ADD myfile /test/myfile

Так при каждом изменении myfile и повторной сборке docker build система повторно использует кэш для команды yum и создает новый слой только для операции ADD.

Если же написать Dockerfile так:

FROM foo
ADD myfile /test/myfile
RUN yum -y install mypackage && yum clean all -y

то при каждом изменении myfile и повторной сборке команда ADD инвалидирует кэш слоя RUN, и операция yum будет выполнена заново.

Отмечайте важные порты

Инструкция EXPOSE делает порт в контейнере доступным для хост-системы и других контейнеров. Хотя можно указать порт для экспонирования при запуске с помощью docker run, использование EXPOSE в Dockerfile облегчает использование вашего образа как людьми, так и программным обеспечением, явно объявляя порты, необходимые для работы вашего ПО:

  • Экспонированные порты отображаются в docker ps для контейнеров, созданных из вашего образа.
  • Экспонированные порты присутствуют в метаданных образа, возвращаемых docker inspect.
  • Экспонированные порты связываются при связывании одного контейнера с другим.

Устанавливайте переменные окружения

Рекомендуется устанавливать переменные окружения с помощью инструкции ENV. Например, можно указать версию вашего проекта. Это облегчает пользователям определение версии без просмотра Dockerfile. Другой пример — объявление пути в системе, который может использоваться другим процессом, например, JAVA_HOME.

Избегайте паролей по умолчанию

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

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

Избегайте sshd

Лучше не запускать sshd в вашем образе. Вы можете использовать команду docker exec для доступа к контейнерам, запущенным на локальном хосте. Также можно использовать docker exec для доступа к контейнерам, запущенным в кластере Alauda Container Platform. Установка и запуск sshd в образе открывает дополнительные векторы атак и требует регулярного обновления безопасности.

Используйте тома для постоянных данных

Образы используют тома для хранения постоянных данных. Таким образом Alauda Container Platform монтирует сетевое хранилище на узел, где запущен контейнер, и если контейнер перемещается на другой узел, хранилище монтируется заново. Использование тома для всех постоянных данных сохраняет содержимое даже при перезапуске или перемещении контейнера. Если ваш образ записывает данные в произвольные места внутри контейнера, эти данные не сохранятся.

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

Явное определение томов в вашем Dockerfile помогает потребителям образа понять, какие тома необходимо определить при запуске вашего образа.

См. документацию Kubernetes для получения дополнительной информации о том, как тома используются в Alauda Container Platform.

Примечание:

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

Включение метаданных в образы

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

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

Определение метаданных образа

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

См. документацию Docker для получения дополнительной информации об инструкции LABEL.

Имена меток обычно имеют пространство имён. Пространство имён устанавливается в соответствии с проектом, который будет использовать метки. Для Kubernetes пространство имён — io.k8s.

См. документацию Docker по пользовательским метаданным для деталей формата.