Skip to content

Instantly share code, notes, and snippets.

@romansklenar
Last active February 19, 2020 14:14
Show Gist options
  • Star 37 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save romansklenar/5948258 to your computer and use it in GitHub Desktop.
Save romansklenar/5948258 to your computer and use it in GitHub Desktop.
How to set up your VPS with Chef Solo

How to set up your VPS with Chef Solo

1. What is it?

There are many different provisioning tools out there, the most popular of which are Chef and Puppet. Chef uses Ruby, Puppet uses a DSL (Domain Specific Language), there are others that use simple bash too, but today we're going to focus on Chef Solo.

2. Dependencies

To get Chef working properly on your local machine you need a few things.

Make sure you use Ruby 1.9.x and not Ruby 2.x as you will get errors with the json 1.6.1 gem on 2.x. Use rbenv or RVM to manage several different Rubies on the one machine.

You can install dependencies via bundler or manually.

2.1 Installing dependencies via Bundler

Add following content to new Gemfile in your future "chef kitchen" (let's say in ~/Projects/chef-demo) and run command bundle install.

source 'https://rubygems.org'
ruby '1.9.3'

gem 'knife-solo'
gem 'librarian-chef'

2.2 Installing dependencies manually

Because Chef runs on our server and not on our local machine, we don't need it in our dependencies. So alternativelly you can install gems globally by runnig these commands:

gem install knife-solo --no-ri --no-rdoc
gem install librarian-chef --no-ri --no-rdoc

You can now test your new setup by running knife solo and you should get output like:

% knife solo
Available solo subcommands: (for details, knife SUB-COMMAND --help)

** SOLO COMMANDS **
knife solo cook [USER@]HOSTNAME [JSON] (options)
knife solo prepare [USER@]HOSTNAME [JSON] (options)
knife solo bootstrap [USER@]HOSTNAME [JSON] (options)
knife solo clean [USER@]HOSTNAME
knife solo init DIRECTORY

And running librarian-chef which should produce output like:

% librarian-chef
Commands:
  librarian-chef clean           # Cleans out the cache and install paths.
  librarian-chef config          # Show or edit the config.
  librarian-chef help [COMMAND]  # Describe available commands or one specific command
  librarian-chef init            # Initializes the current directory.
  librarian-chef install         # Resolves and installs all of the dependencies you specify.
  librarian-chef outdated        # Lists outdated dependencies.
  librarian-chef show            # Shows dependencies
  librarian-chef update          # Updates and installs the dependencies you specify.
  librarian-chef version         # Displays the version.

3. Basic setup

Create a new directory structure (i.e. "kitchen") that fits with Chef's standard structure and can be used to build and store recipes.

cd ~/Projects
mkdir chef-demo
cd chef-demo
knife solo init .

The last . is important. It tells knife-solo that we want to create the project in the current directory. You can change it and place it to another directory. It should create following files and directories structure:

chef-demo/
├── cookbooks
├── data-bags
├── nodes
├── roles
├── site-cookbooks
├── tmp
├── Cheffile
├── Cheffile.lock
├── Gemfile
├── Gemfile.lock
├── solo.rb

Now we have a basic Chef project it’s time to get some cookbooks to install some stuff on our server.

Run librarian-chef init in the root of your project to make librarian-chef manage it. You should now have a file in the root of your project called Cheffile. Add there available cookbooks - you can choose from official repository. For example this is Cheffile for LAMP server.

#!/usr/bin/env ruby
#^syntax detection

site 'http://community.opscode.com/api/v1'

cookbook 'apache2'
cookbook 'mysql'
cookbook 'php'

Now run librarian-chef install and it should go off and grab your cookbooks and dependencies for you.

Third party cookbooks should always live in ./cookbooks, so this is where librarian-chef has put them. If you ever need to override something in a cookbook, never modify it, instead, put the corresponding changes in ./site-cookbooks.

If you want to use git, add cookbooks and tmp directories into .gitignore.

echo /cookbooks >> .gitignore
echo /tmp >> .gitignore

4. Nodes

In Digital Ocean a VPS is a droplet. In Chef a VPS or server is called a node. Not surprisingly, node configuration files live in ./nodes. They should be named in the format {hostname|ip}.json. Your hostname is probably better long term as your IP address can change. If you don't know either yet, you can call it anything you want, but you will lose a little syntactic sugar on the command-line a little later on.

Before we start bootstraping server try to connect via ssh by calling ssh root@YOUR_SERVER_IP_OR_ALIAS to check that you're able to make a connection. If everything is OK leave shh by typing exit.

You can install Chef on a given host by command knife solo prepare root@YOUR_SERVER_IP_OR_ALIAS. This will login to your server, then download and install chef. It's structured to auto-detect the target OS and change the installation process accordingly. If everything was done correctly you should see similar output like this:

$ knife solo prepare root@YOUR_SERVER_IP_OR_ALIAS

Bootstrapping Chef...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  6516  100  6516    0     0  15228      0 --:--:-- --:--:-- --:--:-- 15931
Downloading Chef  for ubuntu...
Installing Chef 
(Reading database ... 38511 files and directories currently installed.)
Preparing to replace chef 11.4.4-2.ubuntu.11.04 (using .../tmp.6Bob8rAQ/chef__amd64.deb) ...
Unpacking replacement chef ...
Setting up chef (11.4.4-2.ubuntu.11.04) ...
Thank you for installing Chef!

Now we need to specify which recipes and commands we want to run on server. In case of LAMP the content of our node configuration in file nodes/YOUR_SERVER_IP_OR_ALIAS.json would be following:

{
  "run_list": [
    "recipe[apache2]",
    "recipe[mysql]",
    "recipe[php]"
  ]
}

Next we need to upload the current kitchen (Chef repo) to the target host and runs chef-solo on that host with our node configuration. This will login to your server, copy across your cookbooks, and then run chef:

$ knife solo cook root@YOUR_SERVER_IP_OR_ALIAS nodes/YOUR_SERVER_IP_OR_ALIAS.json

Once Chef has finished its run open up a browser and visit your IP Address or Hostname for this Droplet and you should see response from Apache server. And that's it! We have basic LAMP server installed.

For better workflow you can use knife solo bootstrap instead of running knife solo prepare and then knife solo cook:

$ knife solo bootstrap root@YOUR_SERVER_IP_OR_ALIAS nodes/YOUR_SERVER_IP_OR_ALIAS.json

knife solo bootstrap is combination of those two commands and will do all work for us in single command. If something went wrong use parameter -V for verbose output or -h for help. For more information about knife solo visit documentation.

5. Final steps

We're nearly there. We have a working server and now you need to deploy your application. This might be very specific for your workflow, application and environment so this is place where this tutorial ends.

Basicly you now need to run your app specific commands and configure your environment. For example you if will need to add deployer user, set his home and rights, you should make site-cookbooks recipe(s). Usually place it to site-cookbooks/main/recipes/default.rb and add it into bottom of run_list of you noce configuration file.

{
  "user": {
    "name": "deployer",
    "password": $PASSWORD
  },
  "environment": "production",
  "run_list": [
    "recipe[apache2]",
    "recipe[mysql]",
    "recipe[php]"
    "recipe[main]"
  ]
}

Nice example of custom site-cookbooks recipe for set up Ruby on Rails environment with Nginx and Unicorn is in references.

6. References

@skinitimski
Copy link

Much appreciated -- this doc has the pieces I was missing, specifically updating the run list before running knife solo cook.

@kirillshevch
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment