This post is just going to be a cool story. I was on my laptop in a local coffee shop, and I had a lot of terminal windows open, so I guess whatever I was doing looked high tech. And this young man who was working there said “Hey, is that code? Are you programming?” We talked for a while, and traded email addresses. I’ll call him Steve. Continue reading “Helping Folks”
I just finished The Hard Thing about Hard Things by Ben Horowitz. This post will be about that book (which I read as an audio book), and have two parts: A general recommendation, and a key lesson. Continue reading “Book Review: The Hard Thing about Hard Things”
I love this book, but its title might be a slight exaggeration. I would have called it Some analogies of varying strength between computer science questions and life questions, with some special focus on optimal stopping, sorting, scheduling, and game theory. I guess that doesn’t have quite the same ring to it. Continue reading “Book Review: Algorithms to Live By”
In the time I’ve spent learning to code, I often see a little uptick in difficulty around packages (or dll’s, or gems, or imports, or whatever). Getting to “hello world” is pretty easy, but then getting to a program that prints hello world but also imports some system library for regexes or whatever is slightly harder, and often not covered well in tutorials. So I think that part of basic competency in a language is being able to publish and consume bundled code. I’ve been learning Ruby recently, so I’m going to do three things in this post and the following post:
- Go through making a gem for myself to use in a silly web app.
- Import said gem and use it.
- Import some published gem and use that.
Last week, I looked at the getting a rails server pushed up to AWS using a Vagrant. After that was working, I decided I wanted to be able to test changes on a local VM, then push that VM to the cloud when I liked it, rather than test all my changes in the cloud.
In the directory where I had the Vagrantfile and the shared folder for the rails server, I did
vagrant up --provider=virtualbox, and I got this:
An active machine was found with a different provider. Vagrant currently allows each machine to be brought up with only a single provider at a time. A future version will remove this limitation. Until then, please destroy the existing machine to up with a new provider. Machine name: default Active provider: aws Requested provider: virtualbox
Last time, we learned why
vagrant up with the AWS provider sometimes hangs on “waiting for SSH to become ready” (because I accidentally set it to use a private IP, but didn’t map routes or anything), and why it sometimes says “invalid group ID” (because if the group id provided doesn’t match your security role and region, AWS reports the same error as if you’d passed in a null group id).
Now, I’m going to resume doing the rails tutrial book’s “mostly static pages” and try to deploy it in AWS. I’m not going to worry about DNS entries for this post – I’ll declare victory when I can paste the public DNS entry that AWS generates for my instance in the browser and see some Rails content come back. Continue reading “Simple Rails Server on AWS with Vagrant”
My goal for this post is to take the sample app steps from the rails tutorial book, work on them locally, and deploy them in AWS from a script. Then I will share the script. To start with, I have a Vagrantfile that works fine for doing rails development locally, and I have an AWS account. One of the first things I did was set environment variables on my host machine to store my AWS credentials in. Then I can refer to those environment variables in my Vagranfiles, and I don’t need to risk checking an API key into github or something. In the vagrant file, it looks like this:
aws.secret_access_key = ENV['AWS_SECRET_KEY']
And then in my ~/.profile:
export AWS_SECRET_KEY="Wouldn't you like to know"
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!
Eric Lippert has a post where he talks about idempotencce. He points out that in programming when we say a function is idempotent we mean:
the effect of the function … is invariant over the number of calls.
In other words, if we call the same function over and over again, the state of the system will be the same as if we’d called the function only once. That can be a big help, because the invariant “this function has been called at least once” is a ton easier to maintain than the invariant “this function has been called exactly once.”
I like idempotence in configuration and set up code. Let’s take a line from my Vagrantfile for this project. (It’s inside an call to the shell script. In Ruby it’s a string literal; we’re interested in what it does in the shell.)
git --version || apt-get install -y git
In other words, “If git is installed, do nothing; otherwise install git.” You’ll notice that no matter how often I run this line, I’ll always have git installed, but the installer won’t check update or anything except for the first time this is run. This is awesome in configuration, because it lets us write commands that say “assert that this is installed,” and not have to remove them later.
Ok, so idempotent is a favorite word, but I’m done talking about it for now. Let’s move on getting some rails done. For this post, I’m going to do part of the rails tutorial book, but I’m going to use this little Vagrant VM we’re working on as the development environment.