Dockerize Your Rails Application !
This is the right time to invest time and resources in containerization technologies to make sure your projects are scalable and portable. Docker is the de-facto containerization platform we’ve at the moment.
Prerequisites
- You should know the basics of Containerization and Docker, if not start here.
- Your application should be designed according to The twelve-factor app standards. You can dockerize your app without this, but sooner you do this lesser evils you’ll have to face.
Writing Dockerfile
I’ve created a default blog application for demo with rails new blogger
, get in to blogger
app directory.
To create docker image for application, we need to write the Dockerfile
.
Create a new file with name Dockerfile
, name of Dockerfile is arbitery which means you can name it staging.Dockerfile
if you prefer, let’s stick to Dockerfile
for the demo.
Dockerfile
FROM ruby:2.3.7
WORKDIR usr/src/blogger
EXPOSE 3000
RUN apt-get update
RUN apt-get install -y nodejs
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
ENTRYPOINT ["scripts/init.sh"]
CMD ["bundle", "exec", "rails", "s"]
scripts/init.sh
#! /bin/sh
bundle exec rake db:migrate
Commands Explained
FROM
FROM ruby:2.3.7
We are setting ruby base image for our blogger image, you can select a prebuilt linux distribution with ruby installed so
that you don’t have to take care of installing ruby and it’s neccessary dependencies. You can chose for a variety of Ruby
versions from their official Dockerhub profile.
Take away here is chose an official image whenever possible, so that you don’t have to write/maintain base software. You
can opt for smaller sized compact images as well, any image that ends with slim
, alpine
are stripped off additional
libraries and kept with minimum viable libraries and apps to keep size in check. Opting for smaller base image reduce your
image size considerably which helps when you download/upload your images.
WORKDIR
WORKDIR usr/src/blogger
With WORKDIR
we are setting up our default directory for operations, which means any file that gets copied or any command
that runs without absolute path
will be in effect from this directory. usr/src
is arbitory, it’s just that I prefer
putting my code there.
EXPOSE
EXPOSE 3000
We use EXPOSE
command to open up container port to outside world, we opened up 3000
port of container in above example
as it was the rails default port.
RUN
RUN apt-get update
RUN apt-get install -y nodejs
RUN
command is used to run shell commands. Most of the time we need libraries and supporting softwares to run
applications, we need nodejs
to run Rails application, that’s why we’re installing nodejs in above example. -y
flag
will prevent any prompts and install without intervention.
COPY
COPY Gemfile Gemfile.lock ./
COPY
command is used to copy files/directory from host to container image. Usage of COPY
is just similar to cp
command,
COPY source_of_file_in_host destination_of_file_in_container
. If you use destination as relative path then path will start
from WORKDIR
as it’s the default directory in container.
To build docker image, run docker build -t albertpaulp/blogger:v1 .
To run the image we just builded, docker run -p 80:3000 albertpaulp/blogger:v1
ENTRYPOINT
ENTRYPOINT ["scripts/init.sh"]
Applications can have certain chores to do before starting up everytime, for example a typical backend application may need
to run migrations in database everytime before starting up. ENTRYPOINT
is the place where you put these initialization
scripts, this command accepts a command or a file.
CMD
CMD ["bundle", "exec", "rails", "s"]
CMD
just like RUN
except it only execute at runtime and doesn’t create layer while building, usually the final command
is given to CMD
, in our scenario it’s starting the server.
Optimization
Leveraging Docker Cache
If you’ve noticed the order we arranged Dockerfile, we’ve copied Gemfile first and built it, then we are adding rest of the code files. We do this to make use of Docker caching, so that if we keep building without changing Gemfile, docker will make use of it’s caching mechanism to skip installing gems everytime, which saves us a lot of time. Rule of thumb is always arrange Dockerfile instructions in way that less frequent operations comes first, so that Docker can use cache for those, Follow this to learn how Docker caching works.
Customizing App Startup with script
You can make use of ENTRYPOINT
to run specific commands before your application starts, it can be anything from running
migrations, creating databases and checking if database server is up etc.