Skip to end of metadata
Go to start of metadata


Requires Chef 0.10
The Environments feature is only available in chef 0.10.x and higher.

Overview

Environments in Chef provide a mechanism for managing different environments such as production, staging, development, and testing, etc with one Chef setup (or one organization on Hosted Chef).

With environments, you can specify per environment run lists in roles, per environment cookbook versions, and environment attributes.

The _default Environment

When you first create an organization, only one environment will be setup and it will be named the "_default" environment. You can use this environment for viewing, but editing is restricted so you can't modify it. If you try to, you will get an error similar to this:

You'll want to create a new environment if you want to modify it, such as setting the attributes.

Creating Environments

You can create environments in Chef in 5 different ways:

  1. through the creation of environment files in your chef repository (that utilize a ruby DSL, which gets compiled to JSON,)
  2. the creation of the JSON files directly in your chef repository,
  3. through the Open Source Chef Server Management Console,
  4. with Knife, or
  5. through the REST API.

We will cover each option here. When an environment exists, you can set a node to be in the environment using the node's chef_environment method. The remaining sections of this article will show the details of the work-flow.



Chef 0.10
Check out the Opscode Blog for an overview of the Environments feature within chef 0.10.


Choose Your Workflow

There are two workflows you can use to manage your environments: you can either write your environments as ruby or JSON files and push them to the server, or you can create environments with Knife or the Open Source Chef Server Management Console and edit them as you go along.

If you manage environments with files

  • You can use the ruby DSL or JSON
  • You can dynamically generate environment data using the ruby DSL
  • You can keep your environments in your version control system and have a history of who changed what and when.
  • You should not edit environments with Knife or the Open Source Chef Server Management Console, as your edits will be overwritten next time you upload from the file.

If you manage environments with Knife, the REST API and the Open Source Chef Server Management Console

  • You can use the -E ENVIRONMENT switch to knife cookbook upload to automatically configure an environment for a given cookbook version.
  • You can edit your environment with knife or the web interface.
  • The canonical source of a environment's data will be the Chef Server, which makes it difficult to keep in version control
  • You cannot use the ruby DSL.

These workflows are mutually exclusive: if you upload a environment to your Chef server from a file, then edit it with Knife or the Open Source Chef Server Management Console, and then edit the file and upload again, the changes you made with Knife or the Open Source Chef Server Management Console will be lost.

The Ruby DSL

Environments created through this mechanism get compiled to JSON, and then are loaded in to the Chef Server. (We never execute ruby code directly on the chef server!) Each time you rake install your Chef Repository, we will re-compile the corresponding JSON and store it in the chef server.

You should create these files in the 'environments' subdirectory of your chef repository. If your repository doesn't have this directory, create it now. Each DSL file should have a .rb suffix.

A complete environment file looks like this:

The Dev Environment

We'll go over each section below.

name

Each environment must have a unique name, which is made up of [A-Z][a-z][0-9] and [_-]. Spaces are not allowed.

name field

description

A short description of this environment.

description field

cookbook_versions

By specifying cookbook_versions, when chef-client is running on a node within a certain environment, it will pick the specified versions of the cookbooks.

cookbook_versions

Please see Cookbook Version Constraints for more on the syntax for cookbook versions and version constraints, to limit which versions of a cookbook should be used.

cookbook

Specify the version constraints for only one cookbook.

cookbook

attributes

Environments can set attributes at the default and override levels. See the attribute precedence list for a complete description of the precedence of attributes set in an environment. An environment attribute will be applied to all nodes within this environment, except in those places where it is overridden by another attribute with higher precedence.

attributes

In the above example, all nodes with this environment would have node[:apache2][:listen_ports] set to '80' and '443', unless otherwise specified by an attribute of higher precedence.

As JSON

The JSON format for environments maps directly to the Ruby DSL above. For the environment we describe in that section, the corresponding JSON is:

The two additional fields are described below.

json_class

This should always be set to Chef::Environment. This is used internally by Chef to auto-inflate this type of object. It should be ignored if you are re-building objects outside of Ruby, and its value may change in the future.

chef_type

This should always be set to environment. This is the field you should rely on if you are building a system to consume Environments
outside of Ruby.

Managing Environments With Knife

Knife is Chef's powerful command line interface tool. Environments can be managed through Knife. See Managing Environments With Knife for accomplishing this.

Managing Environments With the Management Console

You can create and manage environments through the Management Console. Hosted Chef customers should refer to Managing Environments with the Hosted Chef Management Console. Open Source Chef Server users should refer to Managing Environments through the Management Console.

The REST API

You can also create and manage environments directly in a running Chef Server via the REST API. Please refer to the Server API article for information.

Setting a Node's Environment

A node is considered by Chef associated with an environment by having the chef_environment "attribute" set

There are several ways to set this attribute:

  • Edit the "chef_environment" attribute on the node directly using Knife or the Open Source Chef Server Management Console.
  • Set "environment" config entry in Knife's config file knife.rb, and bootstrap the node by using "knife bootstrap" command, the instance bootstrapped will be in the specified environment.
  • Set "environment" config entry in chef-client's config file (by default /etc/chef/client.rb), when chef-client runs, it will pick up the value and set the chef_environment attribute of the node based on the value.
  • When creating/updating a node programmatically, suppose node is a Chef::Node object, calling node.chef_environment("dev") and node.save will update the chef_environment attribute on the node to "dev".

Note: The chef_environment 'attribute' cannot be set with normal or override attributes (i.e. in a role) since it is actually a method. It must be set explicitly via knife edit, knife exec, or one of the methods listed above. It also cannot be accessed via the typical attribute syntax node[:attribute_name] but rather must be accessed by calling the chef_environment method on the node: node.chef_environment.

Moving nodes in bulk

You can move nodes from, for instance, "_default" to your "dev" environment on the command line with:

Knife Plugin to Set Environment

You can take advantage of another Chef 0.10.0 feature, custom Knife plugins, to facilitate setting the node environment. Here's a plugin to set the node environment.

Per Environment Run Lists in Roles

In addition to being able to pick specific cookbook versions in an environment, per environment run lists in a role allow you to specify a different run list for a role if the role is in the run list of the node in a specific environment. Before the existence of environments, each role has only one run list and it will be expanded and applied to the node when chef-client runs. With environments, in the role you can specify one run list for each environment, such as:

If you do not specify a per environment run list for a certain environment, such as "production" and "preprod" in the above example, chef will use the default run list (like before).

Roles has additional information on role based runlists, including an example of a per environment runlist in .rb format.

Searching within Environments

Within search, chef_environment is treated much like an attribute. Thus search results can be limited to a given environment by using a boolean operator and an extra search term.

To find all the servers running CentOS in the QA environment using search:

Search within a Chef environment.

In a recipe, a code block like this would be useful:

Data Bags and Environments

Data bags are global to your organizations are available in any environment. If you would like to provide per-environment data within a data bag, you can use one of two possible strategies. The strategy that makes the most sense depends on your use case.

  1. Within a databag item, use a top level key that corresponds to the environment. For instance, you might have a databag that looks like this:

    When using the data bag in a recipe, you would then always access the data bag items looking via code similar to:

  2. Within a data bag, use separate items for each environment. Depending on your data, all of your data may fit nicely in a single item. If this is the case, then creating different items for each environment is an easy way to provide per-environment values within a data bag.

For more information about using data bags, see Data Bags.







Environments


Exception and Report Handlers



Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Apr 29, 2011

    It wasn't obvious from this page that you can upload the Ruby environment file with the command:
    knife environment from file environments/dev.rb

  2. Apr 29, 2011

    As far as I can tell, rake install will not upload environment files. At least a rake --dry-run doesn't seem to and I can't find any reference to environments in the chef-0.10.0.rc.1 chef_repo.rake file.

    Am I missing something?

    It would be nice to have rake upload_environments and upload_environment to match the databag and cookbook patterns

  3. May 08, 2011

    It would be really helpful if the section named, "Adding Environment to Nodes" was a bit more explicit in how to add these things. What is the syntax required for specifying an environment in the ~/.chef/knife.rb file?

  4. May 26, 2011

    Hi,

    With the new version of chef, I try to do this.

    For example: knife cookbook upload tcloudIaaSupdate -E tcloud.

    When I press Enter show next error:
    Uploading tcloudIaaSupdate [0.0.2]
    ERROR: TypeError: wrong argument type Hash (expected Data)

    After that I go to the chef-server web and I cannot see that this version its upload.

    What is the problem?

    Best Regards,
    Javier

  5. May 30, 2011

    Hi,

    When I try to do knife configure -i same error:
    *Creating initial API user...
    ERROR: TypeError: wrong argument type Hash (expected Data)*

    Please tell me something at soon as possible. It's very urgent

    Thanks

    1. May 30, 2011

      Hi Javier,

      Please see Support and seek assistance through IRC, or the Chef mailing list. (Or through help.opscode.com if you are a Platform customer.) You'll likely need to provide info re: your OS Platform and version, and what version of Chef and Ruby and RubyGems you are using - as that error could have a number of causes.

  6. Jul 09, 2011

    I had the same error. I was using Ubuntu 11.4 and chef-client 10.
    Downdagrading chef to 9.16 seemed to be a quickfix for me. I realize that is not a viable solution, but being in the learning chef phaze i needed a fast solution

  7. Aug 12, 2011

    Is it possible to specify an environment in the first-boot.json file?

    I'm trying to auto-provision servers with an environment.

    Alternately, is there a better way to make per environment variables?
    I want variables to apply to groups of machines.
    I'm using roles to control my webservers, then environments to define variables for dev/production. I don't want to version cookbooks for one attribute when I can use the defaults in the environment.
    Am I going about this the wrong way?