Why we’re doing this
Docker is difficult
In my experience, Dockerizing a Rails application for the first time is pretty hard. Actually, doing anything with Docker seems pretty hard. The documentation isn’t that good. Clear examples are hard to find.
Dockerizing Rails is too ambitious as a first goal
Whenever I do anything for the first time, I want to do the simplest, easiest possible version of that thing before I try anything more complicated. I also never want to try to learn more than one thing at once.
If I try to Dockerize a Rails application without any prior Docker experience, then I’m trying to learn the particulars of Dockerizing a Rails application while also learning the general principles of Docker at the same time. This isn’t a great way to go.
Dockerizing a Sinatra application gives us practice
Dockerizing a Sinatra application lets us learn some of the principles of Docker, and lets us get a small Docker win under our belt, without having to confront all the complications of Dockerizing a Rails application. (Sinatra is a very simple Ruby web application framework.)
After we Dockerize our Sinatra application we’ll have a little more confidence and a little more understanding than we did before. This confidence and understanding will be useful when we go to try to Dockerize a Rails application (which will be a future post).
By the way, if you’ve never worked with Sinatra before, don’t worry. No prior Sinatra experience is necessary.
What we’re going to do
Here’s what we’re going to do:
- Create a Sinatra application
- Run the Sinatra application to make sure it works
- Dockerize the Sinatra application
- Run the Sinatra application using Docker
- Shotgun a beer in celebration (optional)
I’m assuming you’re on a Mac and that you already have Docker installed. If you don’t want to copy/paste everything, I have a repo of all the files here.
(Side note: I must give credit to Marko Anastasov’s Dockerize a Sinatra Microservice post, from which this post draws heavily.)
Let’s get started.
Creating the Sinatra application
Our Sinatra “application” will have just one file. The application will have just one endpoint. Create a file called
hello.rb with the following content.
# hello.rb require 'sinatra' get '/' do 'It works!' end
We’ll also need to create a
Gemfile that says Sinatra is a dependency.
# Gemfile source 'https://rubygems.org' gem 'sinatra'
Lastly for the Sinatra application, we’ll need to add the rackup file,
# config.ru require './hello' run Sinatra::Application
After we run
bundle install to install the Sinatra gem, we can run the Sinatra application by running
$ bundle install $ ruby hello.rb
Sinatra apps run on port
4567 by default, so let’s open up
http://localhost:4567 in a browser.
$ open http://localhost:4567
If everything works properly, you should see the following.
Dockerizing the Sinatra application
Dockerizing the Sinatra application will involve two steps. First, we’ll create a
Dockerfile will tells Docker how to package up the application. Next we’ll use our
Dockerfile to build a Docker image of our Sinatra application.
Creating the Dockerfile
Here’s what our
Dockerfile looks like. You can put this file right at the root of the project alongside the Sinatra application files.
# Dockerfile FROM ruby:2.7.1 WORKDIR /code COPY . /code RUN bundle install EXPOSE 4567 CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "4567"]
Since it might not be clear what each part of this file does, here’s an annotated version.
# Dockerfile # Include the Ruby base image (https://hub.docker.com/_/ruby) # in the image for this application, version 2.7.1. FROM ruby:2.7.1 # Put all this application's files in a directory called /code. # This directory name is arbitrary and could be anything. WORKDIR /code COPY . /code # Run this command. RUN can be used to run anything. In our # case we're using it to install our dependencies. RUN bundle install # Tell Docker to listen on port 4567. EXPOSE 4567 # Tell Docker that when we run "docker run", we want it to # run the following command: # $ bundle exec rackup --host 0.0.0.0 -p 4567. CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "4567"]
Building the Docker image
All we need to do to build the Docker image is to run the following command.
I’m choosing to tag this image as
hello, although that’s an arbitrary choice that doesn’t connect with anything inside our Sinatra application. We could have tagged it with anything.
. part of the command tells
docker build that we’re targeting the current directory. In order to work, this command needs to be run at the project root.
$ docker build --tag hello .
docker build command successfully completes, you should be able to run
docker images and see the
hello image listed.
Running the Docker image
To run the Docker image, we’ll run
docker run. The
-p 80:4567 portion says “forward port 4567 to port 80”. This is necessary because Sinatra runs on port 4567 but, for some reason, Docker can apparently only expose port 80.
$ docker run -p 80:4567 hello
If we visit
http://localhost) we should see the Sinatra application being served.
$ open http://localhost
Congratulations. You now have a Dockerized Ruby application!
With this experience behind you, you’ll be better equipped to Dockerize a Rails application the next time you try to take on that task.