Chef

Table Of Contents

Chef for Containers

Containers are an approach to virtualization that allow a single operating system to host many working configurations, with each working configuration running as a process that is isolated from all other processes, including even the host operating system. Each container comprises a working configuration—or application—and all of its dependencies that are not already available from the host operating system or from another container that is also running on the host operating system.

_images/containers.png

LXC—Linux containers—eliminate the need for a hypervisor by leveraging a Linux kernel feature called control groups. Control groups allow a Linux-based operating system to isolate CPU, memory, network, file system volumes, and processes into a userspace commonly referred to as a container. This approach to virtualization allows a single operating system to host many working configurations, with each working configuration running in isolation from the other containers and the host itself, without the need for a hypervisor or a guest operating system. Each container comprises a working configuration—or application—and all of its dependencies that are not already available from the host operationg system or from another conttainer.

chef-container

chef-container is a distribution of the chef-client that includes components designed to support the unique requirements of running the chef-client from within a Linux container.

  • chef-container comes packaged with chef-client, runit and chef-init
  • Bootstrap the chef-client without an SSH connection
  • Use the knife container Knife plugin to work with Linux containers; use the docker build and docker init arguments to manage Docker image contexts
  • Use chef-client resources the same way in a container as on any UNIX- or Linux-based platform

Securing Credentials

The best practice for securing credentials like private keys, secrets, and certificates that are used with containers is to not store them within the container images. To support this best practice, knife container by default deletes these files upon the completion of the image build. The process for mounting or otherwise making these files available to the chef-client varies, depending on the solution being used for containers.

Chef for Docker

Docker is an open-source engine that helps automates the deployment of any working configuration as a lightweight, portable, self-sufficient container. Docker packages a container (a working configuration) into a Docker image, which is then uploaded to the Docker registry. From there, any node that runs the Docker engine can launch this image as a new container. Docker containers can be run anywhere: the same container used by a developer to build and test their code on a laptop can also be run in production, on a virtual machine, a bare-metal server, as part of an OpenStack cluster, and so on. Using Docker helps to

  • Simplify the packaging and deployment of applications
  • Create versitile, lightweight environments
  • Automate testing, continuous integration, and continuous deployment efforts
  • Deploy and scale web applications, databases, and backend services
_images/containers_docker.png

Chef can be used to manage Docker containers, including:

  • Creating and deploying Docker container images
  • Configuring Docker containers on-boot, and then protecting them against configuration drift
  • Provisioning and configuring the environments in which Docker containers are hosted
  • Managing complex, bidirectional dependencies among Docker containers and other nodes in the network
_images/containers_docker_chef.png

Credential Management

Credentials such as private keys, secrets, and certificates should not be kept in Docker images. By default, secure credentials are deleted after the knife container docker build process is completed. In order for the resulting image to launch properly, the secure credentials must be mounted into the /etc/chef/secure directory. Credentials must be copied into a folder on the host machine, and then mounted into the container using the -v flag of the docker run command: https://docs.docker.com/reference/commandline/cli/#run.

For example, if all secure credentials are located in the /etc/chef-container/secure directory on the Docker host, run the following command:

$$ docker run -d -v /etc/chef-container/secure:/etc/chef/secure:ro NAMESPACE/IMAGE

Use the --include-credentials option with the docker init subcommand to override the default behavior and include these secure credentials in the image. For example:

$ knife container docker init example/apache2 -r 'recipe[apache2]' --include-credentials

You will need to define the container_service for the services defined by the apache2 recipe. These will be managed by the runit init scheme that comes with chef-container. For more information about container_service, see http://docs.getchef.com/containers.html#container-services.

Dockerfile

A Dockerfile contains all of the settings needed to use a container with Chef. The following Dockerfile settings are required:

Setting Description
ADD <src> <dest> The path to the location from which files are copied (<src>) and the location in the container’s file system (<dest>) to which those same files will be added. Default value: chef/ /etc/chef/.
CMD Use to specify additional parameters to ENTRYPOINT. Default value: --onboot.
ENTRYPOINT Use to specify that a container be run as an executable. This setting may appear only once in a Dockerfile. Default value: ["chef-init"], which will run the container as the chef-client.
FROM The image from which a container will be built. This must be the first setting in a Dockerfile. This value of this setting is the REPO_NAME_OR_IMAGE_NAME value that is specified when using the docker init argument with the knife container subcommand. Default value: chef/ubuntu_12.04.
RUN A command to be run inside the container. There may be more than one command specified. Default value: chef-init --bootstrap.

For more information about these settings, plus the full list of settings available to a Dockerfile, see http://docs.docker.io/reference/builder/.

knife container

The knife container plugin is used to initialize and build containers. Use the knife container docker arguments to initialize containers using Docker.

Note

This plugin requires that Docker be installed on the same machine from which the plugin will be run. See http://docs.docker.com/installation/ for more information about how to install Docker.

Install this plugin

To install the knife-container plugin, run one of the following commands. When using the ChefDK:

$ chef gem install knife-container

and when using RubyGems:

$ /opt/chef/embedded/bin/gem install knife-container

where /opt/chef/embedded/bin/ is the path to the location in which the chef-client looks for Knife plugins. If the chef-client was installed using RubyGems, omit this path.

docker build

The docker build argument is used to build a Docker container image.

Syntax

This argument has the following syntax:

$ knife container docker build NAMESPACE_OR_IMAGE_NAME

Options

This argument has the following options:

-d DOCKERFILES_PATH, --force DOCKERFILES_PATH
The directory in which Dockerfile contexts are located.
--force
Use to force a build. Default value: false.
--no-berks
Use to prevent Berkshelf from running, even when a Berksfile exists.

docker init

The docker init argument is used to set up a Dockerfile context for the local workstation.

Syntax

This argument has the following syntax:

$ knife container docker init REPO_NAME_OR_IMAGE_NAME

Options

This argument has the following options:

-b, --berksfile
Use to generate a Berksfile based on the run-list specified by the --run-list option. This option requires Berkshelf. Default value: false.
--cookbook-path PATH[:PATH]
The directory in which cookbooks are located. This may be a colon-separated path.
-d DOCKERFILES_PATH, --dockerfiles-path DOCKERFILES_PATH
The directory in which Dockerfile contexts are located.
--environments-path PATH[:PATH]
The directory in which environments are located. This may be a colon-separated path.
-f [REPO/]IMAGE[:TAG], --from [REPO/]IMAGE[:TAG]
Use to specify the image to use as the base image. This image is then tagged and applied as the FROM value in the Dockerfile. Currently, this value must be an image made available via the Chef Docker Hub Account :https://registry.hub.docker.com/repos/chef/. Default value: chef/ubuntu-12.04:latest.
--force
When true, use to overwrite existing Dockerfile contexts.
--include-credentials
Use to include secure credentials in a Docker image.
--node-path PATH[:PATH]
The directory in which nodes are located. This may be a colon-separated path.
--role-path PATH[:PATH]
The directory in which roles are located. This may be a colon-separated path.
-r RUN_LIST, --run-list RUN_LIST
A comma-separated list of roles and/or recipes to be applied.
--secret-file PATH
The path to the file that contains the encryption key.
--server-url URL
The URL for the Chef server.
--trusted-certs-dir PATH
The directory in which trusted certificates are located.
--validation-client-name NAME
The name of the validation client, typically a client named chef-validator.
--validation-key PATH
The path to the validation key used by the client, typically a file named chef-validator.pem.
-z, --local-mode
Use to run the chef-client in local mode. This allows all commands that work against the Chef server to also work against the local chef-repo. This will include and use a local chef-repo when building the Docker image.

Examples

Create a Dockerfile

$ knife container docker init docker -r 'recipe[apache2]' -z -b

will create a directory named docker with a subdirectory named demo in the Chef::Config[:knife][:dockerfiles_path] path. In the docker directory, a subdirectory named chef is created, which contains all of the files and folders that are necessary for the chef-client to run successfully inside a container. The Dockerfile is similar to:

FROM chef/ubuntu_12.04
ADD chef /etc/chef
RUN chef-init --bootstrap
ENTRYPOINT ["chef-init"]
CMD ["--onboot"]

Local mode

$ knife container docker init example/apache2 -r 'recipe[apache2]' -z

will create a directory named example with a subdirectory named demo in the Chef::Config[:knife][:dockerfiles_path] path. In the example directory, a subdirectory named chef is created, which contains all of the files and folders that are necessary for the chef-client to run successfully inside a container.

You will need to define the container_service for the services defined by the apache2 recipe. These will be managed by the runit init scheme that comes with chef-container. For more information about container_service, see http://docs.getchef.com/containers.html#container-services.

Server mode

$ knife container docker init example/apache2 -r 'recipe[apache2]'

will create a directory named example with a subdirectory named demo in the Chef::Config[:knife][:dockerfiles_path] path. In the example directory, a subdirectory named chef is created, which contains all of the files and folders that are necessary for the chef-client to run successfully inside a container.

Include secure credentials in image

To override the default behavior and include secure credentials in an image:

$ knife container docker init example/apache2 -r 'recipe[apache2]' --include-credentials

You will need to define the container_service for the services defined by the apache2 recipe. These are managed by the runit init scheme that comes with chef-container. For more information about container_service, see http://docs.getchef.com/containers.html#container-services.

Container Services

The service that runit will manage is defined as an attribute of the container. This may be done by editing the first-boot.json file or by adding an attribute to a cookbook.

For example, the first-boot.json file may look similar to:

{
  "run_list": [
    "recipe[recipe_name]"
  ],
  "container_service": {
    "service_resource_name": {
      "command": "service_run_command"
    }
  }
}

where:

  • recipe_name is the name of the recipe
  • service_resource_name is the service resource name that will be managed by runit
  • service_run_command is the command that will be executed by runit to manage the service

For example, if the service is Nginx, the container_service paramaters would be similar to:

{
  "run_list": [
    "recipe[nginx]"
  ],
  "container_service": {
    "nginx": {
      "command": "/usr/sbin/nginx -c /etc/conf/nginx.conf"
    }
  }
}

The container service setting may also be specified using an attributes file in a cookbook. For example:

default['container_service']['service_resource_name']['command'] = 'service_run_command'

or, using the same Nginx example as above:

default['container_service']['nginx']['command'] = '/usr/sbin/nginx -c /etc/conf/nginx.conf'