I used Capistrano to deploy my own Rails app.
Basically, I referred to the following article. (Capistrano edition) The most polite AWS commentary in the world. Until you bring your Rails app to AWS using EC2
In this article, I've summarized the parts that were filled with errors along with the reference article, so I hope you find it helpful.
Local side
Server side (EC2)
Gemfile List of gems to install.
(local)Gemfile
group :development, :test do
 gem 'capistrano'
 gem 'capistrano-bundler'
 gem 'capistrano-rails'
 gem 'capistrano-rbenv'
end
group :production, :staging do
  gem 'unicorn'
end
Other literature may use the gem'capistrano3-unicorn', but it is not used here for detailed settings.
Capfile
This is the configuration file for the entire capistrano.
(local)Capfile
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
#Set to read the file that describes the task. Specify the location and extension.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
In the reference article, the last line is "~ / *. Rb", but in the current version, rake is the default, so use that.
Note that the file format of lib / capistrano / tasks / unicorn.rake that you will create later is **. Rake **. Let's make the set file format the same file format. (I got a little stuck here.)
config/deploy/production.rb
This file describes the settings of the production environment.
(local)config/deploy/production.rb
#Describe the IP of the EC2 server, the user name to log in to the EC2 server, and the role of the server.
server '**.***.***.***', user: 'yuki', roles: %w[app db web]
#Describe the key information to ssh login to the server to deploy
set :ssh_options, keys: '~/.ssh/app_key_rsa'
config/deploy.rb
Describe the settings that apply to both the production environment and the stading environment.
(local)config/deploy.rb
#Fixed version of capistrano
lock '3.14.1'
#Application name to deploy
set :application, 'golfour'
#Git repository to clone
set :repo_url, '[email protected]:app/app_aws.git'
#The branch to deploy. The default does not have to be master.
set :branch, 'master'
#The directory to deploy to.
set :deploy_to, '/var/www/rails/app'
# secret_base_Added to read the key
set :linked_files, %w[config/master.key]
#A file with a symbolic link.
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/settings.yml', '.env')
#A folder with symbolic links.
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
#The number of versions to keep. Save up to 5 history.
set :keep_releases, 5
#version of ruby
set :rbenv_ruby, '2.5.1'
#The level of the log to output.
set :log_level, :debug
namespace :deploy do
  desc 'Restart application'
  task :restart do
    invoke 'unicorn:restart'
  end
  desc 'Create database'
  task :db_create do
    on roles(:db) do |_host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:create'
        end
      end
    end
  end
  desc 'Run seed'
  task :seed do
    on roles(:app) do
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:seed'
        end
      end
    end
  end
  after :publishing, :restart
  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
    end
  end
end
The following two codes are added in addition to the reference article.
Here, for symbolic links (files that you don't want to open, like setting gitignore)
# secret_base_Added to read the key
set :linked_files, %w[config/master.key]
#A file with a symbolic link.
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/settings.yml', '.env')
lib/capistrano/tasks/unicorn.rake
A file that describes the unicorn setup task.
(local)lib/capistrano/tasks/unicorn.rake
#Specify the unicorn pid file and configuration file directory
namespace :unicorn do
  task :environment do
    set :unicorn_pid,    "#{current_path}/tmp/pids/unicorn.pid"
    set :unicorn_config, "#{current_path}/config/unicorn/production.rb"
  end
  #Method to start unicorn
  def start_unicorn
    within current_path do
      execute :bundle, :exec, :unicorn, "-c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D"
    end
  end
  #Method to stop unicorn
  def stop_unicorn
    execute :kill, "-s QUIT $(< #{fetch(:unicorn_pid)})"
  end
  #Method to restart unicorn
  def reload_unicorn
    execute :kill, "-s USR2 $(< #{fetch(:unicorn_pid)})"
  end
  #Method to kill unicron
  def force_stop_unicorn
    execute :kill, "$(< #{fetch(:unicorn_pid)})"
  end
  #task to start unicorn
  desc 'Start unicorn server'
  task start: :environment do
    on roles(:app) do
      start_unicorn
    end
  end
  #task to stop unicorn
  desc 'Stop unicorn server gracefully'
  task stop: :environment do
    on roles(:app) do
      stop_unicorn
    end
  end
  #If unicorn is already running, restart it, if not, start it task
  desc 'Restart unicorn server gracefully'
  task restart: :environment do
    on roles(:app) do
      if test("[ -f #{fetch(:unicorn_pid)} ]")
        reload_unicorn
      else
        start_unicorn
      end
    end
  end
  #task to kill unicorn
  desc 'Stop unicorn server immediately'
  task force_stop: :environment do
    on roles(:app) do
      force_stop_unicorn
    end
  end
end
As I explained in Capfile, please note that it is unicorn.rake. If it is set in .rb in Capfile, it will be unicorn.rb.
config/unicorn/production.rb This is the unicorn configuration file.
(local)config/unicorn/production.rb
#Number of workers. See below
$worker = 2
#Decide how many seconds have passed before removing the worker
$timeout = 30
#Note that your application name, current, is added.
$app_dir = '/var/www//rails/golfour/current'
#Specify the port number to receive the request. See below
$listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir
#PID management file directory
$pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
#Directory of files that spit out error logs
$std_log = File.expand_path 'log/unicorn.log', $app_dir
#Defined so that what is set above is applied
worker_processes  $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen  $listen
pid $pid
#Set whether to hot deploy
preload_app true
#Define what to do before fork. See below
before_fork do |server, _worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      Process.kill 'QUIT', File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end
#Define what to do after fork. See below
after_fork do |_server, _worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
shared/config/settings.yml
(server)shared/config/settings.yml
production:
  secret_key_base: jr934ugr89vwredvu9iqfj394vj9edfjcvnxii90wefjc9weiodjsc9o i09fiodjvcijdsjcwejdsciojdsxcjdkkdsv 
(#Paste the generated random number)
shared/config/database.yml
(server)shared/config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
  <<: *default
  database: golfour_development
  username: yuki
  password: password
  host: db
  socket: /tmp/mysql.sock
test:
  <<: *default
  database: golfour_test
  username: yuki
  password: password
  host: db-test
  socket: /tmp/mysql.sock
production:
  <<: *default
  database: <%= ENV['DB_NAME'] %>
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  host: <%= ENV['DB_HOSTNAME'] %>
shared/.env
Describe the environment variables used in datacbase.yml here.
(server)shared/.env
DB_NAME=*****
DB_USERNAME=*****
DB_PASSWORD=*****
DB_HOSTNAME=*****
/etc/nginx/conf.d/app.conf
conf:(server)/etc/nginx/conf.d/app.conf
#Directory settings for various logs
  error_log  /var/www/rails/mumu/current/log/nginx.error.log;
  access_log /var/www/rails/mumu/current/log/nginx.access.log;
#Maximum capacity to receive processing
  client_max_body_size 2G;
  upstream app_server {
#Unicorn socket path to work with
    server unix:/var/www/rails/mumu/current/tmp/sockets/.unicorn.sock fail_timeout=0;
  }
  server {
    listen 80;
    server_name 127.0.0.1; #Change it to your own IP address!
#Waiting time for the next request (seconds)
    keepalive_timeout 5;
#Directory to read static files
    root /var/www/rails/mumu/current/public;
#Cache directory
    try_files $uri/index.html $uri.html $uri @app;
    location @app {
      # HTTP headers
      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;
    }
#Where to place the error page
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/rails/mumu/current/public;
    }
  }
bundle exec cap production deploy
Occurs after deploying. It was caused by insufficient memory of EC2.
console
virtual memory exhausted
This is a method of amplifying the memory so that it can be used by temporarily moving the unused memory to another location. If you refer to the following article, you can easily implement it, so please do.
reference: What is a swap file [Rails] Deploy to EC2 with Capistrano: Troubleshoot EC2 Out of Virtual Memory
Missing secret_key_base for 'production' environment
This is also an error that occurred when executing the deployment.
The cause was that the master.key file was missing. The secret_key_base can be found in the credentials.yml.enc file in the first place. However, this file was encrypted and I needed master.key to read it, but I was getting an error because I didn't have it.
・ Create shared / master.key -Added master.key to symbolic links
By doing so, the error disappeared.
Recommended Posts