Элегантно обрабатывать настройки/настройки сайта в svn/hg/git/etc?
Я искал лучший способ справиться с настройками для сайта (в данном случае, файл django settings.py).
Структура и поля settings.py довольно согласованы, но значения различаются между полями разработчика, интеграцией, QA, тестированием и производственными средами.
Каков элегантный способ управления параметрами, сохраняя при этом изменения между разными полями?
Я также обеспокоен наличием конфиденциальных данных (например, паролей базы данных) в исходном управлении, но мне нужны автоматические развертывания.
Примеры того, что мы использовали:
-
settings.py устанавливает общие значения, затем загружает дополнительный файл настроек на основе имени хоста или имени пользователя.
-
ввод значений в файл settings.py с помощью развертывания script. Но это просто переносит проблему на управление сценариями развертывания вместо параметров settings.py script.
Кто-нибудь имеет особенно элегантный подход?
Ответы
Ответ 1
Создайте основной файл settings.py, который должен включать следующее:
# Pull in hostname-based changes.
import socket
HOSTNAME = socket.gethostname().lower().split('.')[0].replace('-','')
try:
exec "from myproject.settings.host_%s import *" % HOSTNAME
except ImportError:
pass
# Pull in the local changes.
try:
from myproject.settings.local import *
except ImportError:
pass
Теперь вы создаете новый файл настроек для каждого интересующего вас имени хоста. Но они очень маленькие. Каждый из файлов вашего рабочего сервера содержит:
from myproject.settings.production import *
а на ваших промежуточных серверах:
from myproject.settings.staging import *
Теперь вы можете создать файл production.py с производственными переопределениями для настроек, staging.py и т.д. Вы можете создавать новые файлы для каждой роли, которую играет сервер.
Наконец, вы можете создать файл local.py на любом компьютере (включая машины разработчиков) с локальными переопределениями и пометить этот файл как проигнорированный исходным элементом управления, чтобы изменения не попадали в него.
Мы использовали эту структуру в течение многих лет, она работает очень хорошо.
Ответ 2
+1 для ответа Ned, но хочу указать небольшое изменение.
Я вижу настройки Django как падающие на 2 области: проект и экземпляр.
Параметры проекта являются общими для всех экземпляров (dev, testing, production, multiple sites in production), а настройки экземпляра являются локальными только для определенного экземпляра сервера.
Настройки проекта такие, как INSTALLED_APPS
(хотя локальные настройки также могут включать это, чтобы добавить такие вещи, как панель инструментов отладки django для разработчиков), MIDDLEWARE_CLASSES
и TEMPLATE_LOADERS
. Настройки экземпляра - это такие, как настройки базы данных, настройки MEDIA_URL
и т.д.
Настройки проекта входят settings.py
и параметры экземпляра в local_settings.py
, которые импортируются в settings.py
. local_settings.py
указан в .gitignore
, а настройки проекта хранятся в git.
Я попробовал несколько других вариантов этого, но закончился здесь, потому что это намного проще.
Единственный раз, когда мне не нравится эта настройка, - это несколько сайтов (с использованием платформы Django sites), которые в конечном итоге распространяются на такие вещи, как sitename_settings.py
, который импортирует sitename_local_settings.py
и т.д.
Наконец, я сохраняю local_settings_template.py
в git, чтобы использовать в качестве отправной точки для новых экземпляров, а для разработчиков - отслеживать изменения, которые могут потребоваться для их локальных настроек.
Ответ 3
Позволяет разделить эти две различные проблемы: 1) управление настройками для сайта и 2) управление секретами.
1) Настройки для сайта
Версия все (кроме секретов), даже настройки для конкретного разработчика.
С Django и множеством других программных файлов конфигурационный файл представляет собой часть исполняемого кода, что упрощает загрузку общих параметров конфигурации и отменяет все, что необходимо переопределить. Таким образом, вы можете оставаться DRY.
# settings_prod.py
from settings_base import *
... # override whatever needs to be overridden for production environment
Итак, теперь у вас есть settings_base.py
, settings_prod.py
, settings_dev.py
, settings_developper_john.py
и т.д. Как вы скажете Django, какой из них использовать?
Развертывание соответствующего файла настроек на сервере является задачей для развертывания script, я считаю. Развертывание script будет знать, что вы развертываете для размещения prod17, который является производственным сервером, поэтому он будет генерировать на лету файл settings.py
, который будет выглядеть следующим образом:
# settings.py (generated by deployment script)
from settings_prod import *
Другое решение состоит в том, чтобы иметь эту логику в общем settings.py
: он мог читать переменную окружения или получать имя хоста (или применять любую другую логику) и загружать соответствующий модуль настроек:
# settings.py
import os
if os.environ["MY_APP_ENV"] == "prod":
from settings_prod import *
elif ...
Мое любимое решение для настроек Django описано здесь.
Для любого другого программного обеспечения, которое не так гибко с ним связано с конфигурационным файлом, лучшим вариантом является, вероятно, развертывание script генерации файла конфигурации, возможно, с использованием шаблонов (такие инструменты, как Chef или Puppet, делают это проще). Это позволяет вам оставаться сухим: например, скажем, для программного обеспечения требуется плоский файл config.ini
, тогда развертывание script может читать файл common.ini
и production.ini
, смешать их вместе и создать config.ini
готовые к развертыванию в производство.
Управление секретами
Прежде всего, не храните свои пароли в системе управления версиями.: -)
Одним из решений для управления секретами является развертывание script передачи секретов. Например, bob отвечает за развертывание веб-приложений, он знает пароль для базы данных, поэтому, когда он запускает развертывание script, ему предлагается ввести пароль базы данных, а script передает его на сервер. Или развертывание script просто читает пароль в файле на компьютере bob и передает его. Это, вероятно, наиболее распространенное решение. Это нормально в большинстве случаев.
secrets
deployer ================> server
Если вам нужно автоматизировать создание виртуальных машин, и вы не хотите, чтобы автоматизированный разработчик знал какой-либо секрет, вы можете включить секреты в VM-образ. Конечно, во-первых, кто-то должен включать секреты в образ VM.
VM image including secrets
human deployer -------------------------------+
|
|
image_name v
automated deployer ==============> Cloud Service ========> VM including secrets
Проблема с этим решением заключается в том, что вам нужно генерировать новый образ VM каждый раз, когда какие-либо секретные изменения. Если вы хотите этого избежать, тогда вам может понадобиться "секретный сервер": сервер для управления всеми другими секретами сервера. Тогда единственный секрет, который вам нужно включить в образ VM, - это секрет бутстрапа, необходимый для подключения к "секретному серверу".
step 1:
VM image including bootstrap secret
human deployer -----------------------------------+
|
|
image_name v
automated deployer ==================> Cloud Service ========> VM including secrets
step 2:
bootstrap secret
==================>
VM Secret Server
<==================
secrets
Например, секретный сервер может быть сервером шеф-повара, секреты могут храниться в зашифрованных мешках данных, а секретный код бутстрапа будет ключом к расшифровке этих пакетов.
Ответ 4
То, как я обрабатываю это, - это иметь базовый файл settings.py, а затем файл настроек для каждой среды (например, dev_settings.py, live_settings.py)
В верхней части каждого конкретного файла среды у меня есть
from settings import *
Я могу просто переопределить любые настройки, которые мне нужно изменить на основе среды
Чтобы каждая среда использовала правильные настройки, я просто изменяю переменную среды DJANGO_SETTINGS_MODULE. Как вы это делаете, зависит от того, как вы развертываете django (mod_wsgi, mod_python и т.д.)