Basics
Basic Concepts for using Chef
Updated: 03 September 2023
Basics of Chef
1Infrastructure Automation > Learn the Basics > Ubuntu > DockerNote About Environment
I am running a VM with access to a Shared Drive using VirtualBox, this can be found at root/media/sf_name on the Ubuntu VM
Set Up a Docker Container to Manage
We’ll make use of a Docker container with Ubuntu to work with Chef - generally though Docker containers are treated as immutable infrastructure
Before starting we will need to ensure that Docker is installed on our system so that we can run chef in the container
Make a Working Directory
Make a new directory in which we can work
1mkdir learn-chef2cd learn-chefStart the Docker Container
Download the Ubuntu 14.04 image from Docker hub and start the container
1docker pull ubuntu:14:04From the shared learn-chef directory, run the following command
1$ docker run -it -v $(pwd):/root/chef-repo -p 8100:80 ubuntu:14.04 /bin/bash1PS> docker run -it -v ${pwd}:/root/chef-repo -p 8100:80 ubuntu:14.04 /bin/bashRunning the container as above will expose also give our docker container access to our system ~ /chef-repo directory so that we can edit our chef code directly from there
From the Container
Update the container package list and install curl
Install Chef in Container
1apt-get update2apt-get install curl -yNext we can run Chef Workstation as follows:
1curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P chef-workstation -c stable -v 0.2.41Set Up the Working Directory
From the container cd into the ~/chef-repo directory that we initialized previously
In this directory (the same as your local learn-chef) directory, create the initial MOTD file by using chef-client in local mode (usually chef-client will download the latest code from a server though)
Inside of the chef-repo directory create a file called hello.rb with the following content
1file '/tmp/motd' do2 content 'hello world'3endAnd then run the above file with the following command
1chef-client --local-mode hello.rbThis will create a new file /tmp/motd which contains the text hello world
We can view the contents of this file using more or cat
1more /tmp/motdIf we run the chef-client command again we will see that no resources were updated
We can update the hello.rb file contents to contain the following
1file '/tmp/motd' do2 content 'hello chef'3endAnd then update the resource with
1chef-client --local-mode hello.rbAnd we will see that the file was updated with the following
1- update content in file /tmp/motd from b94d27 to c38c602--- /tmp/motd 2019-02-11 14:47:29.431735359 +00003+++ /tmp/.chef-motd20190211-4014-8rvcal 2019-02-11 14:53:48.291735359 +00004@@ -1,2 +1,2 @@5-hello world6+hello chefIf we manually change the /tmp/motd file, running chef-client will restore the correct configuration
You can test this by running the following command to modify the file
1echo 'hello robots' > /tmp/motdAnd then having chef restore it
1chef-client --local-mode hello.rbChef endsures that the actual state of a resource matches the state that was specified, even if it is altered by an external resource. Usually we configure chef-client to run periodically or as part of a continuous automation system which helps our resources be correctly configured
Delete MOTD file
Create a file called goodbye.rb with the following contents
1file '/tmp/motd' do2 action :delete3endThen use the chef-client to run it
1chef-client --local-mode goodbye.rbThis will give us the following output
1Recipe: @recipe_files::/root/chef-repo/goodbye.rb2 * file[/tmp/motd] action delete3 - delete file /tmp/motd1more /tmp/motd2#/tmp/motd: No such file or directorySummary
Resources describe the what, not the how. A recipe is a file that describes what state a part of the system should be in, but not how to get there - that is handled by Chef
Resources have actions, such as :delete which is a process by which a desired state is reached. Every resource has a default action, such as create a file or install a package. :create is the defult action for a file resource
Recipes are an ordered list of configuration states and typically contain related states
Configure a Package and Service
Packages and services, like files, are also resource types
For this portion we will be managing an Apache HTTP Server Package and its associated Service
Update Apt Cache
We can run the apt-get update command manually every time we bring up an instance, but chef provides us with an apt_update resource to automate the process
Chef allows us to periodically carry out a specific task, in this case we can update our apt cache every 24 hours (86 400 seconds)
In the chef-repo directory create a webserver.rb file with the instructions to periodically update the cache as follows
1apt_update 'Update the apt cache daily' do2 frequency 86_4003 action :periodic4endInstead of :periodic we can also use the :update action to update each time chef runs
Install the Apache Package
Next we can install the apache2 package, modify the webserver.rb package to do this
1apt_update 'Update the apt cache daily' do2 frequency 86_4003 action :periodic4end5
6package 'apache2'We don’t need to specify the :install action as this is the default
Now run the recipe with
1chef-client --local-mode webserver.rbTypically (if not the root user) we need to run Chef with sudo
Start and Enable the Apache Service
Update the webserver.rb file to enable the Apache service when the server boots and then start the service, this is one by way of the action list given in which the following actions on a resource will be carried out
1apt_update 'Update the apt cache daily' do2 frequency 86_4003 action :periodic4end5
6package 'apache2'7
8service 'apache2' do9 supports status: true10 action [:enable, :start]11endNow re-run the recipe in order to start the service
1chef-client --local-mode webserver.rbAdd a Home Page
We can use the file resource to create a homepage for our site at /var/www/html/index.html with a basic hello world message. This can be added to the webserver.rb recipe as follows
1apt_update 'Update the apt cache daily' do2 frequency 86_4003 action :periodic4end5
6package 'apache2'7
8service 'apache2' do9 supports status: true10 action [:enable, :start]11end12
13file '/var/www/html/index.html' do14 content '<html>15 <body>16 <h1>hello world</h1>17 </body>18</html>'19endAnd we can run chef-client to apply it
1chef-client --local-mode webserver.rbIf we do not see any errors we can continue and make an HTTP request with curl inside the container, making a curl to localhost will by default hit port 80, we can do this from the container as follows
1curl localhostOr
1curl localhost:80Furthermore we can view this on the host machine’s browser due to the port forwarding we initially set up for the container -p 8100:80 on which maps port 80 on the container to 8100 on the host. We can do this simply by visiting localhost:8100 from the host or making an HTTP request from the terminal
Summary
Chef allows us to automate and configure multiple resource types as well as carry out tasks periodically, manage installed packages, and specify actions for those packages
Making Recipes More Managable
The problem with the recipe we are currently using is that the HTML for the webpage was embedded in the recipe, this is not practical. In order to more easily reference external files we can make use of a Cookbook
Create a Cookbook
From the chef-repo directory create a cookbooks directory, in this run the use Chef to generate a Cookbook named learn_chef_apache2
1mkdir cookbooks2chef generate cookbook cookbooks/learn_chef_apache2The cookbooks/learn_chef_apache2 part tells chef to create a new Cookbook in the cookbooks directory called learn_chef_apache2
Thereafter install tree on the container so that we can view the directory structure and then look at the cookbooks directory
1apt-get install tree -y2tree cookbooksThe file structure can be seen to be:
1cookbooks2`-- learn_chef_apache23 |-- Berksfile4 |-- CHANGELOG.md5 |-- LICENSE6 |-- README.md7 |-- chefignore8 |-- metadata.rb9 |-- recipes10 | `-- default.rb11 |-- spec12 | |-- spec_helper.rb13 | `-- unit14 | `-- recipes15 | `-- default_spec.rb16 `-- test17 `-- integration18 `-- default19 `-- default_test.rbThe default recipe is in the recipes/default.rb file, our recipe will be written in there
Create a Template
A new template file can be generated with the chef generate command, generate a new template called index.html as follows
1chef generate template cookbooks/learn_chef_apache2 index.htmlMove the index.html content we made previously to a template file which will be added as templates/index.html.erb into which we must add the following
1<html>2 <body>3 <h1>hello cookbook</h1>4 </body>5</html>We have added the content directly into the cookbook for the purpose of the tutorial, but realstically the application would be some set of build artifacts that will then be pulled from a build server to be deployed
Update the Recipe
Now update the recipe in the default.rb file to once again update the apt cache, start the Apache Web Server, and reference the HTML template with the following
1apt_update 'Update the apt cache daily' do2 frequency 86_4003 action :periodic4end5
6package 'apache2'7
8service 'apache2' do9 supports status: true10 action [:enable, :start]11end12
13template '/var/www/html/index.html' do14 source 'index.html.erb'15endRun the Cookbook
chef-client can be used to run the Cookbook, we will again use the --local-mode flag and specify the required recipes with the --runlist flag
1chef-client --local-mode --runlist 'recipe[learn_chef_apache2]'Note the recipe[learn_chef_apache2] which specifies that we want to run the learn_chef_apache2’s default.rb recipe. This is the same as recipe[learn_chef_apache2::default]
We can check that the file was updated with
1curl localhostAnd by visiting localhost:8100 on the Host