Coming from ruby and rails managing application dependencies and deployment is quite easy and straightforward thanks to tools like capistrano, rvm and bundler. A relatively young technology like node.js seems not to have any best practice for these common tasks.
Time to show how adeven manages it.
As mentioned we come from ruby and rails so there is no reason why not to use capistrano for deploying node applications. Although capistrano was originally build for rails application @hollow made quite a good job in generalizing capistrano recipes. Thats why we added some recipes to capper for node.
When deploying node application you basically have to think about the five main tasks:
Node version management
Working with different Environments and stages
Deploy your app to different servers
Node version management
node 0.8 is around the corner and we have the need to run our application with different node versions. The ruby community uses rvm to manage different ruby versions. Although there no silver bullet in the node.js world to manage different node version nave is adevens weapon of choice for this task.
It’s just a shell script that installs it’s node versions into
~/.nave by default and can be used pretty much like rvm.
Usage: nave <cmd> Commands: install <version> Install the version passed (ex: 0.1.103) use <version> Enter a subshell where <version> is being used use <ver> <program> Enter a subshell, and run "<program>", then exit use <name> <ver> Create a named env, using the specified version. If the name already exists, but the version differs, then it will update the link. usemain <version> Install in /usr/local/bin (ie, use as your main nodejs) clean <version> Delete the source code for <version> uninstall <version> Delete the install for <version> ls List versions currently installed ls-remote List remote node versions ls-all List remote and local node versions latest Show the most recent dist version help Output help information <version> can be the string "latest" to get the latest distribution. <version> can be the string "stable" to get the latest stable version.
So no root access needed for installing different node versions - awesome.
With npm managing third party dependencies becomes easy. Simply define a package.json file that looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
And a simple
from your apps root will install all the modules under a
For us dealing with quite complex application and thus complex dependencies both does not work due to different platforms (MacOs for development, gentoo for production) and environments.
The ruby community uses
Gemfile.lock for managing dependency and locking them down.
With npm you can
package.json file and will get something similar to
Read Managing Node.js Dependencies with Shrinkwrap about the motivation.
So you should definitely run
node_module to your
You want your app to run in the background and automatically start on error? Forever deamonizes your app and let your easily start and stop it.
usage: forever [options] [action] SCRIPT [script-options] Monitors the script specified in the current process or as a daemon actions: start Start SCRIPT as a daemon stop Stop the daemon SCRIPT stopall Stop all running forever scripts restart Restart the daemon SCRIPT restartall Restart all running forever scripts list List all running forever scripts config Lists all forever user configuration set <key> <val> Sets the specified forever config <key> clear <key> Clears the specified forever config <key> logs Lists log files for all forever processes logs <script|index> Tails the logs for <script|index> columns add <col> Adds the specified column to the output in `forever list` columns rm <col> Removed the specified column from the output in `forever list` columns set <cols> Set all columns for the output in `forever list` cleanlogs [CAREFUL] Deletes all historical forever log files options: -m MAX Only run the specified script MAX times -l LOGFILE Logs the forever output to LOGFILE -o OUTFILE Logs stdout from child script to OUTFILE -e ERRFILE Logs stderr from child script to ERRFILE -p PATH Base path for all forever related files (pid files, etc.) -c COMMAND COMMAND to execute (defaults to node) -a, --append Append logs --pidFile The pid file --sourceDir The source directory for which SCRIPT is relative to --minUptime Minimum uptime (millis) for a script to not be considered "spinning" --spinSleepTime Time to wait (millis) between launches of a spinning script. --plain Disable command line colors -d, --debug Forces forever to log debug output -v, --verbose Turns on the verbose messages from Forever -s, --silent Run the child script silencing stdout and stderr -w, --watch Watch for file changes --watchDirectory Top-level directory to watch from -h, --help You're staring at it [Long Running Process] The forever process will continue to run outputting log messages to the console. ex. forever -o out.log -e err.log my-script.js [Daemon] The forever process will run as a daemon which will make the target process start in the background. This is extremely useful for remote starting simple node.js scripts without using nohup. It is recommended to run start with -o -l, & -e. ex. forever start -l forever.log -o out.log -e err.log my-daemon.js forever stop my-daemon.js
Working with different Environments and stages
In the rails world different environments for development, test and production are quite common. Especially when dealing with databases it is quite usefull to have different work environments. With node.js manage different configurations with environment variables and modules
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
Starting your app with the right NODE_ENV environment variable will give you the right configuration when required:
1 2 3 4
Putting it all together deployment with capistrano and capper:
I don’t want to go into the details about capistrano there are tons of very good documentations about this. With our capper fork things are pretty straight forward.
To add capper to your app, create a Gemfile with capper dependency in your app’s root:
1 2 3
You can then simply
gem install bundler and run
Next creates two files:
Capfile specifies which recipes you want to use. It should look something like this:
1 2 3 4 5 6 7 8 9 10
The deployment configuration goes into config/deploy.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
Having the tasks
staging gives us the ability to use different settings for our deploy scenarios.
bundle exec cap -T to see whats in the box:
cap deploy # Deploys your project. cap deploy:cleanup # Clean up old releases. cap deploy:cold # Deploys and starts a `cold' application. cap deploy:migrate # Blank task exists as a hook into which to install ... cap deploy:migrations # Deploy and run pending migrations. cap deploy:pending # Displays the commits since your last deploy. cap deploy:pending:diff # Displays the `diff' since your last deploy. cap deploy:restart # Blank task exists as a hook into which to install ... cap deploy:rollback # Rolls back to a previous version and restarts. cap deploy:rollback:code # Rolls back to the previously deployed version. cap deploy:setup # Prepares one or more servers for deployment. cap deploy:start # Blank task exists as a hook into which to install ... cap deploy:stop # Blank task exists as a hook into which to install ... cap deploy:symlink # Updates the symlink to the most recently deployed ... cap deploy:update # Copies your project and updates the symlink. cap deploy:update_code # Copies your project to the remote servers. cap deploy:web:disable # Present a maintenance page to visitors. cap deploy:web:enable # Makes the application web-accessible again. cap forever:restart # Restart the servers using the forever cmd If the f... cap forever:start # Start the servers using the forever cmd If the for... cap forever:stop # Stop the servers using the forever cmd If the fore... cap forever:tail # tail the forever logfile using the forever cmd If ... cap invoke # Invoke a single command on the remote servers. cap log # tail the application logfile cap nave:install # set :node_ver, "stable" # e.g. cap nave:setup # Install nave into nave target dir. cap npm:install # Install the current npm environment. cap production # production stage cap shell # Begin an interactive Capistrano session. cap staging # staging stage
To get more detailed informations enter
bundle exec cap -e taskname
To run a dry test for your deployment run:
cap staging deploy -n
And enjoy the output.