Deployment

Our application will be located at '/var/www/apps/mysite'. We will use capistrano v3 for deploying.

Overview

  • Architecture
  • Repositories
  • Setup capistrano v3
  • Shared data
  • Deploy init
  • Deploy
  • Sync shared data

Prerequisites

  • Create virtual host / server on Apache/Nginx before deployment.

If you are using Nginx web server and Passenger, read this to setup a server for Rails app.

Architecture

We have - local machine with our app - server where the site will be installed - server where git repository is located

Git server can be the same server we are deploying to or Github can be used.

Local machine: - folder 'site' - stores development/production versions of site in git - folder 'site_production_shared' - stores shared data

Repositories - Local repository with branches: master, production, production-shared - Remote repository with branches: production, production-shared - Git on server for shared data in /var/www/apps/mysite/shared/ with branches: production-shared

Branches in repository: - branch master - development version - branch production - deployment will be from this branch - branch production-shared - shared data that can be syncing with the server

Server: - /var/www/apps/mysite/ - folder with the app - /var/www/apps/mysite/public/ - entry point for the site for Nginx - /var/www/apps/mysite/shared/ - shared folder - /var/www/logs/ - site logs

Repositories

Local repository

in the main app folder:

Create branch 'production' from 'master':

git checkout -b production

Create empty branch 'production-shared':

git checkout --orphan production-shared

site_production_shared

create folder 'site_production_shared' for storing shared data on local machine .

For this folder:

  • init git:
git init

git checkout -b production-shared

Remote repository

Create a repository from which app will be deployed. It can be on Github, your server with git, or it can be placed on the same server where the app is located.

Add remote repository to your local git:

# locally. from the main app

git remote add origin ssh://myserver.com/repos/reponame.git

For the folder site_production_shared

git remote add origin ssh://myserver.com/repos/reponame.git

Capistrano

basic setup

Edit config/deploy.rb:


#
set :deploy_user, 'myrvmuser'


# IP of your server
role :app, %w{123.45.67.99}
role :web, %w{123.45.67.99}
role :db,  %w{123.45.67.99}

edit config/deploy/production.rb:

set :application, "mysite" # app in '/var/www/apps/mysite'
set :rails_env, 'production'
set :branch, 'production'

server '11.22.33.44', user: 'myrvmuser', roles: %w{web}, primary: true
set :deploy_to, "/var/www/apps/#{fetch(:application)}"


set :ssh_options, {
    forward_agent: true,
    user: 'myrvmuser'
}

Find more features for deployment here.

Shared data

Some files and folders should be shared on the server. These are config files (like 'config/database.yml' or 'log/') or files/folders which should not be overwritten by local version of app.

Such files are place in folder '/var/www/apps/mysite/shared' on the server.

If OptimaCMS is used than files in 'app/views' folder can be edited by web site administrator on server.

We should prevent overwriting such files by our local version while deploying. Also we should be able to update that files from the local version of app.

Specify such files and folders in config/deploy.rb:

# Add necessary files and directories which can be changed on server.
my_config_dirs = %W{config config/environments}
my_config_files = %W{config/database.yml config/secrets.yml config/environments/#{fetch(:stage)}.rb }
my_app_dirs = %W{public/system public/uploads public/img app/views}


# do not change below
set :linked_dirs, fetch(:linked_dirs, []).push('bin', 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle')
set :linked_dirs, fetch(:linked_dirs) + my_app_dirs
set :linked_files, fetch(:linked_files, []) + my_config_files

set :config_dirs,  my_config_dirs+my_app_dirs
set :config_files, my_config_files

Setup shared folder on local machine

Shared data is stored in production-shared branch.

In our scenario we have a separate folder site_production_shared to store shared data on local machine.

Copy necessary files to local folder site_prudction_shared.

We have my_app_dirs = %W{public/system public/uploads public/img app/views} in deploy.rb.

Copy 'app/views' from the main site to folder 'site_production_shared'.

.gitignore

Modify '.gitignore' in the shared repository to exclude files/folders you don't want to be syncing. For example, if you have photos uploaded by users stored in '/var/www/apps/mysite/shared/public/photos' and you don't want to store them in the remote repository then include '/public/photos' in '.gitignore'. Or if you have images stored 'public/img' and you want to upload them from your local version to the server, then do not include this folder in '.gitignore'.

Edit .gitignore for the shared folder appropriately:

/.bundle
/db/*.sqlite3

# Ignore all logfiles and tempfiles.
/log/*.log
/tmp
/bin
/log
/vendor
/vendor/bundle
.DS_Store
.idea/
.vagrant/
*.swp
.vagrant/machines/default/virtualbox/id

/config/secrets.yml
/config/deploy.rb
/config/deploy/
/config/application.yml

/public/assets
/public/uploads
/public/photos
/public/system/maintenance.html

Find basic example of this file in gitignore_shared.

Setup shared folder on server

run capistrano task:

cap production my_server_setup:init_shared_folder

It will: - create directory 'var/www/apps/mysite/shared' - initialize git repository in the directory

The 'shared' folder will store data in 'production-shared' branch.

Edit '/var/www/apps/mysite/shared/.gitignore' - see .gitignore for shared folder on local machine.

Deploy init

Push to remote repository

First, commit your changes on local machine:

git checkout master
git add -all
git commit -m "my changes"

Merge branch 'production' and push to the remote git server:

git checkout production
git merge master

git push origin production

go back to master branch:

git checkout master

Copy config files

cap production deploy:copy_config_files

This will copy config files to server.

Upload shared data to server

Copy files to shared folder site_production_shared on local machine.

Commit and push to the remote repository:

git checkout production-shared

git add .
git commit -m "my changes"

git push origin production-shared

Update shared folder on the server - run capistrano task from the app folder:

cap production mysync:shared:update_server

Deploy

cap production deploy

Issues

  • If you get this error
DEBUG [6692d638]      cannot access /var/www/apps/tpl_demo/releases/20150717052152/public/assets/manifest*.*
DEBUG [6692d638]        : No such file or directory

to fix this run the commands on server:

cd /var/www/apps/mysite/releases/_release_id/

rake assets:precompile RAILS_ENV=production

run again 'cap production deploy'.

Sync shared data

Upload shared data to server

We want to upload shared data from local machine to the server.

cd site_production_shared

git checkout production-shared

git push origin production-shared

cd ../site

cd ../site
call cap production mysync:shared:update_server

Get shared data from server

Shared data can be updated on the server. For example, OptimaCMS can change files in app/views.

We want to get files from the server to our local machine (stored in folder site_production_shared).

# from main site folder
cd site
cap production mysync:shared:commit_server


# in site_production_shared
cd ../site_production_shared

git checkout production-shared
git pull origin production-shared