Skip to content

Instantly share code, notes, and snippets.

@zentetsukenz
Last active December 2, 2024 01:26
Show Gist options
  • Save zentetsukenz/5e330b801f983e3d39757686dcb41cc2 to your computer and use it in GitHub Desktop.
Save zentetsukenz/5e330b801f983e3d39757686dcb41cc2 to your computer and use it in GitHub Desktop.
Deploy Ruby on Rails application with Docker Compose and Capistrano with ease

Docker

Files and Folders.

|
|\_ app
|...
|\_ docker
| |
| |\_ development
| |\_ staging
|  \_ production
|   |
|   |\_ .env
|   |\_ app-env.onf
|   |\_ app.nginx.conf
|   |\_ Dockerfile
|   |\_ postgres-env.conf
|    \_ rails-env.conf
|
|\_ docker-compose.yml
|\_ docker-compose.staging.yml
 \_ docker-compose.production.yml

Your docker/development folder contain Dockerfile for your development. Staging and Production have the same file, but their content will be different. For example, .env file which contain your secret.

".env", This file will be use as an application environment while deploying.

This file should be listed in your gitignore

RAILS_ENV=production
SECRET_KEY_BASE=your_secret_key

Please note that, your SECRET_KEY_BASE should never ever appear in your repository, I add it here because I have it in my .gitignore file. This file will later be copied to your remote host.

"app-env.conf", application environment.

# /etc/nginx/conf.d/00_app_env.conf
# File will be overwritten if user runs the container with `-e PASSENGER_APP_ENV=...`!
passenger_app_env production;

"app.nginx.conf", an Nginx configuration for your server. Please note that your ruby version at the last line must match your Docker file base image ruby version.

# /etc/nginx/sites-enabled/app.nginx.conf:
server {
    listen 80;
    root /home/app/your_app_name/public;

    passenger_enabled on;
    passenger_user app;

    passenger_ruby /usr/bin/ruby2.3;
}

"Dockerfile", base image for your application.

FROM phusion/passenger-ruby23:latest
MAINTAINER Wiwatta  Mongkhonchit "[email protected]"

# Set correct environment variables.
ENV HOME /root

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

# Expose Nginx HTTP service
EXPOSE 80

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

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

# Nginx App setup
ADD docker/staging/app.nginx.conf /etc/nginx/sites-enabled/app.nginx.conf
ADD docker/staging/postgres-env.conf /etc/nginx/main.d/postgres-env.conf
ADD docker/staging/rails-env.conf /etc/nginx/main.d/rails-env.conf
ADD docker/staging/app-env.conf /etc/nginx/conf.d/00_app_env.conf

# Update for security reason
RUN apt-get update && apt-get upgrade -y -o Dpkg::Options::="--force-confold"

# Gem caching
WORKDIR /tmp
ADD Gemfile /tmp/
ADD Gemfile.lock /tmp/
RUN bundle install --jobs 20 --retry 5

# App setup
#
# This is your application setup steps, you should also do what you need to do here to make your 
# application working for production environment.
#
WORKDIR /home/app/your_app_name
ADD . /home/app/your_app_name
RUN rm -f config/database.yml
RUN mv config/database.yml.sample config/database.yml
RUN chown -R app:app /home/app/your_app_name
RUN rake assets:precompile RAILS_ENV=production

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

"postgres-env.conf", just a postgres environment variable, so that your app can pickup your database.

# /etc/nginx/main.d/postgres-env.conf:
env POSTGRES_PORT_5432_TCP_ADDR;
env POSTGRES_PORT_5432_TCP_PORT;

"rails-env.conf", To set environment variable for your application while running. This related to your .env file.

# /etc/nginx/main.d/rails-env.conf:
env RAILS_ENV;
env SECRET_KEY_BASE;

docker-compose.yml

There are 3 docker-compose files. The normal one, docker-compose.yml is for you development. As for your staging and production, I separated it into 2 file because I would like let Capistrano be able to pickup staging and production compose file which inside contain some different things.

docker-compose.staging.yml

version: "2"
services:
  web:
    restart: always
    build:
      context: .
      dockerfile: docker/staging/Dockerfile
    env_file: docker/staging/.env
    
    # Map your desire staging port here, if you plan to run this in the same host without using 
    # subdomain.
    ports:
      - "9876:80"
    depends_on:
      - postgres

  postgres:
    image: postgres:9.5
    ports:
      - "5432"
    volumes_from:
      - data

  data:
    image: postgres:9.5

docker-compose.production.yml

version: "2"
services:
  web:
    restart: always
    build:
      context: .
      dockerfile: docker/production/Dockerfile
    env_file: docker/production/.env
    ports:
      - "80:80"
    depends_on:
      - postgres

  postgres:
    image: postgres:9.5
    ports:
      - "5432"
    volumes_from:
      - data

  data:
    image: postgres:9.5

Capistrano

If you are not familiar with Capistrano please visit their site, then do install it into your project.

After setup Capistrano, here is a steps to take to be able to deploy your app with just one command.

cap production deploy

First, make sure that you setup your remote host for Capistrano to be able to do things, e.g. if you're using DigitalOcean, you should follow Initial Server Setup and create some user you use for deployment. I will call this guy "deploy" for the sake of simplicity.

References

@felipearaujoh00d
Copy link

No such file or directory @ rb_file_s_stat - 'docker/production/.env'

setup:env
01 ls
✔ 01 ubuntu@ip
02 pwd
02 /home/ubuntu
✔ 02 ubuntu@ip

Why can't I find the .env file?

@zentetsukenz
Copy link
Author

@h00dstoker this gist use an old docker/docker-compose version. There might be a change in how docker-compose read a file. By the way, what is the step it fails?

@felipearaujoh00d
Copy link

@zentetsukenz Thanks for answering.
I could understand the operation. It was lack of knowledge on my part.
Thanks for the tutorial.

@sokhorn-houn
Copy link

anyone could give me for all required files & it's content?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment