最近,我一直在为简化Lincoln Loop的标准部署系统而努力。我们一直有一个问题,就是如何处理应用程序的配置。
在过去,我们会让我们的配置管理系统把配置写到文件系统上的一个已知位置的JSON文件中。应用程序将读取JSON文件并相应地设置必要的变量。这实现了几个目标。
- 部署不需要对上游存储库的代码进行任何形式的修改。
- 生产秘密可以被加密并安全地存储在远离代码的地方。
- 与环境变量不同,数据可以有适当的类型(布尔值、列表等)。
- 它完全避免了使用环境变量,这在许多情况下从安全角度来看是有问题的。
话虽如此,这种设置也有一些弊端。
- 所需的配置变量没有很好的记录。你必须通过阅读代码来了解它们的使用方式和位置。
- 由于文件不在本地使用,我们为本地和部署环境维护了一个单独的Django设置模块。
- 配置文件对其他服务(如Heroku或Docker)并不友好,因为这些服务通常使用环境变量。
基本上,我想使用我们的Python项目,就像我期望使用任何其他软件一样。安装软件,创建一个配置文件,然后运行。
介绍一下Goodconf
我写了Goodconf(在Chris Beaven的大量帮助下),以解决我们在一个可重复使用的库中的一些问题。
Goodconf的灵感来自于derpconf和logan,它们分别从Thumbor和Sentry中衍生出来。
使用Goodconf,你可以创建一个类,定义你的应用程序期望接收的所有配置值。它们可以有默认值和帮助文本,可以用来生成文档。
from goodconf import GoodConf, Value
class MyConf(GoodConf):
"Configuration for My App"
DEBUG = Value(default=False, help="Toggle debugging.")
DATABASE_URL = Value(
default='postgres://localhost:5432/mydb',
help="Database connection.")
SECRET_KEY = Value(
initial=lambda: base64.b64encode(os.urandom(60)).decode(),
help="Used for cryptographic signing. "
"https://docs.djangoproject.com/en/2.0/ref/settings/#secret-key")
然后你可以像这样实例化这个类。
config = MyConf(
file_env_var="MYAPP_CONF",
default_files=["/etc/myapp/myapp.yml", "myapp.yml"])
这可以让你定义配置文件的默认位置(/etc/myapp/myapp.yml ,如果不存在的话,可以定义$(pwd)/myapp.yml ),也可以定义一个环境变量,用来从不同的位置加载文件。
还有一个Django助手,可以让你做manage.py --config=/path/to/config.yml ... 。
定义好配置后,你只需要加载它并开始使用它。加载配置时,会尝试从配置文件中读取,如果没有找到环境变量,则会退回到环境变量上(投到合适的Python类型)。
config.load()
SECRET_KEY = config.SECRET_KEY
...
我最喜欢Goodconf的特点是你可以从一个配置类中生成输出。
config.generate_yaml()以帮助文本为注释的模板YAML配置config.generate_json()JSON配置模板config.generate_markdown()Markdown格式的文档
这可以让你快速生成一个用于本地开发的配置文件,并将文档放入README.md 。
使用Goodconf
Goodconf的README中有一些关于如何使用该库的例子,但如果你像我一样,看到一个例子会更容易。请看我们的saltdash repo,它是一个在Django项目中使用Goodconf的例子。
saltdash/__init__.py定义了配置saltdash/settings/__init__.py展示了如何使用它来定义Django设置setup.cfg(under[options.entry_points]) 显示了如何安装管理命令和配置生成器的脚本。
试试吧
我们现在正在生产中使用Goodconf,并对其结果感到满意。我们希望你能在自己的项目中试用它。如果你这样做了,请在这里或GitHub上给我们反馈。