【问题标题】:Managing configurations for different environments管理不同环境的配置
【发布时间】:2018-11-09 16:07:31
【问题描述】:

我与工作中的一些人进行了讨论,但我们无法得出结论。
我们遇到了一个难题 - 您如何管理不同环境的不同配置值?

我们提出了一些选择,但似乎没有一个能让我们满意:
- 单独的配置文件(即config.testconfig.prod 等),并有一个指向所选文件的文件(例如~/env)或指向它的环境变量。
- 使用单个数据库存储所有配置(您使用环境查询它并获取相应的配置值)
- 在部署时创建配置文件(使用 CI/CD 系统,如 Atlassian Bamboo)

哪个是更广泛使用的选项?有没有更好的办法?
配置文件是否应该与其余代码一起保存在 git 存储库中? 我们的系统是用 python(2.7 和 3)编写的

【问题讨论】:

    标签: python configuration continuous-integration configuration-files continuous-deployment


    【解决方案1】:

    您可以将所有这些配置放在单个配置文件 config.py 中。

    class Base():
        DEBUG = False
        TESTING = False
    
    class DevelopmentConfig(Base):
        DEBUG = True
        DEVELOPMENT = True
        DATABASE_URI = "mysql+mysqldb://root:root@localhost/demo"
    
    class TestingConfig(Base):
        DEBUG = False
        TESTING = True
        DATABASE_URI = "mysql+mysqldb://root:root@test_server_host_name/demo_test"
    
    class ProductionConfig(Base):
        DEBUG = False
        TESTING = False
        DATABASE_URI = "mysql+mysqldb://root:root@prod_host_name/demo_prod"
    

    关于shell设置环境变量之类的

    APP_SETTINGS = config.DevelopmentConfig

    在您的主应用程序 app.py 中,加载此环境变量(以烧瓶应用程序为例)

    from flask import Flask
    import os
    
    app = Flask(__name__)
    app.config.from_object(os.environ['APP_SETTINGS'])
    

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      将您的配置设置提交到源代码管理通常是个坏主意,尤其是当这些设置包含密码或其他机密时。我更喜欢使用环境变量将这些值传递给程序。我发现最灵活的方法是使用argparse 模块,并使用环境变量作为默认值。这样,您可以在命令行上覆盖环境变量。不过,在命令行中输入密码时要小心,因为其他用户可能会在进程列表中看到您的命令行参数。

      这是使用argparse 和环境变量的an example

      def parse_args(argv=None):
          parser = ArgumentParser(description='Watch the raw data folder for new runs.',
                                  formatter_class=ArgumentDefaultsHelpFormatter)
          parser.add_argument(
              '--kive_server',
              default=os.environ.get('MICALL_KIVE_SERVER', 'http://localhost:8000'),
              help='server to send runs to')
          parser.add_argument(
              '--kive_user',
              default=os.environ.get('MICALL_KIVE_USER', 'kive'),
              help='user name for Kive server')
          parser.add_argument(
              '--kive_password',
              default=SUPPRESS,
              help='password for Kive server (default not shown)')
      
          args = parser.parse_args(argv)
          if not hasattr(args, 'kive_password'):
              args.kive_password = os.environ.get('MICALL_KIVE_PASSWORD', 'kive')
          return args
      

      设置这些环境变量可能有点混乱,尤其是对于系统服务。如果您使用的是 systemd,请查看 service unit,并小心使用 EnvironmentFile 而不是 Environment 来获取任何秘密。任何使用systemctl show 的用户都可以查看Environment 值。

      我通常使默认值对在他们的工作站上运行的开发人员有用,这样他们就可以在不更改任何配置的情况下开始开发。

      另一种选择是将配置设置放在settings.py 文件中,并注意不要将该文件提交到源代码管理。我经常提交用户可以复制的settings_template.py 文件。

      【讨论】:

        【解决方案3】:

        一种方法是为每种配置文件编写一个“模板”,其中模板主要包含纯文本,但带有一些占位符。这是一个示例模板配置文件,使用符号${foo} 表示占位符。

        serverName  = "${serverName}"
        listenPort  = "${serverPort}"
        logDir      = "/data/logs/${serverName}";
        idleTimeout = "5 minutes";
        workingDir  = "/tmp";
        

        如果您对应用程序使用的所有配置文件都这样做,那么您可能会发现对模板配置文件执行全局搜索和替换,并使用相对较少的占位符的值将产生就绪-为特定部署运行配置文件。如果您正在寻找一种简单的方法来对模板文件中的占位符执行全局搜索和替换并且熟悉 Java,那么您可能需要考虑 Apache Velocity。但我想在 Python 中开发类似的功能将是微不足道的。

        【讨论】:

          【解决方案4】:

          我们最终使用了类似于one 的方法。 我们有一个基本设置文件和环境特定文件,它们只是从基本文件中导入所有内容 base.py:

          SAMPLE_CONFIG_VARIABLE = SAMPLE_CONFIG_VALUE
          

          prod.py:

          from base.py import *
          

          因此,当从配置中访问值时,我们所要做的就是读取环境变量并创建与之对应的文件。

          【讨论】:

            【解决方案5】:

            如果我们使用烧瓶,那么我们可以像这样进行环境特定的配置管理:

            -- project folder structure
            
            config/
               default.py
               production.py
               development.py
            instance/
              config.py
            myapp/
              __init__.py
            

            在应用初始化期间,

            # app/__init__.py
            
            app = Flask(__name__, instance_relative_config=True)
            
            # Load the default configuration
            app.config.from_object('config.default')
            
            # Load the configuration from the instance folder
            app.config.from_pyfile('config.py')
            
            # Load the file specific to environment based on ENV environment variable
            # Variables defined here will override those in the default configuration
            app.config.from_object('config.'+os.getenv("ENV"))
            

            在运行应用程序时:

            # start.sh
            # ENV should match the file name    
            ENV=production python run.py
            

            上述方法是我的首选方法。此方法基于best practices described here,只对基于环境变量的文件名进行少量修改。

            但还有其他选择

            【讨论】:

              猜你喜欢
              • 2023-04-10
              • 2020-08-09
              • 1970-01-01
              • 2018-10-26
              • 1970-01-01
              • 2012-11-25
              • 2020-04-16
              • 2013-07-25
              • 1970-01-01
              相关资源
              最近更新 更多