Heroku makes it dead simple to deploy and operate apps; Docker makes it even easier! Heroku has a Docker runtime in beta.
This article will review how to setup a simple Ruby app to build and deploy as a Docker container on Heroku using CircleCI.
The app we’ll be using
We run a dashboard for internal use with a range of widgets that give us data about various events in the company and application. We use Smashing, which is a Sinatra-esque Ruby framework for building dashboards.
Setting up the Dockerfile
Heroku recently released their new Heroku-16 stack. We’ll base our image off it. We’ll then install required system dependencies so we can install gems. Next we’ll install bundler
and our gem dependencies. From there we’ll give the container a default CMD
that will boot up the dashboard.
FROM heroku/heroku:16
RUN apt-get update -qq && apt-get install -y \
build-essential \
libpq-dev \
nodejs \
ruby-dev
RUN mkdir /my_dashboard
WORKDIR /my_dashboard
ADD Gemfile /my_dashboard/Gemfile
ADD Gemfile.lock /my_dashboard/Gemfile.lock
RUN gem install bundler
RUN bundle install
ADD . /my_dashboard
CMD rackup --port=$PORT
In order to build this image, we’ll need to install Docker. Assuming we’re on Mac, we’ll head over here to install Docker. Once we’ve installed Docker, we’ll cd
into the project directory and run the following commands:
docker build . -t my_dashboard
docker run -p 9292:9292 my_dashboard rackup
Now we should have the app up and running!
If everything looks good, deploy the image manually to Heroku using the following commands.
heroku plugins:install heroku-container-registry
heroku container:login
heroku container:push
heroku open
Our dashboard is alive on Docker!
Building and deploying via CI
We want to be able to deploy our app from our continuous integration system instead of pushing manually. We’ll use CircleCI.
Add a circle.yml
file to our project with the following config.
machine:
services:
- docker
dependencies:
override:
- echo "no deps"
test:
post:
- echo "yay - no tests"
deployment:
production:
branch: master
commands:
- docker build -t my_dashboard .
- docker login --email=_ --username=_ --password=$HEROKU_TOKEN registry.heroku.com
- docker tag my_dashboard:latest registry.heroku.com/my_dashboard/web
- docker push registry.heroku.com/my_dashboard/web
We’ll need to configure an environment variable for HEROKU_TOKEN
(taken from our Heroku dashboard) so Circle can authenticate against the Heroku container registry.
Upon the next successful master
build, we should see our image be built and then deployed to Heroku all from CI!
Open questions
Working with Docker raises some open questions around developer workflow, especially for more complicated applications (e.g. those with a separate worker process).
Here are some of the issues:
- How do we run tests? Do we build an image (including test gems) and run tests against it?
- How would we manage compiling assets if we needed to?
- How do we ergonomically deploy multiple processes (assuming one process per container)?
Further reading
This post is just a taste of working with Docker. If you’re interested, check out the following resources to learn more.
- Docker video intro
- Written tutorial on getting started
- Introduction to Docker Compose if you want to have multiple containers coordinating with each other
- Overview of using registries