Contents

Docker and Rails in Production

Contents

Last week, I deployed a Rails app in a Docker container onto AWS Elastic Beanstalk. It was an unncessarily time consuming task due to small gaps in my knowledge and unfamiliarity with Docker and Elastic Beanstalk. This blog post is written during my first month working as a junior system administrator (“devops”) and this is a recap of my experience to the best of my memory.

Super helpful links: https://github.com/phusion/passenger-docker https://intercityup.com/blog/deploy-rails-app-including-database-configuration-env-vars-assets-using-docker.html https://intercityup.com/blog/how-i-build-a-docker-image-for-my-rails-app.html https://rossfairbanks.com/2015/03/06/rails-app-on-docker-using-passenger-image.html

Thanks to these blog posts (amongst many others), I was able to cut down a lot of time out of learning how to deploy this rails app.

First thing’s first. I installed docker-machine, which is the new boot2docker, and attempted to run my docker image containing the Rails app locally, in production, on my Macbook.

Here is the Dockerfile that I used:

FROM phusion/passenger-ruby22:0.9.17
MAINTAINER Brian Choy <bycEEE@gmail.com>

# Set correct environment variables.
ENV HOME /root

# Use baseimage-docker's init system.
CMD ["/sbin/my_init"]

# Start Nginx / Passenger
RUN rm -f /etc/service/nginx/down

# Remove the default site
RUN rm /etc/nginx/sites-enabled/default

# Add the nginx info
ADD nginx.conf /etc/nginx/sites-enabled/webapp.conf

# Add the rails-env configuration file
ADD rails-env.conf /etc/nginx/main.d/rails-env.conf

# Run Bundle in a cache efficient way
WORKDIR /tmp
ADD Gemfile /tmp/
ADD Gemfile.lock /tmp/

# Add the rails app
ADD . /home/app
WORKDIR /home/app
RUN chown -R app:app /home/app

# Run bundle and expose port 80
RUN sudo -u app bundle install --deployment --without test development doc
RUN sudo -u app RAILS_ENV=production rake assets:precompile
EXPOSE 80

# Clean up
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

The reason why I used passenger-docker is included on their GitHub. Basically they’re maintaining a Ubuntu 14.04 base image that is tweaked and configured properly for Docker.

My nginx.conf:

server {
  listen 80;
  server_name websiteurl.com;
  root /home/app/public;

  passenger_enabled on;
  passenger_user app;
  passenger_app_env production;
  passenger_ruby /usr/bin/ruby2.2;
}

My rails-env.conf

env APP_DB_DATABASE;
env APP_DB_HOST;
env APP_DB_PASSWORD;
env APP_DB_USERNAME;
env AWS_ACCESS_KEY_ID;
env AWS_SECRET_ACCESS_KEY;
env FACEBOOK_APP_ID;
env FACEBOOK_APP_SECRET;
env SECRET_KEY_BASE;
env TWITTER_API_KEY;
env TWITTER_API_SECRET;

These Rails environment variables are now accessible to me and can be changed via my AWS console. My database also resides in AWS RDS so I did not set up a local MySQL database to connect to.

Running my app:

docker run --rm -p 80:80 myappname

Shell access to my container to poke around for errors:

sudo docker exec -i -t 665b4a1e17b6 bash

Afterwards just go to your AWS account, spin up another instance of Elastic Beanstalk, add in all your environment variables, and make sure RAILS_ENV is set to production in your environment variables.

I’m sure there were way more pain points in this process not mentioned in this blog post and I probably blocked them out of my memory. So far I can relax and be satisfied that this works, but eventually I’ll have to do this again. Will update this blog post or make another one in the future with more info.