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.
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!
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)?
This post is just a taste of working with Docker. If you’re interested, check out the following resources to learn more.