Оригинальная ссылка:Что именно стоит за созданием подов kubectl?
Представьте, если бы я хотел развернуть nginx в кластере Kubernetes, я мог бы ввести в терминале такую команду:
$ kubectl run --image=nginx --replicas=3
Затем введите. Через несколько секунд вы должны увидеть три модуля nginx, распределенных по всем рабочим узлам. Это похоже на волшебство, но вы не знаете, что происходит за кулисами.
Магия Kubernetes заключается в том, что он может работать с несколькими инфраструктурами через удобный API.deployments
, а основная сложность скрыта в простых абстракциях. Но чтобы полностью понять ценность, которую он нам дает, нам нужно понять его внутреннюю работу.
Это руководство проведет вас через понимание от клиента кKubelet
Полный жизненный цикл запроса с исходным кодом, где это необходимо, чтобы проиллюстрировать, что происходит за кулисами.
Это документ, который можно изменить онлайн, если вы найдете что-то, что можно улучшить или переписать, помощь приветствуется!
1. kubectl
Проверка и генератор
После нажатия клавиши ввода,kubectl
Сначала выполняется некоторая проверка на стороне клиента, чтобы гарантировать, что недопустимые запросы (например, создание неподдерживаемого ресурса или использование неправильного имени изображения) быстро завершатся ошибкой и не будут отправлены вkube-apiserver
. Улучшите производительность системы, уменьшив ненужную нагрузку.
После прохождения проверки kubectl начинает инкапсулировать HTTP-запрос, отправленный kube-apiserver.kube-apiserver
Для связи с etcd все запросы на доступ или изменение состояния системы Kubernetes проходят через kube-apiserver, и kubectl не исключение. kubectl использует генераторы (generators) для создания HTTP-запроса. Генераторы — это абстракция для обработки сериализации.
пройти черезkubectl run
не только может бегатьdeployment
, вы также можете указать параметры--generator
для развертывания нескольких других типов ресурсов. Если не указано--generator
Значение параметра kubectl автоматически определяет тип ресурса.
Например, с параметрами--restart-policy=Always
Ресурс будет развернут как Deployment с параметрами--restart-policy=Never
Ресурсы будут развернуты в виде модулей. В то же время kubectl также проверяет, нужно ли инициировать другие действия, такие как команды ведения журнала (для отката или аудита).
После того, как kubectl решит создать развертывание, он будет использоватьDeploymentV1Beta1
Генератор генерируетобъект времени выполнения.
Согласование версий API и группы API
Чтобы упростить устранение полей или реорганизацию структур ресурсов, Kubernetes поддерживает несколько версий API, каждая из которых находится под своим путем к API, например./api/v1
или/apis/extensions/v1beta1
. Разные версии API указывают на разные уровни стабильности и поддержки, более подробные описания можно найти вОбзор API Kubernetes.
Группы API предназначены для категоризации похожих ресурсов, чтобы упростить расширение API Kubernetes. Имя группы API находится в пути REST или в сериализованном объекте.apiVersion
указано поле. Например, имя группы API развертывания:apps
, последняя версия APIv1beta2
, поэтому вы вводите в верхней части манифеста развертыванияapiVersion: apps/v1beta2
.
После того, как kubectl сгенерирует объект времени выполнения, начните его генерацию.Найдите подходящую группу API и версию API,ПотомСобрать в версионный клиент, клиент знает различную семантику ресурса REST. Этот этап называется согласованием версии и сканированием kubectl.remote API
Вверх/apis
путь для получения всех возможных групп API. Так как kube-apiserver находится в/apis
Документ спецификации в формате OpenAPI отображается на пути, поэтому клиентам легко найти подходящий API.
Для повышения производительности kubectlСпецификации OpenAPI кэшированияприбыть~/.kube/cache
содержание. Если вы хотите понять процесс обнаружения API, попробуйте удалить каталог и запустить команду kubectl с-v
Значение параметра установлено на максимальное значение, и вы увидите все HTTP-запросы, пытающиеся найти эти версии API. Ссылаться нашпаргалка кубектл.
Последним шагом является фактическая отправка HTTP-запроса. Как только запрос будет отправлен с успешным ответом, kubectl напечатает сообщение об успешном выполнении в соответствии с желаемым форматом вывода.
Аутентификация клиента
Аутентификация клиента также требуется перед отправкой HTTP-запроса, что не упоминалось ранее и может быть замечено сейчас.
Чтобы успешно отправлять запросы, kubectl необходимо сначала пройти аутентификацию. Учетные данные пользователя хранятся вkubeconfig
kubectl находит файл kubeconfig в следующем порядке:
- если предусмотрено
--kubeconfig
kubectl использует файл kubeconfig, указанный в параметре --kubeconfig.
- Если параметр --kubeconfig не указан, но задана переменная окружения
$KUBECONFIG
, используется файл kubeconfig, предоставленный этой переменной среды.
- Если параметр --kubeconfig и переменная среды
$KUBECONFIG
не предоставляются, kubectl использует файл kubeconfig по умолчанию$HOME/.kube/config
.
После синтаксического анализа файла kubeconfig kubectl определяет текущий контекст для использования, кластер, на который он в данный момент указывает, и любую информацию об аутентификации, связанную с текущим пользователем. Если пользователь предоставляет дополнительные параметры (например, --username), они используются предпочтительно для переопределения значений, указанных в kubeconfig. Как только эта информация будет получена, kubectl заполнит эту информацию в заголовках HTTP-запроса для отправки:
- использование сертификата x509tls.TLSConfigОтправить (включая сертификат CA).
-
bearer tokens
в заголовке HTTP-запросаAuthorization
серединаОтправить.
- Имя пользователя и пароль через базовую аутентификацию HTTPОтправить.
-
OpenID
Процесс аутентификации заранее обрабатывается пользователем вручную, в результате чего токен отправляется как токен носителя.
2. kube-apiserver
Сертификация
Теперь, когда наш запрос был успешно отправлен, что произойдет дальше? Вот когдаkube-apiserver
Он сияет! kube-apiserver — это основной интерфейс, используемый клиентами и системными компонентами для сохранения и получения состояния кластера. Чтобы выполнить соответствующую функцию, kube-apiserver должен быть в состоянии проверить, является ли запросчик законным, процесс, называемый аутентификацией.
Так как же apiserver аутентифицирует запрос? Когда kube-apiserver запускается в первый раз, он просматривает все предоставленные пользователемпараметры интерфейса командной строки, и объединены в список подходящих токенов.
**Пример:**Если указано--client-ca-file
параметр, в список токенов добавляется проверка подлинности клиентского сертификата x509, если она указана--token-auth-file
токен передышки будет добавлен в список токенов.
Каждый раз, когда поступает запрос, apiserverАутентификация через цепочку токенов до тех пор, пока определенная аутентификация не будет успешной:
-
обработчик x509Проверит, что HTTP-запрос закодирован с помощью ключа TLS, подписанного корневым сертификатом ЦС.
-
обработчик токена носителяпроверит
--token-auth-file
Существует ли файл маркера, предоставленный параметром.
-
Базовый обработчик аутентификацииУбедитесь, что учетные данные базовой проверки подлинности HTTP-запроса соответствуют локальному состоянию.
еслиОшибка аутентификации, запрос завершается неудачно и возвращается соответствующее сообщение об ошибке; если проверка прошла успешно,Authorization
заголовки запроса удалены, иДобавьте информацию о пользователе вв его контексте. Это предоставляет контроллерам последующей авторизации и допуска возможность доступа к ранее установленным идентификаторам пользователей.
Разрешить
Хорошо, теперь, когда запрос отправлен, и kube-apiserver успешно подтвердил, кто мы такие, мы наконец-то свободны!
Но дело не кончено, хотя мы и доказалимы законны, но уполномочены ли мы на это? В конце концов, личность и авторитет — не одно и то же. Для выполнения последующих операций kube-apiserver также необходимо авторизовать пользователя.
kube-apiserver обрабатывает авторизацию аналогично аутентификации: через параметры запуска kube-apiserver--authorization_mode
настройки параметров. Он будет объединять серию авторизаторов, которые будут авторизовать каждый входящий запрос. Если все авторизаторы отклоняют запрос, на запрос запрещается отвечать ине будет продолжать отвечать. Если авторизатор одобряет запрос, запрос продолжается.
kube-apiserver в настоящее время поддерживает следующие методы авторизации:
-
webhook: взаимодействует со службами HTTP(S) за пределами кластера.
-
ABAC: Применяет политику, определенную в статическом файле.
-
RBAC: оно использует
rbac.authorization.k8s.io
API Group реализует решения об авторизации, позволяя администраторам динамически настраивать политики через Kubernetes API.
-
Node: гарантирует, что kubelet может получить доступ к ресурсам только на своем собственном узле.
входной контроль
После преодоления двух барьеров аутентификации и авторизации, упомянутых выше, может ли запрос вызова клиента получить реальный ответ от сервера API? Ответ - нет!
С точки зрения kube-apiserver, он аутентифицировал нас и дал соответствующие разрешения, позволяющие нам продолжить работу, но с Kubernetes другие компоненты по-прежнему очень скептически относятся к тому, что должно происходить. Таким образом, этот запрос также должен пройтиAdmission Controller
контролируемый准入控制链
Существует около десяти официальных стандартных «уровней», которые можно настраивать и расширять!
В то время как точка авторизации заключается в том, чтобы ответить, есть ли у пользователя разрешение, контроллер допуска перехватывает запрос, чтобы убедиться, что он соответствует более широким ожиданиям и правилам кластера. Это объекты ресурсов, сохраненные вetcd
Последний бастион включает в себя серию дополнительных проверок, чтобы гарантировать, что операция не приведет к неожиданным или отрицательным результатам. В отличие от авторизации и аутентификации, которые заботятся только о запрошенном пользователе и операции, управление доступом также имеет дело с содержимым запроса и действует только для создания, обновления, удаления или соединений (таких как прокси), но не для операций чтения.
Контроллеры доступа работают аналогично авторизаторам и валидаторам, с одним отличием: в отличие от цепочек аутентификации и цепочек авторизации, если контроллер допуска не проходит проверку, вся цепочка разрывается и весь запрос будет сразу отклонен, а в конце будет возвращена ошибка. Пользователь.
Ключевым моментом конструкции контроллера доступа является улучшение масштабируемости, контроллер хранится в виде подключаемого модуля.plugin/pkg/admission
каталог, соответствует интерфейсу и, наконец, компилируется в двоичный файл kube-apiserver.
Большинство контроллеров допуска относительно просты для понимания, и далее основное внимание будет уделено введению.SecurityContextDeny
,ResourceQuota
а такжеLimitRanger
Эти три контроллера допуска.
- SecurityContextDenyЭтот плагин отключит создание модулей с установленным контекстом безопасности.
-
ResourceQuotaМожно не только ограничить количество ресурсов, созданных в пространстве имен, но и ограничить общий объем ресурсов, запрашиваемых модулями в пространстве имен. Контроллер допуска и объекты ресурсов
ResourceQuota
Вместе для достижения управления квотами ресурсов. -
LimitRangerЭта функция аналогична приведенному выше контроллеру ResourceQuota, который является квотой ресурса для каждого отдельного (пода, контейнера и т. д.) ресурса пространства имен. Плагин и объекты ресурсов
LimitRange
Вместе внедрите управление квотами ресурсов.
3. etcd
До сих пор Kubernetes тщательно проверял запрос вызова клиента, и он был проверен, запуская его по следующей ссылке. Следующим шагом kube-apiserver десериализует HTTP-запрос, а затем использует результат для создания объекта среды выполнения (что-то вроде инверсии генератора kubectl) и сохраняет его вetcd
середина. Ниже мы разберем этот процесс.
Как kube-apiserver узнает, что делать, когда получит запрос? На самом деле, прежде чем клиент отправит запрос на вызов, был сгенерирован ряд очень сложных процессов. Начнем с первого запуска бинарника kube-apiserver:
- При запуске двоичного файла kube-apiserver онСоздайте цепочку сервисов, позволяющую агрегировать API-серверы.. это пара
Kubernetes API
способ расшириться.
- также создаст
generic apiserver
в качестве API-сервера по умолчанию.
- затем используйтеСгенерированная спецификация OpenAPIдля заполнения конфигурации apiserver.
- Затем kube-apiserver просматривает все группы API, указанные в структуре данных, и сохраняет каждую группу API в etcd как общую абстракцию хранилища. Эти группы API вызываются kube-apiserver при доступе к ресурсу или изменении его состояния.
- Каждая группа API выполняет итерацию по всем версиям своей группы и маршрутизирует каждый HTTP-запрос.Сопоставлен с путем REST.
- Когда запрошенный МЕТОД
POST
, kube-apiserver перенаправит запрос наобработчик создания ресурса.
Теперь kube-apiserver знает все маршруты и соответствующие им пути REST, чтобы знать, какие обработчики и хранилища ключей и значений вызывать при совпадении запроса. Какой продуманный дизайн! Теперь предположим, что клиентский HTTP-запрос получен kube-apiserver:
- Если цепочка обработки может сопоставить запрос с уже зарегистрированным маршрутом, запрос передаетсявыделенный процессордля обработки; если ни один из маршрутов не соответствует запросу, запрос перенаправляетсяпроцессор на основе пути(например, при вызове
/apis
время); если ни один из обработчиков на основе пути не зарегистрирован с путем, запрос перенаправляетсяне найден процессор, и, наконец, вернуться404
.
- К счастью, у нас есть
createHandler
Маршрут регистрации! Что оно делает? Сначала он декодирует HTTP-запрос и выполняет базовую проверку, например проверяет, соответствует ли предоставленный запросом json версии ресурса API.
- Введите следующийАудит и допускной контрольсцена.
- Тогда ресурс пройдетstorage providerспастик и т. д.середина. Формат ключей, сохраняемых в etcd по умолчанию, таков:
<namespace>/<name>
, вы также можете настроить.
- Любые ошибки во время создания ресурса отлавливаются, и, наконец,
storage provider
будет выполнятьget
Вызывается для подтверждения того, что ресурс был успешно создан. Постсозданные обработчики и декораторы вызываются, если требуется дополнительная очистка.
- Наконец, HTTP-ответ создается и возвращается клиенту.
Получается, что apiserver проделал столько работы, а я его раньше не нашел! На данный момент мы создалиDeployment
Ресурс сохранился в etcd, но аписервер его все равно не видит.
4. Инициализация
После того как ресурсный объект был сохранен в хранилище данных, apiserver не может полностью увидеть или запланировать его, пока не выполнит ряд операций.Initializers. Инициализаторы — это контроллеры, связанные с типом ресурса, которые выполняют некоторую логику, прежде чем ресурс станет доступным для внешнего мира. Если тип ресурса не имеет инициализаторов, этот шаг инициализации пропускается, и ресурс немедленно становится видимым для внешнего мира.
так какБлог Большого ПарняКак уже отмечалось, инициализаторы — это мощная функция, поскольку она позволяет нам выполнять общие действия начальной загрузки. Например:
- Добавьте прокси-контейнер sidecar в модуль, предоставляющий порт 80, или добавьте конкретный
annotation
.
- будет хранить тестовый сертификат
volume
Внедряется во все модули в определенном пространстве имен.
- если
Secret
Если пароль меньше 20 символов, его создание будет заблокировано.
initializerConfiguration
Объекты ресурсов позволяют вам объявить, какие инициализаторы должны запускаться для определенных типов ресурсов. Если вы хотите запускать настраиваемые инициализаторы каждый раз при создании пода, вы можете сделать это:
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:
name: custom-pod-initializer
initializers:
- name: podimage.example.com
rules:
- apiGroups:
- ""
apiVersions:
- v1
resources:
- pods
Создайте объект ресурса с этой конфигурациейInitializerConfiguration
После этого в каждом подеmetadata.initializers.pending
поле добавленоcustom-pod-initializer
поле. Контроллер инициализации периодически сканирует новые поды, как только подpending
Если в поле будет обнаружено его собственное имя, будет выполнена его логика, а после выполнения логикиpending
собственное имя под полем удаляется.
только вpending
Первые Инициализаторы в списке под полем могут работать с ресурсом, когда все Инициализаторы закончат выполнение, иpending
Когда поле пусто, объект считается успешно инициализированным.
Вы можете заметить проблему: если kube-apiserver не может отображать эти ресурсы, как контроллер уровня пользователя обрабатывает ресурсы?
Чтобы решить эту проблему, kube-apiserver предоставляет?includeUninitialized
Параметр запроса, который возвращает все объекты ресурсов (включая неинициализированные).
5. Контур управления
Deployments controller
На этом этапе наша запись Deployment сохранена в etcd, и вся логика инициализации выполнена, на следующем этапе будет задействована топология, от которой зависит ресурс. В Kubernetes развертывание — это просто последовательностьReplicaset
, а Replicaset — это наборPod
коллекция. Так как же Kubernetes создает эти ресурсы в иерархическом порядке из HTTP-запроса? На самом деле эти задания встроены в Kubernetes.Controller
(контроллер) для завершения.
Kubernetes использует большое количество контроллеров по всей системе, контроллер — это асинхронный скрипт, используемый для корректировки состояния системы с «текущего состояния» на «желаемое состояние». Все контроллеры проходятkube-controller-manager
Компоненты работают параллельно, и каждый контроллер отвечает за определенный поток управления. Сначала позвольте мне представитьDeployment Controller
:
После того, как запись о развертывании сохранена в etcd и инициализирована, ее можно сделать видимой через kube-apiserver, а затемDeployment Controller
обнаружит его (его задача — прослушивать изменения, записанные развертыванием). В нашем случае контроллер передаетInformer
Зарегистрируйте определенную функцию обратного вызова, которая создает событие(Смотрите ниже для получения дополнительной информации).
Когда Развертывание впервые станет видимым для внешнего мира, КонтроллерДобавьте объект ресурса во внутреннюю рабочую очередь, а затем начать обработку объекта ресурса:
запросив kube-apiserver с помощью селектора теговэкзаменИмеет ли развертывание связанный
ReplicaSet
илиPod
Записывать.
Интересно, что этот процесс синхронизации не зависит от состояния и проверяет новые записи так же, как и существующие записи.
понимая, что нет никакого связанногоReplicaSet
илиPod
После входа в систему контроллер развертывания начинает выполнятьсяЭластичный процесс масштабирования:
Создайте ресурс ReplicaSet, назначьте ему селектор меток и установите для его версии номер 1.
Набор репликPodSpec
Поля копируются из манифеста развертывания и других соответствующих метаданных. Иногда записи развертывания также необходимо обновить после этого (например, если установленоprocess deadline
).
После выполнения вышеуказанных шагов развертываниеstatus
обновляется, а затем повторно входит в тот же цикл, что и раньше, ожидая, пока развертывание не будет соответствовать желаемому состоянию. Поскольку контроллер развертывания заботится только о наборе реплик, ему необходимо передатьReplicaSet Controller
продолжить согласование.
ReplicaSets controller
На предыдущих шагах контроллер развертывания создал первый набор реплик, но подов все еще нет, поэтому пришло времяReplicaSet Controller
Появился! Задача контроллера наборов реплик заключается в наблюдении за жизненным циклом наборов реплик и связанных с ними ресурсов (модулей). Как и большинство других контроллеров, он делает это, запуская обработчики определенных событий.
Когда ReplicaSet создается (создается контроллером развертывания), контроллер RSПроверьте статус нового набора реплик., и проверьте отклонение, которое существует между текущим состоянием и желаемым состоянием, затем передайтеНастройте количество реплик для подадля достижения желаемого состояния.
Создание подов также выполняется партиями, начиная сSlowStartInitialBatchSize
start, затем на каждой успешной итерации сslow start
Двойная операция. Целью этого является снижение риска того, что kube-apiserver будет поглощен большим количеством ненужных HTTP-запросов, когда большое количество подов не запустится (например, из-за квот на ресурсы). В случае сбоя создания лучше всего сделать это корректно с минимальным воздействием на другие компоненты системы!
Kubernetes черезOwner References
(ссылаясь на идентификатор своего родительского ресурса в поле дочернего ресурса), чтобы построить строгую иерархию объектов ресурсов. Это гарантирует, что дочерние ресурсы удаляются сборщиком мусора, как только ресурс, управляемый контроллером, удаляется (каскадное удаление), а также обеспечивает эффективный способ для родительских ресурсов избежать их конкуренции за один и тот же дочерний ресурс (представьте, что два для сценариев когда оба родителя думают, что у них один и тот же ребенок).
Еще одним преимуществом ссылок на владельцев является то, что они сохраняют состояние. Если какой-либо Контроллер будет перезапущен, операция не повлияет на стабильную работу системы, поскольку топологическая взаимосвязь объектов ресурсов не имеет ничего общего с Контроллером. Этот акцент на изоляцию ресурсов также отражен в конструкции самого контроллера: контроллеры не могут работать с ресурсами, которыми они явно не владеют, они должны владеть ресурсами, не мешая друг другу и не разделяя их друг с другом.
Иногда в системе также появляются потерянные ресурсы, обычно генерируемые следующими двумя способами:
- Родительский ресурс удаляется, но дочерний ресурс не удаляется
- Политика сборки мусора запрещает удаление дочерних ресурсов
Когда это происходит, Контроллер гарантирует, что потерянный ресурс имеет новыйOwner
. Несколько родительских ресурсов могут конкурировать друг с другом за один и тот же потерянный ресурс, но только один из них будет успешным (другие родительские ресурсы получат ошибки проверки).
Informers
Возможно, вы заметили, что некоторым контроллерам (например, авторизатору RBAC или контроллеру развертывания) необходимо получить состояние кластера, прежде чем они смогут функционировать должным образом. В качестве примера возьмем авторизатор RBAC, когда приходит запрос, авторизатор кэширует начальное состояние пользователя, а затем использует его для получения всех ролей, связанных с пользователем в etcd (Role
) и привязка символов (RoleBinding
). Итак, вопрос в том, как Контроллер получает доступ к этим объектам ресурсов и изменяет их? На самом деле Kubernetes реализуется черезInformer
механизм решения этой проблемы.
Informer — это шаблон, который позволяет контроллерам искать данные, кэшированные в локальной памяти (эти данные поддерживаются самим Informer), и перечислять интересующие их ресурсы.
Несмотря на то, что дизайн Informer очень абстрактный, внутри него реализовано много логики обработки деталей (например, кеширование).Кэширование очень важно, потому что оно может не только сократить количество прямых вызовов API Kubenetes, но и уменьшить количество серверных запросов. и контроллер повторяющаяся работа. Используя Informer, различные контроллеры могут взаимодействовать потокобезопасным образом, не беспокоясь о конфликтах, когда несколько потоков обращаются к одному и тому же ресурсу.
Для более подробного анализа Информера, пожалуйста, обратитесь к этой статье:Kubernetes: Controllers, Informers, Reflectors and Stores
Scheduler
Когда все контроллеры работают нормально, Deployment, ReplicaSet и три записи ресурсов Pod будут сохранены в etcd, которые можно просмотреть через kube-apiserver. Однако эти ресурсы Pod все еще находятся вPending
состоянии, потому что они не были запланированы для запуска на соответствующих узлах в кластере. Эта проблема в конечном итоге зависит от планировщика (Scheduler), который нужно решить.
Scheduler
Запускается на плоскости управления кластером как независимый компонент и работает так же, как и любой другой контроллер: слушает фактическое и настраивает состояние системы до желаемого состояния. В частности, роль планировщика заключается в том, чтобы связать под, который должен быть запланирован, с подходящим узлом в кластере в соответствии с определенным алгоритмом и политикой планирования, а также записать информацию о привязке в etcd (он будет фильтровать свой средний PodSpec).NodeName
Pods с пустыми полями), алгоритм планирования по умолчанию работает следующим образом:
-
Когда Планировщик запустится, онЗарегистрировать цепочку политик предварительного выбора по умолчанию,Эти
预选策略
Узлы-кандидаты будут оцениваться, чтобы определить, являются ли узлы-кандидатыУдовлетворение потребностей альтернативных модулей. Например, если поле PodSpec ограничивает ресурсы ЦП и памяти, то, когда емкость ресурсов узла-кандидата не соответствует потребностям пода-кандидата, под-кандидат не будет запланирован на узле (Емкость ресурсов = общее количество альтернативных ресурсов узла — сумма требуемых ресурсов (ЦП и памяти) всех контейнеров с существующими подами в узле.) -
После того, как узлы-кандидаты, отвечающие требованиям, отфильтрованы,
优选策略
Подсчитайте оценку для каждого узла-кандидата, затем отсортируйте эти узлы-кандидаты, и побеждает тот, у кого наивысшая оценка. Например, чтобы распределить рабочую нагрузку по системе, эти политики предпочтений выбирают узел с наименьшим потреблением ресурсов из списка узлов-кандидатов. Когда каждый узел проходит стратегию оптимизации, он вычисляет балл, вычисляет каждый балл и, наконец, выбирает узел с наибольшим баллом в качестве предпочтительного результата.
Как только подходящий узел найден, Планировщик создаетBinding
объект, объектName
а такжеUid
соответствует Pod и егоObjectReference
поле содержит имя выбранного узла, за которым следуетPOST
проситьотправить на аписервер.
Когда kube-apiserver получает этот объект Binding, он регистрирует объектдесериализоватьи обновите следующие поля в ресурсе Pod:
- Буду
NodeName
Значение установлено в NodeName в ObjectReference.
- Добавьте соответствующие примечания.
- Буду
PodScheduled
изstatus
Значение установлено на Истина. Вы можете просмотреть его с помощью kubectl:
$ kubectl get <PODNAME> -o go-template='{{range .status.conditions}}{{if eq .type "PodScheduled"}}{{.status}}{{end}}{{end}}'
После того, как Планировщик назначит Pod узлу, узелKubelet
Pod будет принят, и начнется развертывание.
Как стратегия предварительного выбора, так и предпочтительная стратегия могут быть пропущены через
--policy-config-file
Параметры для расширения, если планировщик по умолчанию не соответствует требованиям, вы также можете развернуть собственный планировщик. еслиpodSpec.schedulerName
настроен на другой планировщик, Kubernetes перенаправит планирование Pod этому планировщику.
6. Kubelet
Синхронизация модуля
Теперь, когда все контроллеры сделали свою работу, давайте подведем итоги:
- HTTP-запрос проходит этапы аутентификации, авторизации и контроля доступа.
- Ресурсы Deployment, ReplicaSet и три Pod сохраняются в хранилище etcd.
- Затем запускается серия инициализаторов.
- Наконец, каждый модуль назначается соответствующему узлу.
Однако все изменения состояния до сих пор были только для записей ресурсов, хранящихся в etcd, следующие шаги включают распределение запущенных подов между рабочими узлами, что является ключевым фактором в распределенных системах, таких как Kubernetes. Эти задачиKubelet
Компоненты готовы, приступим!
В кластере Kubernetes на каждом узле узла запускается служебный процесс Kubelet, который используется для обработки задач, отправляемых на узел планировщиком, и управления жизненным циклом пода, включая монтирование томов, ведение журнала контейнеров, сборку мусора и т. д. и другие события, связанные с модулями.
Если вы измените свой образ мышления, вы можете думать о Kubelet как об особом типе контроллера, который переходит к kube-apiserver каждые 20 секунд (можно настроить).NodeName
Получите список модулей для запуска на вашем собственном узле. Как только он получает этот список, он обнаруживает только что добавленный модуль, сравнивая его со своим внутренним кешем, и, если есть несоответствие, он начинает синхронизировать список модулей. Разберем процесс синхронизации подробно:
-
Если Pod создается, Kubelet будетзаписать некоторые в
Prometheus
Метрики, используемые для отслеживания задержки запуска Pod в. -
затем создайте
PodStatus
Объект, представляющий состояние текущего этапа пода. Состояние пода (Phase
) — это наиболее компактная сводка Pod в течение его жизненного цикла, включаяPending
,Running
,Succeeded
,Failed
а такжеUnkown
эти значения. Процесс генерации состояния очень процедурный, поэтому необходимо глубоко понимать лежащий в его основе принцип:-
Сначала последовательно выполните серию процессоров синхронизации Pod (
PodSyncHandlers
), каждый процессор проверяет, должен ли Pod работать на этом узле. Когда все процессоры согласны с тем, что Pod не должен работать на узле, PodPhase
значение станетPodFailed
, и выселите Pod из узла. Например, когда вы создаетеJob
, если Pod терпит неудачу, время повторной попытки превышаетspec.activeDeadlineSeconds
Установите значение, Pod будет выселен из узла. -
Затем значение фазы пода определяется как
init 容器
Он определяется вместе с состоянием контейнера приложения. Поскольку контейнер в данный момент не запущен, он считаетсяв ожидании, если хотя бы один контейнер в Pod находится в фазе ожидания, егоPhase
значениеPending. -
Наконец, Pod
Condition
Поля определяются состоянием всех контейнеров в поде. Теперь наш контейнер не был создан средой выполнения контейнера, поэтомуPodReady
Статус установлен наFalse
. Вы можете просмотреть его с помощью kubectl:$ kubectl get <PODNAME> -o go-template='{{range .status.conditions}}{{if eq .type "Ready"}}{{.status}}{{end}}{{end}}'
-
-
После создания PodStatus (в Pod
status
поле), Kubelet отправляет его менеджеру состояния пода, которому поручено асинхронно обновлять записи в etcd через apiserver. -
Далее запускаем сериюобработчик допускачтобы убедиться, что Pod имеет соответствующие разрешения (включая принудительное
AppArmor
файл конфигурации иNO_NEW_PRIVS
), блоки, отклоненные контроллером допуска, останутсяPending
условие. -
Если Kubelet был запущен с
cgroups-per-qos
параметры, Kubelet создастcgroup
и реализовать соответствующие ограничения ресурсов. Это сделано для упрощения управления качеством обслуживания (QoS) модулей. -
Затем создайте соответствующие каталоги для модуля, включая каталог модуля (
/var/run/kubelet/pods/<podID>
), каталог тома пода (<podDir>/volumes
) и каталог плагинов для этого пода (<podDir>/plugins
). -
менеджер громкостиМогуустанавливать
Spec.Volumes
Соответствующий том данных, определенный в , а затем дождитесь успешного монтирования.. В зависимости от типа подключенного тома некоторые поды могут ждать дольше (например, тома NFS). -
получить с аписервера
Spec.ImagePullSecrets
все определено вSecret
, а затем введите его в контейнер. -
Наконец, через интерфейс среды выполнения контейнера (
Container Runtime Interface(CRI)
), чтобы запустить контейнер (подробно описано ниже).
CRI и контейнер паузы
На данном этапе выполнена большая работа по инициализации, контейнер готов к запуску, и контейнер запускаетсясреда выполнения контейнера(НапримерDocker
а такжеRkt
) активируется.
Для упрощения расширения Kubelet был принят с версии 1.5.0.Интерфейс среды выполнения контейнераВзаимодействие со средой выполнения контейнера. Короче говоря, CRI предоставляет абстрактный интерфейс между Kubelet и конкретной средой выполнения, через которыйбуфер протокола(это как более быстрый JSON) иgRPC API(API, который отлично подходит для выполнения операций Kubernetes). Это действительно крутая идея: благодаря использованию контрактных отношений, определенных между Kubelet и средой выполнения, конкретные детали реализации того, как организован контейнер, становятся неактуальными. Поскольку нет необходимости изменять основной код Kubernetes, разработчики могут добавлять новые среды выполнения с минимальными затратами.
Извините, что немного не по теме, вернемся к этапу запуска контейнера. При первом запуске Pod Kubelet пройдетRemote Procedure Command
вызовы протокола (RPC)RunPodSandbox.sandbox
Используется для описания набора контейнеров, например, в Kubernetes это означает Pod.sandbox
— это широкое понятие, поэтому оно по-прежнему имеет смысл для других сред выполнения, не использующих контейнеры (например, вhypervisor
среда выполнения, песочница может относиться к виртуальной машине).
Среда выполнения контейнера, используемая в нашем примере, — это Docker, первое, что создается при создании песочницы, — этоpause
контейнер. Контейнер паузы выступает в качестве базового контейнера для всех других контейнеров в том же поде.Он предоставляет большое количество ресурсов уровня пода для каждого бизнес-контейнера в поде, которые являются пространствами имен Linux (включая сетевое пространство имен, пространство имен IPC и именование PID). ) пространство).
Контейнеры pause предоставляют способ управления всеми этими пространствами имен и позволяют бизнес-контейнерам совместно использовать их. Преимущество нахождения в одном и том же сетевом пространстве имен заключается в том, что контейнеры в одном модуле могут использоватьlocalhost
общаться друг с другом. Вторая функция контейнера паузы связана с тем, как работает пространство имен PID.В пространстве имен PID между процессами формируется древовидная структура.Как только дочерний процесс становится «процессом-сиротой» из-за ошибки родительского процесса, его бытьinit
Процессы принимают и в конечном итоге восстанавливают ресурсы. Для получения дополнительной информации о том, как работает пауза, см.:The Almighty Pause Container.
После создания контейнера паузы следующим шагом будет проверка состояния диска и запуск бизнес-контейнера.
CNI и сеть Pod
Теперь у нашего пода есть базовый скелет: контейнер паузы, который использует все пространства имен, чтобы бизнес-контейнеры могли взаимодействовать в одном поде. Но вот еще вопрос, а как устроена сеть контейнера?
Когда Kubelet создает сеть для пода, он делегирует задачу создания сетиCNI
плагин. CNI расшифровывается как Container Network Interface, и, подобно тому, как работает среда выполнения контейнера, это также абстракция, которая позволяет различным сетевым провайдерам предоставлять различные сетевые реализации для контейнеров. Добавив файл конфигурации json (по умолчанию в/etc/cni/net.d
путь) к соответствующему двоичному файлу CNI (по умолчанию в/opt/cni/bin
path), плагин cni может настроить соответствующую сеть для контейнера паузы, а затем другие контейнеры в поде будут использовать сеть контейнера паузы. Вот простой пример файла конфигурации:
{
"cniVersion": "0.3.1",
"name": "bridge",
"type": "bridge",
"bridge": "cnio0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"ranges": [
[{"subnet": "${POD_CIDR}"}]
],
"routes": [{"dst": "0.0.0.0/0"}]
}
}
Плагин CNI также пройдетCNI_ARGS
Переменные среды указывают дополнительные метаданные для модуля, включая имя модуля и пространство имен.
Приведенные ниже шаги зависят от плагина CNI, мы начинаем сbridge
Пример плагина:
-
Плагин сначала устанавливает локальный мост Linux в корневом сетевом пространстве имен (то есть в сетевом пространстве имен хоста) для предоставления сетевых услуг всем контейнерам на этом хосте.
-
Затем он поставит сетевой интерфейс (
veth
пара устройств) в сетевое пространство имен контейнера паузы и подключите другой конец к мосту. Вы можете думать о паре устройств veth следующим образом: это как длинный канал, один конец которого подключен к контейнеру, другой конец подключен к пространству имен корневой сети, и пакеты распространяются по каналу. -
Далее указывается в файле json
IPAM
Плагин назначит IP-адрес сетевому интерфейсу контейнера паузы и установит соответствующий маршрут, и теперь у Pod есть свой собственный IP-адрес.- Плагин IPAM работает аналогично плагину CNI: он вызывается через бинарный файл и имеет стандартизированный интерфейс.Каждый плагин IPAM должен определять IP, подсеть, шлюз и маршрут сетевого интерфейса контейнера и возвращать информацию в плагин CNI. Самый распространенный плагин IPAM:
host-local
, который назначает IP-адреса контейнерам из предопределенного набора пулов адресов. Он сохраняет информацию о пуле адресов и информацию о распределении в файловой системе хоста, тем самым обеспечивая уникальность IP-адреса каждого контейнера на одном хосте.
- Плагин IPAM работает аналогично плагину CNI: он вызывается через бинарный файл и имеет стандартизированный интерфейс.Каждый плагин IPAM должен определять IP, подсеть, шлюз и маршрут сетевого интерфейса контейнера и возвращать информацию в плагин CNI. Самый распространенный плагин IPAM:
-
Наконец, Kubelet будет
DNS
сервераCluster IP
Адреса передаются подключаемому модулю CNI, а подключаемый модуль CNI записывает их в контейнер/etc/resolv.conf
в файле.
Как только вышеуказанные шаги будут выполнены, плагин CNI вернет результат операции в Kubelet в формате json.
Межхостовая контейнерная сеть
До сих пор мы описали, как контейнеры взаимодействуют с хостом, но как контейнеры взаимодействуют между хостами?
Обычно используетсяoverlay
сеть для обмена контейнерами между хостами, метод динамической синхронизации маршрутов между несколькими хостами. Один из наиболее часто используемых плагинов оверлейной сети — этоflannel
, конкретный метод работы фланели может относиться кДокументация для CoreOS.
запуск контейнера
После того, как все сети настроены, следующим шагом будет фактический запуск бизнес-контейнера!
После того, как песочница завершила инициализацию и находится вactive
состояние, Kubelet может начать создавать для него контейнеры. первыйЗапустите контейнер инициализации, определенный в PodSpec., а затем запустите бизнес-контейнер. Конкретный процесс выглядит следующим образом:
- Сначала вытащите образ контейнера. Если это образ частного репозитория, он будет использовать секрет, указанный в PodSpec, для извлечения образа.
- Затем контейнеры создаются через интерфейс CRI. Kubelet заполняет PodSpec
ContainerConfig
структура данных (где определяются команды, изображения, метки, смонтированные тома, устройства, переменные среды и т. д.), затем передаетсяprotobufs
Отправлено на интерфейс CRI. Для Docker он десериализует и заполняет эту информацию своей собственной информацией о конфигурации, прежде чем отправлять ее вDockerd
демон. Во время этого процесса он добавит в контейнер некоторые теги метаданных (например, тип контейнера, путь к журналу, идентификатор дандбокса и т. д.).
- Далее мы будем использовать диспетчер ЦП для ограничения контейнеров — новая альфа-функция, добавленная в Kubelet 1.8, которая использует
UpdateContainerResources
Метод CRI назначает контейнер пулу ресурсов ЦП на этом узле.
- Наконец контейнер действительно запускаетсязапускать.
- Если в поде настроены хуки жизненного цикла контейнера (хуки), они будут запускаться после запуска контейнера.
Hook
. Тип крючка включает в себя два типа:Exec
(выполняет команду) иHTTP
(отправить HTTP-запрос). Если хук PostStart запускается слишком долго, зависает или дает сбой, контейнер никогда не станетrunning
условие.
7. Резюме
Если все прошло хорошо, теперь у вас должно быть три контейнера, работающие в вашем кластере, со всеми сетями, томами данных и ключами, добавленными в контейнеры через интерфейс CRI и успешно настроенными.
Блок-схема всего процесса создания пода, описанного выше, выглядит следующим образом:
Процесс создания пода в Kubelet