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.
- 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.
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
Create a new file with name
Dockerfile, name of Dockerfile is arbitery which means you can name it
if you prefer, let’s stick to
Dockerfile for the demo.
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"]
#! /bin/sh bundle exec rake db:migrate
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
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 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 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 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.
will prevent any prompts and install without intervention.
COPY Gemfile Gemfile.lock ./
COPY command is used to copy files/directory from host to container image. Usage of
COPY is just similar to
COPY source_of_file_in_host destination_of_file_in_container. If you use destination as relative path then path will start
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
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 ["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.
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.