[Системное администрирование, *nix, DevOps, Микросервисы, Kubernetes] Ломаем и чиним etcd-кластер

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
01-Мар-2021 22:32


etcd — это быстрая, надёжная и устойчивая к сбоям key-value база данных. Она лежит в основе Kubernetes и является неотъемлемой частью его control-plane. Именно поэтому критически важно уметь бэкапить и восстанавливать работоспособность как отдельных нод, так и всего etcd-кластера.В предыдущей статье мы подробно рассмотрели перегенерацию SSL-сертификатов и static-манифестов для Kubernetes, а также вопросы связанные восстановлением работоспособности Kubernetes. Эта статья будет посвящена целиком и полностью восстановлению etcd-кластера.Для начала я сразу должен сделать оговорку, что рассматривать мы будем лишь определённый кейс, когда etcd задеплоен и используется непосредственно в составе Kubernetes. Приведённые в статье примеры подразумевают что ваш etcd-кластер развёрнут с помощью static-манифестов и запускается внутри контейнеров.Для наглядности возьмём схему stacked control plane nodes из предыдущей статьи:
(стрелочки указывают на связи клиент --> сервер)Предложенные ниже команды можно выполнить и с помощью kubectl, но в данном случае мы постараемся абстрагироваться от плоскости управления Kubernetes и рассмотрим локальный вариант управления контейнеризированным etcd-кластером с помощью crictl.Данное умение также поможет вам починить etcd даже в случае неработающего Kubernetes API.ПодготовкаПо этому, первое что мы сделаем, это зайдём по ssh на одну из master-нод и найдём наш etcd-контейнер:
CONTAINER_ID=$(crictl ps -a --label io.kubernetes.container.name=etcd --label io.kubernetes.pod.namespace=kube-system | awk 'NR>1{a=$1} END{print a}')
Так же установим алиас, чтобы каждый раз не перечислять пути к сертификатам в командах:
alias etcdctl='crictl exec "$CONTAINER_ID" etcdctl --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --cacert /etc/kubernetes/pki/etcd/ca.crt'
Приведённые выше команды являются временными, вам потребуется выполнять их каждый раз перед тем как начать работать с etcd. Конечно, для своего удобства вы можете добавить их в .bashrc. Как это сделать выходит за рамки этой статьи.
Если что-то пошло не так и вы не можете сделать exec в запущенный контейнер, посмотрите логи etcd: crictl logs "$CONTAINER_ID"А также убедитесь в наличии static-манифеста и всех сертифиткатов в случае если контейнер даже не создался. Логи kubelet так же бывают весьма полезными.
Проверка состояния кластераЗдесь всё просто:
# etcdctl member list -w table
+------------------+---------+-------+---------------------------+---------------------------+------------+
|        ID        | STATUS  | NAME  |        PEER ADDRS         |       CLIENT ADDRS        | IS LEARNER |
+------------------+---------+-------+---------------------------+---------------------------+------------+
| 409dce3eb8a3c713 | started | node1 | https://10.20.30.101:2380 | https://10.20.30.101:2379 |      false |
| 74a6552ccfc541e5 | started | node2 | https://10.20.30.102:2380 | https://10.20.30.102:2379 |      false |
| d70c1c10cb4db26c | started | node3 | https://10.20.30.103:2380 | https://10.20.30.103:2379 |      false |
+------------------+---------+-------+---------------------------+---------------------------+------------+
Каждый инстанс etcd знает всё о каждом. Информация о members хранится внутри самого etcd и по этому любое изменение в ней будет также обновленно и на остальных инстансах кластера.Важное замечание, команда member list отображает только статус конфигурации, но не статус конкретного инстанса. Чтобы проверить статусы инстансов есть команда endpoint status, но она требует явного указания всех эндпоинтов кластера для проверки.
ENDPOINTS=$(etcdctl member list | grep -o '[^ ]\+:2379' | paste -s -d,)
etcdctl endpoint status --endpoints=$ENDPOINTS -w table
в случае если какой-то из эндпоинтов окажется недоступным вы увидите такую ошибку:
Failed to get the status of endpoint https://10.20.30.103:2379 (context deadline exceeded)
Удаление неисправной нодыИногда случается так что какая-то из нод вышла из строя. И вам нужно восстановить работоспособность etcd-кластера, как быть?Первым делом нам нужно удалить failed member:
etcdctl member remove d70c1c10cb4db26c
Прежде чем продолжить, давайте убедимся, что на упавшей ноде под с etcd больше не запущен, а нода больше не содержит никаких данных:
rm -rf /etc/kubernetes/manifests/etcd.yaml /var/lib/etcd/
crictl rm "$CONTAINER_ID"
Команды выше удалят static-pod для etcd и дирректорию с данными /var/lib/etcd на ноде.Разумеется в качестве альтернативы вы также можете воспользоваться командой kubeadm reset, которая удалит все Kubernetes-related ресурсы и сертифиткаты с вашей ноды.Добавление новой нодыТеперь у нас есть два пути:В первом случае мы можем просто добавить новую control-plane ноду используя стандартный kubeadm join механизм:
kubeadm init phase upload-certs --upload-certs
kubeadm token create --print-join-command --certificate-key <certificate_key>
Вышеприведённые команды сгенерируют команду для джойна новой control-plane ноды в Kubernetes. Этот кейс довольно подробно описан в официальной документации Kubernetes и не нуждается в разъяснении.Этот вариант наиболее удобен тогда, когда вы деплоите новую ноду с нуля или после выполнения kubeadm resetВторой вариант более аккуратный, так как позволяет рассмотреть и выполнить изменения необходимые только для etcd не затрагивая при этом другие контейнеры на ноде.Для начала убедимся что наша нода имеет валидный CA-сертификат для etcd:
/etc/kubernetes/pki/etcd/ca.{key,crt}
В случае его отсутсвия скопируейте его с других нод вашего кластера. Теперь сгенерируем остальные сертификаты для нашей ноды:
kubeadm init phase certs etcd-healthcheck-client
kubeadm init phase certs etcd-peer
kubeadm init phase certs etcd-server
и выполним присоединение к кластеру:
kubeadm join phase control-plane-join etcd --control-plane
Для понимания, вышеописанная команда сделает следующее:
  • Добавит новый member в существующий etcd-кластер:
    etcdctl member add node3 --endpoints=https://10.20.30.101:2380,https://10.20.30.102:2379 --peer-urls=https://10.20.30.103:2380
  • Сгенерирует новый static-manifest для etcd /etc/kubernetes/manifests/etcd.yaml с опциями:
    --initial-cluster-state=existing
    --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380
    эти опции позволят нашей ноде автоматически добавиться в существующий etcd-кластер.
Создание снапшота etcdТеперь рассмотрим вариант создания и восстановления etcd из резервной копии.Создать бэкап можно довольно просто, выполнив на любой из нод:
etcdctl snapshot save /var/lib/etcd/snap1.db
Обратите внимание я намерянно использую /var/lib/etcd так как эта директория уже прокинута в etcd контейнер (смотрим в static-манифест /etc/kubernetes/manifests/etcd.yaml)После выполнения этой команды по указанному пути вы найдёте снапшот с вашими данными, давайте сохраним его в надёжном месте и рассмотрим процедуру восстановления из бэкапаВосстановление etcd из снапшотаЗдесь мы рассмотрим кейс когда всё пошло не так и нам потребовалось восстановить кластер из резервной копии.У нас есть снапшот snap1.db сделанный на предыдущем этапе. Теперь давайте полностью удалим static-pod для etcd и данные со всех наших нод:
rm -rf /etc/kubernetes/manifests/etcd.yaml /var/lib/etcd/member/
crictl rm "$CONTAINER_ID"
Теперь у нас снова есть два пути:Вариант первый создать etcd-кластер из одной ноды и присоединить к нему остальные ноды, по описанной выше процедуре.
kubeadm init phase etcd local
эта команда сгенерирует статик-манифест для etcd c опциями:
--initial-cluster-state=new
--initial-cluster=node1=https://10.20.30.101:2380
таким образом мы получим девственно чистый etcd на одной ноде.
# etcdctl member list -w table
+------------------+---------+-------+---------------------------+---------------------------+------------+
|        ID        | STATUS  | NAME  |        PEER ADDRS         |       CLIENT ADDRS        | IS LEARNER |
+------------------+---------+-------+---------------------------+---------------------------+------------+
| 1afbe05ae8b5fbbe | started | node1 | https://10.20.30.101:2380 | https://10.20.30.101:2379 |      false |
+------------------+---------+-------+---------------------------+---------------------------+------------+
Восстановим бэкап на первой ноде:
etcdctl snapshot restore /var/lib/etcd/snap1.db \
  --data-dir=/var/lib/etcd/new
  --name=node1 \
  --initial-advertise-peer-urls=https://10.20.30.101:2380 \
  --initial-cluster=node1=https://10.20.30.101:2380
mv /var/lib/etcd/member /var/lib/etcd/member.old
mv /var/lib/etcd/new/member /var/lib/etcd/member
crictl rm "$CONTAINER_ID"
rm -rf /var/lib/etcd/member.old/ /var/lib/etcd/new/
На остальных нодах выполним присоединение к кластеру:
kubeadm join phase control-plane-join etcd --control-plane
Вариант второй: восстановить бэкап сразу на всех нодах кластера. Для этого копируем файл снапшота на остальные ноды, и выполняем восстановление вышеописанным образом. В данном случае в опциях к etcdctl нам потребуется указать сразу все ноды нашего кластера, к примерудля node1:
etcdctl snapshot restore /var/lib/etcd/snap1.db \
  --data-dir=/var/lib/etcd/new \
  --name=node1 \
  --initial-advertise-peer-urls=https://10.20.30.101:2380 \
  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380
для node2:
etcdctl snapshot restore /var/lib/etcd/snap1.db \
  --data-dir=/var/lib/etcd/new \
  --name=node2 \
  --initial-advertise-peer-urls=https://10.20.30.102:2380 \
  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380
для node3:
etcdctl snapshot restore /var/lib/etcd/snap1.db \
  --data-dir=/var/lib/etcd/new \
  --name=node3 \
  --initial-advertise-peer-urls=https://10.20.30.103:2380 \
  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380

===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_sistemnoe_administrirovanie (Системное администрирование), #_*nix, #_devops, #_mikroservisy (Микросервисы), #_kubernetes, #_kubernetes, #_etcd, #_administrirovanie (администрирование), #_kto_chitaet_tegi? (кто читает тэги?), #_sistemnoe_administrirovanie (
Системное администрирование
)
, #_*nix, #_devops, #_mikroservisy (
Микросервисы
)
, #_kubernetes
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 14-Май 07:45
Часовой пояс: UTC + 5