Kubernetes Control Plane

Alex WolfAlex Wolf
7 min read

В кластере 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.

Особенности.

  1. Это единственнный компонент кластера, который имеет интерфейс для операций, связанных с БД ETCD;

  2. Принимает запросы на порту 6443;

  3. Поддерживает AAA;

  4. Типы поддерживаемых запросов к базе: хранение и извлечение;

  5. Взаимодействие с API Server, со стороны пользователя, осуществляется посредством REST API;

  6. Взаимодействие с ETCD строится с помощью gRPC;

  7. Взаимодействие с kubelet, scheduler, controller manaer строится с помощью protobuf;

  8. При увеличении нагрузки может горизонтально массштабироваться.

Стандартный манифест выглядит так:

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 хранятся:

  1. Состояние кластера;

  2. Cпецификации объектов, которые работают в кластере.

Отказоустойчивый кластер etcd.

  • Используется 3 или 5 мастеров. Более не имеет особого смысла;

  • Общение между экземплярами etcd происходит по протоколу RAFT;

  • Для передачи сообщений используется gRPC.

В отказоустойчивом кластере etcd только один мастер работает на запись. Другие работают только на чтение. Читающие экземпляры постоянно синхронизируются с пишущим экземпляром etcd.

Особенности.

  1. Сильно зависит от скорости дисков на которых он крутится и ширины полосы пропускания сети. Если скорость дисков или ширина канала будут маленькими, то есть риск того, что сабкластер etcd развалится. Что приведет к падению и k8s кластера;

  2. Слушает порты 2379 и 2380;

  3. Взаимодействует только с 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 учитывает множество параметров:

  1. Какие ресурсы нужны контейнеру(ам) в поде для их запуска на ноде;

  2. Есть ли необходимые для запуска контейнеров из пода ресурсы на ноде кластера;

  3. Требуется ли для работы контейнера специальное оборудование, вроде GPU;

  4. Не помечены ли ноды taint и есть ли соответствующий toleration у пода;

  5. Используется ли в манифесте пода podAffinity/podAntiAffinity;

  6. Используется ли в манифесте пода nodeName/NodeSelector/nodeAffinity;

  7. Какой приоритет у пода;

  8. Какой QOS класс у пода.

Под назначается на ту ноду, которая набрала больше всего очков.

Особенности.

  1. Scheduler мониторит API Server на предмет наличия там манифестов подов без проставленного поля nodes. Его задача проставить в манифест в поле nodes имя ноды и маякнуть etcd чтобы он обновил у себя конфигурацию заданного ресурса;

  2. Scheduler при планировании пода на ноду создаёт объект класса bindings. Он связывает под с определённой нодой кластера;

  3. Поды находятся в очереди на обработку, а шедулер берёт их из очереди.

Файл манифеста дефолтного шедуллера.

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/

0
Subscribe to my newsletter

Read articles from Alex Wolf directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Alex Wolf
Alex Wolf