Как добавить master-узел в статическом или гибридном кластере?
Важно иметь нечетное количество master-узлов для обеспечения кворума.
Добавление master-узла в статический или гибридный кластер ничем не отличается от добавления обычного узла в кластер. Воспользуйтесь для этого соответствующими примерами. Все необходимые действия по настройке компонентов control plane кластера на новом узле будут выполнены автоматически, дождитесь их завершения — появления master-узлов в статусе Ready
.
Как добавить master-узлы в облачном кластере (single-master в multi-master)?
Перед добавлением узлов убедитесь в наличии необходимых квот.
Важно иметь нечетное количество master-узлов для обеспечения кворума.
- Сделайте резервную копию
etcd
и папки/etc/kubernetes
. - Скопируйте полученный архив за пределы кластера (например, на локальную машину).
- Убедитесь, что в кластере нет алертов, которые могут помешать созданию новых master-узлов.
- Убедитесь, что очередь Deckhouse пуста.
-
На локальной машине запустите контейнер установщика Deckhouse соответствующей редакции и версии (измените адрес container registry при необходимости):
DH_VERSION=$(kubectl -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/version}') \ DH_EDITION=$(kubectl -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/edition}' | tr '[:upper:]' '[:lower:]' ) \ docker run --pull=always -it -v "$HOME/.ssh/:/tmp/.ssh/" \ registry.deckhouse.io/deckhouse/${DH_EDITION}/install:${DH_VERSION} bash
-
В контейнере с инсталлятором выполните следующую команду, чтобы проверить состояние перед началом работы:
dhctl terraform check --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> --ssh-user=<USERNAME> --ssh-host <MASTER-NODE-0-HOST>
Ответ должен сообщить, что Terraform не нашел расхождений и изменений не требуется.
-
В контейнере с инсталлятором выполните следующую команду и укажите требуемое количество мастер-узлов в параметре
masterNodeGroup.replicas
:dhctl config edit provider-cluster-configuration --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> --ssh-user=<USERNAME> \ --ssh-host <MASTER-NODE-0-HOST>
Для Yandex Cloud при использовании внешних адресов на master-узлах количество элементов массива в параметре masterNodeGroup.instanceClass.externalIPAddresses должно равняться количеству master-узлов. При использовании значения
Auto
(автоматический заказ публичных IP-адресов) количество элементов в массиве все равно должно соответствовать количеству master-узлов.Например, при трех master-узлах (
masterNodeGroup.replicas: 3
) и автоматическом заказе адресов параметрmasterNodeGroup.instanceClass.externalIPAddresses
будет выглядеть следующим образом:externalIPAddresses: - "Auto" - "Auto" - "Auto"
-
В контейнере с инсталлятором выполните следующую команду для запуска масштабирования:
dhctl converge --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> --ssh-user=<USERNAME> --ssh-host <MASTER-NODE-0-HOST>
-
Дождитесь появления необходимого количества master-узлов в статусе
Ready
и готовности всех экземпляровcontrol-plane-manager
:kubectl -n kube-system wait pod --timeout=10m --for=condition=ContainersReady -l app=d8-control-plane-manager
Как уменьшить число master-узлов в облачном кластере (multi-master в single-master)?
Описанные ниже шаги необходимо выполнять с первого по порядку master-узла кластера (master-0). Это связано с тем, что кластер всегда масштабируется по порядку: например, невозможно удалить узлы master-0 и master-1, оставив master-2.
- Сделайте резервную копию
etcd
и папки/etc/kubernetes
. - Скопируйте полученный архив за пределы кластера (например, на локальную машину).
- Убедитесь, что в кластере нет алертов, которые могут помешать обновлению master-узлов.
- Убедитесь, что очередь Deckhouse пуста.
-
На локальной машине запустите контейнер установщика Deckhouse соответствующей редакции и версии (измените адрес container registry при необходимости):
DH_VERSION=$(kubectl -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/version}') \ DH_EDITION=$(kubectl -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/edition}' | tr '[:upper:]' '[:lower:]' ) \ docker run --pull=always -it -v "$HOME/.ssh/:/tmp/.ssh/" \ registry.deckhouse.io/deckhouse/${DH_EDITION}/install:${DH_VERSION} bash
-
В контейнере с инсталлятором выполните следующую команду и укажите
1
в параметреmasterNodeGroup.replicas
:dhctl config edit provider-cluster-configuration --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> \ --ssh-user=<USERNAME> --ssh-host <MASTER-NODE-0-HOST>
Для Yandex Cloud при использовании внешних адресов на master-узлах количество элементов массива в параметре masterNodeGroup.instanceClass.externalIPAddresses должно равняться количеству master-узлов. При использовании значения
Auto
(автоматический заказ публичных IP-адресов) количество элементов в массиве все равно должно соответствовать количеству master-узлов.Например, при одном master-узле (
masterNodeGroup.replicas: 1
) и автоматическом заказе адресов параметрmasterNodeGroup.instanceClass.externalIPAddresses
будет выглядеть следующим образом:externalIPAddresses: - "Auto"
- Снимите следующие лейблы с удаляемых master-узлов:
node-role.kubernetes.io/control-plane
node-role.kubernetes.io/master
node.deckhouse.io/group
Команда для снятия лейблов:
kubectl label node <MASTER-NODE-N-NAME> node-role.kubernetes.io/control-plane- node-role.kubernetes.io/master- node.deckhouse.io/group-
-
Убедитесь, что удаляемые master-узлы пропали из списка членов кластера etcd:
kubectl -n kube-system exec -ti $(kubectl -n kube-system get pod -l component=etcd,tier=control-plane -o name | head -n1) -- \ etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \ --cert /etc/kubernetes/pki/etcd/ca.crt --key /etc/kubernetes/pki/etcd/ca.key \ --endpoints https://127.0.0.1:2379/ member list -w table
-
Выполните
drain
для удаляемых узлов:kubectl drain <MASTER-NODE-N-NAME> --ignore-daemonsets --delete-emptydir-data
-
Выключите виртуальные машины, соответствующие удаляемым узлам, удалите инстансы соответствующих узлов из облака и подключенные к ним диски (
kubernetes-data-master-<N>
). -
Удалите в кластере поды, оставшиеся на удаленных узлах:
kubectl delete pods --all-namespaces --field-selector spec.nodeName=<MASTER-NODE-N-NAME> --force
-
Удалите в кластере объекты
Node
удаленных узлов:kubectl delete node <MASTER-NODE-N-NAME>
-
В контейнере с инсталлятором выполните следующую команду для запуска масштабирования:
dhctl converge --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> --ssh-user=<USERNAME> --ssh-host <MASTER-NODE-0-HOST>
Как убрать роль master-узла, сохранив узел?
- Сделайте резервную копию etcd и папки
/etc/kubernetes
. - Скопируйте полученный архив за пределы кластера (например, на локальную машину).
- Убедитесь, что в кластере нет алертов, которые могут помешать обновлению master-узлов.
- Убедитесь, что очередь Deckhouse пуста.
- Снимите лейблы
node.deckhouse.io/group: master
иnode-role.kubernetes.io/control-plane: ""
. -
Убедитесь, что удаляемый master-узел пропал из списка членов кластера etcd:
kubectl -n kube-system exec -ti $(kubectl -n kube-system get pod -l component=etcd,tier=control-plane -o name | head -n1) -- \ etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \ --cert /etc/kubernetes/pki/etcd/ca.crt --key /etc/kubernetes/pki/etcd/ca.key \ --endpoints https://127.0.0.1:2379/ member list -w table
-
Зайдите на узел и выполните следующие команды:
rm -f /etc/kubernetes/manifests/{etcd,kube-apiserver,kube-scheduler,kube-controller-manager}.yaml rm -f /etc/kubernetes/{scheduler,controller-manager}.conf rm -f /etc/kubernetes/authorization-webhook-config.yaml rm -f /etc/kubernetes/admin.conf /root/.kube/config rm -rf /etc/kubernetes/deckhouse rm -rf /etc/kubernetes/pki/{ca.key,apiserver*,etcd/,front-proxy*,sa.*} rm -rf /var/lib/etcd/member/
Как изменить образ ОС в multi-master-кластере?
- Сделайте резервную копию
etcd
и папки/etc/kubernetes
. - Скопируйте полученный архив за пределы кластера (например, на локальную машину).
- Убедитесь, что в кластере нет алертов, которые могут помешать обновлению master-узлов.
- Убедитесь, что очередь Deckhouse пуста.
-
На локальной машине запустите контейнер установщика Deckhouse соответствующей редакции и версии (измените адрес container registry при необходимости):
DH_VERSION=$(kubectl -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/version}') \ DH_EDITION=$(kubectl -n d8-system get deployment deckhouse -o jsonpath='{.metadata.annotations.core\.deckhouse\.io\/edition}' | tr '[:upper:]' '[:lower:]' ) \ docker run --pull=always -it -v "$HOME/.ssh/:/tmp/.ssh/" \ registry.deckhouse.io/deckhouse/${DH_EDITION}/install:${DH_VERSION} bash
-
В контейнере с инсталлятором выполните следующую команду, чтобы проверить состояние перед началом работы:
dhctl terraform check --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> --ssh-user=<USERNAME> \ --ssh-host <MASTER-NODE-0-HOST> --ssh-host <MASTER-NODE-1-HOST> --ssh-host <MASTER-NODE-2-HOST>
Ответ должен сообщить вам, что Terraform не хочет ничего менять.
-
В контейнере с инсталлятором выполните следующую команду и укажите необходимый образ ОС в параметре
masterNodeGroup.instanceClass
(укажите адреса всех master-узлов в параметре--ssh-host
):dhctl config edit provider-cluster-configuration --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> --ssh-user=<USERNAME> \ --ssh-host <MASTER-NODE-0-HOST> --ssh-host <MASTER-NODE-1-HOST> --ssh-host <MASTER-NODE-2-HOST>
Следующие действия выполняйте поочередно на каждом master-узле, начиная с узла с наивысшим номером (с суффиксом 2) и заканчивая узлом с наименьшим номером (с суффиксом 0).
-
Выберите master-узел для обновления (укажите его название):
NODE="<MASTER-NODE-N-NAME>"
-
Выполните следующую команду для снятия лейблов
node-role.kubernetes.io/control-plane
,node-role.kubernetes.io/master
,node.deckhouse.io/group
с узла:kubectl label node ${NODE} \ node-role.kubernetes.io/control-plane- node-role.kubernetes.io/master- node.deckhouse.io/group-
-
Убедитесь, что узел пропал из списка членов кластера etcd:
kubectl -n kube-system exec -ti $(kubectl -n kube-system get pod -l component=etcd,tier=control-plane -o name | head -n1) -- \ etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \ --cert /etc/kubernetes/pki/etcd/ca.crt --key /etc/kubernetes/pki/etcd/ca.key \ --endpoints https://127.0.0.1:2379/ member list -w table
-
Выполните
drain
для узла:kubectl drain ${NODE} --ignore-daemonsets --delete-emptydir-data
-
Выключите виртуальную машину, соответствующую узлу, удалите инстанс узла из облака и подключенные к нему диски (kubernetes-data).
-
Удалите в кластере поды, оставшиеся на удаляемом узле:
kubectl delete pods --all-namespaces --field-selector spec.nodeName=${NODE} --force
-
Удалите в кластере объект
Node
удаленного узла:kubectl delete node ${NODE}
-
В контейнере с инсталлятором выполните следующую команду для создания обновленного узла:
Вам нужно внимательно прочитать, что converge собирается делать, когда запрашивает одобрение.
Если converge запрашивает одобрение для другого мастер-узла, его следует пропустить, выбрав
no
.dhctl converge --ssh-agent-private-keys=/tmp/.ssh/<SSH_KEY_FILENAME> --ssh-user=<USERNAME> \ --ssh-host <MASTER-NODE-0-HOST> --ssh-host <MASTER-NODE-1-HOST> --ssh-host <MASTER-NODE-2-HOST>
-
На созданном узле посмотрите журнал systemd-unit’а
bashible.service
. Дождитесь окончания настройки узла — в журнале появится сообщениеnothing to do
:journalctl -fu bashible.service
-
Убедитесь, что узел появился в списке членов кластера etcd:
kubectl -n kube-system exec -ti $(kubectl -n kube-system get pod -l component=etcd,tier=control-plane -o name | head -n1) -- \ etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \ --cert /etc/kubernetes/pki/etcd/ca.crt --key /etc/kubernetes/pki/etcd/ca.key \ --endpoints https://127.0.0.1:2379/ member list -w table
-
Убедитесь, что
control-plane-manager
функционирует на узле.kubectl -n kube-system wait pod --timeout=10m --for=condition=ContainersReady \ -l app=d8-control-plane-manager --field-selector spec.nodeName=${NODE}
-
Перейдите к обновлению следующего узла.
Как изменить образ ОС в single-master-кластере?
- Преобразуйте single-master-кластер в multi-master в соответствии с инструкцией.
- Обновите master-узлы в соответствии с инструкцией.
- Преобразуйте multi-master-кластер в single-master в соответствии с инструкцией
Как посмотреть список member’ов в etcd?
Вариант 1
Используйте команду etcdctl member list
Пример:
kubectl -n kube-system exec -ti $(kubectl -n kube-system get pod -l component=etcd,tier=control-plane -o name | head -n1) -- \
etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
--cert /etc/kubernetes/pki/etcd/ca.crt --key /etc/kubernetes/pki/etcd/ca.key \
--endpoints https://127.0.0.1:2379/ member list -w table
Внимание! Последний параметр в таблице вывода показывает, что член etcd находится в состоянии learner, а не в состоянии leader.
Вариант 2
Используйте команду etcdctl endpoint status
. Для этой команды, после флага --endpoints
нужно подставить адрес каждого узла control-plane.
Пятый параметр в таблице вывода будет true
у лидера.
Пример скрипта, который автоматически передает все адреса узлов control-plane:
MASTER_NODE_IPS=($(kubectl get nodes -l \
node-role.kubernetes.io/control-plane="" \
-o 'custom-columns=IP:.status.addresses[?(@.type=="InternalIP")].address' \
--no-headers))
unset ENDPOINTS_STRING
for master_node_ip in ${MASTER_NODE_IPS[@]}
do ENDPOINTS_STRING+="--endpoints https://${master_node_ip}:2379 "
done
kubectl -n kube-system exec -ti $(kubectl -n kube-system get pod \
-l component=etcd,tier=control-plane -o name | head -n1) \
-- etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/ca.crt \
--key /etc/kubernetes/pki/etcd/ca.key \
$(echo -n $ENDPOINTS_STRING) endpoint status -w table
Что делать, если что-то пошло не так?
В процессе работы control-plane-manager
оставляет резервные копии в /etc/kubernetes/deckhouse/backup
, они могут помочь.
Что делать, если кластер etcd развалился?
- Остановите (удалите
/etc/kubernetes/manifests/etcd.yaml
) etcd на всех узлах, кроме одного. С него начнется восстановление multi-master’а. - На оставшемся узле в манифесте
/etc/kubernetes/manifests/etcd.yaml
укажите параметр--force-new-cluster
вspec.containers.command
. - После успешного подъема кластера удалите параметр
--force-new-cluster
.
Внимание! Операция деструктивна, она полностью уничтожает консенсус и запускает etcd-кластер с состояния, которое сохранилось на узле. Любые pending-записи пропадут.
Что делать, если etcd постоянно перезапускается с ошибкой?
Данный вариант может понадобиться, если --force-new-cluster
не восстанавливает работу etcd. Такое может случиться при неудачном converge master-узлов, когда новый master-узел был создан со старым диском etcd, поменял свой адрес из локальной сети, и другие master-узлы отсутствуют. Симптомы, при которых стоит использовать данный способ: контейнер etcd в бесконечном рестарте, в его логе ошибка: panic: unexpected removal of unknown remote peer
.
- Установите утилиту etcdutl.
-
С текущего локального снапшота базы etcd (
/var/lib/etcd/member/snap/db
) выполните создание нового снапшота:./etcdutl snapshot restore /var/lib/etcd/member/snap/db --name <HOSTNAME> \ --initial-cluster=HOSTNAME=https://<ADDRESS>:2380 --initial-advertise-peer-urls=https://ADDRESS:2380 \ --skip-hash-check=true --data-dir /var/lib/etcdtest
, где:
<HOSTNAME>
— название master-узла;<ADDRESS>
— адрес master-узла.
-
Выполните команды, для использования нового снапшота:
cp -r /var/lib/etcd /tmp/etcd-backup rm -rf /var/lib/etcd mv /var/lib/etcdtest /var/lib/etcd
-
Найдите контейнеры
etcd
иapi-server
:crictl ps -a | egrep "etcd|apiserver"
-
Удалите найденные контейнеры
etcd
иapi-server
:crictl rm <CONTAINER-ID>
- Перезапустите master-узел.
Как настроить дополнительные политики аудита?
-
Включите параметр auditPolicyEnabled в настройках модуля:
apiVersion: deckhouse.io/v1alpha1 kind: ModuleConfig metadata: name: control-plane-manager spec: version: 1 settings: apiserver: auditPolicyEnabled: true
-
Создайте Secret
kube-system/audit-policy
с YAML-файлом политик, закодированным в Base64:apiVersion: v1 kind: Secret metadata: name: audit-policy namespace: kube-system data: audit-policy.yaml: <base64>
Минимальный рабочий пример
audit-policy.yaml
выглядит так:apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: Metadata omitStages: - RequestReceived
Подробную информацию по настройке содержимого
audit-policy.yaml
можно получить по следующим ссылкам:
Как исключить встроенные политики аудита?
Установите параметр apiserver.basicAuditPolicyEnabled модуля в false
.
Пример:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: control-plane-manager
spec:
version: 1
settings:
apiserver:
auditPolicyEnabled: true
basicAuditPolicyEnabled: false
Как вывести аудит-лог в стандартный вывод вместо файлов?
Установите параметр apiserver.auditLog.output модуля в значение Stdout
.
Пример:
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: control-plane-manager
spec:
version: 1
settings:
apiserver:
auditPolicyEnabled: true
auditLog:
output: Stdout
Как работать с журналом аудита?
Предполагается наличие на master-узлах «скрейпера логов» (log-shipper, promtail, filebeat), который будет следить за файлом с логами:
/var/log/kube-audit/audit.log
Параметры ротации файла журнала предустановлены и их изменение не предусмотрено:
- Максимальное занимаемое место на диске
1000 МБ
. - Максимальная глубина записи
7 дней
.
В зависимости от настроек политики (Policy
) и количества запросов к apiserver логов может быть очень много, соответственно глубина хранения может быть менее 30 минут.
Предостережение
Внимание! Текущая реализация функционала не является безопасной с точки зрения возможности временно сломать control plane.
Если в Secret’е с конфигурационным файлом окажутся неподдерживаемые опции или опечатка, apiserver не сможет запуститься.
В случае возникновения проблем с запуском apiserver потребуется вручную отключить параметры --audit-log-*
в манифесте /etc/kubernetes/manifests/kube-apiserver.yaml
и перезапустить apiserver следующей командой:
docker stop $(docker ps | grep kube-apiserver- | awk '{print $1}')
# Или (в зависимости используемого вами CRI).
crictl stopp $(crictl pods --name=kube-apiserver -q)
После перезапуска будет достаточно времени исправить Secret или удалить его:
kubectl -n kube-system delete secret audit-policy
Как ускорить перезапуск подов при потере связи с узлом?
По умолчанию, если узел за 40 секунд не сообщает свое состояние, он помечается как недоступный. И еще через 5 минут поды узла начнут перезапускаться на других узлах. Итоговое время недоступности приложений около 6 минут.
В специфических случаях, когда приложение не может быть запущено в нескольких экземплярах, есть способ сократить период их недоступности:
- Уменьшить время перехода узла в состояние
Unreachable
при потере с ним связи настройкой параметраnodeMonitorGracePeriodSeconds
. - Установить меньший таймаут удаления подов с недоступного узла в параметре
failedNodePodEvictionTimeoutSeconds
.
Пример
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: control-plane-manager
spec:
version: 1
settings:
nodeMonitorGracePeriodSeconds: 10
failedNodePodEvictionTimeoutSeconds: 50
В этом случае при потере связи с узлом приложения будут перезапущены через ~ 1 минуту.
Предостережение
Оба описанных параметра оказывают непосредственное влияние на потребляемые control-plane'ом
ресурсы процессора и памяти. Уменьшая таймауты, мы заставляем системные компоненты чаще производить отправку статусов и сверку состояний ресурсов.
В процессе подбора подходящих вам значений обращайте внимание на графики потребления ресурсов управляющих узлов. Будьте готовы к тому, что чем меньшие значения параметров вы выбираете, тем больше ресурсов может потребоваться для выделения на эти узлы.
Резервное копирование etcd и восстановление
Как сделать бэкап etcd?
Войдите на любой control-plane-узел под пользователем root
и используйте следующий bash-скрипт:
#!/usr/bin/env bash
pod=etcd-`hostname`
kubectl -n kube-system exec "$pod" -- /usr/bin/etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/ca.crt --key /etc/kubernetes/pki/etcd/ca.key --endpoints https://127.0.0.1:2379/ snapshot save /var/lib/etcd/${pod##*/}.snapshot && \
mv /var/lib/etcd/"${pod##*/}.snapshot" etcd-backup.snapshot && \
cp -r /etc/kubernetes/ ./ && \
tar -cvzf kube-backup.tar.gz ./etcd-backup.snapshot ./kubernetes/
rm -r ./kubernetes ./etcd-backup.snapshot
В текущей директории будет создан файл kube-backup.tar.gz
со снимком базы etcd одного из членов etcd-кластера.
Из полученного снимка можно будет восстановить состояние кластера etcd.
Также рекомендуем сделать бэкап директории /etc/kubernetes
, в которой находятся:
- манифесты и конфигурация компонентов control-plane;
- PKI кластера Kubernetes.
Мы рекомендуем хранить резервные копии снимков состояния кластера etcd, а также бэкап директории /etc/kubernetes/
в зашифрованном виде вне кластера Deckhouse.
Для этого вы можете использовать сторонние инструменты резервного копирования файлов, например Restic, Borg, Duplicity и т. д.
О возможных вариантах восстановления состояния кластера из снимка etcd вы можете узнать здесь.
Как выполнить полное восстановление состояния кластера из резервной копии etcd?
Далее будут описаны шаги по восстановлению кластера до предыдущего состояния из резервной копии при полной потере данных.
Восстановление кластера single-master
Для корректного восстановления кластера single-master выполните следующие шаги:
-
Загрузите утилиту etcdctl на сервер (желательно чтобы её версия была такая же, как и версия etcd в кластере).
wget "https://github.com/etcd-io/etcd/releases/download/v3.5.4/etcd-v3.5.4-linux-amd64.tar.gz" tar -xzvf etcd-v3.5.4-linux-amd64.tar.gz && mv etcd-v3.5.4-linux-amd64/etcdctl /usr/local/bin/etcdctl
Посмотреть версию etcd в кластере можно выполнив следующую команду:
kubectl -n kube-system exec -ti etcd-$(hostname) -- etcdctl version
-
Остановите etcd.
mv /etc/kubernetes/manifests/etcd.yaml ~/etcd.yaml
-
Сохраните текущие данные etcd.
cp -r /var/lib/etcd/member/ /var/lib/deckhouse-etcd-backup
-
Очистите директорию etcd.
rm -rf /var/lib/etcd/member/
-
Положите резервную копию etcd в файл
~/etcd-backup.snapshot
. -
Восстановите базу данных etcd.
ETCDCTL_API=3 etcdctl snapshot restore ~/etcd-backup.snapshot --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/ca.crt \ --key /etc/kubernetes/pki/etcd/ca.key --endpoints https://127.0.0.1:2379/ --data-dir=/var/lib/etcd
-
Запустите etcd.
mv ~/etcd.yaml /etc/kubernetes/manifests/etcd.yaml
Восстановление кластерa multi-master
Для корректного восстановления кластера multi-master выполните следующие шаги:
-
Явно включите режим High Availability (HA) с помощью глобального параметра highAvailability. Это нужно, например, чтобы не потерять одну реплику Prometheus и её PVC, поскольку в режиме single-master HA отключен по умолчанию.
-
Переведите кластер в режим single-master, в соответствии с инструкцией для облачных кластеров или самостоятельно выведите статические master-узлы из кластера.
-
На оставшемся единственном master-узле выполните шаги по восстановлению etcd из резервной копии в соответствии с инструкцией для single-master.
-
Когда работа etcd будет восстановлена, удалите из кластера информацию об уже удаленных в п.1 master-узлах, воспользовавшись следующей командой (укажите название узла):
kubectl delete node <MASTER_NODE_I>
-
Перезапустите все узлы кластера.
-
Дождитесь выполнения заданий из очереди Deckhouse:
kubectl -n d8-system exec svc/deckhouse-leader -c deckhouse -- deckhouse-controller queue main
-
Переведите кластер обратно в режим multi-master в соответствии с инструкцией для облачных кластеров или инструкцией для статических или гибридных кластеров.
Как восстановить объект Kubernetes из резервной копии etcd?
Чтобы получить данные определенных объектов кластера из резервной копии etcd:
- Запустите временный экземпляр etcd.
- Наполните его данными из резервной копии.
- Получите описания нужных объектов с помощью
etcdhelper
.
Пример шагов по восстановлению объектов из резервной копии etcd
В примере далее etcd-snapshot.bin
— резервная копия etcd (snapshot), infra-production
— namespace, в котором нужно восстановить объекты.
- Запустите под с временным экземпляром etcd.
-
Подготовьте файл
etcd.pod.yaml
шаблона пода, выполнив следующие команды:cat <<EOF >etcd.pod.yaml apiVersion: v1 kind: Pod metadata: name: etcdrestore namespace: default spec: containers: - command: - /bin/sh - -c - "sleep 96h" image: IMAGE imagePullPolicy: IfNotPresent name: etcd volumeMounts: - name: etcddir mountPath: /default.etcd volumes: - name: etcddir emptyDir: {} EOF IMG=`kubectl -n kube-system get pod -l component=etcd -o jsonpath="{.items[*].spec.containers[*].image}" | cut -f 1 -d ' '` sed -i -e "s#IMAGE#$IMG#" etcd.pod.yaml
-
Создайте под:
kubectl create -f etcd.pod.yaml
-
-
Скопируйте
etcdhelper
и снимок etcd в контейнер пода.etcdhelper
можно собрать из исходного кода или скопировать из готового образа (например, из образаetcdhelper
на Docker Hub).Пример:
kubectl cp etcd-snapshot.bin default/etcdrestore:/tmp/etcd-snapshot.bin kubectl cp etcdhelper default/etcdrestore:/usr/bin/etcdhelper
-
В контейнере установите права на запуск
etcdhelper
, восстановите данные из резервной копии и запустите etcd.Пример:
~ # kubectl -n default exec -it etcdrestore -- sh / # chmod +x /usr/bin/etcdhelper / # etcdctl snapshot restore /tmp/etcd-snapshot.bin / # etcd &
-
Получите описания нужных объектов кластера, отфильтровав их с помощью
grep
.Пример:
~ # kubectl -n default exec -it etcdrestore -- sh / # mkdir /tmp/restored_yaml / # cd /tmp/restored_yaml /tmp/restored_yaml # for o in `etcdhelper -endpoint 127.0.0.1:2379 ls /registry/ | grep infra-production` ; do etcdhelper -endpoint 127.0.0.1:2379 get $o > `echo $o | sed -e "s#/registry/##g;s#/#_#g"`.yaml ; done
Замена символов с помощью
sed
в примере позволяет сохранить описания объектов в файлы, именованные подобно структуре реестра etcd. Например:/registry/deployments/infra-production/supercronic.yaml
→deployments_infra-production_supercronic.yaml
. -
Скопируйте полученные описания объектов на master-узел:
kubectl cp default/etcdrestore:/tmp/restored_yaml restored_yaml
-
Удалите из полученных описаний объектов информацию о времени создания, UID, status и прочие оперативные данные, после чего восстановите объекты:
kubectl create -f restored_yaml/deployments_infra-production_supercronic.yaml
-
Удалите под с временным экземпляром etcd:
kubectl -n default delete pod etcdrestore
Как выбирается узел, на котором будет запущен под?
За распределение подов по узлам отвечает планировщик Kubernetes (компонент scheduler
).
У него есть 2 фазы — Filtering и Scoring (на самом деле их больше, есть еще pre-filtering / post-filtering, но глобально можно свести к двум фазам).
Общее устройство планировщика Kubernetes
Планировщик состоит из плагинов, которые работают в рамках какой-либо фазы (фаз).
Примеры плагинов:
- ImageLocality — отдает предпочтение узлам, на которых уже есть образы контейнеров, которые используются в запускаемом поде. Фаза: Scoring.
- TaintToleration — реализует механизм taints and tolerations. Фазы: Filtering, Scoring.
- NodePorts — проверяет, есть ли у узла свободные порты, необходимые для запуска пода. Фаза: Filtering.
Полный список плагинов можно посмотреть в документации Kubernetes.
Логика работы
Сначала идет фаза фильтрации (Filtering). В этот момент работают filter
-плагины, которые из всего списка узлов выбирают те, которые попадают под условия фильтров (taints
, nodePorts
, nodeName
, unschedulable
и т. д.). Если узлы лежат в разных зонах, при выборе зоны чередуются, чтобы не размещать все поды в одной зоне.
Предположим, что узлы распределяются по зонам следующим образом:
Zone 1: Node 1, Node 2, Node 3, Node 4
Zone 2: Node 5, Node 6
В этом случае они будут выбираться в следующем порядке:
Node 1, Node 5, Node 2, Node 6, Node 3, Node 4
Обратите внимание, что с целью оптимизации выбираются не все попадающие под условия узлы, а только их часть. По умолчанию функция выбора количества узлов линейная. Для кластера из ≤50 узлов будут выбраны 100% узлов, для кластера из 100 узлов — 50%, а для кластера из 5000 узлов — 10%. Минимальное значение — 5% при количестве узлов более 5000. Таким образом, при настройках по умолчанию узел может не попасть в список возможных узлов для запуска. Эту логику можно изменить (см. подробнее про параметр percentageOfNodesToScore
в документации Kubernetes), но Deckhouse не дает такой возможности.
После того как выбраны узлы, подходящие под условия, запускается фаза Scoring. Каждый плагин анализирует список отфильтрованных узлов и назначает оценку (score) каждому узлу. Оценки от разных плагинов суммируются. На этой фазе оцениваются доступные ресурсы на узлах, pod capacity, affinity, volume provisioning и так далее. По итогам этой фазы выбирается узел с наибольшей оценкой. Если сразу несколько узлов получили максимальную оценку, узел выбирается случайным образом.
В итоге под запускается на выбранном узле.
Документация
Как изменить/расширить логику работы планировщика
Для изменения логики работы планировщика можно использовать механизм плагинов расширения.
Каждый плагин представляет собой вебхук, отвечающий следующим требованиям:
- Использование TLS.
- Доступность через сервис внутри кластера.
- Поддержка стандартных Verbs (filterVerb = filter, prioritizeVerb = prioritize).
- Также, предполагается что все подключаемые плагины могут кэшировать информацию об узле (
nodeCacheCapable: true
).
Подключить extender можно при помощи ресурса KubeSchedulerWebhookConfiguration.
При использовании опции failurePolicy: Fail
, в случе ошибки в работе вебхука, планировщик прекратит работу и новые поды не смогут запуститься.