Basics
Basic Concepts for using Chef
Basics of Chef
Infrastructure Automation > Learn the Basics > Ubuntu > Docker
Note 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
mkdir learn-chef
cd learn-chef
Start the Docker Container
Download the Ubuntu 14.04 image from Docker hub and start the container
docker pull ubuntu:14:04
From the shared learn-chef
directory, run the following command
$ docker run -it -v $(pwd):/root/chef-repo -p 8100:80 ubuntu:14.04 /bin/bash
PS> docker run -it -v ${pwd}:/root/chef-repo -p 8100:80 ubuntu:14.04 /bin/bash
Running 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
apt-get update
apt-get install curl -y
Next we can run Chef Workstation as follows:
curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P chef-workstation -c stable -v 0.2.41
Set 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
file '/tmp/motd' do
content 'hello world'
end
And then run the above file with the following command
chef-client --local-mode hello.rb
This 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
more /tmp/motd
If 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
file '/tmp/motd' do
content 'hello chef'
end
And then update the resource with
chef-client --local-mode hello.rb
And we will see that the file was updated with the following
- update content in file /tmp/motd from b94d27 to c38c60
--- /tmp/motd 2019-02-11 14:47:29.431735359 +0000
+++ /tmp/.chef-motd20190211-4014-8rvcal 2019-02-11 14:53:48.291735359 +0000
@@ -1,2 +1,2 @@
-hello world
+hello chef
If 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
echo 'hello robots' > /tmp/motd
And then having chef restore it
chef-client --local-mode hello.rb
Chef 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
file '/tmp/motd' do
action :delete
end
Then use the chef-client
to run it
chef-client --local-mode goodbye.rb
This will give us the following output
Recipe: @recipe_files::/root/chef-repo/goodbye.rb
* file[/tmp/motd] action delete
- delete file /tmp/motd
more /tmp/motd
#/tmp/motd: No such file or directory
Summary
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
apt_update 'Update the apt cache daily' do
frequency 86_400
action :periodic
end
Instead 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
apt_update 'Update the apt cache daily' do
frequency 86_400
action :periodic
end
package 'apache2'
We don't need to specify the :install
action as this is the default
Now run the recipe with
chef-client --local-mode webserver.rb
Typically (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
apt_update 'Update the apt cache daily' do
frequency 86_400
action :periodic
end
package 'apache2'
service 'apache2' do
supports status: true
action [:enable, :start]
end
Now re-run the recipe in order to start the service
chef-client --local-mode webserver.rb
Add 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
apt_update 'Update the apt cache daily' do
frequency 86_400
action :periodic
end
package 'apache2'
service 'apache2' do
supports status: true
action [:enable, :start]
end
file '/var/www/html/index.html' do
content '<html>
<body>
<h1>hello world</h1>
</body>
</html>'
end
And we can run chef-client
to apply it
chef-client --local-mode webserver.rb
If 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
curl localhost
Or
curl localhost:80
Furthermore 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
mkdir cookbooks
chef generate cookbook cookbooks/learn_chef_apache2
The 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
apt-get install tree -y
tree cookbooks
The file structure can be seen to be:
cookbooks
`-- learn_chef_apache2
|-- Berksfile
|-- CHANGELOG.md
|-- LICENSE
|-- README.md
|-- chefignore
|-- metadata.rb
|-- recipes
| `-- default.rb
|-- spec
| |-- spec_helper.rb
| `-- unit
| `-- recipes
| `-- default_spec.rb
`-- test
`-- integration
`-- default
`-- default_test.rb
The 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
chef generate template cookbooks/learn_chef_apache2 index.html
Move 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
<html>
<body>
<h1>hello cookbook</h1>
</body>
</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
apt_update 'Update the apt cache daily' do
frequency 86_400
action :periodic
end
package 'apache2'
service 'apache2' do
supports status: true
action [:enable, :start]
end
template '/var/www/html/index.html' do
source 'index.html.erb'
end
Run 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
chef-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
curl localhost
And by visiting localhost:8100
on the Host