Managing application configuration in a chef envir

2020-07-19 03:53发布

问题:

I am new to chef and have been struggling to find best practices on how to configure application configuration in an environment cookbook [source #1].

The environment cookbook I'm working on should do the following:

  • Prepare the node for a custom application deployment by creating directories, users, etc. that are specific for this deployment only.
  • Add initialization and monitoring scripts specific for the application deployment.
  • Define the application configuration settings.

This last responsibility has been a particularly tough nut to crack.

An example configuration file of an application deployment might look as follows:

{
    "server": {
        "port": 9090
    },
    "session": {
        "proxy": false,
        "expires": 100
    },
    "redis": [{
        "port": 9031,
        "host": "rds01.prd.example.com"
    }, {
        "port": 9031,
        "host": "rds02.prd.example.com"
    }],
    "ldapConfig": {
        "url": "ldap://example.inc:389",
        "adminDn": "CN=Admin,CN=Users,DC=example,DC=inc",
        "adminUsername": "user",
        "adminPassword": "secret",
        "searchBase": "OU=BigCustomer,OU=customers,DC=example,DC=inc",
        "searchFilter": "(example=*)"
    },
    "log4js": {
        "appenders": [
            {
                "category": "[all]",
                "type": "file",
                "filename": "./logs/myapp.log"
            }
        ],
        "levels": {
            "[all]": "ERROR"
        }
    },
    "otherService": {
        "basePath" : "http://api.prd.example.com:1234/otherService",
        "smokeTestVariable" : "testVar"
    }
}

Some parts of this deployment configuration file are more stable than others. While this may vary depending on the application and setup, things like port numbers and usernames I prefer to keep the same across environments for simplicity's sake.

Let me classify the configuration settings:

Stable properties

  • session
  • server
  • log4js.appenders
  • ldapConfig.adminUsername
  • ldapConfig.searchFilter
  • otherService.basePath
  • redis.port

Environment specific properties

  • log4js.levels
  • otherService.smokeTestVariable

Partial-environment specific properties

  • redis.host: rds01.[environment].example.com
  • otherService.basePath: http://api.[environment].example.com:1234/otherService

Encrypted environment specific properties

  • ldapConfig.adminPassword

Questions

  1. How should I create the configuration file? Some options: 1) use a file shipped within the application deployment itself, 2) use a cookbook file template, 3) use a JSON blob as one of the attributes [source #2], 4)... other?
  2. There is a great diversity of variability in the configuration file; how best to manage these using Chef? Roles, environments, per-node configuration, data-bags, encrypted data-bags...? Or should I opt for environment variables instead?

Some key concerns in the approach:

  • I would prefer there is only 1 way to set the configuration settings.
  • Changing the configuration file for a developer should be fairly straightforward (they are using Vagrant on their local machines before pushing to test).
  • The passwords must be secure.
  • The chef cookbook is managed within the same git repository as the sourcecode.
  • Some configuration settings require a great deal of flexibility; for example the log4js setting in my example config might contain many more appenders with dozens of fairly unstructured variables.

Any experiences would be much appreciated!

Sources

  1. http://blog.vialstudios.com/the-environment-cookbook-pattern/
  2. http://lists.opscode.com/sympa/arc/chef/2013-01/msg00392.html
  3. http://jtimberman.housepub.org/blog/2013/01/28/local-templates-for-application-configuration/
  4. http://realityforge.org/code/2012/11/12/reusable-cookbooks-revisited.html

回答1:

Jamie Winsor gave a talk at chefconf that goes further in explaining the environment cookbook pattern's rationale and usage:

  • Chefcon: talking about self-contained releases, using chef
  • Slides

In my opinion one of the key concepts this pattern introduces is the idea of using chef environments to control the settings of each application instance. The environment is updated, using berkshelf, with the run-time version of the cookbooks being used by the application.

What is less obvious is that if you decide to reserve a chef environment for the use of a single application instance, it then it becomes safe to use that environment to configure the application's global run-time settings.

An example if given in the berkshelf-api installation instructions. There you will see production environment (for the application) being edited with various run-time settings:

knife environment edit berkshelf-api-production

In conclusion, chef gives us lots of options. I would make the following generic recommendations:

  1. Capture defaults in the application cookbook
  2. Create an environment for each application instance (as recommended by pattern)
  3. Set run-time attribute over-rides in the environment

Notes:

  • See also the berksflow tool. Designed to make the environment cookbook pattern easier to implement.
  • I have made no mention of using roles. These can also be used to override attributes at run-time, but might be simpler to capture everything in a dedicated chef environment. Roles seem better suited to capturing information peculiar to a component of an application.