[Ruby] Automate deployment

6 minute read

Introduction

The procedure for “using the AWS server” is divided into 5 parts.

Please check the articles as summarized below.

EC2 initial settingsCreate a database in the production environmentStart Rails of EC2Set Web ServerAutomate deployment ← Imakoco

Deployment automation

The deployment work (the means to start the server using “unicorn_rails command”) that was done manually, It can be done with one command from the local terminal. For that purpose, we use what is called an “automatic deployment tool”.

This time, we will introduce an automatic deployment tool called Capistrano.

Preparation for introduction

Install Gem to use Capistrano in Gemfile Then in the application directory bundle install

group :development, :test do
  gem'capistrano'
  gem'capistrano-rbenv'
  gem'capistrano-bundler'
  gem'capistrano-rails'
  gem'capistrano3-unicorn'
end

After reading the gem, enter the following command

Terminal (local) *Application directory

% bundle exec cap install

The file is generated as below Image from Gyazo

Edit ###Capfile capfile

require "capistrano/setup"
require "capistrano/deploy"
require'capistrano/rbenv'
require'capistrano/bundler'
require'capistrano/rails/assets'
require'capistrano/rails/migrations'
require'capistrano3/unicorn'

Dir.glob("lib/capistrano/tasks/*.rake").each {|r| import r}

Edit ###production.rb

config/deploy/production.rb


server'Elastic IP prepared', user:'ec2-user', roles: %w{app db web}

Edit ###deploy.rb Delete all the description of deploy.rb and paste the following code Attention points “Capistrano version” → It is described in Gemfile.lock “Application name” “GitHub username, repository name” “The version of ruby used in this app” “Own key pair name”

config/deploy.rb


Described the version of #capistrano. Continue to use fixed version and prevent troubles due to version change
lock'Capistrano version'

# Used to display the Capistrano log
set :application,'your application name'

# Specify which repository to pull the app from
set :repo_url,'[email protected]:Github username/repository name.git'

# Specify a common directory to reference even if the version changes
set :linked_dirs, fetch(:linked_dirs, []).push('log','tmp/pids','tmp/cache','tmp/sockets','vendor/bundle','public/system', ' public/uploads')

set :rbenv_type, :user
set :rbenv_ruby,'Version of ruby used in this application' # If you proceed according to the article, '2.6.5'

# Which public key to use for deployment
set :ssh_options, auth_methods: ['publickey'],
                                  keys: ['~/.ssh/ own key pair name.pem']

# File location with process number
set :unicorn_pid, -> {"#{shared_path}/tmp/pids/unicorn.pid"}

# Unicorn configuration file location
set :unicorn_config_path, -> {"#{current_path}/config/unicorn.rb"}
set :keep_releases, 5

# Description to restart Unicorn after the deployment process is completed
after'deploy:publishing','deploy:restart'
namespace :deploy do
  task :restart do
    invoke'unicorn:restart'
  end
end

Once automatic deployment by Capistrano is executed, the directory of the application in the production environment changes. Multiple directories are created, such as Capistrano’s backup of apps.

The following three are particularly important

releases directory

The “releases directory” is a collection of apps that have been deployed through Capistrano. If you have any problems during deployment, you can revert to the previous version by keeping the apps for the past here. The description of “set :keep_releases” in deploy.rb specifies the number of saved files for the past. This time, set to save 5 past versions.

current directory

In the “current directory”, the newest one in the releases folder It is as if it was copied automatically. In other words, “currently deployed contents = contents in current”.

shared directory

The directory that stores the commonly referenced directories even if the version changes. Specifically, log, public, tmp, and vendor directories are stored.

Edit Unicorn configuration file

Compared to manual deployment, Rails application directory is One step deeper. Therefore, it is necessary to make some changes.

``` [Before editing] config/unicorn.rb

Put the directory where the application code on the server is installed in a variable

app_path = File.expand_path(‘../../’, FILE)

Determine the performance of the application server

worker_processes 1

Specify the directory where the application is installed

working_directory app_path

Specify the location of the file required to start #Unicorn pid “#{app_path}/tmp/pids/unicorn.pid”

Specify port number

listen 3000

Specify a file to log errors

stderr_path “#{app_path}/log/unicorn.stderr.log”

Specify a file to record normal logs

stdout_path “#{app_path}/log/unicorn.stdout.log”

(abridgement)


``` [after editing] config/unicorn.rb
# "../" has increased by one
app_path = File.expand_path('../../../', __FILE__)

# Determine the performance of the application server
worker_processes 1

# Specify "current"
working_directory "#{app_path}/current"

# Change to refer to "shared"
listen "#{app_path}/shared/tmp/sockets/unicorn.sock"

# Change to refer to "shared"
pid "#{app_path}/shared/tmp/pids/unicorn.pid"

# Change to refer to "shared"
stderr_path "#{app_path}/shared/log/unicorn.stderr.log"

# Change to refer to "shared"
stdout_path "#{app_path}/shared/log/unicorn.stdout.log"
(abridgement)

Edit Nginx configuration file

Similar to Unicorn’s configuration file, compared to the time of manual deployment, The Rails application directory is one level deeper during automatic deployment. Therefore, it is necessary to make some changes.

Run in terminal (inside EC2)

$ sudo vim /etc/nginx/conf.d/rails.conf

Edit below ① 3rd line: Edit to “~application name/shared/tmp/~” ② Line 14: Add entire line → root /var/www/application name/current/public; ③ Line 20: Add entire line → root /var/www/application name/current/public;

/etc/nginx/conf.d/rails.conf


upstream app_server {
  # Settings for linking with Unicorn
  server unix:/var/www/application name/shared/tmp/sockets/unicorn.sock;
}

The part enclosed in # {} is called a block. Can set the server
server {
  # The port number this program accepts connections from
  listen 80;
  #Request URL for accepting connections URLs not listed here cannot be accessed
  server_name Elastic IP;

  # Set the maximum size of files uploaded from clients to 2 gigs. The default is 1 mega, so keep it largeclient_max_body_size 2g;

# Root directory when connection comes
  root /var/www/application name/current/public;

Settings that are applied when # assets files (CSS and JavaScript files, etc.) are accessed
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    root /var/www/application name/current/public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

After completing the input, execute in the order of “esc key” → “:wq” and save. Don’t forget to reload/reboot after changing Nginx settings

Run in terminal (inside EC2)

[[email protected]***-**-**-*** ~]$ sudo systemctl reload nginx
[[email protected]***-**-**-*** ~]$ sudo systemctl restart nginx

Confirm database startup

If the database is not started, the deployment will fail. Check the database status with the following command.

Run in terminal (inside EC2)

[[email protected]***-**-**-*** ~]$ sudo systemctl status mariadb

If “active” is displayed as shown below, it is running.

● mariadb.service-MariaDB database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2020-07-17 03:46:51 UTC; 8s ago
  Process: 17044 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=exited, status=0/SUCCESS)
  Process: 17008 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exited, status=0/SUCCESS)
 Main PID: 17043 (mysqld_safe)
   CGroup: /system.slice/mariadb.service
           ├─17043 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
           └─17206 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/ mariadb/mariadb.log --pid-file=/var/run/mariadb/mariadb.pid --so...

*If it is not “active”, execute sudo systemctl start mariadb

kill the Unicorn process

Before auto-deploying, you need to kill the unicorn process. When automatic deployment is done with the unicorn server already running, Because it will start the server in duplicate. (Automatic deployment is also responsible for starting the server)

① Check the process

[[email protected]***-**-**-*** <repository name>]$ ps aux | grep unicorn

ec2-user 17877 0.4 18.1 588472 182840 ?Sl 01:55 0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881 0.0 17.3 589088 175164 ?Sl 01:55 0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911 0.0 0.2 110532 2180 pts/0 S+ 02:05 0:00 grep --color=auto unicorn

② Kill the process

# In the above example, it is "7877"
[[email protected]***-**-**-*** <repository name>]$ kill process number

Push all local modifications to master

Make sure all local code changes are pushed to master. This completes the preparation for automatic deployment.

Execute auto deploy

Return to the local terminal and execute auto deploy with the following command

# Run in application directory
% bundle exec cap production deploy

*After restarting EC2 instance, be sure to restart “database” and “Nginx”

Run in terminal (inside EC2)

[[email protected]***-**-**-*** ~]$ sudo systemctl restart mariadb
[[email protected]***-**-**-*** ~]$ sudo systemctl restart nginx

Confirm with browser

Access with Elastic IP from a browser. *Be careful as “http:///" instead of "http://:3000/".


that’s all. Thank you for your hard work.