Итак повторим: Kubelet - управляет pod-ами, общается с api-server-ом для этого. При этом именно api-server и передаём kubelet задачи: "Разверни мне pod". И api-server передаёт kubelet файл createMyApp.yaml, kubelet взаимодействует с container runtime, с сетевыми плагинами и создаёт pod на основе createMyApp.yaml файла Pod.
Api-server это компонент, который живёт на Master-ноде, и является единой точкой для общения с кластером.
Любой компонент кластера, который хочет что-либо сделать - он общается с api-server-ом (REST, https).
API server - точка входа для всех взаимодействий компонентов kubernetes.
Но это не укладывается в концепцию "отсутствия единой точки отказа". Но Master-нод может быть много, и api-server-ов таким образом может быть много.
А что делает api-server? Он проверяет конфигурации и конфигурирует api-объекты (pods, services и т.д.)
Когда kubelet общается с api-server-ом, то он получает от api-server-а информацию в виде yaml (json) файла, kubelet и отвечает также yaml (json).
Всё что компоненты сказали api-server-у, он сохраняет в etcd.
etcd - это key-value хранилище.
Ещё один важным компонент, который живёт на Master-ноде, это kube-controller-manager.
Kube-api-server, etcd, kube-controller-manager - это просто контейнеры, которые запускаются на Master ноде.
Kube-controller-manager состоит из абстракций, называемых контроллерами. Они постоянно сравнивают текущее состояние кластера с желаемым.
Откуда они берут текущее состояние? Текущее состояние им даёт kubelet.
C Worker-нод kubelet-ы передают информацию о том, что там происходит. Эта вся информация через api-server попадает в etcd, и туда же через api-server идёт controller-manager и узнаёт текущее состояние кластера.
В etcd сохраняются два знания:
- О том как дела у кластера.
- И как админ хочет, чтобы были дела у кластера.
И контроллер сравнивает эти два состояния: текущее и желаемое, и принимает решение, кому передать команду, чтобы привести состояние кластера к желаемому.
Вот в этом месте на сцену выходит ещё один компонент kube-scheduler.
Kube-scheduler - это компонент, который управляет вычислительными ресурсами.
Во-первых, он учитывает какие ресурсы есть.
- Пришла новая нода в кластер, запустился на ней kubelet - "я новенький, загрузка слабая, оперативки не меряно".
- Kube-scheduler - "хорошо, имеем новую ноду, с такими-то характеристиками"
Во-вторых, он ведёт учёт требований к ресурсам.
- Так смотри, админ запустил сейчас вот этот контейнер.
- Он хочет, чтобы контейнеру сразу дали 1 Гбайт оперативки с возможностью расширения до 4 Гбайт.
Kube-scheduler отмечает себе - вот этот контейнер в максимуме может занять вот столько оперативной памяти, в минимуме вот столько. И принимает решение, куда эту нагрузку раскладывать.
В-третьих kube-scheduler учитывает ограничения по ресурсам (affinity, anti-affinity)
Master-ноды отличается от worker-нод тем, что они имеют различные пометки, что туда нельзя класть обычную нагрузку. И Master-ноды крутят в себе только компоненты kubernetes.
А ваши контейнеры с приложениями не могут запускаться на Master-ноде. Это для того, чтобы избежать влияния Applications (ваших приложений) на Master-ноду. Высокая нагрузка на Master-ноду может приводить к печальным последствиям.
В итоге kube-scheduler решает, где запустить контейнер. При этом вариант "не могу запустить" - это тоже решение.
Не следует ожидать, что Master будет "помирать", но "тащить" нагрузку. Если вы захотите запустить контейнер, которому требуется 30 Гбайт оперативки, а в наличии только 2, то ваш контейнер нигде не запустится.
Потому, что kube-scheduler скажет, что на 30 гигов у него ничего нет. И сделает пометку, что этот контейнер запустить не может. И пойдёт по своим делам.
Это не значит, что kube-scheduler не пересмотрит своё решение. Когда появится нода с 30 Гбайтами оперативки, kube-scheduler "вспомнит" и запустит контейнер, которому требовалось 30 Гбайт.
Kube-scheduler не допустит, чтобы стало совсем плохо.