Jack Moore

Email: jack(at)jmoore53.com
Project Updates

Dockerized Rails Applications P1

01 Jan 2019 »

Running Rails applications in a container makes managing configurations easy on my device and cross platform compatibility really easy for code reviews.

This post goes into containerizing a new rails applicaiton. It is a very “in the weeds” techincal post. Also after looking at the way I formatted this post, I would not recommend using this kind of setup for a new rails setup. I would use chruby or rvm. I have used both for development and they are both good, but currently I prefer chruby. There are benefits and drawbacks to everything.

Rails in a Container from Scratch

From my linux machine I ran mkdir dds and then created a Dockerfile with touch Dockerfile.

The contents of the Dockerfile look like this:

FROM ruby:2.6.0

RUN apt-get update && apt-get install -y \ 
  build-essential

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
    && apt-get install -y nodejs

RUN mkdir -p /app
WORKDIR /app

RUN gem install rails

RUN rails new .

I then built the dockerfile into an image and tagged it using docker build -t rails:dds .: note -t for tag and the . for using this folders Dockerfile.

I then created a container named with docker create --name dds_rails rails:dds with the docker image I just created. This command then returned a container id for the container. The container id is a UUID generated by the Docker application.

I used docker container ls -a to find the container id, as docker container ls only shows the running containers.

I then ran docker cp -a container_id:/app . to copy the application code down into a folder on my host named app. I refreshed the folder on my local machine and the application code from the intermediary container copied into a new folder named ./app on my host machine.

Back to Dockerfile

Now that I had the start to a rails project on my computer, I went back to my Dockerfile and made some revisions. The dockerfile from above was more of a big bang and was and wil only be used once. It needs to be revised to host the application.

I changed the Dockerfile to look like:

FROM ruby:2.6.0

RUN apt-get update && apt-get install -y \ 
  build-essential vim

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
    && apt-get install -y nodejs

RUN mkdir -p /app
WORKDIR /app

ENV EDITOR=vim

COPY Gemfile Gemfile.lock ./ 
RUN gem install bundler && bundle install --jobs 20 --retry 5

COPY . ./

EXPOSE 3000

CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]

Then I moved this Dockerfile into the app directory that has just been copied into your working directory.

Change directories into the app folder and docker build -t rails:app-name . to create the image. You will then need to create the container like we did before with docker create --name dds-app rails:app-name, note we used the rails:app-name tag because this is the image we gave to our new Dockerfile image.

Then running docker run -it -p 3000:3000 rails:dds we will be running our application on our host machine from a temporary container on port 3000.

A quick update is the ENV EDITOR=vim line and the ..apt-get build-essential vim with the vim package added/ installed. This will allow us to edit secret credentials using the /usr/local/bundle/bin/rails credentials:edit command.

Run Rails Commands from the host using commands from the Container with a Volume

To run all rails commands and create controllers and models, you will need to be in the container and copy down the changes as you make them. This is a little inconvient for now, but I will be using the container’s /usr/local/bundle/bin/rails command from the host machine and a bash alias to copy the changes down.

I crafted up this docker run -it -p 3000:3000 -v $(pwd):/app rails:dds /usr/local/bundle/bin/rails generate controller static to generate a static controller as a test, but I think I will alias the first part of this command, docker run -it -v $(pwd):/app rails:dds /usr/local/bundle/bin/rails to something easier on my local development machine like drails.. Note this drails will only work from the present working directory of the rails application.. From my bash terminal in my Mac, I ran alias drails=docker run -it -v $(pwd):/app rails:dds /usr/local/bundle/bin/rails to create the drails alias. Note the $(pwd) will give you trouble if you have a file or directory that has spaces. You will have to swap the $(pwd) with the full location of the app directory.

With this alias configured, we can run drails g model test and this will create a new model. With this we have access to all the normal rails commands.

I then created essentially the same alias for the rest of the container binaries, but I may go back and write a bash function to run anything from the container.

We are now able to run everything from our local machine without having to install ruby or rails on our machine. We can then run the rails application with docker run -t -p 3000:3000 rails:dds from the host machine and our host will have our rails application running on port 3000.

I opened my browser and everything appeared to be working well.

Rework

If I were to redo this, I think I would have modified the second dockerfile in this post to allow me to attach to the application container and run the commands in the container and using the attached host:container volume I would be able to modify the files on my host machine.

More

It is really inconvienent to run rails commands from the host to the container using the drails alias I created, but I am going to work on a simple bash function to run all the container binaries (everything in the /usr/local/bundle/bin/ folder). This will be covered in the second part of this post.

More

Checkout Part 2 for more on bash scripts around docker. Part 3 ofwill deal with deploying a containerized rails site to production.

I also made a youtube video for our metrics application (under development) dealing with containers and how to get started.

© Jack Moore