Developing on a Mac

I’m a mac user. I like the idea of switching to a Linux system for my everyday computing, some laptop running Ubuntu would be cool. But I just can’t seem to give up this retina screen. That and the fact that I do a fair bit of iOS development. It’s also hard to give up something you’re so intimately familiar with. In production environments, the majority of my experience is with CentOS (versions 5 and 6). But lately I’ve been running my services on Google Compute Engine using Debian. So far I have no complaints, and I’m enjoying the more up-to-date packages (if you’ve used CentOS before, you know what I mean). Though I have to admit, CentOS 7 has some interesting changes like systemd and Docker support baked in. But I think if I’m going to switch to another OS, it’ll be CoreOS.

So, I develop on a mac, but deploy to a Debian environment. Sounds like a perfect use case for Vagrant! If you’ve never heard of or used Vagrant before, I highly suggest you take a peek at the documentation. A simple explanation of Vagrant according to their site:

Vagrant provides easy to configure, reproducible, and portable work environments built on top of industry-standard technology and controlled by a single consistent workflow to help maximize the productivity and flexibility of you and your team.

In my case, I’m using VirtualBox as my provider. It’s free and works exactly as you would expect, without any noticeable performance problems. I’m not going to explain how to get everything setup, I’ll leave that as an exercise for you to tackle on your own.

What are we solving?

One of the key problem I have specifically, is that I don’t like cluttering up my mac with every service I may need for every project. In theory I could just install everything locally with Brew:

brew install nginx
brew install postgresql
brew install mongodb
brew install redis
brew install beanstalk

Along with those packages, Brew would also install the needed dependencies: openssl, readline, and pcre.

So that’s not terrible, and besides how much CPU could be sucked up with all those processes idle? But here’s another question, what if some of your projects run on different OSs, or more importantly different versions? If you attempt to install MongoDB with apt-get install mongodb on a vanilla Debian, it’ll install version 2.0.6. Brew will install 2.6.5. That’s a pretty big gap in versions, and who knows whats been fixed or broken between versions. Another big difference most of us forget about are OS specific implementations like kqueue vs epoll.

How Vagrant can solve this

So lets say we have a simple blogging web app written in Go. It persists it’s data in postgres. Previously we would have had a code snippet like this to hook it up in code:

import (
    _ "github.com/lib/pq"
    "database/sql"
)

db, err := sql.Open("postgres", "dbname=unrolled user=root host=127.0.0.1 port=5432 sslmode=disable")
if err != nil {
    panic(err)
}
// Do something with db.

This assumes postgres is running on our localhost (127.0.0.1). So lets fix this up so we don’t need postgres installed on our local system.

Vagrant setup

I have created two Gists. Lets go over the bootstrap.sh file first:

This bootstrap installs most of the services I need to use on daily basis. Nothing to special, but I’d like to draw your attention to lines 38, 53, 58, and 72. These simple configuration tweaks tell the services to listen on any network interface, not just the localhost. If we didn’t apply these changes, the services would only listen to connections from within the virtual machine, which wouldn’t help us much.

Now we can change our above Go snippet to something like this:

import (
    _ "github.com/lib/pq"
    "database/sql"
)

db, err := sql.Open("postgres", "dbname=unrolled user=root host=unrolled.vm port=5432 sslmode=disable")
if err != nil {
    panic(err)
}
// Do something with db.

Notice the host is now pointing at our VM. Obviously this assumes you have added your virtual machine’s name to your /etc/hosts file on your mac.

But we can go one step further to make this even more or a seamless transition. Checkout the Vagrantfile:

Specifically checkout lines 11 to 16. We can forward the VM’s ports and map them to our local system! We don’t even need to change our code now. You can leave the host as 127.0.0.1 and it will actually be using the VM. This also comes in handy when using GUI applications on your mac.

Happy developing!