Это шутливая статья, не стоит ее воспринимать серьезно.
Источником вдохновения выступила статья и высказывание в чатике kubernetes_ru, а также дискуссия на эту тему с Дмитрием Евдокимовым из luntry, а триггером к написанию - пост Дмитрия.
client-go - наше все
На самом деле, большая часть магии куба находится в этом пакете. Используют контроллеры, kube-apiserver, kubelet. Что неудивительно, если посмотрим в описание на гитхабе, то увидим следующий список, что включено в данный пакет:
The kubernetes package contains the clientset to access Kubernetes API.
The discovery package is used to discover APIs supported by a Kubernetes API server.
The dynamic package contains a dynamic client that can perform generic operations on arbitrary Kubernetes API objects.
The plugin/pkg/client/auth packages contain optional authentication plugins for obtaining credentials from external sources.
The transport package is used to set up auth and start a connection.
The tools/cache package is useful for writing controllers.
Но самая мощь, по моему мнению - это informers. Более подробно можно почитать здесь, если коротко, это подход который позволяет избегать continuous polling к API, иначе это могло бы привести к деградация нашего кластера.
Если посмотрим на первый пункт что произойдет когда сделаем kubectl apply - то увидим, что сперва производится валидация данных, перед тем как отправить запрос, если валидация прошла успешно - отправляется запрос и получает OpenAPI schema которая хэшируется, чтобы меньше нагружать как kube-apiserver, так и etcd.
Это подход называется client-side caching, и используется, например, в redis.
Но не забываем, что client-go есть в kube-apiserver, а так же имеется пакет cacher, задача которого - кэшировать ответы, чтобы не нагружать сторадж. Если интересно чуть более подробнее почитать, то можно это сделать здесь. Это уже server-side caching.
Таким образом мы получаем распределенную систему хранения кэша, то есть по сути своей - распределенную in-memory database.
в кубе все YAML-манифесты?
А так ли это? На самом деле kubernetes ничего не знает про YAML. Это лишь упрощенный способ людей визуализировать схему данных которая хранится в etcd (не только, но об этом позже). С YAML умеет работать cli. Cli уже валидирует, а затем и генерит данные в формате OpenAPI schema. Вот с ним уже kube-apiserver и работает. Эту схему мы уже можем поменять, через изменение CRD.
Если посмотреть на порядок обновления компонентов в kubernetes, то можно заметить, что первым будет обновляться etcd, потом kube-apiserver, а затем уже сильно не важно что, и в каком порядке (утрирую). А почему так? Потому что необходимы наши любимые миграции. Есть KEP на эту тему.
Таким образом у нас особо нет особой привязки к yaml-манифестам. Мы не перемещаем YAML-файлы для обновления kubernetes. А работаем по тем же правилам, как и с обычной базой данных.
ETCD - это же база данных, причем тут kubernetes?
ETCD довольно простая k-v база данных. В ней нет очередей, нет поисков по лейблам. Если интересно про ETCD, рекомендую вот эту и эту статьи. Я бы сказал бы, что ETCD для kubernetes - это движок, который еще умеет данные реплицировать (на самом деле у ETCD движок bbolt, но я намеренно упрощаю). Такой упрощенный аналог leveldb/rockdb для kuberntes. Еще одним доказательством, что ETCD для kubernetes - это движок, является проект kine. Для нас, как пользователей работы с БД, ничего не меняется. Мы так же взаимодействуем с API, меняем схемы через CRD и так далее. Меняется только способ хранения данных, скрытый от нас под капотом (а под капотом, обычно, находится двигатель))).
В ETCD на запись мы всегда упираемся в лидера. И нам нужно как-то эту запись скейлить. Сам ETCD в шардирование не умеет. Таким образом, в ETCD отсутствуют много разных вещей, которые бы упрощали нам работу в нагруженных и распределенных системах.
И тут нам на помощь приходит kube-apiserver. Использование версионирования, поиск по лейблам, полям, объектам - со всем этим умеет работаеть kube-apiserver.
Необходим шардинг? опция --etcd-servers-override в kube-apiserver позволяет нам в рамках нашего кластера использовать более одного ETCD кластера (в моей практике, чаще всего приходилось выделять отдельные ETCD для /events и для CNI). Таким образом мы можем скейлить наш кластер и на запись.
Вообще, данная схема c "умным" api gateway, который умеет в service discovery, кэширование и так далее, используется во многих распределенных базах данных, например в spanner похожее поведение у location proxy, в cockroach - proxy pod (не тот pod что в kubernetes))), ydb - grpc proxy c query движком.
Так что kubernetes вполне проходит утиный тест как распределенная база данных - если нечто выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, и есть утка.
Кстати, если интересна тема с распределёнными базами данных, то рекомендую курс Романа Липовского. Cмотрел данный курс с большим удовольствием.