Using n as a Tool to Provision Node.js
When provisioning servers with a tool like Chef, you really don't want to find yourself in the position of building Node.js from source. It takes a long time, especially if you're working with something like an AWS instance where there usually isn't a great deal of computational horsepower under the hood. Unfortunately the standard situation for Node.js on any given Linux platform is that packages in the default repositories are ancient releases and tools like the Node.js cookbook for Chef can have issues when it comes to installing a recent binary distribution.
There are many ways around this issue, but one of the easier approaches is to use the n tool as a basis for your provisioning setup. The tool must be built from source, but that takes very little time at all. After it is installed, n then manages installation of the right Node.js binary distribution for your current platform.
Provisioning via Bash Script
The bash script below illustrates the desired outcome, with the caveat that it is specific to Debian distributions. If you are familiar with rpm-based distributions it won't be difficult to adapt it, however.
#!/bin/bash # # Provisioning script to install Node.js using n. # # This must run as root. # N_VERSION=1.2.1 # Install the latest stable version. NODE_VERSION=stable # Remove downloaded files. function cleanup() { rm -rf n-${N_VERSION} rm -f ${N_VERSION}.tar.gz } # -------------------------------------------------------------------------- # Install build tools. # -------------------------------------------------------------------------- apt-get update apt-get install -y build-essential # Curl is needed by n. apt-get install -y curl # -------------------------------------------------------------------------- # Install n and Node.js. # -------------------------------------------------------------------------- # Clean out any leftovers from an earlier provisioning run. cleanup # Obtain n and install it. wget https://github.com/tj/n/archive/v${N_VERSION}.tar.gz tar zxf v${N_VERSION}.tar.gz cd n-${N_VERSION} make install cd .. # Install the Node.js binary distribution. n $NODE_VERSION cleanup
Provisioning via Chef Cookbook
Since n really is a very simple build that only depends on the presence of build tools and curl, making a cross-distribution cookbook is easy. You can find such a cookbook over at GitHub. The core of it is contained in these files, showing that it just recapitulates the actions of the bash script above, but in a way that will work for any Linux distribution:
metadata.rb:
name 'n-and-nodejs' license 'MIT' description 'Install Node.js version manager n and Node.js.' version '0.0.1' recipe 'n-and-nodejs', 'Install Node.js version manager n and Node.js.' # We will be building n from source. depends 'build-essential' # n uses curl to download Node.js binaries. depends 'curl' %w{ fedora redhat centos ubuntu debian amazon suse scientific oracle smartos}.each do |os| supports os end attribute 'n-and-nodejs/n/version', :display_name => 'n version.', :description => 'Version to install.', :default => '1.2.1' attribute 'n-and-nodejs/nodejs/version', :display_name => 'Node.js version', :description => 'Version to install; "stable" means the latest stable version.', :default => 'stable'
recipes/default.rb:
# # Install n and Node.js. # # ---------------------------------------------------------------------------- # Install n by building from source. # ---------------------------------------------------------------------------- # Obtain the source from GitHub. remote_file "/tmp/#{node['n-and-nodejs']['n']['version']}.tar.gz" do source "https://github.com/tj/n/archive/v#{node['n-and-nodejs']['n']['version']}.tar.gz" action :create_if_missing end # Build and install. execute "tar zxf #{node['n-and-nodejs']['n']['version']}.tar.gz" do cwd "/tmp" end execute "make install" do cwd "/tmp/n-#{node['n-and-nodejs']['n']['version']}" end # -------------------------------------------------------------------------- # Install Node.js # -------------------------------------------------------------------------- execute "n #{node['n-and-nodejs']['nodejs']['version']}"
To use the cookbook, add it and its dependencies to your run list:
run_list [ 'recipe[build-essential]', 'recipe[curl]', 'recipe[n-and-nodejs]' ]
Then set up the attributes appropriately. For example:
default_attributes( "n-and-nodejs" => { "n" => { "version" => "1.2.1" }, "nodejs" => { # Install a specific version. # "version" => "0.10.26", # # Install the latest stable version. "version" => "stable" } } )