Создание оптимизированных контейнеров для Kubernetes

Вступление

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

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

Характеристики эффективных контейнерных изображений

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

Некоторые качества, к которым нужно стремиться:

Единая, четко определенная цель

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

Общий дизайн с возможностью ввода конфигурации во время выполнения

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

Маленький размер изображения

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

Состояние, управляемое извне

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

Легко понять

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

Следуйте лучшим практикам контейнерного программного обеспечения

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

Полностью используйте возможности Kubernetes

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

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

Повторное использование минимальных общих базовых слоев

Мы можем начать с изучения ресурсов, из которых построены образы контейнеров: базовые образы. Каждый образ контейнера создается либо изparent image, изображения, используемого в качестве отправной точки, либо из абстрактного слояscratch, пустого слоя изображения без файловой системы. base image - это образ контейнера, который служит основой для будущих образов, определяя базовую операционную систему и обеспечивая основные функции. Изображения состоят из одного или нескольких слоев изображения, построенных друг на друге для формирования окончательного изображения.

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

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

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

Alpine Linux является популярной альтернативой для базовых образов, поскольку она успешно упаковывает множество функций в очень маленький базовый образ (~ 5 МБ). Он включает в себя менеджер пакетов со значительными репозиториями и имеет большинство стандартных утилит, которые вы ожидаете от минимальной среды Linux.

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

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

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

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

Понимание слоев изображения и кеша сборки

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

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

Хотя это может быть неочевидно сразу, это поведение может привести к неожиданным результатам, если вы не будете осторожны. Типичным примером этого является обновление локального индекса пакета и установка пакетов в два отдельных этапа. В этом примере мы будем использовать Ubuntu, но основная предпосылка в равной степени применима к базовым образам для других дистрибутивов:

Пример установки пакета Dockerfile

FROM ubuntu:18.04
RUN apt -y update
RUN apt -y install nginx
. . .

Здесь индекс локального пакета обновляется в одной инструкцииRUN (apt -y update), а Nginx устанавливается в другой операции. Это работает без проблем при первом использовании. Однако, если Dockerfile обновляется позже для установки дополнительного пакета, могут возникнуть проблемы:

Пример установки пакета Dockerfile

FROM ubuntu:18.04
RUN apt -y update
RUN apt -y install nginx php-fpm
. . .

Мы добавили второй пакет в команду установки, запускаемую второй инструкцией. Если со времени предыдущей сборки образа прошло значительное количество времени, новая сборка может завершиться ошибкой. Это связано с тем, что в инструкции обновления индекса пакета (RUN apt -y update) измененnot, поэтому Docker повторно использует слой изображения, связанный с этой инструкцией. Поскольку мы используем старый индекс пакета, версия пакетаphp-fpm, которая есть в наших локальных записях, может больше не находиться в репозиториях, что приводит к ошибке при выполнении второй инструкции.

Чтобы избежать этого сценария, обязательно объедините все взаимозависимые шаги в одну инструкциюRUN, чтобы Docker повторно выполнил все необходимые команды, когда произойдет изменение:

Пример установки пакета Dockerfile

FROM ubuntu:18.04
RUN apt -y update && apt -y install nginx php-fpm
. . .

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

Уменьшение размера слоя изображения путем настройки инструкций RUN

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

В общем, объединение команд в единую инструкциюRUN обеспечивает большой контроль над слоем, который будет записан. Для каждой команды вы можете настроить состояние слоя (apt -y update), выполнить основную команду (apt install -y nginx php-fpm) и удалить все ненужные артефакты, чтобы очистить среду до ее фиксации. Например, многие Dockerfiles связываютrm -rf /var/lib/apt/lists/* в конец командapt, удаляя индексы загруженных пакетов, чтобы уменьшить окончательный размер слоя:

Пример установки пакета Dockerfile

FROM ubuntu:18.04
RUN apt -y update && apt -y install nginx php-fpm && rm -rf /var/lib/apt/lists/*
. . .

Для дальнейшего уменьшения размера слоев изображений, которые вы создаете, может быть полезна попытка ограничить другие непреднамеренные побочные эффекты команд, которые вы запускаете. Например, в дополнение к явно объявленным пакетам,apt также по умолчанию устанавливает «рекомендуемые» пакеты. Вы можете включить--no-install-recommends в свои командыapt, чтобы устранить это поведение. Возможно, вам придется поэкспериментировать, чтобы выяснить, используете ли вы какие-либо функции, предоставляемые рекомендованными пакетами.

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

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

Multi-stage builds были введены в Docker 17.05, что позволяет разработчикам более жестко контролировать конечные образы среды выполнения, которые они создают. Многоступенчатые сборки позволяют разделить файл Dockerfile на несколько разделов, представляющих отдельные этапы, каждый с операторомFROM для указания отдельных родительских образов.

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

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

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

Функциональность определения объема на уровне контейнера и контейнера

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

Контейнерирование по функциям

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

Это отличается от распространенных стратегий, используемых в средах виртуальных машин, где приложения часто группируются в одном образе, чтобы уменьшить размер и минимизировать ресурсы, необходимые для работы виртуальной машины. Поскольку контейнеры - это легкие абстракции, которые не виртуализируют весь стек операционной системы, этот компромисс менее убедителен для Kubernetes. Таким образом, хотя виртуальная машина веб-стека может объединять веб-сервер Nginx с сервером приложений Gunicorn на одной машине для обслуживания приложения Django, в Кубернетесе они могут быть разделены на отдельные контейнеры.

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

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

Объединение изображений контейнера в контейнерах

В Kubernetespods - это наименьшая единица, которой может напрямую управлять плоскость управления. Модули состоят из одного или нескольких контейнеров вместе с дополнительными данными конфигурации, чтобы сообщить платформе, как должны выполняться эти компоненты. Контейнеры в модуле всегда планируются на одном рабочем узле в кластере, и система автоматически перезапускает отказавшие контейнеры. Абстракция pod очень полезна, но она вводит еще один уровень решений о том, как объединять компоненты ваших приложений.

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

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

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

  • Ambassador: контейнер-представитель отвечает за обнаружение и подключение к (часто сложным) внешним ресурсам. Основной контейнер может подключаться к контейнеру посла по известным интерфейсам, используя внутреннюю среду pod. Амбассадор абстрагирует внутренние ресурсы и передает трафик между основным контейнером и пулом ресурсов.

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

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

Проектирование для конфигурации времени выполнения

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

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

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

Поскольку Kubernetes манипулирует объектами более высокого уровня, такими как pods, вместо непосредственного управления контейнерами, существуют механизмы, позволяющие определить конфигурацию и внедрить ее в среду контейнера во время выполнения. KubernetesConfigMaps иSecrets позволяют определять данные конфигурации отдельно, а затем проецировать значения в среду контейнера как переменные среды или файлы во время выполнения. ConfigMaps - это объекты общего назначения, предназначенные для хранения данных конфигурации, которые могут различаться в зависимости от среды, стадии тестирования и т. Д. Секреты предлагают аналогичный интерфейс, но специально предназначены для конфиденциальных данных, таких как пароли учетных записей или учетные данные API.

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

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

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

Рассматривать контейнеры как приложения, а не службы

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

Хосты управляют событиями жизненного цикла контейнера, отправляя сигналы процессу, работающему как PID (ID процесса) 1 внутри контейнера. PID 1 - это первый запущенный процесс, который будет системой init в традиционных вычислительных средах. Однако, поскольку хост может управлять только PID 1, использование обычной системы инициализации для управления процессами в контейнере иногда означает, что нет способа контролировать основное приложение. Хост может запускать, останавливать или уничтожать внутреннюю систему инициализации, но не может напрямую управлять основным приложением. Сигналы иногда распространяют предполагаемое поведение на работающее приложение, но это добавляет сложности и не всегда необходимо.

В большинстве случаев лучше упростить рабочую среду внутри контейнера, чтобы PID 1 выполнял основное приложение на переднем плане. В случаях, когда необходимо запустить несколько процессов, PID 1 отвечает за управление жизненным циклом последующих процессов. Некоторые приложения, такие как Apache, обрабатывают это изначально, порождая и управляя работниками, которые обрабатывают соединения. Для других приложений в некоторых случаях может использоваться сценарий оболочки или очень простая система инициализации, напримерdumb-init, или включенная система инициализацииtini. Независимо от выбранной вами реализации, процесс, работающий как PID 1 в контейнере, должен соответствующим образом реагировать на сигналыTERM, отправленные Kubernetes, чтобы вести себя должным образом.

Управление работоспособностью контейнеров в Кубернетесе

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

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

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

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

Заключение

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

  • Используйте минимальные разделяемые родительские изображения для создания изображений с минимальным раздуванием и уменьшением времени запуска

  • Использование многоэтапных сборок для разделения среды сборки контейнера и среды выполнения

  • Объедините инструкции Dockerfile, чтобы создать чистые слои изображения и избежать ошибок кэширования изображений

  • Контейнерные, изолируя отдельные функции, чтобы обеспечить гибкое масштабирование и управление

  • Дизайнерские модули должны нести единую целенаправленную ответственность

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

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

  • Запуск приложений в качестве основных процессов в контейнерах, чтобы Kubernetes мог управлять событиями жизненного цикла

  • Разработайте конечные точки здоровья и жизнеспособности в приложении или контейнере, чтобы Kubernetes мог отслеживать состояние контейнера

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

Related