Ранее я рассказывал про то, как настраиваю .NET приложение.
Если у Вас приложение запускается только из вашего одного CI/CD, то скорее всего с описанными ниже проблемами Вы не сталкивались и подход из поста выше будет вполне успешно работать.
Но если есть много стендов, которые еще и поддерживаются не вашей командой: e2e тесты, on-prem для заказчиков и прочее, то appsettings автоматически становится публичным контрактом.
А это означает что он должен быть и прямо и обратно-совместимым между минорными и патч версиями образов.
Когда у Вас много разных стендов, версии образов между ними непременно разъедутся и когда появится необходимость обновиться, то к Вам придут с вопросами почему приложение не запускается, потому что сами скорее всего не разберутся из-за непонятных ошибок в логах. В итоге придется appsettings.json сформировать заново ориентируясь на appsettings из исходного репозитория, что естественно займет не мало времени.
Таким образом appsettings.json - это деталь реализации .NET приложения и его не стоит светить наружу.
Собственно это одна из причин почему мне захотелось пересмотреть конфигурирование и я выделил следующие требования, чтобы проще управлять поставками.
1. Использовать исключительно Environment Variables для настроек запуска. Никаких подкладываний файлов и монтирований вольюмов.
appsettings должен поставляться вместе с приложением т.е. быть внутри образа. В свою очередь, чтобы не нарушать twelve factor app, он должен быть один на все окружения и заполняться общими значениями, которые не зависят от окружения (например все URI приходят из env). Для локальной разработки env задаются через launchSettings.json, а для интеграционных тестов через Environment.SetEnvironmentVariable.
Плюсы:
- Упрощается поддержка множества разных стендов т.к. не нужно копировать или синхронизировать файлы между окружениями.
- Следуем DevOps практикам и собираем один образ для test, staging и prod
- Нет нужды сохранять совместимость в appsettings.json т.к. он внутри образа и больше не перезагружается в рантайме
Минусы:
- Некоторые вещи проще описать в JSON одним объектом, чем несколькими отдельными энвами. Задание одного энва может требовать заполнение и другого.
- У env есть ограничения как на названия (набор символов, длина), так и значения (размер и кол-во).
- У энвов свой стандарт именования в UPPER_UNDER_SCORE, поэтому в нужен маппинг env -> appsettings.json для сохранения привычной работы.
- С ростом приложения может стать очень много переменных окружения и помогает только структуризация и нейминг.
2. Приложение обязано проверять, что все переменные заданы и корректны.
Плюсы:
- Приложение не запустится с неверной конфигурацией, что предотвращает скрытые баги и порчу данных.
- Ускоряет отладку т.к. в логах сразу видно, какие переменные невалидны или отсутствуют.
- Поды с прошлого релиза не будут заменяться новыми, пока они успешно не поднимутся. А значит не нужен ручной откат.
- Все это повышает надежность релизов и снижает вероятность инцидентов.
3. Обязательные и опциональные переменные в зависимости от фич
Переменные делятся на обязательные и опциональные в зависимости от включенных feature flags (FF).
Если FF может меняться в рантайме, то следует требовать все переменные нужные для фичи.
Если же меняться в рантайме не может и фича выключена — нет смысла требовать лишние переменные.
4. Приложение должно предоставлять список всех переменных окружения, которые можно настроить
Плюсы:
- Из списка можно сгенерировать документацию которая будет всегда актуальна
- Проще определить наличие breaking changes в образе и лучше следовать semver. Например через сравнение набора обязательных env между версиями.
Чтобы было наглядно, я подготовил пример проекта в dotnet-tips, в котором используется данный подход.
Если у Вас приложение запускается только из вашего одного CI/CD, то скорее всего с описанными ниже проблемами Вы не сталкивались и подход из поста выше будет вполне успешно работать.
Но если есть много стендов, которые еще и поддерживаются не вашей командой: e2e тесты, on-prem для заказчиков и прочее, то appsettings автоматически становится публичным контрактом.
А это означает что он должен быть и прямо и обратно-совместимым между минорными и патч версиями образов.
Когда у Вас много разных стендов, версии образов между ними непременно разъедутся и когда появится необходимость обновиться, то к Вам придут с вопросами почему приложение не запускается, потому что сами скорее всего не разберутся из-за непонятных ошибок в логах. В итоге придется appsettings.json сформировать заново ориентируясь на appsettings из исходного репозитория, что естественно займет не мало времени.
Таким образом appsettings.json - это деталь реализации .NET приложения и его не стоит светить наружу.
Собственно это одна из причин почему мне захотелось пересмотреть конфигурирование и я выделил следующие требования, чтобы проще управлять поставками.
1. Использовать исключительно Environment Variables для настроек запуска. Никаких подкладываний файлов и монтирований вольюмов.
appsettings должен поставляться вместе с приложением т.е. быть внутри образа. В свою очередь, чтобы не нарушать twelve factor app, он должен быть один на все окружения и заполняться общими значениями, которые не зависят от окружения (например все URI приходят из env). Для локальной разработки env задаются через launchSettings.json, а для интеграционных тестов через Environment.SetEnvironmentVariable.
Плюсы:
- Упрощается поддержка множества разных стендов т.к. не нужно копировать или синхронизировать файлы между окружениями.
- Следуем DevOps практикам и собираем один образ для test, staging и prod
- Нет нужды сохранять совместимость в appsettings.json т.к. он внутри образа и больше не перезагружается в рантайме
Минусы:
- Некоторые вещи проще описать в JSON одним объектом, чем несколькими отдельными энвами. Задание одного энва может требовать заполнение и другого.
- У env есть ограничения как на названия (набор символов, длина), так и значения (размер и кол-во).
- У энвов свой стандарт именования в UPPER_UNDER_SCORE, поэтому в нужен маппинг env -> appsettings.json для сохранения привычной работы.
- С ростом приложения может стать очень много переменных окружения и помогает только структуризация и нейминг.
2. Приложение обязано проверять, что все переменные заданы и корректны.
Плюсы:
- Приложение не запустится с неверной конфигурацией, что предотвращает скрытые баги и порчу данных.
- Ускоряет отладку т.к. в логах сразу видно, какие переменные невалидны или отсутствуют.
- Поды с прошлого релиза не будут заменяться новыми, пока они успешно не поднимутся. А значит не нужен ручной откат.
- Все это повышает надежность релизов и снижает вероятность инцидентов.
3. Обязательные и опциональные переменные в зависимости от фич
Переменные делятся на обязательные и опциональные в зависимости от включенных feature flags (FF).
Если FF может меняться в рантайме, то следует требовать все переменные нужные для фичи.
Если же меняться в рантайме не может и фича выключена — нет смысла требовать лишние переменные.
4. Приложение должно предоставлять список всех переменных окружения, которые можно настроить
Плюсы:
- Из списка можно сгенерировать документацию которая будет всегда актуальна
- Проще определить наличие breaking changes в образе и лучше следовать semver. Например через сравнение набора обязательных env между версиями.
Чтобы было наглядно, я подготовил пример проекта в dotnet-tips, в котором используется данный подход.