Engine Yard Kontainers: the Dockerfile

When deploying an application that uses a Dockerfile, there are some details to notice. The Dockerfile will be used in order to build the Docker image that all your pods will use upon deployment. This means that the Dockerfile should have the gems and packages that you web server, background processes, cron etc will need. 

Dockerfile: parent image 

This is basically the FROM keyword that will be used. For a rails application some potential candidates are:

  • FROM ruby:2.4-alpine3.10
  • FROM ruby:2.5-buster

A list of currently supported ruby parent images can be found here. The parent image can be any Linux distribution. For example, as seen above you can use Alpine or Debian as your parent image. This means that you will need to use the corresponding package manager and packages in order to get the needed packages in place.

Dockerfile: installing packages

Based on the parent image you can use the package manager in order to install the needed packages. For example in a Dockerfile that uses Alpine as the parent image, in order to install nodejs (that is needed for your assets precompilation) you should write:

 RUN apk update && apk add nodejs

If Debian is used as parent image, the command would be:

 RUN apt-get update && apt-get install -y nodejs

The update part is essential, as most parent images try to be as small as possible, thus updating the packages registry will let you fetch and install the required package.

Dockerfile: expose port

The EXPOSE keyword instructs the platform on which port the web pods accept traffic. This port is expected to respond to TCP health checks, and is the one to receive external traffic.

Dockerfile: default command to execute

This can be defined via the CMD keyword. It will instructs the container what command to execute once it gets up. This will be overridden by the Procfile and the processes we define in there.

Dockerfile example

Since the basic parts of a Dockerfile have been explained, an example is provided along with the explanation:


 FROM ruby:2.5-buster
 RUN apt-get update && apt-get install -y nodejs build-essential tzdata sqlite3 

 # Configure the main working directory. This is the base 
 # directory used in any further RUN, COPY, and ENTRYPOINT 
 # commands.
 # In the running container the code will be under /app
 RUN mkdir -p /app 

 # Copy the Gemfile as well as the Gemfile.lock and install 
 # the RubyGems. This is a separate step so the dependencies 
 # will be cached unless changes to one of those two files 
 # are made.
 COPY Gemfile ./ 
 RUN gem install bundler -v '1.16.3' && bundle install --without development test --jobs 20 --retry 5

 # Copy the main application.
 COPY . ./

 # Expose port 5000 to the Docker host, so we can access it 
 # from the outside. This is the same as the one set with
 # `deis config:set PORT 5000`
 EXPOSE 5000

 # The main command to run when the container starts. Also 
 # tell the Rails dev server to bind to all interfaces by 
 # default.
 CMD bundle exec rails server -b -p 5000 -e development

In the above Dockerfile the parent image is ruby on Debian OS. Then some packages installation follow via the apt package manager. Then a new directory named /app is created and set as the working directory (via the keyword WORKDIR). The copy of the Gemfile follows and later on the bundling of the gems based on it. After that the whole code gets copied and the EXPOSE, CDM instruct on the defaults for every container that will be based on the image to be created.


Article is closed for comments.

Powered by Zendesk