Dockerfile Creation and Explanation
Learn how to create a Dockerfile.
Dockerfile for Rails app
A Dockerfile is made up of various instructions such as FROM
, RUN
, COPY
, and WORKDIR
, each capitalized by convention. Let’s look at a specific example.
Here is a basic Dockerfile for running our Rails app.
FROM ruby:2.7
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
COPY myapp /usr/src/app/
WORKDIR /usr/src/app
RUN bundle install
Every image has to start from another, preexisting image. For that reason, every Dockerfile begins with a FROM
instruction, which specifies the image to be used as its starting point. Typically, we will look for a starting image that is close to what we need but more general. That way we can extend and customize it to our needs.
Dockerfile explanation
FROM instruction
The first line of our Dockerfile is:
FROM ruby:2.7.2
This is saying that our image will be based on the ruby:2.7.2
image, which, as you have probably guessed, has Ruby 2.7.2 preinstalled. We have chosen to start from this image because having Ruby installed is our biggest requirement and this image gets us most of the way there.
RUN instruction
The next two lines of our Dockerfile are RUN
instructions, which tell Docker to execute a command:
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
-
The command
apt-get
is used to install software on Debian (and some other) Linux distributions. We are using it in our Dockerfile because the official Ruby image that our image builds on is based on Debian, and more specifically, on a version called Stretch. -
The
apt-get update
command tells the package manager to download the latest package information. Many Dockerfiles will have a similar line because without itapt
has no package information at all, and therefore won’t be able to install anything. -
The
-yqq
option is a combination of the-y
option, which says to answer “yes” to any prompts, and the-qq
option, which enables the “quiet” mode to reduce the printed output. -
The
apt-get install
command installs Node.js, a prerequisite for running Rails. The--no-install-recommends
says not to install other recommended but non-essential packages because we do not need them, and we want to keep our image size as small as possible by not installing unnecessary files.
Mount the volume
Let’s shift gears briefly before we look at the next line of our Dockerfile.
Remember that images, and the containers they spawn, are separate from our local machine. They are isolated, sandboxed environments. Therefore, we need a way to include some of our local files inside the containers we run.
A mounted volume acts as a shared directory between the container and the host and is one way we can make local files accessible inside the container.
However, mounting a volume has a serious downside if it is the only way you get files into a container. Files in a volume are not part of the image itself; they are overlaid onto the image at runtime (when you start a container). If the mounted files were essential, the image would not function without them, but the whole point of images is to package everything they need in order to run. Therefore, it is good practice to bake any needed files into the image itself.
COPY instruction
The next line in our Dockerfile serves exactly this purpose:
COPY myapp /usr/src/app/
This tells Docker to copy all the files from our directory myapp
into /usr/src/app
on the filesystem of the new image. Effectively we are saying, “Copy our Rails app into the container at /usr/src/app
”. The source path on our local machine is always relative to where the Dockerfile is located.
WORKDIR instruction
By default, a container’s working directory is /
, which does not contain our Rails app files since we copied those into /usr/src/app
.
However, the WORKDIR
instruction can help us fix the situation. It performs a change directory cd
command and changes what the image considers its current directory. The next line in our Dockerfile uses it to set /usr/src/app
as the working directory:
WORKDIR /usr/src/app
You can use multiple WORKDIR
instructions in your Dockerfile, each one remaining in effect until another one is issued. The final WORKDIR
will be the initial working directory for containers created from the image.
RUN instruction
Finally, we come to the last line of our Dockerfile:
RUN bundle install
The command is executed from the container’s current working directory, which in the previous command was set to be /usr/src/app
. This will install the gems defined in our Rails project’s Gemfile, which are needed in order to start the application.
Get hands-on with 1400+ tech skills courses.