Kubernetes Control Plane
В кластере Kubernetes используются хосты двух типов: мастера и воркеры.
Воркеры - рабочие лошадки, на которых располагается полезная нагрузка в кластере. На мастере располагаются управляющие работой кластера приложения. Компоненты мастера также часто называют Control Plane. О компонентах мастера, обеспечивающих работу Kubernetes и поговорим далее.
На мастере работают 4 основных компонента: API Server, ETCD, Scheduler, Controller Manager. Отдельно стоит упомянуть kubelet и kube-proxy. Также есть ряд необязательных компонентов, например, node-autoscaler.
Схема взаимодействия компонентов control plane между собой и воркером.
Трафик между компонентами шифруется с помощью SSL шифрования. Сертификаты подкладываются в поды при их запуске.
При взаимодействии в кластере используются разные технологии. Схематично компоненты и их взаимодействие описано ниже.
API Server
Когда оператор или администратор кластера отправляет свой запрос в k8s, то он попадает в компонент мастера - API Server. Также через API Server происходит взаимодействие разных компонентов кластера между собой.
По своему устройству данный компонент очень сильно напоминает брокер очередей Apache Kafka.
Особенности.
Это единственнный компонент кластера, который имеет интерфейс для операций, связанных с БД ETCD;
Принимает запросы на порту 6443;
Поддерживает AAA;
Типы поддерживаемых запросов к базе: хранение и извлечение;
Взаимодействие с API Server, со стороны пользователя, осуществляется посредством REST API;
Взаимодействие с ETCD строится с помощью gRPC;
Взаимодействие с kubelet, scheduler, controller manaer строится с помощью protobuf;
При увеличении нагрузки может горизонтально массштабироваться.
Стандартный манифест выглядит так:
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.0.17.6:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=10.0.17.6
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-allowed-names=front-proxy-client
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.96.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
image: registry.k8s.io/kube-apiserver:v1.27.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 10.0.17.6
path: /livez
port: 6443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: kube-apiserver
readinessProbe:
failureThreshold: 3
httpGet:
host: 10.0.17.6
path: /readyz
port: 6443
scheme: HTTPS
periodSeconds: 1
timeoutSeconds: 15
resources:
requests:
cpu: 250m
startupProbe:
failureThreshold: 24
httpGet:
host: 10.0.17.6
path: /livez
port: 6443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
volumeMounts:
- mountPath: /etc/ssl/certs
name: ca-certs
readOnly: true
- mountPath: /etc/ca-certificates
name: etc-ca-certificates
readOnly: true
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
- mountPath: /usr/local/share/ca-certificates
name: usr-local-share-ca-certificates
readOnly: true
- mountPath: /usr/share/ca-certificates
name: usr-share-ca-certificates
readOnly: true
hostNetwork: true
priority: 2000001000
priorityClassName: system-node-critical
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/ssl/certs
type: DirectoryOrCreate
name: ca-certs
- hostPath:
path: /etc/ca-certificates
type: DirectoryOrCreate
name: etc-ca-certificates
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
- hostPath:
path: /usr/local/share/ca-certificates
type: DirectoryOrCreate
name: usr-local-share-ca-certificates
- hostPath:
path: /usr/share/ca-certificates
type: DirectoryOrCreate
name: usr-share-ca-certificates
status: {}
По пути /etc/ssl/certs находятся открытые ключи CA.
По пути /etc/kubernetes/pki находятся сгенерированные ключи для разных сущностей. В под они подключаются в виде volume.
Процесс создания пода.
ETCD
База данных типа ключ-значение. Также как и Redis. Что обуславливает очень высокую скорость работы. В etcd хранятся:
Состояние кластера;
Cпецификации объектов, которые работают в кластере.
Отказоустойчивый кластер etcd.
Используется 3 или 5 мастеров. Более не имеет особого смысла;
Общение между экземплярами etcd происходит по протоколу RAFT;
Для передачи сообщений используется gRPC.
В отказоустойчивом кластере etcd только один мастер работает на запись. Другие работают только на чтение. Читающие экземпляры постоянно синхронизируются с пишущим экземпляром etcd.
Особенности.
Сильно зависит от скорости дисков на которых он крутится и ширины полосы пропускания сети. Если скорость дисков или ширина канала будут маленькими, то есть риск того, что сабкластер etcd развалится. Что приведет к падению и k8s кластера;
Слушает порты 2379 и 2380;
Взаимодействует только с API Server посредством gRPC.
Утилита для работы с etcd.
etcdctl - утилита для работы с хранилищем etcd. Установить ее можно по следующей инструкции: https://github.com/etcd-io/etcd/releases
Примеры использования etcdctl.
./etcdctl put key1 value1
./etcdctl get key1
./etcdctl version
В k8s etcd работает в поде. Его манифест представлен ниже:
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/etcd.advertise-client-urls: https://10.0.24.3:2379
creationTimestamp: null
labels:
component: etcd
tier: control-plane
name: etcd
namespace: kube-system
spec:
containers:
- command:
- etcd
- --advertise-client-urls=https://10.0.24.3:2379
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd
- --experimental-initial-corrupt-check=true
- --experimental-watch-progress-notify-interval=5s
- --initial-advertise-peer-urls=https://10.0.24.3:2380
- --initial-cluster=controlplane=https://10.0.24.3:2380
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --listen-client-urls=https://127.0.0.1:2379,https://10.0.24.3:2379
- --listen-metrics-urls=http://127.0.0.1:2381
- --listen-peer-urls=https://10.0.24.3:2380
- --name=controlplane
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
- --peer-client-cert-auth=true
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --snapshot-count=10000
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
image: registry.k8s.io/etcd:3.5.7-0
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 127.0.0.1
path: /health?exclude=NOSPACE&serializable=true
port: 2381
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: etcd
resources:
requests:
cpu: 100m
memory: 100Mi
startupProbe:
failureThreshold: 24
httpGet:
host: 127.0.0.1
path: /health?serializable=false
port: 2381
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
volumeMounts:
- mountPath: /var/lib/etcd
name: etcd-data
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
hostNetwork: true
priority: 2000001000
priorityClassName: system-node-critical
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/kubernetes/pki/etcd
type: DirectoryOrCreate
name: etcd-certs
- hostPath:
path: /var/lib/etcd
type: DirectoryOrCreate
name: etcd-data
status: {}
В каталоге /var/lib/etcd/member/snap лежат снапшоты базы.
После того как запрос поступает в API Server, он транслируется в etcd для того чтобы получить оттуда достоверную информацию. Etcd обрабатывает запрос от api server и возвращает результат
Scheduler
Этот компонент отвечает за назначение поду определённой ноды кластера. Или это можно сформулировать по иному - выбор определённой ноды(хоста) кластера для размещения на ней пода.
Он не отвечает за реальный запуск пода. Это делает kubelet.
При подборе определённой ноды scheduler учитывает множество параметров:
Какие ресурсы нужны контейнеру(ам) в поде для их запуска на ноде;
Есть ли необходимые для запуска контейнеров из пода ресурсы на ноде кластера;
Требуется ли для работы контейнера специальное оборудование, вроде GPU;
Не помечены ли ноды taint и есть ли соответствующий toleration у пода;
Используется ли в манифесте пода podAffinity/podAntiAffinity;
Используется ли в манифесте пода nodeName/NodeSelector/nodeAffinity;
Какой приоритет у пода;
Какой QOS класс у пода.
Под назначается на ту ноду, которая набрала больше всего очков.
Особенности.
Scheduler мониторит API Server на предмет наличия там манифестов подов без проставленного поля nodes. Его задача проставить в манифест в поле nodes имя ноды и маякнуть etcd чтобы он обновил у себя конфигурацию заданного ресурса;
Scheduler при планировании пода на ноду создаёт объект класса bindings. Он связывает под с определённой нодой кластера;
Поды находятся в очереди на обработку, а шедулер берёт их из очереди.
Файл манифеста дефолтного шедуллера.
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: kube-scheduler
tier: control-plane
name: kube-scheduler
namespace: kube-system
spec:
containers:
- command:
- kube-scheduler
- --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
- --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
- --bind-address=127.0.0.1
- --kubeconfig=/etc/kubernetes/scheduler.conf
- --leader-elect=true
image: registry.k8s.io/kube-scheduler:v1.27.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 127.0.0.1
path: /healthz
port: 10259
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: kube-scheduler
resources:
requests:
cpu: 100m
startupProbe:
failureThreshold: 24
httpGet:
host: 127.0.0.1
path: /healthz
port: 10259
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
volumeMounts:
- mountPath: /etc/kubernetes/scheduler.conf
name: kubeconfig
readOnly: true
hostNetwork: true
priority: 2000001000
priorityClassName: system-node-critical
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/kubernetes/scheduler.conf
type: FileOrCreate
name: kubeconfig
status: {}
Controller Manager
Это набор, состоящий из многочисленных контроллеров в кластере k8s. Контроллеры приводят текущее состояние системы к желаемому.
К контроллерам относятся: Deployment, DaemonSet, StatefulSet, ReplicaSet, Service, Ingress, HPA, PDB, ResourceQuota, LimitRange, Job, CronJob, etc.
Ещё некоторые контроллеры:
Node controller;
Job controller;
EndpointSlice controller;
ServiceAccount controller;
Garbage Collector.
Полный список контроллеров представлен здесь:
https://github.com/kubernetes/kubernetes/blob/7c75723867e9e431da323b8cc410bab928cada17/cmd/kube-controller-manager/app/controllermanager.go#L330
Пример манифеста.
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: kube-controller-manager
tier: control-plane
name: kube-controller-manager
namespace: kube-system
spec:
containers:
- command:
- kube-controller-manager
- --allocate-node-cidrs=true
- --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
- --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
- --bind-address=127.0.0.1
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --cluster-cidr=10.244.0.0/16
- --cluster-name=kubernetes
- --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
- --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
- --controllers=*,bootstrapsigner,tokencleaner
- --kubeconfig=/etc/kubernetes/controller-manager.conf
- --leader-elect=true
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --root-ca-file=/etc/kubernetes/pki/ca.crt
- --service-account-private-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.96.0.0/12
- --use-service-account-credentials=true
image: registry.k8s.io/kube-controller-manager:v1.27.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 127.0.0.1
path: /healthz
port: 10257
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: kube-controller-manager
resources:
requests:
cpu: 200m
startupProbe:
failureThreshold: 24
httpGet:
host: 127.0.0.1
path: /healthz
port: 10257
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
volumeMounts:
- mountPath: /etc/ssl/certs
name: ca-certs
readOnly: true
- mountPath: /etc/ca-certificates
name: etc-ca-certificates
readOnly: true
- mountPath: /usr/libexec/kubernetes/kubelet-plugins/volume/exec
name: flexvolume-dir
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
- mountPath: /etc/kubernetes/controller-manager.conf
name: kubeconfig
readOnly: true
- mountPath: /usr/local/share/ca-certificates
name: usr-local-share-ca-certificates
readOnly: true
- mountPath: /usr/share/ca-certificates
name: usr-share-ca-certificates
readOnly: true
hostNetwork: true
priority: 2000001000
priorityClassName: system-node-critical
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/ssl/certs
type: DirectoryOrCreate
name: ca-certs
- hostPath:
path: /etc/ca-certificates
type: DirectoryOrCreate
name: etc-ca-certificates
- hostPath:
path: /usr/libexec/kubernetes/kubelet-plugins/volume/exec
type: DirectoryOrCreate
name: flexvolume-dir
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
- hostPath:
path: /etc/kubernetes/controller-manager.conf
type: FileOrCreate
name: kubeconfig
- hostPath:
path: /usr/local/share/ca-certificates
type: DirectoryOrCreate
name: usr-local-share-ca-certificates
- hostPath:
path: /usr/share/ca-certificates
type: DirectoryOrCreate
name: usr-share-ca-certificates
status: {}
Особенности.
- Контроллеры работают в бесконечном цикле и проверяют подведомственные ресурсы на предмет их состояния
Полезные ссылки
Controller Manager:
https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/
APIServer:
https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/
Scheduler:
https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/
https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/#scoring
ETCD:
https://etcd.io/docs/v3.5/
ETCD faq:
https://etcd.io/docs/v3.5/faq/
ETCD метрики:
https://etcd.io/docs/v3.5/metrics/
Features Gates:
https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/
Простое описание компонентов Control Plane (Habr, Флант):
https://habr.com/ru/companies/flant/articles/583660/
Как работает планировщик (Habr, Флант):
https://habr.com/ru/companies/flant/articles/335552/