реальная задача из жизни devops
Mar. 12th, 2022 04:07 pmЭта проблема есть и у админов, но у них она менее выражена, потому что многие процессы ручные. В автоматическом режиме оно становится более резким.
Простая задача: есть stateful нечто. Для простоты, пусть приложение с sqlight базой в которых нет серкетных данных (это важно в свете тестов на стейджингах).
Надо его деплоить, бэкапить, уметь восстанавливать из бэкапа, тестировать получившееся, и делать это периодически (но быть готовым к тому, что код тестового восстановления из бэкапа будет запущен и в продакшене).
Простая схема выглядит так:
* Деплой код не трогает файл базы.
* Деплой код настраивает backup_url для бэкапа по таймеру. Оба этих этапа работают одинаково в продакшене и на стейджингах, включая эфимерную среду для проверки кода деплоя.
* Отдельный workflow (или другой CI процесс) регулярно поднимает эфимерную среду, которая берёт backup_url из продакшена и восстанавливает данные приложения. Приложение уже установлено (обычный делой код). После чего мы тестируем приложение на актуальность бэкапа.
Каждая среда имеет раздельный backup_url и restore_url, которые не совпадают в общем случае (стейджинг восстанавливает из продакшен-бэкапа, продакшен восстанавливается из продакшен-бэкапа).
Наивный код деплоя в случае аварии делает:
1. Деплой приложения.
2. Деплой бэкап-сервиса с backup_url.
3. Код restore backup, запущенный для production-среды.
Проблема: если между п.2 и п.3 запустится регулярный бэкап (настроенный в п.2), то самый свежий бэкап будет содержать в себе пустоту (т.к. приложение только что было задеплоено).
Решение, которое я пока придумал - recovery, когда запускает деплой для продакшена, ставит backup_url в пустоту, а уже после успешного восстановления и тестов (и, возможно, ручной валидации успеха) уже включает backup_url на нормальный адрес.
Соответственно, будет общая кодовая база между рекавери и тестовыми рекавери, состоящая из deploy и recovery. Единственное их различие (помимо серверов) - в том, что в настоящем recovery backup_url выставлен в пустоту.
... Но мы не можем иметь код в продакшене без тестов, особенно, код такой важности.
Таким образом, в периодическом запуске тестов рекавери мы _всегда_ отключаем бэкап перед деплоем, причём это отключение должно побеждать deployment-код, который всегда backup url прописывает.
... но это не решает проблемы аварии. Если у нас авария, и был автоматически запущен деплой (по любой другой причине), то он может отработать до recovery (т.е. поднять пустое приложение и включить бэкапы).
Получается, что мы не можем полагаться на поведение recovery, т.к. есть конкуретные процессы деплоя, которые про аварию ничего не знают и которые просто поднимут приложение с нуля.
Выглядит так, что включение продакшен-бэкапа - это сингулярность, которую делает человек, вне основных workflow.
---
Уточнённая схема:
deployment - делает пустое приложение и backup-сервис с ненастроенным backup_url. Вполне допустимо, что тесты такое обнаруживают и орут.
recovery - восстанавливает из restore_url.
enable_backups - прописывает backup_url.
test_recovery - поднимает deployment на тестовой среде, делает туда recovery делает тесты приложения на правильность восстановления.
staging (который тестирует код) дополнительно, запускает enable_backups с ephimerial локацией бэкапа.
Провера выполнения:
* deployment - выполняется всегда и на продакшене, и на стейджинге
* recovery - выполняется на стейджинге в полном объёме во время test_recovery.
* enable_backups - выполняется на стейджинге.
Взаимные отношения:
prod:
* backup_url == recovery_url
staging:
* backup_url = (ephimerial)
* recovery_url = production_backup_url
По локациям:
backup_url восстанавливается кодом каждый раз во время test_recovery
recovery_url можно сделать общим между стейджингом и продакшеном, что гарантирует, что это одна и та же штука.
Если мы забудем сделать enable_backup в продакшене, то сломается test_recovery из-за старого бэкапа, плюс, наверное, будут орать тесты.
Может ли оказаться так, что у нас разный код в продакшене и стейджинге? Нет, потому что код деплоя общий, код бэкапа общий, код восстановления общий, проверяется, что код восстановления совместим со старыми данными из текущего продакшен-бэкапа.
Кажется, решение есть.
Простая задача: есть stateful нечто. Для простоты, пусть приложение с sqlight базой в которых нет серкетных данных (это важно в свете тестов на стейджингах).
Надо его деплоить, бэкапить, уметь восстанавливать из бэкапа, тестировать получившееся, и делать это периодически (но быть готовым к тому, что код тестового восстановления из бэкапа будет запущен и в продакшене).
Простая схема выглядит так:
* Деплой код не трогает файл базы.
* Деплой код настраивает backup_url для бэкапа по таймеру. Оба этих этапа работают одинаково в продакшене и на стейджингах, включая эфимерную среду для проверки кода деплоя.
* Отдельный workflow (или другой CI процесс) регулярно поднимает эфимерную среду, которая берёт backup_url из продакшена и восстанавливает данные приложения. Приложение уже установлено (обычный делой код). После чего мы тестируем приложение на актуальность бэкапа.
Каждая среда имеет раздельный backup_url и restore_url, которые не совпадают в общем случае (стейджинг восстанавливает из продакшен-бэкапа, продакшен восстанавливается из продакшен-бэкапа).
Наивный код деплоя в случае аварии делает:
1. Деплой приложения.
2. Деплой бэкап-сервиса с backup_url.
3. Код restore backup, запущенный для production-среды.
Проблема: если между п.2 и п.3 запустится регулярный бэкап (настроенный в п.2), то самый свежий бэкап будет содержать в себе пустоту (т.к. приложение только что было задеплоено).
Решение, которое я пока придумал - recovery, когда запускает деплой для продакшена, ставит backup_url в пустоту, а уже после успешного восстановления и тестов (и, возможно, ручной валидации успеха) уже включает backup_url на нормальный адрес.
Соответственно, будет общая кодовая база между рекавери и тестовыми рекавери, состоящая из deploy и recovery. Единственное их различие (помимо серверов) - в том, что в настоящем recovery backup_url выставлен в пустоту.
... Но мы не можем иметь код в продакшене без тестов, особенно, код такой важности.
Таким образом, в периодическом запуске тестов рекавери мы _всегда_ отключаем бэкап перед деплоем, причём это отключение должно побеждать deployment-код, который всегда backup url прописывает.
... но это не решает проблемы аварии. Если у нас авария, и был автоматически запущен деплой (по любой другой причине), то он может отработать до recovery (т.е. поднять пустое приложение и включить бэкапы).
Получается, что мы не можем полагаться на поведение recovery, т.к. есть конкуретные процессы деплоя, которые про аварию ничего не знают и которые просто поднимут приложение с нуля.
Выглядит так, что включение продакшен-бэкапа - это сингулярность, которую делает человек, вне основных workflow.
---
Уточнённая схема:
deployment - делает пустое приложение и backup-сервис с ненастроенным backup_url. Вполне допустимо, что тесты такое обнаруживают и орут.
recovery - восстанавливает из restore_url.
enable_backups - прописывает backup_url.
test_recovery - поднимает deployment на тестовой среде, делает туда recovery делает тесты приложения на правильность восстановления.
staging (который тестирует код) дополнительно, запускает enable_backups с ephimerial локацией бэкапа.
Провера выполнения:
* deployment - выполняется всегда и на продакшене, и на стейджинге
* recovery - выполняется на стейджинге в полном объёме во время test_recovery.
* enable_backups - выполняется на стейджинге.
Взаимные отношения:
prod:
* backup_url == recovery_url
staging:
* backup_url = (ephimerial)
* recovery_url = production_backup_url
По локациям:
backup_url восстанавливается кодом каждый раз во время test_recovery
recovery_url можно сделать общим между стейджингом и продакшеном, что гарантирует, что это одна и та же штука.
Если мы забудем сделать enable_backup в продакшене, то сломается test_recovery из-за старого бэкапа, плюс, наверное, будут орать тесты.
Может ли оказаться так, что у нас разный код в продакшене и стейджинге? Нет, потому что код деплоя общий, код бэкапа общий, код восстановления общий, проверяется, что код восстановления совместим со старыми данными из текущего продакшен-бэкапа.
Кажется, решение есть.