public
Description: Dress to impress / Our minimalistic server configuration tool
Homepage: http://blog.labnotes.org/2009/11/04/necktie-dress-to-impress/
Clone URL: git://github.com/assaf/necktie.git
assaf (author)
Fri Nov 06 12:21:44 -0800 2009
commit  23d1239102d5818018b306e12ebc1411585eebc2
tree    0aaa98352cf78bcf097f810342e9666680c74e17
parent  111de47350fae6ef067586ec3978b8a2ec320da3
README.rdoc

Minimalistic server configuration tool

Necktie is tool for running configuration tasks: setting up new servers and upgrading production servers. You can use it to manage services, mount volumes, change configuration, manage cronjobs, etc.

To install Necktie:

  $ gem install necktie --source http://gemcutter.org

To use Necktie:

  1. Write a Necktie file with configurtaion tasks
  2. Include any support files: config, scripts, binaries, etc
  3. git push && cap necktie

Introduction to Necktie: blog.labnotes.org/2009/11/04/necktie-dress-to-impress/

Tasking

Necktie is based on Rake, so if you know Rake you already know most of Necktie. This document will teach you the rest.

At the base of your Necktie project there’s a file called Necktie (or necktie, or necktie.rb), with a list of tasks. For example:

  file "/var/myapp" do
    append "/etc/fstab", "/mnt/myapp /var/myapp none bind\n" unless read("/etc/fstab")["/mnt/myapp"]
    mkdir_p "/var/myapp/"
    sh "mount /var/myapp"
  end

  desc "Install/update ruby gems"
  task :rubygems do
    FileList["gems/*.gem"].each do |gem|
      install_gem gem
    end
    sh "gem clean"
  end

  desc "Setup and start Nginx"
  task :nginx do
    rm_rf "/etc/nginx/sites-enabled/*"
    cp "etc/nginx/unicorn.conf", "/etc/nginx/sites-available/"
    ln_sf "/etc/nginx/sites-available/unicorn.conf", "/etc/nginx/sites-enabled/"
    services.start "nginx"
  end

  desc "Setup and start Unicorn"
  task :unicorn=>[:rubygems, "/var/myapp"] do
    cp "etc/init.d/unicorn", "/etc/init.d/"
    chmod 0750, "/etc/init.d/unicorn"
  end

  desc "Perform all tasks for the role app"
  task :app=>["/var/myapp", :nginx, :unicorn]

When you run the app task, it runs the tasks that setup the application directory, install gems, configure Nginx and Unicorn. When it’s done, you’re ready to deploy.

Necktie deals with initial configuration, and also ongoing maintenance. Say you change a configuration file, or add another Gem to the gems directory. Push these changes into your Git repository and run Necktime again. That simple.

Note: In the example above, the nginx and unicorn tasks run each time, you can use them to push out new configurations. In contrast, the /var/myapp file task only runs once, before that directory exists.

cap necktie

I use Capistrano to setup new instances and upgrade existing ones.

To use the Necktie task, set the necktie_url variable to the URL of your Necktie repository, and require necktie/capistrano. For example:

  require "necktie/capistrano"
  set :necktie_url, "git@example.com:mysetup"

Setting up a new EC2 instance:

  cap necktie ROLES=app HOSTS=ec2-75-101-239-12.compute-1.amazonaws.com

Upgrading running instances with new configuration:

  git push && cap necktie

Feel the rush

Necktie includes Rush, so you can write tasks like this:

  task :memcached do
    unless processes.find { |p| p.cmdline[/memcached\s.*-l\s0.0.0.0/] }
      box["/etc/memcached.conf"].replace_contents! /^-l 127.0.0.1/, "-l 0.0.0.0"
      services.start "memcached"
    end
  end

You can learn more about Rush here: rush.heroku.com

Of course, there’s also FileUtils, system and sh (courtesy of Rake), so you can also:

  # Update whenever we have a newer config file.
  file "/etc/nginx/nginx.conf"=>"etc/nginx.conf" do
    cp "etc/nginx.conf", "/etc/nginx/nginx.conf"
    sh "service nginx restart"
  end

The current directory (Dir.pwd and launch_dir) is the root directory of your Necktie repository. You can depend on relative paths when accessing files in your Necktie repository.

Role play

If you have different setups, split them into roles and give each role its own main task. Have that main task depend on all the specific setup tasks for this role. For example:

  task :app=>[:rubygems, :nginx, :unicorn, "/var/myapp"]
  task :db=>[:mount, :master, :backup]

You can then run Necktie with a list of roles. I recommend using the same roles with Necktie and Capistrano, that way you can:

  cap necktie ROLES=app,db

This usage will pass the role names as task names to the necktie command.

If you have only one role, or work frequently with a given role, you can define the default task instead of setting ROLES each time. In your Necktie file add:

  task :default=>:app

You may also want to take advantage of different environments, customizing your setup differently between production, staging, etc.

Check the example directory for ideas on how to split large configurations into smaller files and tasks.

Note: As with Rake, command line arguments are either options (see necktie -H), task names (executed in order), or name=value pairs that set environment variables (e.g. RAILS_ENV=production).

gem install

You can use install_gem in one of two ways. You can pass it a gem name and version requirement. For example:

  install_gem "unicorn", "~= 0.93"

You can store the gem file in your Necktie repository and install it from there:

  install_gem "gems/unicorn-0.93.3.gem"

I prefer the later, not depending on the Gem servers being online when I decide to upgrade.

Since install_gem will only install the same gem/version once, a run-always rubygems.rb task is all you need:

  task :rubygems do
    Dir["gems/*.gem"].each do |gem|
      install_gem gem
    end
  end

One on one

You can also run Necktie from the command line directly on the server you’re configuring. The first time you run Necktie, it clones the Git repository into the ~/.necktie directory. You’ll need to give it the Git URL, like this:

  necktie --source git@example.com:mysetup app

Subsequent runs use that repository. You can launch the necktie command from anywhere, it will always switch to the ~/.necktie directory, run the tasks and switch back to the previous working directory.

If you want to pull changes from the Git repository, use the -U option:

  necktie -U app

If you have read/write access to the Git repository you use that to tweak and add new tasks, and test them out before using your setup in production.

License

Necktie, copyright (C) 2009 Assaf Arkin, released under the "Use for good, not evil" license (www.json.org/license.html)

Includes Rake, created by Jim Weirich and released under the MIT license rake.rubyforge.org/ github.com/jimweirich/rake

Includes Rush, created by Adam Wiggins and released under the MIT License rush.heroku.com github.com/adamwiggins/rush

Includes Session, created by Ara T. Howard and released under the Ruby License raa.ruby-lang.org/project/session www.codeforpeople.com/lib/ruby/session

Atomic file write adapted from Rails.

ERB task adapted from Luke Bayes gist.github.com/215270.

Developed for managing EC2 instances for apartly.com