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