** note: I recently updated this post to make sure all of the commands still work. **
I’ve spent some time recently using the Go programming language for my side web projects. The Go standard libraries are minimal by design - meaning it doesn’t come with a prescriptive web framework out of the box. The good news is that there are a ton of options:
Of course, you could decide to just not use a web framework at all. Comparing these is a topic of great debate - but that topic is for another post :) I decided to try out Revel first, as it was the closest to a full featured rails-esque framework at a glance. I’ll likely give all of these a shot at some point.
After building an app on Revel, I wanted to get a feel for deploying my app to see if it posed any unique challenges. I recently started a new gig working on Google Cloud, and decided to try out App Engine. The default runtime environment for Go in App Engine is sandboxed. This comes with some benefits, and a few challenges. You get a lot of stuff for free, but you also are restricted in terms of file system access, network access, and library usage. Given the restrictions, I decided to use the new App Engine Flexible service. App Engine Flex lets you deploy your application in a docker container, while still having access to the other App Engine features like datastore, logging, caching, etc. The advantage of using docker here is that I don’t need to write any App Engine specific code. I can write a standard Go/Revel app, and just deploy to docker.
Starting with Revel
Before touching App Engine Flexible, the first step is to get it working with docker. It took a little time and effort, but once docker is completely set up on your machine, writing the docker file is straight forward.
Here’s the docker file I’m using right now:
There are a few things to call out with this Dockerfile:
I chose to use the golang docker image as my base. You could replicate the steps needed to install and configure go with a base debian/ubuntu image, but I found this easier. I could have also used the pre-configured App ngine golang image, but I did not need the additional service account support.
ENTRYPOINTcommand tells Docker (and App Engine) which process to run when the container is started. I’m using the CLI included with revel.
EXPOSEdirectives, make sure to use port 8080 - this is a hard coded port for App Engine.
To start using docker with your existing revel app, you need to install docker and copy the dockerfile into the root of your app. Update the dockerfile to change the path in the
ENTRYPOINT instructions to use the local path to your revel app instead of mine.
After you have docker setup, build your image and try running the app:
This will run docker, build the image locally, and then run it. Try hitting
http://localhost:8080 in your browser. You should see the revel startup page:
Now we’re running revel inside of docker.
App Engine Flexible
The original version of App Engine had a bit of a funny way of managing application runtimes. There are a limited set of stacks available, and you’re left using a locked down version an approved runtime. Flex gets rid of this restriction by letting you run pretty much anything inside of a container. You just need to define a little bit of extra config in a
app.yaml file that tells App Engine how to treat your container:
This config lets me use App Engine, with a custom docker image as my runtime, running on a managed virtual machine. You can copy my app.yaml into your app directory, alongside the Dockerfile. Next, make sure you’ve signed up for a Google Cloud account, and download the Google Cloud SDK. After getting all of that setup, you’ll need to create a new project in the developer console.
That covers the initial setup. After you have a project created, you can try deploying the app. This is essentially going to startup your app using the Dockerfile we defined earlier on Google Cloud:
After deploying, you can visit your site here:
So that’s it. I decided to use revel for this one, but the whole idea behind using docker for App Engine is that you can bring pretty much any stack. If you have any questions, feel free to check out the source, or find me @JustinBeckwith.