In this article, we will details all the required steps to build up an environment to host the previous incarnation of this blog on Nginx using Chef on HP Cloud. Twelve years later the world has changed and this blog is now hosted on a bare metal machine in Germany.
Chef Repo cloning
First of all, if you don’t already have a Chef Repository available on your Chef Workstation, you can clone one easily :
% git clone git://github.com/opscode/chef-repo.git
% cd chef-repo
Install cookbooks to your newly cloned repo
% knife cookbook site install build-essential apt chef-client sudo
For Nginx and users cookbooks install the latest version available on github
% git clone https://github.com/planetrobbie/nginx.git
% git clone https://github.com/opscode-cookbooks/users.git
Patch Nginx cookbook to correct default_site_enabled. See my pull request for details or the following file cookbooks/nginx/definitions/nginx_site.rb
Upload cookbooks to Hosted Chef
% knife cookbook upload --all
Create a new Environment for HP Cloud
File chef-repo/environments/hpcloud.json
#!json
{
"name": "production_hpcloud",
"description": "HP Cloud Servers",
"json_class": "Chef::Environment",
"chef_type": "environment",
"override_attributes": {
"datacenter": "hpcloud"
}
}
% knife environment from file environments/hpcloud.json
% knife environment show production_hpcloud
Create a new bootstrap cookbook
This cookbook will
- install base packages: htop, iftop, vnstat, vim, tree, curl, ntp, ntpdate, byobu
- create new unix accounts from users data bag
- put the users in their respective groups.
% knife cookbook create bootstrap
and copy source file linked below
File cookbooks/bootstrap/recipes/default.rb
Create a new yet_site cookbook
This cookbook will
- create
/var/www/yet
owned bywww-data:www-data
- add all data bag users which are declared in
www-data
to this group by using opscode users cookbook, it require adepends "users"
in cookbookmetadata.rb
- enable Nginx Yet site by symlinking
sites-enabled/yet
tosites-available/yet
% knife cookbook create yet_site
to create the cookbook, see content below.
File cookbooks/yet_site/recipe/default
include_recipe "users"
include_recipe "nginx"
directory "/var/www" do
owner "www-data"
group "www-data"
mode "0775"
end
directory "/var/www/yet" do
owner "www-data"
group "www-data"
mode "0775"
end
users_manage "www-data" do
group_id 33
end
template "#{node['nginx']['dir']}/sites-available/yet" do
source "yet.erb"
owner "root"
group "root"
mode 00644
end
nginx_site "yet" do
action :enable
end
File cookbooks/yet_site/templates/default/yet.erb
server {
listen 80;
server_name yet.org;
root /var/www/yet;
}
Create a base role
A role with configuration common to all nodes
File roles/base.rb
name "base"
description "Base role applied to all nodes."
run_list(
"recipe[apt]",
"recipe[chef-client]",
"recipe[bootstrap]",
"recipe[sudo]"
)
override_attributes(
:authorization => {
:sudo => {
:users => ["ubuntu", "brauns"],
:passwordless => true
}
}
)
NOTE: chef-client recipe used to configure our node with a chef daemon which runs every 1800 seconds with a variance of 20 seconds and a log file at
/var/log/chef
.
% knife role from file roles/base.rb
to upload the new role to the Chef Server
Create a yet_server role
This role will be used to apply Nginx, yet_site recipes and disable default_site.
File chef-repo/roles/yet_server.rb
name "yet_server"
description "YET static site server"
run_list "recipe[nginx]", "recipe[yet_site]"
override_attributes(
"nginx" => {
"default_site_enabled" => false
}
)
% knife role from file roles/yet_server.rb
to upload the new role to the Chef Server
Create databags for unix accounts
users cookbook consume a databag to create sysadmin account on all nodes, it’s recommended to use the same user account as on your Chef Workstation.
First, create a new data bag file named after the user you want to create:
% mkdir -p data_bags/users
% vi data_bags/users/$USER.json
{
"id": "USER",
"ssh_keys": "ssh-rsa AAAAB3N...9Ve4w7b email@email.com",
"groups": [ "admin", "adm", "www-data" ],
"uid": 2000,
"shell": "\/bin\/bash"
}
ssh_keys
should contains your ~/.ssh/id_rsa.pub key, use an Array if you have multiple keys to upload.
% knife data bag create users
to create users databag on the Chef Server
% knife data bag from file users $USER.json
to add the first sysadmin
Bootstrap an HP cloud instance using Knife
We can now bootstrap a new node using the command below which assume you’ve prepared your environment for knife hp
% knife hp server create --flavor 100 --image 48335 --ssh-key USERNAME -N ww1.yet.org --ssh-user ubuntu -r 'role[base],role[yet_server]'
Refer to our HP cloud cheatsheet for details.
% knife search node "role:yet_server"
to check if your node is provisionned correctly
Note: On Ubuntu 12.04 (precise), knife bootstrapping use the following template
./.rvm/gems/ruby-1.9.3-p286/gems/chef-10.16.2/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb
You can change it and provide it with the –template argument, place it under ~/.chef
This template do the following :
- configure env variable http_proxy to knife_config[:bootstrap_proxy]
- install packages: *Ruby 1.8-dev, build-essential, wget, libruby1.8, rubygems
- update gems
- install gems: ohai, chef
- create /etc/chef directory
- output validation_key to /tmp/validation.pem, modifies (remove blank lines, mode 0600) and sent to /etc/chef
- output encrypted_databag_secret to /tmp, modifies (remove blank lines, mode 0600) and send to /etc/chef
- output Ohai hints if @chef_config[:knife][:hints] to /etc/chef/ohai/hints
- output config_content -> /etc/chef/client.rb
- output first_boot.json -> /etc/chef/first-boot.json which contains {“run_list”:[]}
- start chef
NOTE: to Synchronise clock on your Chef Workstation if it is out of sync:
% sudo systemctl restart ntpd.service
Add host attribute to node
#!json
% knife node edit ww1.yet.org
{
"name": "ww1.yet.org",
"chef_environment": "production_hpcloud",
"normal": {
"host": "www.yet.org",
"tags": [
],
"runit": {
"sv_bin": "/usr/bin/sv",
"chpst_bin": "/usr/bin/chpst",
"service_dir": "/etc/service",
"sv_dir": "/etc/sv"
},
"chef_client": {
"bin": "/usr/bin/chef-client"
},
"ohai": {
"plugins": {
}
}
},
"run_list": [
"role[base]",
"role[yet_server]",
"recipe[bootstrap::hostname]"
]
}
Associate role to node
If you didn’t provide run_list info while boostrapping with -r
argument, you now have to associate your node with your run_list
% knife node run_list add ww1.yet.org 'role[base], role[yet_server]'
Run chef-client
You can force a chef-client run on your remote node with:
% knife ssh name:www.yet.org -x ubuntu "sudo chef-client"
NOTE: Don’t forget to update your DNS record to resolve your host FQDN
Rake tasks for Rsync deployment
# encoding: utf-8
ssh_user = "ubuntu@yet"
remote_root = "/var/www/yet/"
desc "builds and deploy"
task :deploy do
puts "*** compile yet ***"
system "nanoc compile"
puts "*** deploy yet ***"
system "rsync -avz --delete output/* #{ssh_user}:#{remote_root}"
end
Update default security group
to allow TCP/80,
% hpcloud securitygroups:rules:add default tcp -p 80..80
% hpcloud securitygroups:rules default
refer to my HP Cloud cheatsheet to install hpcloud.
Upgrade all nodes packages
% knife ssh 'name:*' -x ubuntu "sudo aptitude upgrade -y"
SSH Configuration
NOTE: to avoid SSH issues, switch to non
StrictHostKeyChecking
for HP Cloud IP addresses in your/etc/ssh/ssh_config
Host 15.*
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null
Links, Tips & Tricks
/usr/lib/update-notifier/apt-check -p --human-readable
list packages available for update on Ubuntu/Debianknife search node "name:NODENAME" -F json
dump a node to JSON to get all its detailsknife ssh -x ubuntu "id:*" "uptime"
Get uptimes of all your hosts or run any command remotly- Attributes docs and samples on Chef Wiki.
- A Brief Chef Tutorial (From Concentrate) article
- Some Awk one liners
Conclusion
As you’ve seen in this article, building up YET using Opscode Chef is great because if we need to build it again we won’t have to redo all the steps one more time. It is just necessary to bootstrap a new node in any cloud, he will then come up ready to receive our content using Rsync and will publish it using Nginx. If you want, you can now procede to part 2.