Перейти к содержанию

Восстановление после аварии

Средства создания снимков и восстановления etcd v3

etcd рассчитан на отказы машин. Кластер etcd автоматически восстанавливается после временных сбоев, например перезагрузки машины, и допускает до (N-1)/2 постоянных отказов в кластере из N участников. При постоянном отказе из-за неисправности оборудования или повреждения диска участник теряет доступ к кластеру. Если кластер навсегда теряет более (N-1)/2 участников, происходит катастрофический отказ с безвозвратной потерей кворума. Без кворума кластер не может достичь консенсуса и продолжать принимать обновления.

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

Создание снимка пространства ключей

Для восстановления кластера сначала нужен снимок пространства ключей одного участника etcd. Его можно создать с работающего участника командой etcdctl snapshot save либо скопировать файл member/snap/db из каталога данных etcd. Следующая команда сохраняет пространство ключей, обслуживаемое $ENDPOINT, в файл snapshot.db:

$ ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshot.db

Обратите внимание: снимок из файла member/snap/db может потерять ещё не записанные данные, находящиеся в каталоге wal (журнале предзаписи).

Состояние снимка

Чтобы узнать ревизию и хеш снимка, используйте команду etcdutl snapshot status:

$ etcdutl snapshot status snapshot.db -w table
+---------+----------+------------+------------+
|  HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+---------+----------+------------+------------+
| 7ef846e |   485261 |      11642 |      94 MB |
+---------+----------+------------+------------+

Восстановление кластера

Разница ревизий

При восстановлении кластера существующие клиенты могут увидеть откат ревизии на сотни или тысячи значений. Снимок содержит историю данных только до момента создания, тогда как текущее состояние могло уйти далеко вперёд.

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

При известных потребителях API наблюдения, локальных кэшированных копиях данных etcd или использовании Kubernetes настоятельно рекомендуется восстанавливать снимок с описанным ниже «увеличением ревизии».

Восстановление из снимка

Для восстановления кластера достаточно одного файла снимка “db”. Команда etcdutl snapshot restore создаёт новые каталоги данных etcd; все участники должны восстанавливаться из одного снимка. При восстановлении перезаписывается часть метаданных снимка, в частности идентификаторы участника и кластера, поэтому участник теряет прежнюю идентичность. Это не позволяет новому участнику случайно присоединиться к существующему кластеру. Следовательно, восстановление из снимка обязательно должно запускать новый логический кластер.

Простое восстановление выполняется так:

$ etcdutl snapshot restore snapshot.db --data-dir output-dir

Проверка целостности

Целостность снимка можно проверить при восстановлении. Снимок, созданный etcdctl snapshot save, содержит хеш целостности, который проверяет etcdutl snapshot restore. У снимка, скопированного из каталога данных, хеша нет, и восстановить его можно только с --skip-hash-check.

Восстановление с увеличением ревизии

Чтобы после восстановления ревизии никогда не уменьшались, укажите --bump-revision. Параметр принимает 64 bit целое число ревизий, добавляемых к текущей ревизии снимка. Каждая запись в etcd увеличивает ревизию на один, поэтому для снимка недельной давности достаточно увеличения на 1'000'000'000, если etcd обрабатывает менее 1500 записей в секунду.

Для контроллеров Kubernetes важно также пометить все ревизии, включая добавленные, как компактизированные через --mark-compacted. Тогда все наблюдения завершаются, а etcd не отвечает на запросы о ревизиях после создания снимка, фактически инвалидируя кэши informer.

Полная команда выглядит так:

$ etcdutl snapshot restore snapshot.db --bump-revision 1000000000 --mark-compacted --data-dir output-dir

Восстановление с обновлённым составом

Участники кластера etcd хранятся в самом etcd и обслуживаются алгоритмом консенсуса Raft. После полной потери кворума можно изменить место и способ формирования нового кластера, например создать его из совершенно нового набора участников.

При восстановлении из снимка новый состав можно сразу записать в хранилище:

$ etcdutl snapshot restore snapshot.db \
  --name m1 \
  --data-dir m1.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host1:2380

Так новый кластер будет подключаться только к другим восстановленным участникам с указанным токеном, а не к старым участникам, которые ещё могут работать и пытаться подключиться.

В качестве альтернативы при запуске etcd можно указать --force-new-cluster, чтобы перезаписать состав кластера, сохранив данные приложения. Это настоятельно не рекомендуется: если другие участники прежнего кластера ещё работают, произойдёт аварийное завершение. Обязательно регулярно сохраняйте снимки.

Сквозной пример End-2-End

Получите снимок работающего кластера командой:

$ etcdctl snapshot save snapshot.db

В продолжение примера следующие команды создают новые каталоги данных etcd (m1.etcd, m2.etcd, m3.etcd) для кластера из трёх участников:

$ etcdutl snapshot restore snapshot.db \
  --name m1 \
  --data-dir m1_data_dir.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host1:2380
$ etcdutl snapshot restore snapshot.db \
  --name m2 \
  --data-dir m2_data_dir.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host2:2380
$ etcdutl snapshot restore snapshot.db \
  --name m3 \
  --data-dir m3_data_dir.etcd \
  --initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
  --initial-cluster-token etcd-cluster-1 \
  --initial-advertise-peer-urls http://host3:2380

Затем запустите etcd с новыми каталогами данных:

$ etcd \
  --name m1 \
  --data-dir m1_data_dir.etcd \
  --listen-client-urls http://host1:2379 \
  --advertise-client-urls http://host1:2379 \
  --listen-peer-urls http://host1:2380 &
$ etcd \
  --name m2 \
  --data-dir m2_data_dir.etcd \
  --listen-client-urls http://host2:2379 \
  --advertise-client-urls http://host2:2379 \
  --listen-peer-urls http://host2:2380 &
$ etcd \
  --name m3 \
  --data-dir m3_data_dir.etcd \
  --listen-client-urls http://host3:2379 \
  --advertise-client-urls http://host3:2379 \
  --listen-peer-urls http://host3:2380 &

Теперь восстановленный кластер etcd должен быть доступен и обслуживать пространство ключей из снимка.

Начиная с etcd v3.6, снимок данных создаётся только с помощью etcdctl, а восстановление выполняется через etcdutl. Если --data-dir не указан, значение --data-dir по умолчанию — <name>.etcd, где <name> берётся из --name. Например, если --data-dir отсутствует, а участников зовут m1, m2 и m3, каталогами --data-dir будут m1.etcd, m2.etcd и m3.etcd.