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:
vagrant up --provision
rails new toy_app
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
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
|# -*- 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||
|config.vm.box = "ubuntu/trusty64"|
|config.vm.network "forwarded_port", guest: 3000, host: 3000|
|# runs as root|
|config.vm.provision "shell", inline: <<-SHELL|
|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://keys.gnupg.net –recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3|
|curl -sSL https://get.rvm.io | bash -s stable –rails|
|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!