Over the past week, I started learning Chef. There are a few different configuration management toolsets out there such as Puppet, SaltStack, and Ansible. But Puppet and Chef have majority amount of market share and use Ruby as its code base so it made sense for me to start there. There's no point in starting a project unless you have a goal to accomplish so after I read more about Chef cookbooks, recipes, attributes, etc it seemed like making a JumpSquares cookbook would be a good place to start.
Skip the blah blah and see the code at chef-jumpsquares or read on for the complete back story.
The setup of Chef is simple and only takes about an hour or two to complete. After the server is up and a node has been added, that's where the fun begins. I began my involvement with looking around for cookbooks that use the same components that are needed in the JumpSquares appliance model. Cookbooks such as postgres for database, rvm for ruby, and nginx for web/application servers were already available and made my job starting out much easier.
After a while of figuring out how to correctly upload cookbooks via knife (aka, renaming folders for cookbooks properly) and looking at code recipes it was time to go ahead and deploy to see what happens. Of course, everything always fails miserably when you're first starting out, but I was quickly able to read the chef console output and know where something messed up. At this point, I was successfully getting apt, openssl, and postgresql all working correctly. Now it was time to create a JumpSquares recipe to bring the code down. Read along to know what's going on...
include_recipe "postgresql::server" include_recipe "postgresql::libpq" include_recipe "postgresql::client" #create our postgresql user that will have access to the server pg_user "jumpgres" do privileges superuser: true, createdb: true, login: true password "jump123" end #create the jumpsquares appliance-production environment database pg_database "jumpsquares_prod" do owner "jumpgres" encoding "UTF-8" template "template0" locale "en_US.UTF-8" end #create the directory where www files live. most likley this is /var/www/ directory node['jumpsquares']['www_dir'] do owner "www-data" group "www-data" mode 00755 action :create end #create the subdirectory where our application will live directory node['jumpsquares']['jumpsquares_dir'] do owner "www-data" group "www-data" mode 00755 action :create end #copy from git our jumpsquares project git node['jumpsquares']['jumpsquares_dir'] do user "www-data" group "www-data" repository "https://github.com/kacole2/JumpSquares.git" reference "master" action :sync end #imagemagick is needed for our apptype images. this is a beastly install. just hang tight apt_package "imagemagick" do action :install end #Bundle install runs. This relies on the rvm shell script #this will also setup the environment by creating the database tables and precomiling some stuff #IMPORTANT NOTE: the recipe may die here because the rvm environment isn't set. you have two options. #1. reboot the machine, then run chef-client again #2. go to the console of the machine and key in "source /usr/local/rvm/scripts/rvm" then run chef-cleint rvm_shell "bundle install" do ruby_string "#{node['rvm']['default_ruby']}" cwd node['jumpsquares']['jumpsquares_dir'] code %{ source #{node['jumpsquares']['rvm_source']} rvmsudo bundle install rvmsudo rake RAILS_ENV=appliance-production db:setup rvmsudo rake RAILS_ENV=appliance-production assets:precompile } end
This script successfully creates:
- a postgresql user and database
- /var/www/jumpsquares folder
- clones the git repository
- installs ImageMagick
- installs all required gems for JumpSquares
- creates the database schema
- precompiles all the assets
It's still not done. Now that we have the base setup, we have to serve it up. The nginx cookbook from OpsCode uses Passenger as it's webserver. It took me about 2.5 days to figure out why it wasn't working correctly as you can see from stackoverflow thread. Come to find out it was a simple fix, but it isn't implemented anywhere in the nginx cookbook. So for that fix to work, I created a new recipe called jumpsquares::passenger_nginx. This recipe will install all the necessary components (including the jumpsquares::default) and then make changes to nginx configuration files. Remember, the latest code will always be available on github at chef-jumpsquares:
include_recipe "apt" include_recipe "openssl" include_recipe "rvm::system" rvm_shell "bundle install" do ruby_string "#{node['rvm']['default_ruby']}" code %{ source #{node['jumpsquares']['rvm_source']} rvmsudo gem install passenger -v 4.0.42 --no-rdoc --no-ri rvmsudo gem install rake -v 10.3.1 --no-rdoc --no-ri } end include_recipe "jumpsquares::default" include_recipe "nginx::source" ENV['PATH']="#{node['nginx']['rvm_path']}:#{ENV['PATH']}" #the passenger configuration is never enabled with the OpsCode nginx cookbook. let's add it ruby_block "add passenger variable" do block do site_file = Chef::Util::FileEdit.new("#{node["nginx"]["dir"]}/sites-enabled/000-default") site_file.insert_line_after_match(/\slocation\s\/\s{/, " passenger_enabled on;") site_file.write_file end end #we have to specify the rails environment we want to use since we do not want to use 'production' ruby_block "add rails environment" do block do passenger_file = Chef::Util::FileEdit.new("#{node["nginx"]["dir"]}/conf.d/passenger.conf") passenger_file.insert_line_if_no_match(/passenger_app_env appliance-production;/, "passenger_app_env appliance-production;") passenger_file.write_file end end
During those 2.5 days, I got fed up and decided I could do it my own way. I've always had great success running thin + nginx for the JumpSquares appliance as well as MonsterRemote. There were no cookbooks for thin + nginx so I decided to make one. Take a look at chef-thin_nginx. It's not fancy, but it gets the job done. So now there is an additional JumpSquares recipe called 'jumpsquares::thin_nginx' that will use this particular cookbook. All of the parameters need to be set in attributes and the chef-thin_nginx cookbook. Remember, the latest code will always be available on github at chef-jumpsquares:
include_recipe "apt" include_recipe "openssl" include_recipe "rvm::system" include_recipe "jumpsquares::default" include_recipe "thin_nginx"
You shouldn't have to change any attribute settings for any of these recipes to work correctly.
This was all a great learning experience and made me hate webservers just a little bit more :). But it was simple enough to finally figure out my frustrations and create some open source code as well.