Golang Cross Compiler on Heroku (with Docker)
Heroku unveils new CLI functionality heroku docker:release
(cf. “Heroku | Introducing ‘heroku docker:release’: Build & Deploy Heroku Apps with Docker”). You can run Heroku’s Cedar environment on Docker container and test your application in local environment (Environment parity). In addition to that, you can create Slug from that docker image and deploy it directly to Heroku.
Before this release, Heroku provided the way to create Slug by Buildpack. Buildpack is powerful but for me it’s a little bit complex and hard to write from scratch. From this release you can create Slug from Dockerfile
. It’s more clearly and easy to understand.
So I played it and wrote a simple service, tcnksm/gox-server. This is a golang cross compile service and you can run it on Heroku (Sample application is on https://gox-server.herokuapp.com/). You don’t need to prepare golang runtime on your local PC. You can get a binary from it (Currently support platform is Darwin/Linux/Windows, 386/amd64 and repository must be on Github).
Usage is simple. Just provide github repository and user name. For example, if you want to get github.com/Soulou/curl-unix-socket compiled binary,
$ curl -A "`uname -sp`" https://gox-server.herokuapp.com/Soulou/curl-unix-socket > curl-unix-socket
$ chmod a+x curl-unix-socket
(This is just POC and playing with Heroku with Docker. Don’t depend on this service for production tooling, you should prepare your own build environment. And if repository owner provides binary as release, you should use it.)
Tips of writing Dockefile for Heroku
Dockerfile
for this project is https://github.com/tcnksm/gox-server/blob/master/Dockerfile.
I’ve started from minimal template,
$ heroku docker:init --template minimal
Wrote Dockerfile (minimal)
Miminal requirement we must follow is below,
- Start
FROM heroku:cedar:14
- Changes localized to the
/app
directory
While I was writing Dockefile
for Heroku Slug, I got some tips. So I’ll share them.
Debugging
You can run application by heroku docker:start
command. Actually this is just docker container, so you can enter it like you do heroku run bash
for debug. Docker image name is heroku-docker-${hash}-start
,
$ docker run -it heroku-docker-${hash}-start /bin/bash
Or using exec
to running container.
Slug size
Slug size must be under 300MB
(https://devcenter.heroku.com/articles/slug-compiler#slug-size). Check it by below commands,
$ docker run -it heroku-docker-${hash}-start /bin/bash
$ tar cfvz /tmp/slug.tgz -C / --exclude=.git --exclude=.heroku ./app
$ ls -lh /tmp/slug.tgz
(tar
command is same as heroku docker:release
command does)
Procfile
You need to prepare Procfile
to run the application.
In Procfile
, you should not include environmental variable like $PORT
. It works on Heroku, but doesn’t work on local environment with heroku docekr:start
. Because Procfile
is directly used for docker run
command and environmental variable in Procfile
would extract from your host machine, not docker container. So your need to read environment variable from your source code.
WORKDIR
You may set WORKDIR
on Dockerfile
, root directory of docker run
. To enable it on Heroku environment, you need to write .procfile.d
, so that directory is changed when starting application.
ONBUILD RUN echo "cd /app/src/root" >> /app/.profile.d/init.sh