среда, 1 июля 2020 г.

 Restore heketi DB from scratch


Shit happens и надо быть готовым ко всему. Мне было интересно, можно ли восстановить базу данных Heketi для рабочего кластера GlusterFS, если по какой-то причине ничего от старой базы не осталось, а бэкапы либо не делались, либо был "бэкап Шрёдингера". Эта статья больше объясняет, как устроена база данных Heketi, чем несет практическую пользу.

* Как работает Heketi, я уже рассказывал на medium. Там же описывал структуру базы данных.


Как восстановить базу данных Heketi, если нет ни базы, ни бэкапов.


1. Создать JSON для новой базы данных Heketi


Для начала необходимо создать шаблон JSON для пустой базы данных. Можно воспользоваться моим, который я сделал на основе тестовой базы данных. Правки можно делать в локальном редакторе (я работал в vs code). Я специально оставил все данные, они сгенерированы мной рандомно. Думаю, что так будет более понятно, чем использовать переменные.

```
{
    "clusterentries": {
        "3e16d5aafa1eababeceb6719e5e703co": {
            "Info": {
                "id": "3e16d5aafa1eababeceb6719e5e703co",
                "nodes": [
                    "220bf6e83b3aba8fb5a972a6da6ef045",
                    "d447a9156b88b6295a507a965186ba1",
                    "ccbee9af6981bb1eba6630a7d9dc2217"
                ],
                "volumes": [
                ],
                "block": true,
                "file": true,
                "blockvolumes": []
            }
        }
    },
    "volumeentries": {
    },
    "brickentries": {
    },
    "nodeentries": {
        "220bf6e83b3aba8fb5a972a6da6ef045": {
            "State": "online",
            "Info": {
                "zone": 1,
                "hostnames": {
                    "manage": [
                        "10.2.5.59"
                    ],
                    "storage": [
                        "10.2.5.59"
                    ]
                },
                "cluster": "3e16d5aafa1eababeceb6719e5e703co",
                "id": "220bf6e83b3aba8fb5a972a6da6ef045"
            },
            "Devices": [
                "38425d179befcb2ae9a54a1ee5f19e94"
            ]
        },
        "d447a9156b88b6295a507a965186ba1": {
            "State": "online",
            "Info": {
                "zone": 1,
                "hostnames": {
                    "manage": [
                        "10.2.5.145"
                    ],
                    "storage": [
                        "10.2.5.145"
                    ]
                },
                "cluster": "3e16d5aafa1eababeceb6719e5e703co",
                "id": "d447a9156b88b6295a507a965186ba1"
            },
            "Devices": [
                "fb6728748a570fdcaba70d192e3eb4a6"
            ]
        },
        "ccbee9af6981bb1eba6630a7d9dc2217": {
            "State": "online",
            "Info": {
                "zone": 1,
                "hostnames": {
                    "manage": [
                        "10.2.5.232"
                    ],
                    "storage": [
                        "10.2.5.232"
                    ]
                },
                "cluster": "3e16d5aafa1eababeceb6719e5e703co",
                "id": "ccbee9af6981bb1eba6630a7d9dc2217"
            },
            "Devices": [
                "0888196c04e9e5f7ad346ba7ec173c01"
            ]
        }
    },
    "deviceentries": {
        "0888196c04e9e5f7ad346ba7ec173c01": {
            "State": "online",
            "Info": {
                "name": "/dev/xvdb2",
                "storage": {
                    "total": 74313728,
                    "free": 12058624,
                    "used": 62255104
                },
                "id": "0888196c04e9e5f7ad346ba7ec173c01"
            },
            "Bricks": [
            ],
            "NodeId": "ccbee9af6981bb1eba6630a7d9dc2217",
            "ExtentSize": 4096
        },
        "38425d179befcb2ae9a54a1ee5f19e94": {
            "State": "online",
            "Info": {
                "name": "/dev/xvdb2",
                "storage": {
                    "total": 74444800,
                    "free": 21659648,
                    "used": 52785152
                },
                "id": "38425d179befcb2ae9a54a1ee5f19e94"
            },
            "Bricks": [
            ],
            "NodeId": "220bf6e83b3aba8fb5a972a6da6ef045",
            "ExtentSize": 4096
        },
        "fb6728748a570fdcaba70d192e3eb4a6": {
            "State": "online",
            "Info": {
                "name": "/dev/xvdb2",
                "storage": {
                    "total": 74313728,
                    "free": 16252928,
                    "used": 58060800
                },
                "id": "fb6728748a570fdcaba70d192e3eb4a6"
            },
            "Bricks": [
            ],
            "NodeId": "d447a9156b88b6295a507a965186ba1",
            "ExtentSize": 4096
        }
    },
    "blockvolumeentries": {},
    "dbattributeentries": {
        "DB_BRICK_HAS_SUBTYPE_FIELD": {
            "Key": "DB_BRICK_HAS_SUBTYPE_FIELD",
            "Value": "yes"
        },
        "DB_CLUSTER_HAS_FILE_BLOCK_FLAG": {
            "Key": "DB_CLUSTER_HAS_FILE_BLOCK_FLAG",
            "Value": "yes"
        },
        "DB_GENERATION_ID": {
            "Key": "DB_GENERATION_ID",
            "Value": "581979e87e70c2b99f4e11d22dbdba8d"
        },
        "DB_HAS_PENDING_OPS_BUCKET": {
            "Key": "DB_HAS_PENDING_OPS_BUCKET",
            "Value": "yes"
        }
    },
    "pendingoperations": {}
}
```

Что необходимо поменять в шаблоне и где найти:

ClusterID (3e16d5aafa1eababeceb6719e5e703co)
NodeID (220bf6e83b3aba8fb5a972a6da6ef045, d447a9156b88b6295a507a965186ba1, ccbee9af6981bb1eba6630a7d9dc2217)
  - лог установки heketi, если он у вас сохранился
  - если лога нет, то можно сгенерировать эти ID вручную


DeviceID (38425d179befcb2ae9a54a1ee5f19e94, fb6728748a570fdcaba70d192e3eb4a6, 0888196c04e9e5f7ad346ba7ec173c01)
Чтобы их найти, выполните для любого живого Volume на сервере GlusterFS:

gluster volume info {VOLUME}  | grep Brick

Будет приблизительно такой вывод:


# gluster volume info vol_c81ae8f759bb214fb620d4a8bcdf398e | grep Brick
Number of Bricks: 1 x 3 = 3
Bricks:
Brick1: 10.2.5.59:/var/lib/heketi/mounts/vg_38425d179befcb2ae9a54a1ee5f19e94/brick_d2fa8721fb41b8e26b9e5bf8c93dc500/brick
Brick2: 10.2.5.232:/var/lib/heketi/mounts/vg_0888196c04e9e5f7ad346ba7ec173c01/brick_4ac0c2982d5b853d64dd126df51a69b9/brick
Brick3: 10.2.5.145:/var/lib/heketi/mounts/vg_fb6728748a570fdcaba70d192e3eb4a6/brick_e33f76882cb33a6562ec57a226695d34/brick


DeviceID  это часть имени volume group, которая идет после 'vg_'.

nodeentries.[].Info.hostnames.[]
Меняем IP адреса для GlusterFS нод. Они видны в предыдущем пункте. В каждой nodeentries должны быть IP, которые соответствуют DeviceID.

deviceentries.[].info.name
Посмотреть можно с помощью команды pvs на любом сервере GlusterFS. Это диск, на котором GlusterFS нарезает LV.

deviceentries.[].info.storage {}
Установить корректные значения (в килобайтах). Можно посмотреть на нодах используя команду 'vgs'.

2. Создание heketi.db из JSON


Теперь необходимо из данного файла сделать базу данных heketi. Для этого надо:

1. Запустить контейнер heketi на любой из нод в кластере и зайти в его консоль:

docker run --rm -it --endpoints bash heketi/heketi

2. Создать в контейнере, который мы запустили, JSON файл. Например так:

 cat << EOL >> /tmp/db.json
...
myjson
...
EOL

3. Импортировать json в базу данных

heketi db import --jsonfile=/tmp/db.json --dbfile=/tmp/heketi.db

4. Открываем другой терминал к этой же ноде и копируем файл на heketidbstorage:

# Получаем ID контейнера
docker ps | grep heketi 

# Копируем базу (в вашем случае папка назначения может отличаться)
mkdir /mnt/heketi
mount.glusterfs 127.0.0.1:/heketidbstorage /mnt/heketi
docker cp {ContainerID}:/tmp/heketi.db /mnt/heketi/
umount /mnt/heketi

5. Завершаем работу контейнера heketi

6. Перезапускаем POD heketi. Проверяем, что он запустился корректно (смотрим логи контейнера, что там нет ошибок)

3. Добавляем в базу данных Heketi существующие волумы GlusterFS


На этом этапе heketi уже работает, но в нем нет никаких данных. Добавляем в нее Volumes используя утилиту heketi-tools:

https://github.com/TargetProcess/heketi_tools

Проблема только в том, что эти скрипты не умеют добавлять Volumes с именами, которые заданы не через PVC. Например heketidbstorage.

4. Алгоритмы восстановления Volume 'heketidbstorage'


# Вариант 1. Универсальный, но сложный.

1. Создаем новый волум через heketi-cli, например 'test'

2. Экспортируем базу данных в JSON и там правим волум 'test' подменяя в нем все значения, которые относятся к волуму 'heketidbstorage'. Всю необходимую информацию можно увидеть в выводе команды 'gluster volume info {volumename}'

3. Удаляем волум 'test'

4. Импортируем базу из JSON, подменяем heketi.db

5. Перезапускаем сервер Heketi

### Вариант 2. Подходит, если Heketi запущен как POD Kubernetes.

1. Создаем волум 'test' через heket-cli

2. Копируем на волум 'test' данные из 'heketidbstorage'

3. Правим deployment heketi, где заменяем Volume 'heketidbstorage'  на  'test'

4. Проверяем, что POD Heketi работает

5. Удаляем волум 'heketidbstorage' из GlusterFS (glusterfs volume delete).

6. Прогоняем скрипт из 'helm-tools' чтобы почистить Logical Volumes, которые остались от GlusterFS Volume

7. В Heketi создаем волум для базы командой:

heketi-cli setup-heketi-db-storage --durability

8. Переносим базу с волума 'test' на 'heketidbstorage'

9. Правим deployment heketi для использования 'heketidbstorage'

5. Проверить, что Heketi работает корректно


Тут всё просто - проверяем логи Heketi, пробуем создать и удалить PVC.

------

На этом всё! Если что-то хотите уточнить - задавайте вопросы в комментариях.

1 комментарий: