More Portable Vagrancy

Last time, I talked about finding a pre-made vagrant box that would be useful for rails development. I found one that’s pretty good, but it turns out not to be perfect. I decided to try to write my own Vagrantfile for getting a simpl rails server running on localhost, and I came up with the following success criterion:

No care or feeding. In other words, I could open the vagrant file, and run the following commands straight through and have them just work:

  1. vagrant up --provision
  2. vagrant ssh
  3. cd /vagrant
  4. rails new toy_app
  5. cd toy_app
  6. rails server

And then in the host machine, browsing to localhost:3000 should show the standard “hello from rails” screen. Anything less than that and I feel like I’m sacrificing the real benefit of Vagrant, namely, a repeatable, portable environment setup.

I am doing this by iterative experiment. I started with a Vagrantfile that was empty except for setting the base image of ubuntu/trusty64.

Each iteration, I run vagrant up --provision, then ssh into the box, then try to start a rails server. If I get an error (or am missing a dependency), I exit the ssh session, edit the Vagrantfile, and reload the vm. Periodically, I destroy the vm to make sure that I’m not dependent on some sequence of shell commands I happened to run.

One thing I’ve found useful is this command:

cp $HISTFILE /vagrant/history.txt

It copies the list of shell commands that I’ve run (since the last time I destroyed the vm) into the shared folder, so I can access them from the host machine. That way, if I manage to do something important while I’m ssh’ed into the box, I can read the steps carefully when I’m trying to figure out how to add them to the Vagrantfile so that they become a repeatable part of the environment.

The following Vagrantfile almost passes the test:

# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config| = "ubuntu/trusty64" "forwarded_port", guest: 3000, host: 3000
# runs as root
config.vm.provision "shell", inline: <<-SHELL
apt-get update
git –version || apt-get install -y git
rails –version || apt-get install -y ruby-railties-4.0
nodejs –version || apt-get install -y nodejs
# runs as non-root user "vagrant"
config.vm.provision "shell", privileged: false, inline: <<-SCRIPT
gpg –keyserver hkp:// –recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL | bash -s stable –rails
source /home/vagrant/.rvm/scripts/rvm
rbenv install 2.0.0-p353
rbenv global 2.0.0-p353
yes | gem update
gem install rdoc
gem install rails pg
if [ ! -d "/vagrant/toy_app" ]; then
(cd /vagrant && rails new toy_app)
(cd /vagrant/toy_app && bundle install)

What it’s still missing is that rails server doesn’t quite do what it should; for some reason, running rails server will launch the rails server just fine, but will not enable port forwarding, and for that I need to run bundle exec puma -C config/puma.rb. Next time, I’ll try to figure out why the default commands executed by rails ignore config/puma.rb. Also, there are a few warnings printed to the terminal when I vagrant up -- provision from that file. I haven’t noticed any ill effects yet, but I might still try to chase down the errors in a future post.

Till next time, happy learning!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s