Inside thredUP
Published in

Inside thredUP

Building Microservices with Docker and the Rails API gem

photo credit:

At the company that I work for, we have been using Docker to have consistent development environments for all of our engineers. This makes onboarding a new engineer a piece of cake. I’m still particularly new to Docker and want to share my experience just getting a basic Rails API application setup as a microservice. Like most companies that struggle over the long run with a monolithic Rails app, a microservice architecture provides loose coupling, strong cohesion, independent deploys, and much more.

I’ve built quite a few applications where we’ve used Rails as an API, which is a little overkill since you don’t need all the view logic and additional middleware. Instead, we’ll be using the Rails API gem to build out our microservice APIs. The Rails API gem is integrated into the Rails 5 release, which is currently in beta. I’ve explored this option using Docker, but struggled with setting it up so I’ll be writing about using a Rails 4 setup and adding the rails-api gem as a dependency to the Gemfile.

You may ask yourself why use Rails API as the tech stack for your microservice. I think the answer lies on what works best for your team. There are plenty of talks on the internet about whether or not your team should move towards microservices and what technology to use. There are a ton of other great technologies where using Node.js, Go, Scala, or Java might fit your situation. I’ve spent some time exploring some of these options and I think they are all great, but my team knows Rails the best and we can develop quickly with it. If I were to pick another tech stack that would fit well with my team, I would go with Node.js since a lot of our new apps are being built with it. I think the overall goal is to make sure your services are small enough to be rewritten if needed.

My biggest recommendation, if this is your first time using Docker, is to go through the tutorial and installation at (I’m using a mac, but there are tutorials for all the platforms). Next, go through the Rails tutorial setup on the Docker website . This will give you the fundamentals to understand how Docker works and setting up a container to run a Rails app with Postgres.

This tutorial is for Mac users, but you can adopt it for a Linux distribution or figure out the equivalent on a Windows platform. First create the directory for your project within the terminal. I’ll be making a project called “inventory manager”, but you can name your project whatever.

mkdir inventory_manager && cd inventory_manager

Then create a few files within the root directory of the project.

touch Dockerfile docker-compose.yml Gemfile Gemfile.lock

The Dockerfile is everything we need to set up our Docker container’s environment.

FROM ruby:2.3.0RUN apt-get update -qq && apt-get install -y build-essential libmysqlclient-devRUN mkdir /inventory_managerWORKDIR /inventory_managerADD Gemfile /inventory_manager/GemfileADD Gemfile.lock /inventory_manager/Gemfile.lockRUN bundle installADD . /inventory_manager

So what is happening in this file? Here we are creating an image using the latest version of Ruby (2.3.0) at the time of this writing from We then run the following apt package manager commands on the container. We’ll be using the MySQL client library for development. We’ll then add the local Gemfile and Gemfile.lock to our container’s filesystem and then install the dependencies. Lastly, we add all the contents of the project directory to the container.

We need to setup our docker-compose.yml file so that the Docker Compose tool can orchestrate the communication between our Rails API app and our MySQL container.

image: mysql:latest
— “3306:3306”
build: .
command: puma
— “9292:9292”
- db
— .:/inventory_manager

This configuration sets us up with a mysql container and also a container called web that builds from the Dockerfile and runs the Puma webserver on port 9292. We then link the Rails app container to the mysql container so that they can communicate to each other.

Inside the Gemfile we will add the Rails gem, the Rails API gem, the mysql client adapter, Puma web server, and the Active Model Serializers (this is for your formatted JSON responses).

Now its time to create the Docker image.

docker-compose build
running the docker build command will go through your Dockerfile to build the image and then install gems.
docker image successfully created

You will need to run this command to rebuild your Docker image anytime you make a change to the Gemfile or the Dockerfile . You can see that an image is created by typing:

docker images

Next we’ll create the application structure by running the Rails API commands in the Docker image. In our docker-compose.yml we have named “web” as the container to run our commands against.

docker-compose run web rails-api new .
Creating the rails api application structure

Now we need to configure our database.yml file so we can start writing a migration.

adapter: mysql2
encoding: utf8
reconnect: false
database: inventory_manager_dev
pool: 5
username: root
password: mypassword
host: db
adapter: mysql2
encoding: utf8
reconnect: false
database: inventory_manager_test
pool: 5
username: root
password: mypassword
host: db

The host is “db”, which is the same name we’ve defined in our docker-compose.yml file. This host’s value must match what you’ve defined as your database container in the docker-compose.yml file.

Now that the app structure has been built, lets run the web server to see if we can see the Rails status page.

docker-compose up web
Runs both our database and web app in their respective containers and then runs the puma server listening on port 9292
my docker-machine ip is running on port

Make sure to find your docker ip by running docker-machine ip <docker vm host> (for me this is aliased to default).

docker-machine ip default

Now that we’ve got our app running we can start development by creating data models, controllers, etc…

We can create more microservices in this manner and facilitate communication between apps using JSON over http by exposing different web server ports on the same Docker host. Another form of communicating between services is by utilizing messaging such as RabbitMQ. I’ll most likely be writing another blog post on RabbitMQ and communicating between services and how to get that setup.

I hope this post helps others as this was definitely a learning experience for me and I’m continuing to learn more and more about Docker. Feel free to comment and make any suggestions on improving the setup.

Want to know more? Hit me up at



Stories about product, design, engineering, data science, culture and more from the teams building the world’s largest online thrift store

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store