## Kubernetes

1. Чем отличается Kubernetes от Openshift?

<details>
  <summary>Ответ</summary>

https://www.redhat.com/cms/managed-files/cl-openshift-and-kubernetes-ebook-f25170wg-202010-en.pdf

1. Openshift имеет более строгие политики безопасности и модели аутентификации.
2. Openshift поддерживает полную интеграцию CI/CD Jenkins.
3. Openshift имеет веб-консоль по-умолчанию. В Kubernetes консоль необходимо дополнительно устанавливать консоль.
4. В Kubernetes возможно устанавливать сторонние сетевые плагины. В Openshift используется собственное сетевое решение Open vSwitch, которое предоставляет 3 различный плагина.
5. Kubernetes может быть установлен практически на любой дистрибутив Linux. Openshift имеет ограничения на устанавливаемые дистрибутивы, преимущественно используются RH-дистрибутивы.
6. Kubernets доступен в большинстве облачных платформ - GCP, AWS, Azure, Yandex.Cloud. Openshift доступен на облачной платформе Azure и облаке от IBM.
7. По-умолчанию, в Openshift поды в кластере могут быть запущены только под обычным пользователем, чтобы запустить под под пользователем root необходимо выдать права для сервисного аккаунта. В Kubernetes по-умолчанию поды могут быть запущены по пользователем root.

</details>

2. Чем отличаются *ReplicationController* от *ReplicaSet*?

<details>
  <summary>Ответ</summary>

ReplicationController гарантирует, что указанное количество реплик подов будут работать одновременно. Другими словами, ReplicationController гарантирует, что под или набор подов всегда активен и доступен.

ReplicaSet - это следующее поколение Replication Controller. Единственная разница между ReplicaSet и Replication Controller - это поддержка селектора. ReplicaSet поддерживает множественный выбор в селекторе, тогда как ReplicationController поддерживает в селекторе только выбор на основе равенства.

</details>

3. Если на каждой ноде Kubernetes кластера нужно запустить контейнер, то какой ресурс Kubernetes вам подойдет?

<details>
  <summary>Ответ</summary>

DaemonSet является контроллером, основным назначением которого является запуск подов на всех нодах кластера. Если нода добавляется/удаляется — DaemonSet автоматически добавит/удалит под на этой ноде.

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

</details>

4. Как поды разнести на разные ноды?

<details>
  <summary>Ответ</summary>

Необходимо настроить podAntiAffinity. Данное указание определяет, что для определенных подов следует использовать их размещание на разных нодах.

</details>

5. В облаке есть 3 зоны доступности. Как сделать так, чтобы поды приложения распределились по этим зонам доступности равномерно?

<details>
  <summary>Ответ</summary>

Необходимо настроить [podAntiAffinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#an-example-of-a-pod-that-uses-pod-affinity). Либо, более новый вариант для данной задачи, настроить [topologySpreadConstraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/) с указание ключа лейбла зон.

</details>

6. Как контейнеры одного пода разнести на разные ноды?

<details>
  <summary>Ответ</summary>

Никак. Под - минимальная и неделимая сущность, Kubernetes оперирует подами, а не отдельными контейнерами. 

</details>

7. Как обеспечить, чтобы поды никогда не перешли в состояние Evicted на ноде? 

<details>
  <summary>Ответ</summary>

Когда узлу (node) кластера не хватает памяти или дискового пространства, он активирует флаг, сигнализирующий о данной проблеме. Данное действие блокирует любое новое выделение ресурсов на ноде и запускает процесс "выселения" (evicted) пода с ноды.

В этот момент kubelet начинает восстанавливать ресурсы, удаляя контейнеры и объявляя поды, как Failed, пока использование ресурсов снова не станет ниже порога "выселения".

Сначала kubelet пытается освободить ресурсы узла, особенно диск, путем удаления мертвых модулей и их контейнеров, а затем неиспользуемых образов. Если этого недостаточно, kubelet начинает выселять поды конечных пользователей в следующем порядке:

1. Best Effort.
2. Burstable поды, использующие больше ресурсов, чем запрос истощенного ресурса.
3. Burstable поды, использующие меньше ресурсов, чем запрос истощенного ресурса.

Чтобы под не был удален при "выселении", необходимо настроить политики QoS для пода как Guaranteed.

Подробнее в документации Kubernetes: [Create a Pod that gets assigned a QoS class of Guaranteed](https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/#create-a-pod-that-gets-assigned-a-qos-class-of-guaranteed)

Кроме того, можно использовать сущность кубернетиса PodDisruptionBudget, которая позволит регулировать количество вытесняемых подов и обеспчивать гарантированную доступность для конкретного микросервиса https://kubernetes.io/docs/tasks/run-application/configure-pdb/

</details>

8. За что отвечает kube-proxy?

<details>
  <summary>Ответ</summary>

Kube-proxy отвечает за взаимодействие между сервисами на разных нодах кластера.

</details>

9. Что находится на master ноде?

<details>
  <summary>Ответ</summary>

- Kube-apiserver отвечает за оркестрацию всех операций кластера.
- Controller-manager (Node controller + Replication Controller) Controller отвечает за функции контроля за нодами, репликами.
- ETCD cluster (распределенное хранилище ключ-значение) ETCD хранит информацию о кластере и его конфигурацию.
- Kube-sheduler отвечает за планирование приложений и контейнеров на нодах.

По-умолчанию на master ноде не размещаются контейнеры приложений, но данный фунционал возможно настроить.

</details>

10. Что находится на worker ноде?

<details>
  <summary>Ответ</summary>

- Kubelet слушает инструкции от kube-apiserver и разворачивает или удаляет контейнеры на нодах.
- Kube-proxy отвечает за взаимодействие между сервисами на разных нодах кластера.

На worker нодах по-умолчанию размещаются контейнеры приложений. На каждой ноде кластера устанавливается Docker или другая платформа контейнеризации (например RKT или containterd). На Master ноде также устанавливается Docker, если необходимо использовать компоненты Kubernetes в контейнерах.

</details>

11. Как установить Kubernetes?

<details>
  <summary>Ответ</summary>

1. Следовать инструкции [установки kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/).

2. Установка с [использованием kubespray](https://github.com/kubernetes-sigs/kubespray).

</details>

12. Чем отличается *StatefulSet* от *Deployment*?

<details>
  <summary>Ответ</summary>

*Deployment* - ресурс Kubernetes предназнваенный для развертывания приложения без сохранения состояния. При использовании PVC все реплики будут использовать один и тот же том, и ни один из них не будет иметь собственного состояния.

*StatefulSet* - поддерживают состояние приложений за пределами жизненного цикла отдельных модулей pod, например для хранилища. Используется для приложений с отслеживанием состояния, каждая реплика модуля будет иметь собственное состояние и будет использовать свой собственный том.

</details>

13. Что такое *операторы* в понятиях Kubernetes?

<details>
  <summary>Ответ</summary>

Операторы -- это программные расширения Kubernetes,призванное автоматизировать выполнение рутинных действий над объектами кластера при определённых событиях.

Оператор работает по подписке на события к API Kubernetes.

</details>

14. Почему *DaemonSet* не нужен scheduler?

<details>
  <summary>Ответ</summary>

DaemonSet гарантирует, что определенный под будет запущен на всех нодах кластера. При наличии DaemonSet в кластере на любой из существующих и будущих нод в кластере зарезервированы ресурсы для пода на ноде.

Здесь стоит сделать оговорку насчет того, что DaemonSet может работать не на всех нодах кластера, а на некоторых, выбранных, например, по nodeSelector. К примеру, у нас есть GPU ноды и нам нужно на все эти ноды задеплоить микросервис выполняющий вычисления на GPU.

</details>

15. В каких случаях не отработает перенос пода на другую ноду?

<details>
  <summary>Ответ</summary>

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

</details>

16. Что делает *ControllerManager*?

<details>
  <summary>Ответ</summary>

Controller выполняет постоянный процесс мониторинга состояния кластера и различных компонент.

Controller-manager (Node controller + Replication Controller) - Controller отвечает за функции контроля за нодами, репликами.

</details>

17. Администратор выполняет команду `kubectl apply -f deployment.yaml`. Опишите по порядку что происходит в каждом из узлов Kubernetes и в каком порядке.

<details>
  <summary>Ответ</summary>

Клиент kubectl обращается к мастер-серверу kube-apiserver (стандартно на порт 6443), адрес мастер сервер задан в *.config* файле. В запросе передаётся информация, которую нужно применить в кластере обращения. API-сервер обращается к etcd хранилищу, проверяет наличие конфигурации запрашиваемого ресурса. Если конфигурация в хранилище etcd есть, то API-сервер сравнивает новую конфигурацию с конфигурацией в базе данных: если конфигурация одинаковая, то изменений в кластере не происходит, клиенту отдается ответ об успешности запрашиваемого действия, если конфигурации нет в etcd, то если требуемое действие касается создания сущностей, которые требуют ресурсов кластера (создания подов, хранилища pv/pvc и т.д.), scheduler проверяет возможность размещения подов на нодах и после чего происходит создание подов, при этом controll-manager контроллирует создание нужного поличества реклик сущности. После создания трубуемой сущности, происходит запись в etcd, controll-manager продолжает отслеживать состояние сущностей на протяжении всего цикла его жизни.

</details>

18. Как выполнить обновление Kubernetes в контуре где нет интернета?

<details>
  <summary>Ответ</summary>

Предварительно с рабочего кластера с новой версией Kubernetes и доступом в Интернет необходимо скачать требуемые пакеты kubeadm и образы api, controllmanager, etcd, scheduler, kubelet, docker-ce. Скачать пакеты с разрешением зависимостей возможно командой `yumdownloader --resolve kubeadm`. Образы скачиваются локально в архив `docker save <имя_образа> > <имя_образа>`.tar.

1. Удалить приложения из кластера.
```sh
helm delete --purge all
```

2. После того, как все необходимые компоненты скачены и загружены в контур без Интернета, выполняет команду сброса kubeadm.
```
kubeadm reset
```

3. Удаляем CNI-плагин Kubernetes.
```
yum remove kubernetes-cni-plugins
```

4. Локально устанавливаем необходимые пакеты.
```
yum install ./kubernetes_packages/*.rpm
```

5. Загружаем образы сервисов Kubernetes.
```
docker load < <имя_образа>.tar
```

6. Отключаем SELinux.
```sh
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
```

7. Определяем IP адрес master сервера.
```
IP=$(ip route get 1 | awk '{print $NF;exit}')
```

8. Инициализируем кластер Kubernetes.
```
kubeadm init --apiserver-advertise-address=$IP
```

9. Далее необходимо установить CNI-плагин, например Weave.

10. Разрешить на master ноде запускать контейнеры приложения.
```
kubectl taint nodes --all node-role.kubernetes.io/master-
```

На worker ноде выполняются аналогичные действия, кроме того, что устанавливается только kubelet. При инициализации master ноды выдаётся token для подключения worker нод, его необходимо сохранить, чтобы позже включить woker ноду в кластер.

</details>

19. Чем Router в Openshift отличается от Ingress в Kubernetes?

<details>
  <summary>Ответ</summary>

Router Openshift использует haproxy, как прокси-вебсервер. Ingress как в Kubernetes, так и OpenShift может быть разным (nginx, haproxy, caddy, etc).

</details>

20. Почему для установки Kubernetes требуется отключить swap?

<details>
  <summary>Ответ</summary>

Планировщик Kubernetes определяет наилучший доступный узел для развертывания вновь созданных модулей. Если в хост-системе разрешена подкачка памяти, это может привести к проблемам с производительностью и стабильностью в Kubernetes. По этой причине Kubernetes требует, чтобы вы отключили swap в хост-системе.

</details>

21. Что такое *Pod* в Kubernetes?

<details>
  <summary>Ответ</summary>

Минимальная сущность в Kubernetes и является абстракцией над контейнерами. Pod представляет собой запрос на запуск одного или более контейнеров на одном узле.

</details>

22. Сколько контейнеров запускается в одном поде?

<details>
  <summary>Ответ</summary>

По умолчанию при запуске одного контейнера в одном поде запускается еще *pause* контейнер. Итого, в одном поде может быть запущено *n+1* контейнеров.

</details>

23. Для чего нужен *pause* контейнер в каждом поде?

<details>
  <summary>Ответ</summary>

Контейнер *pause* запускается первым в поде и создаёт сетевое пространство имен для пода. Затем Kubernetes выполняет CNI плагин для присоединения контейнера *pause* к сети. Все контейнеры пода используют сетевое пространство имён (netns) этого *pause* контейнера.

</details>

24. Чем отличается *Deployment* от *DeploymentConfig* (Openshift)?

<details>
  <summary>Ответ</summary>

https://docs.openshift.com/container-platform/4.1/applications/deployments/what-deployments-are.html

</details>

25. Для чего нужны *Startup*, *Readiness*, *Liveness* пробы? Чем отличаются?

<details>
  <summary>Ответ</summary>

Kubelet использует **Liveness** пробу для проверки, когда перезапустить контейнер. Например, Liveness проба должна поймать блокировку, когда приложение запущено, но не может ничего сделать. В этом случае перезапуск приложения может помочь сделать приложение доступным, несмотря на баги.

Kubelet использует **Readiness** пробы, чтобы узнать, готов ли контейнер принимать траффик. Pod считается готовым, когда все его контейнеры готовы.

Одно из применений такого сигнала - контроль, какие Pod будут использованы в качестве бекенда для сервиса. Пока Pod не в статусе ready, он будет исключен из балансировщиков нагрузки сервиса.

Kubelet использует **Startup** пробы, чтобы понять, когда приложение в контейнере было запущено. Если проба настроена, он блокирует Liveness и Readiness проверки, до того как проба становится успешной, и проверяет, что эта проба не мешает запуску приложения. Это может быть использовано для проверки работоспособности медленно стартующих контейнеров, чтобы избежать убийства kubelet'ом прежде, чем они будут запущены.

</details>

26. Чем отличаются *Taints* и *Tolerations* от *Node Afiinity*?

<details>
  <summary>Ответ</summary>

*Node Affinity* - это свойство подов, которое позволяет нодам выбирать необходимый под. Node Affinity позволяет ограничивать для каких узлов под может быть запланирован, на основе меток на ноде. Node Affinity требует указания nodeSelector для пода с необходимым label ноды кластера.

Типы Node Affinity:
`<Требование 1><Момент 1><Требование 2><Момент 2>
requiredDuringSchedulingRequiredDuringExecution`

| Тип \ Момент | DuringScheduling | DuringExecution |
|-|-|-|
| Тип 1 | Required | Ignored |
| Тип 2 | Preferred | Ignored |
| Тип 3 | Required | Required |

Существуют определенные операторы nodeAffinity: In, NotIn, Exists, DoesNotExist, Gt или Lt.

---

*Taints* - это свойство нод, которое позволяет поду выбирать необходимую ноду. Tolerations применяеются к подам и позволяют (но не требуют) планировать модули на нодах с соответствующим Taints.

Установить для ноды Taints:
```
kubectl taint nodes <node-name> key=value:taint-effect
```
Taint-effect принимает значения - NoSchedule, PreferNoSchedule, NoExecute.

Пример:
```
kubectl taint nodes node1 app=blue:NoSchedule
```

- NoSchedule означает, что пока в спецификации пода не будет соответствующей записи tolerations, он не сможет быть развернут на ноде (в данном примере node10).

- PreferNoSchedule— упрощённая версия NoSchedule. В этом случае планировщик попытается не распределять поды, у которых нет соответствующей записи tolerations на ноду, но это не жёсткое ограничение. Если в кластере не окажется ресурсов, то поды начнут разворачиваться на этой ноде.

- NoExecute — этот эффект запускает немедленную эвакуацию подов, у которых нет соответствующей записи tolerations.

Taints и Tolerations работают вместе, чтобы гарантировать, что поды не запланированы на несоответствующие ноды. На ноду добавляется один или несколько Taints и это означает, что нода не должна принимать никакие поды, не относящиеся к Taints.

---

Taints и Tolerations не гарантирует, что определенный под будет размещен на нужной ноде. NodeAffinity - не гарантирует, что на определенной ноде, кроме выбранных подов, не будет размещены другие поды. 

</details>

27. Чем отличаются *Statefulset* и *Deployment* в плане стратегии обновления подов Rolling Update?

<details>
  <summary>Ответ</summary>

Стратегия обновления Rolling Update в **Deployment** предполагает последовательное обновление подов: сначала будет создан новый под, затем будет переключен трафик на новый под и затем удален старый под.

Стратегия обновления Rolling Update в **StatefulSet** предполагает обновление подов в обратном порядке, то есть под сначала будет удален, а потом установлен новый.

</details>

28. Для чего в Kubernetes используются порты 2379 и 2380?

<details>
  <summary>Ответ</summary>

2379 и 2380 - порты, которые используются etcd. 
2379 используется для взаимодействия etcd с компонентами control plane. 2380 используется только для взаимодействия компонентов etcd в кластере, при наличии множества master нод в кластере.

</details>

29. Задан следующий yaml файл для создания пода Test. Как сделать так, чтобы контейнеры nginx и redis пода test были размещены разных нодах кластера при условии, что существуют лейблы нод `disk=ssd` и `disk=hard`?
```
apiVersion: v1
kind: Pod
metadata:
  name: Test
spec:
  containers:
  - name: nginx
    image: nginx
  - name: redis
    image: redis
  nodeSelector:
    disk: ssd
```

<details>
  <summary>Ответ</summary>

Никак. Контейнеры одного пода могут размещаться только на одной ноде. Под является неделимой сущностью Kubernetes.

</details>

30. Какую функцию выполняют `indent` и `nindent` в Helm чартах?

<details>
  <summary>Ответ</summary>

`indent` делает отступ каждой строки в заданном списке до указанной ширины отступа.
`nindent` аналогична функции `indent`, но добавляет символ новой строки в начало каждой строки в списке.

</details>

31. Чем отличается *Deployment* от *ReplicaSet*?

<details>
  <summary>Ответ</summary>

ReplicaSet гарантирует, что определенное количество экземпляров подов (Pods) будет запущено в кластере Kubernetes.

Deployment предоставляет возможность декларативного обновления для объектов типа поды (Pods) и наборы реплик (ReplicaSets).

Deployment - уровень абстрации над ReplicaSet. Deployment будет создавать объект ReplicaSet, но с возможностью rolling-update и rollback.

Чтобы сохранить состояние при разворачивании Deployment необходимо установить ключ `--record` при применении манифеста.

</details>

32. Чем отличается *Deployment* от *StatefulSet*?

<details>
  <summary>Ответ</summary>

Deployment выполняет обновление подов и RelicaSets, и является наиболее используемым ресурсом Kubernetes для деплоя приложений, как правило – stateless приложений, но если подключить Persistent Volume – приложение можно использовать как stateful, но все поды деплоймента будут совместно использовать это хранилище и данные из него. Для PVC можно указать режим доступа как `ReadWriteMany`, так и `ReadOnlyMany`.

StatefulSet используются для управления stateful-приложениями. Создаёт не ReplicaSet, а Pod напрямую с уникальным именем. В связи с этим – при использовании StatefulSet нет возможности выполнить откат версии, но можно его удалить или выполнить скейлинг. При обновлении StatefulSet – будет выполнено RollingUpdate всех подов. StatefulSet использует `volumeClaimTemplates` для описания хранилища и при использовании PVC для каждого пода будет создан уникальный PVC и режимом доступа `ReadWriteOnce`.

</details>

33. Что такое HPA (Horizontal Pod Autoscaling)? Как он работает и что для этого нужно?

<details>
  <summary>Ответ</summary>

[HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) - механизм, который позволяет указать нужную метрику(и) настроить автоматический порог масштабирования Pod’ов в зависимости от изменения её значений.

Чтобы HPA работал необходимо, чтобы в кластере был установлен metrics-server, чтобы считывать меетрики потребления ресурсов. По умолчанию HPA можно настроить для метрики потребления CPU и/или памяти. Возможно расширение функционала HPA с помощью [keda](https://keda.sh/).

</details>

34. Что такое Headless сервис?

<details>
  <summary>Ответ</summary>

При указании `ClusterIP: None` для сервиса мы создаём "безголовый сервис", у данного сервиса не будет виртуального IP адреса. Headless сервис это просто А-запись в системе DNS, таким образом имя сервиса преобразуется не в виртуальный IP сервиса, а сразу в IP пода. Headless сервисы полезны, когда приложение само должно управлять тем, к какому Pod подключаться. Например, gRPC-клиенты держат по одному соединению с сервисами и сами управляют запросами, мультиплексируя запросы к одному серверу. В случае использования ClusterIP клиент может создать одно подключение и нагружать ровно один Pod сервера.

</details>

35. Что такое ExternalName сервис?

<details>
  <summary>Ответ</summary>

Сервис типа ExternalName добавляет запись типа CNAME во внутренний DNS сервер Kubernetes. Например:
```
apiVersion: v1
kind: Service
metadata:
  name: ya-ru
spec:
  type: ExternalName
  externalName: ya.ru
```
Для сервиса `ya-ru` не создаётся endpoint. Поэтому сразу переходим к запросам к DNS.
```
ya-ru.default.svc.cluster.local. 5 IN CNAME   ya.ru.
```

</details>

36. Что такое ExternalIP сервис?

<details>
  <summary>Ответ</summary>

При определении сервиса можно добавить поле externalIPs, в котором можно указать IP адрес машины кластера. При обращении на этот IP и указанный в сервисе порт, запрос будет переброшен на соответствующий сервис.
Например:
```
apiVersion: v1
kind: Service
metadata:
  name: external-svc-nginx
  labels:
    app: nginx
spec:
  ports:
    - name: http-main
      port: 8080
      protocol: TCP
      targetPort: 8090
  selector:
    app: nginx
  externalIPs:
    - 192.168.218.178
```
При обращении к 192.168.218.178:8080 запрос будет переброшен к сервису external-svc-nginx:8080

</details>

37. Что такое NodePort сервис?

<details>
  <summary>Ответ</summary>

Сервисы типа NodePort открывают порт на каждой ноде кластера на сетевых интерфейсах хоста. Все запросы, приходящие на этот порт, будут пересылаться на endpoints, связанные с данным сервисом.
Диапазон портов, который можно использовать в NodePort — 30000-32767. Но его можно изменить при конфигурации кластера.

</details>

38. Что такое capabilities? Для чего нужно их описывать?

<details>
  <summary>Ответ</summary>

[Capabilities](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container) - это разрешения на уровне ядра, которые позволяют гранулярно управлять разрешениями на вызовы ядра, вместо того, чтобы запускать все от имени пользователя root. Capabilities позволяют изменять права доступа к файлам, управлять сетевой подсистемой и выполняет общесистемные функции администрирования.

</details>
