Foundation of Kubernetes

https://github.com/amorozov87/kubernetes-traning

Kubernetes quick start #

K8S - opensource система оркестрации контейнеров

Основная задача - распределять (по нодам) и менеджить контейнеры с приложениями

Предоставляет:

  • service discovery
  • load balancing
  • autoscaling (как приложения, так и самого кластера)
  • HA
  • декларативный механизм обновлений полезной нагрузки

Контроллер - демон, следящий за состоянием некоторого объекта, например приложения, которое задеплоили

Conceptions #

  • nodes - узлы кластера
    • master - нода, на которой задеплоен control plane
    • worker - нода с бизнес приложениями
  • namespace - виртуальное кластерное пространство внутри одного кластера; нужен для логического разделения задеплоенных приложений
  • pods - базовая сущность кластера, абстракция над одним или несколькими контейнерами
  • controllers
    • controller manager - основной контроллер кластера, входящий в control plane
    • operator - кастомный контроллер; пишется самостоятельно
  • labels
  • volumes
  • jobs - одноразово запущенный контейнер, который будет рестартоваться только если процесс завершился с ненулевым кодом выхода (обычный контейнер будет рестартоваться при любом завершении процесса)
  • kubectl - утилита управления кластером

Кластерная роль затрагивает весь кластер. Простая роль доступна только в том неймспейсе, в котором она создана.

Роль даёт права на выполнение каких-либо действий (внутри неймспейса)

Правили роли:

  • verbs - действия, которые мы можем выполнять
  • apiGroups - каждая сущность кластера имеет собственное API (пустое значение означает, все существующие группы)
  • resources - ресурсы кластера, к которым можно применять перечисленные действия

Роли могут наследовать правила

Kubernetes cluster architecture #

  • master - содержит весь control plane
    • etcd - KV db, содержит весь стейт кластера; работает по принципу кворума, поэтому должно быть нечетное количество экземпляров
    • API server - центральное звено, все запросы идет через него; для настройки HA требуется внешний балансер, так как kubelet не может смотреть в несколько API серверов
    • Scheduler - отвечает за распределение подов по кластеру; *
    • Controller Manager - следит за работой компонентов control plane; *
  • worker node
    • Container engine, например Docker
    • Kubelet - агент, общается с API сервером и управляет подами на локальной ноде; ответственен за то, чтобы состояние рабочей нагрузки соответствовало тому, что указано для нее на API сервере
    • Kubernetes proxy - отвечает за сетевое взаимодействие внутри кластера

* - умеют самостоятельно выбирать лидера в HA-режиме

Основная сетевая концепция Kubernetes - любой под должен быть доступен для любого другого пода напрямую, без участия NAT`а

Deployment exposed #

Namespace #

Создавался для разграничение энвайроментов с большим количеством пользователей.

Ресурсы уникальны в рамках неймспейса.

Обладает своими квотами.

kubectl completion -h                   # добавление автодополнения

kubectl get ns                          # список неймспейсов
kubectl create ns $NS_NAME              # создание неймспейса

kubectl edit clusterrole $ROLE_NAME     # редактирование роли

Deployment #

Сущность, которая отвечает за абстракцию над задеплоеным приложением

Предоставляет декларативные механизмы апдейтов для подов и replicaSet`ов

меняет актуальное состояние на декларированное

использование дейлойментов - best practice, так как при создании отдельных подов, отсутствует автоматический механизм контроля за его состоянием

при обновлении дейплоймента создается новый replicaSet и появляется возможность быстро откатиться к предыдущему состоянию

Deployment workflow:

YAML\JSON Template -> Deployment -> ReplicaSet -> Pod -> Containers
kubectl create deployment deploymentName --image=imageName
kubectl delete deployment deploymentName

Deployment use cases #

  • развернуть replicaSet
  • задекларировать новое состояние для подов
  • откатиться на более раннюю версию деплоймента
  • масштабировать дейлоймент
  • приостановить деплоймент для применения множественных фиксов (вероятно не применяется на практике)
  • просмотр статуса деплоймента

Pods and Containers #

  • базовый “строительный блок” кластера

  • абстракция над одним или несколькими контейнерами

  • всегда имеет уникальный в пределах кластера IP-адрес

  • контейнеры в рамках одного пода:

    • всегда расположены на одной ноде
    • имеют единый сетевой неймспейс, соответственно всегда общаются напрямую друг с другом

Init containers #

Специализированный контейнер, который стартует перед контейнером с приложением

  • могут содержать и запускать дополнительные утилиты, которые не желательно включать в основной контейнер с приложением (например по соображениям безопасности)
  • предоставляют механизм контролируемой задержки старта основного контейнера

Services (discovery) #

Это абстракция, которая определяет логический набор подов и политики доступа к ним. Поды определяются по лейблам.

Типы сервисов:

  • Normal - имя сервиса резолвится в IP кластера
  • Headless - резолвится напрямую в IP-адрес пода

Пример сервиса:

kind: Service
apiVersion: v1
metadata:
  name: nginx-service
spec:
  clusterIP: None     # для создания headless сервиса
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

В качестве протоколов поддерживаются TCP (по умолчанию) и UDP

Сервис без селектора нужен для того чтобы K8S мог ссылаться на внешние объекты. Примеры использования:

  • использование внешней БД в проде и внутренней в тесте
  • использование сервиса в другом неймспейсе
  • миграция нагрузки с K8S на сторонние бакенды

Для такого сервиса EndPoint не будет создан автоматически.

Способы открыть доступ к сервису:

  • ClusterIP
    • открывает доступ по внутреннему кластерному IP
    • соответственно, в этом случае сервис доступен только внутри кластера
    • дефолтный тип
  • NodePort
    • открывает доступ к сервису по адресу ноды на статическом порте
    • с ним можно общаться снаружи
    • ${NodeIP}:${NodePort}
  • LoadBalancer
    • открывает доступ к сервису снаружи с использованием LA, предоставляемого облачным провайдером
kubectl patch...        # обновление ресурсов

Ingress #

  • Предоставляет доступный извне URL
  • Балансирует трафик (RR)
  • Терминирует SSL-соединение
  • предоставляет основанный на именах виртуальный хостинг
  • требует наличия Ingress-контроллера (одна из имплементаций - NGINX)

Типы ингрессов:

  • Single service ingress
  • Simple fanout
  • Name based virtual hosting

Running you app #

Dry run #

Опция kubectl, которая только печатает объект, который должен был бы быть отправлен.

kubectl create deployment deploymentName --image=imageName --dry-run=true
kubectl create deployment deploymentName --image=imageName --dry-run=true -o yaml > deployment.yaml # пример создания файла деплоймента

Using env vars #

При создании пода можно установить переменные окружения, которые будут переданы в контейнер.

spec:
  containers:
    ...
    env:
    - name: DEMO_KUBERNETES
      value: "Hello from k8s"

Также можно передавать в переменные окружения информацию о самом контейнере:

  • metadata.name
  • metadata.namespace
  • metadata.labels
  • metadata.annotations
  • spec.nodeName
  • spec.serviceAccountName
  • status.hostIP
  • status.podIP
spec:
  containers:
    ...
    env:
    - name: MY_NODE_NAME
      valueFrom:
        fieldPath:
          fieldPath: metadata.name

Commands and arguments #

Аналог ENTRYPOINT и CMD инструкций Docker. Задаются в полях command и args конфига. Не могут быть изменены после того, как Под был создан.

Перетирают дефолтные команды и аргументы, которые указаны при сборке образа.

Если указаны только аргументы, дефолтная команда из образа будет использована с новыми аргументами.

DescriptionDocker fieldKubernetes field
Команда, которая будет запущена контейнеромEntrypointcommand
Аргументы, которые будут переданы командеCmdargs
Image EntrypointImage CmdContainer commandContainer argsCommand run
[/ep1][foo bar][ep-1 foo bar]
[/ep1][foo bar][/ep-2][ep-2]
[/ep1][foo bar][zoo boo][ep-1 zoo boo]
[/ep1][foo bar][/ep-2][zoo boo][ep-2 foo bar]

Scheduling #

Механизмы распределения Подов:

  • все механизмы используют лейблы
  • Node Selector (позволяет указать, что деплоймент должен быть размещен на ноде с определенным лейблом; устаревший)
    • можно объединять несколько лейблов
spec:
  nodeSelector:
    labelName: labelValue
  • Node affinity and anti-affinity (похож на первый, но более гибкий)
    • позволяет операции над лейблами:
      • And
      • In
      • NotIn
      • Exists
      • DoesNotExists
      • Gt
      • Lt
    • правила бывают:
      • soft/preferred - предпочтение отдаётся нодам с указанными лейблами, но если они недоступны, под будет задеплоен на любую доступную ноду
      • hard/required - требуется полное соответствие лейблам
    • все правила применяются только в момент деплоя пода, позднейшие изменения не будут иметь эффекта, пока под не будет передеплоен
    • под может быть задеплоен на ноду, если одно из условий nodeSelectorTerms удовлетворено
    • –--, если все условия matchExpressions были удовлетворены
spec:
  ...
  spec:
    affinity:
      requiredDuringSchedulingInnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: lableName
            operator: In
            values:
            - labelValue
  • inter-pod affinity and inti-affinity
    • аналогично, но с подами, а не с нодами
    • вариант применения - исключить деплой реплик приложения на одну ноду
  • Taints
    • имеет:
      • ключ
      • значение
      • эффект
        • NoSchedule
        • PreferNoSchedule
        • NoExecute
  • Tolerations
    • имеет:
    • ключ
    • значение
    • оператор
      • Exists
      • Equal
    • эффект

Image pull policies #

  • ifNotPresent(DEFAULT) - скачивает образ, если его нет в локальном кеше той ноды, куда приезжает приложение
  • Always(:LATEST)
  • Never

Application restarts #

  • Always (default)
  • OnFailure
  • Never

Применяется ко всем контейнерам в поде. Поды рестартуют с экспоненциальной дажержкой (10с, 20с, 40с…)

Application logs #

kubectl logs ${podName}

--\\-- --previous       # следует использовать в случае, если контейнер завалился

Если под имеет несколько контейнеров, то нужно указывать имя конкретного контейнера.

Если контейнер рестартует, k8s сохраняет один остановленный контейнер с логами.

Если под выселяется с ноды, то все относящиеся к нему контейнеры выселяются вместе с логами.

В логи пишется только stdout и stderr PID1

Application scaling #

Replica sets #

Может использовать независимо от других сущностей

Но рекомендуется использовать деплойменты, так как в этом случае, не нужно следить за жизнью контейнера

Описывает конкретное число подов с приложением, которое должно существовать в конкретный момент времени

Scaling #

  • по дефолту стартует один под
  • можно скейлить до нуля (выключение)
  • пропорциональное обновление

Autoscaling #

kubectl sutoscale deployment podName
  • предствален в виде отдельно ресурса и контроллера
  • дефолтное значение задержки 30 сек
  • собирает как ресурсные метрики, так и кастомные
  • заданный процент потреблённых ресурсов высчитывается от requests (см. ниже); если это значение не задано, работать не будет

Compute resources managing #

containers:
  ...
  resources:
    requests:
      memory: "64Mi"
      cpu: "250m"
    limits:
      memory: "128Mi"
      cpu: "500m"

Updating an application #

Deployment update #

  • Kubectl set image
kubectl run nginx --image=nginx:1.12 --replicas=3
kubectl rollout status deploy nginx
kubectl set image deploy nginx nginx=nginx:1.13
  • Kubectl edit
kubectl edit deploy nginx
kubectl rollout status nginx
  • Kubectl apply
kubectl get deploy nginx -o yaml > nginx_deploymetn.yaml
kubectl apply -f nginx_deployment.yaml
kubectl rollout status deploy nginx
  • У k8s есть политика, говорящая сколько подов может быть недоступно в ходе апдейта
  • –\–, может быть создано сверх желаемого значение
  • раскатка деплоймента стриггерится только, если поменялся сам шаблон (изменение метадаты к этому не приводит)
  • каждый раз создается новый ReplicaSet

Deployment rollouts and rollbacks #

  • Rollout
kubectl apply -f nginx_deployment.yaml --record
kubectl rollout status deploy nginx
kubectl get deployments
  • Update
kubectl set image deploy nginx nginx=nginx:1.13 --record=true
kubectl rollout status deploy nginx
kubectl get pods
  • Rollback
kubectl rollout history deploy nginx
kubectl history deploy nginx --revision=2
kubectl rollout ubdo deploy nginx

The deployment lifecycle #

  • Pregressing
    • создается новый ReplicaSet
    • поднимается новый ReplicaSet
    • тушится старый ReplicaSet
  • Complete
    • все реплики обновлены до последней версии
    • все реплики доступны
    • ни одна старая реплика не запущена
  • Failed
    • insufficient quota
    • insufficient permissions
    • readiness probe failures
    • image pull errors
    • limit ranges
    • application runtime misconfiguration

Dealing with storage #

Empty dir #

  • создается, когда под добавляется на ноду
  • существует, пока под запущен на ноде
  • изначально пустой
  • может быть смонтирован по тому же или отличающемуся пути
  • когда под (по любой причине) удаляется с ноды, данные их emptyDir удалятся безвозвратно
spec:
  containers:
  ...
  volumeMounts:
  - mountPath: /cashe
    name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

Host path #

  • монтирует директорию с хостовой машины
  • может вести себя по разному на различных нодах (поэтому не рекомендуется в проде)
  • нужны привелегии для использования

Git repo #

  • монтирует пустую директорию и клинирует в нее репу

Persistent volumes #

  • абстракция над работой с хранилищем
  • может быть запровиженен как автоматически, так и администратором
  • PersistentVolumeClaim (PVC) - запрос на хранилище со стороны пользователя
  • StorageClass - механизм автоматического привиженинга

Application configuration #

Configmap #

Объект k8s, предоставляющий механизм хранения KV данных.

Может быть использована как:

  • аргумент командной строки
  • переменна окружения
  • файл в волюме
kubectl create configmap nginx-config --from-file=/path/to/dir # k - имя файла, v - содержимое файла

kubectl create configmap nginx-config --from-file=/path/to/file # k - имя файла, v - содержимое файла
kubectl create configmap nginx-config --from-file=${myKeyName}=/path/to/file

kubectl create configmap nginx-config --from-literal=someKey=someValue

Директивы –from-file и –from-literal можно совмещать.

Использование:

  • env var:
    • from a single ConfigMap
    • from multiple ConfigMaps
  • in pod commands:
    • echo ${KEY_NAME} (правда нужно предварительно создать переменную окружения)
  • volume:
    • монтирование тома с данными, сохраненными в ConfigMap
    • добавление ключей ConfigMap в конкретный путь на томе

Secrets #

Аналогично, но хранится в зашифрованном виде

Ограничения:

  • должны быть созданы до пода
  • должны быть созжаны в том же неймспейсе
  • каждый секрет не может быть больше 1 мб

Jobs and daemons #

Jobs #

  • отдельный ресурс со своим контроллером
  • создает один или несколько подов, обеспечивая успешное выполнение указанной в образе команды
  • как только задача успешно завершается, удаляются все поды, относящиеся к ней
  • если задача завершается с ненулевым кодом ответа, под рестартуется (с экспоненциальной задержкой)
  • поды могут выполнять задачу параллельно

Daemons sets #

  • обеспечивают запуск одному экземпляру пода на каждой (или некоторых) нодах
  • если в кластер будет добавлена новая нода, приложение приедет и на нее (с учетом всех ограничений шедулинга)
  • удаление Daemon set приведет к удалению всех подов

Примеры использования:

  • storage daemon (glusterfs, ceph, etc)
  • агенты агрегатора логов
  • мониторинг агенты

Stateful applications #

  • StatefulSet - разрабатывался для обслуживания stateful приложений и распределенных систем
  • предоставляет гарантии очередности старта подов
  • каждый под представляет из себя уникальный объект
  • спецификации подов такие же как в деплойменте, но поды не взаимозаменяемые
  • каждый под имеет собственное не шареное хранилище
  • каожый под имеет уникальное имя вида ${StatefulSetName}-${Ordinal}

Ограничения:

  • удаление не удаляет хранилища
  • требует Headless сервис, так как обычно распределенные приложения плохо работают с прокси

Политики управления подами:

  • OrderedReady (default)
  • Parallel

Стратегии обновления:

  • On Delete
  • Rolling Updates
  • Partitions