いよいよ本題であるCapistranoを使用したデプロイについて解説していきます。
EC2の事前準備
最初に準備としてEC2内に必要なものをインストールしていきます。
1. rbenv, git,環境変数の設定
[sample_user@ip-10-0-0-79 ~] $ sudo yum -y install git
[sample_user@ip-10-0-0-79 ~] $ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv #rbenv
[sample_user@ip-10-0-0-79 ~] $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build #ruby-build
[sample_user@ip-10-0-0-79 ~] $ sudo vim .bash_profile
-----------------------------
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
#この2行を追加してpathを通します
-----------------------------
[sample_user@ip-10-0-0-79 ~] $source ~/.bash_profile #設定の反映
[sample_user@ip-10-0-0-79 ~] $ rbenv -v #pathが通ったかを確認
環境変数
[sample_user@ip-10-0-0-79 ~] $ sudo vim .bashrc #環境変数の設定
-------------------------------
export sample_variable="sample_sample_sample"
#アプリ内で環境変数を使用している方はここで設定
-------------------------------
[sample_user@ip-10-0-0-79 ~] $ source ~/.bashrc
#設定の反映
2. Ruby(version 2.6.3)
[sample_user@ip-10-0-0-79 ~] $ sudo yum install -y gcc
[sample_user@ip-10-0-0-79 ~] $ sudo yum install -y openssl-devel readline-devel zlib-devel
[sample_user@ip-10-0-0-79 ~] $ rbenv install 2.6.3 #ruby2.6.3をインストール
3. bundler
[sample_user@ip-10-0-0-79 ~] $ rbenv exec gem install bundler
[sample_user@ip-10-0-0-79 ~] $ rbenv rehash
4. mysql
[sample_user@ip-10-0-0-79 ~] $ sudo yum install mysql mysql-server mysql-devel
5. sqlite
[sample_user@ip-10-0-0-79 ~] $ sudo yum install sqlite-devel
6. node.js
[sample_user@ip-10-0-0-79 ~] $ sudo amazon-linux-extras install epel
デプロイ先の作成
Capistranoはgit cloneを通してコードをコピーするため、デプロイ先のディレクトリを作成します。
[sample_user@ip-10-0-0-79 ~] $ sudo mdkir /var/www
[sample_user@ip-10-0-0-79 var] $ sudo chmod 777 www
[sample_user@ip-10-0-0-79 var] $ cd www
[sample_user@ip-10-0-0-79 www] $ mkdir sample_app
[sample_user@ip-10-0-0-79 www] $ cd sample_app
[sample_user@ip-10-0-0-79 sample_app] $ rbenv local 2.6.3 #バージョンを設定
Git HubのSSh設定
前半でlocalからserverへSSH接続した時と同様に、server側からGit HubへSSH接続ができるよう設定を行います。
[sample_user@ip-10-0-0-79 ~]$ cd .ssh
[sample_user@ip-10-0-0-79 .ssh]$ ssh-keygen -t rsa
Enter file in which to save the key (/home/sample_user/.ssh/id_rsa): sample_git_rsa
#sample_git_rsaという名前で鍵を生成
[sample_user@ip-10-0-0-79 .ssh]$ ls
authorized_keys sample_git_rsa sample_git_rsa.pub
[sample_user@ip-10-0-0-79 .ssh]$ cat sample_git_rsa.pub
#中身をコピー
Settings→SSH and GPG keysでNew SSH keyでkeyを新規作成し中身を貼り付ける。
次は設定ファイルを作成。
[sample_user@ip-10-0-0-79 .ssh] $ vim config
-------------------------------------------
Host github
Hostname github.com
User git
IdentityFile ~/.ssh/sample_git_rsa (#先ほど作成した秘密鍵のpath)
-------------------------------------------
最後にserverからGitHubへSSh接続ができているかを確認
[sample_user@ip-10-0-0-79 .ssh] $ sudo chmod 600 config
[sample_user@ip-10-0-0-79 .ssh] $ ssh -T github
#成功
Permanently added the RSA host key for IP address '140.82.114.3' to the list of known hosts.
Hi ichihara-development-github! You've successfully authenticated, but GitHub does not provide shell access.
Nginx
今回はWebサーバーにnginx、アプリケーションサーバーにunicornを使用するのでEC2側でNginxの設定を行います。
Webサーバーとアプリケーションサーバーに関してはこちらの記事が参考になるため、ご一読下さい。
なぜrailsの本番環境ではUnicorn,Nginxを使うのか? ~ Rack,Unicorn,Nginxの連携について ~【Ruby On Railsでwebサービス運営】
Nginx
[sample_user@ip-10-0-0-79 ~] $ sudo yum install nginx #nginxをインストール
[sample_user@ip-10-0-0-79 ~] $ cd /etc/nginx/conf.d/
[sample_user@ip-10-0-0-79 conf.d] $ sudo vim sample_app.conf #nginxはデフォルト設定で.confファイルを読み込みます
--------------------------------------------
#以下を追加
upstream unicorn {
server unix:/tmp/unicorn.sock;
}
server {
listen 80;
server_name 〇.〇.〇.〇(Elastic IP);
access_log /var/log/nginx/sample_access.log;
error_log /var/log/nginx/sample_error.log;
#エラーログの保存先を指定
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://unicorn;
}
}
--------------------------------------------
local
それではCapistranoをlocalにインストールし、デプロイの準備を行いましょう。
#以下を追加
gem 'mysql2'
platforms :ruby do
gem 'unicorn'
end
group :development do
gem 'capistrano'
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano3-unicorn'
end
------------------------------------------
$ bundle install
$ bundle exec cap install
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified
bundle exec cap installを実行するとCapistanoの設定ファイルが自動生成されます。
1. Capfileの設定
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'
capistranoを使用できるように読み込みます。
2. config/deploy.rbの設定
lock '3.12.0'
set :application, 'sample_app'
#アプリ名を記載
set :repo_url, 'github:ichihara-development-github/sample_app.git'
#cloneを行うリモートリポジトリを記載
#ただし、configファイルでgithub.com→githubとして置き換えられているので注意
set :rbenv_type, :user
set :rbenv_ruby, '2.6.3'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all
set :log_level, :warn
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :keep_releases, 3
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"
set :unicorn_config_path, -> { File.join(current_path, "config", "unicorn.rb") }
namespace :deploy do
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
end
end
end
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
task :restart do
invoke 'unicorn:restart'
end
end
3. config/deploy/production.rbの設定
server "〇.〇.〇.〇", user: "sample_user", roles: %w{app db web}
#serverのIPと、ログイン可能なuser名を記載してください
set :ssh_options, {
keys: %w(~/.ssh/sample_app_key_rsa), #秘密キーのpathを記載
forward_agent: true,
auth_methods: %w(publickey),
port: 22
}
4. unicornの設定(local側)
config配下にunicron.rbを作成します。
APP_PATH = "#{File.dirname(__FILE__)}/.." unless defined?(APP_PATH)
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
worker_processes 3
listen "/tmp/unicorn.sock"
pid "tmp/pids/unicorn.pid"
preload_app true
timeout 60
working_directory APP_PATH
# logのpath
stderr_path "#{RAILS_ROOT}/log/unicorn_error.log"
stdout_path "#{RAILS_ROOT}/log/unicorn_access.log"
if GC.respond_to?(:copy_on_write_friendly=)
GC.copy_on_write_friendly = true
end
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = APP_PATH + "/Gemfile"
end
before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
old_pid = "#{ server.config[:pid] }.oldbin"
unless old_pid == server.pid
begin
Process.kill :QUIT, File.read(old_pid).to_i
rescue Errno::ENOENT, Errno::ESRCH
end
end
end
after_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
最後にここまでの内容をGitHubに反映しておきましょう。
$ git add .
$ git commit -m "first_commit"
$ git push origin master
デプロイ!
これでようやくデプロイに必要な設定が終了しました!
いやー長かった…
というわけで早速デプロイができる状態なのかをチェックしていきます。
$ bundle exec cap production deploy:check
すると順々に処理が走っていき、以下のようなエラーが発生すると思います。
00:10 deploy:check:linked_dirs
01 mkdir -p /var/www/sample_app/shared/log /var/www/sample…
✔ 01 sample_user@3.21.59.95 0.675s
00:10 deploy:check:make_linked_dirs
01 mkdir -p /var/www/sample_app/shared/config
✔ 01 sample_user@3.21.59.95 0.554s
00:12 deploy:check:linked_files
ERROR linked file /var/www/sample_app/shared/config/databa…
これは/sample_app/shared/config配下にdatabase.ymlが存在しませんというエラーです。
実はCapistranoのdeployコマンドを実行するとサーバー側のディレクトリの構造が少しだけ変化し、新たにsharedというディレクトリが生成されます。
[sample_user@ip-10-0-0-79 sample_app] $ ls
releases shared
そのためshared配下にdatabase.ymlを作成、編集していきます。
[sample_user@ip-10-0-0-79 config] $ vim database.yml
-----------------------------------
default: &default
adapter: sqlite3
pool: 5
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: db/test.sqlite3
production:
adapter: mysql2
pool: 5
database: sample_app_db #RDSに設定したデータベース名
host: database-1.ckbaeqyxwuvr.us-east-2.rds.amazonaws.com #エンドポイント
username: sample_user #RDSに設定したuser名
password: password #RDSに設定したパスワード
-----------------------------------
localにあるdatabase.ymlにproduction環境のみ変更を加えました。
新たにRDSの情報を記載することで、RDSをデータベースとして使用することが可能です。さらにこちらの内容をlocalにもコピーしておきましょう。
この状態でdeploy:checkを実行すると、同様にsecrets.ymlがないといったエラーも発生してしますので、事前に作成します。
[sample_user@ip-10-0-0-79 config] $ vim secrets.yml
-------------------------------------------------
development:
secret_key_base: bf8daa05189f332e986f7fcb26bbb25c9c34da0257b9994931dd0f5265e325f3a84c9630b1e264b96c8e28276ab7bc41a9c6761b8b2befeb1bd53bbcb53afb59
test:
secret_key_base: 0c1f0d49d25f201c31378d38eb12cf87f4684f321ed0f2b1b66f704c6daf77690f487c77ab6347d1ddf5bfc3c258048be5ca34e406c0d4de34599305623f699d
# Do not keep production secrets in the unencrypted secrets file.
# Instead, either read values from the environment.
# Or, use `bin/rails secrets:setup` to configure encrypted secrets
# and move the `production:` environment over there.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
-------------------------------------------------
これでlocalに戻り、もう一度deploy:checkを実行すると、今度はエラーがなく処理が終わるはずです。以下のコマンドで本デプロイを行って下さい。
$ bundle exec cap production deploy
以下のようにエラーが出なればデプロイ完了です。
01:27 deploy:cleanup
Keeping 3 of 33 deployed releases on 3.21.59.95
01 rm -rf /var/www/sample_app/releases/20200227082245 /var/www/sample_app/releases/20200227082547 /var/www/ …
✔ 01 sample_user@3.21.59.95 0.899s
01:31 deploy:log_revision
01 echo "Branch master (at 803b41a3fe36f77c2682d9f740f4dbd45047b08d) deployed as release 20200228055144 by …
✔ 01 sample_user@3.21.59.95 0.826s
そして最後の仕上げにsecret_key_baseを生成してsecrets.ymlに張り付けましょう。
デプロイ自体にエラーは出ていませんが実はこの状態でアクセスしてもページが表示されません。
そのためunicornのエラーログを確認してみると…
[sample_user@ip-10-0-0-79 ~] $ cat /var/www/sample_app/current/log/unicorn_error.log
I, [2020-02-28T05:52:58.354411 #23838] INFO -- : worker=2 ready
I, [2020-02-28T05:52:58.420071 #23777] INFO -- : reaped #<Process::Status: pid 23780 exit 0> worker=0
I, [2020-02-28T05:52:58.420171 #23777] INFO -- : reaped #<Process::Status: pid 23781 exit 0> worker=1
I, [2020-02-28T05:52:58.420211 #23777] INFO -- : reaped #<Process::Status: pid 23782 exit 0> worker=2
I, [2020-02-28T05:52:58.420260 #23777] INFO -- : master complete
E, [2020-02-28T06:05:54.876223 #23838] ERROR -- : app error: Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml` (RuntimeError)
とsecret_key_baseがないとのエラーが発生しているのが分かります。
(currentディレクトリはCapistranoのデプロイによってデプロイ先の配下に新しく生成されるディレクトリで、ここにGitt Hubからコードがcloneされます。)
なので
[sample_user@ip-10-0-0-79 ~] $ cd /var/www/sample_app
[sample_user@ip-10-0-0-79 current] $ bundle exec rake secret
81734ede2dfc8644523baabe7b8614081c53c43580feb5f9f23140d946040d22dfe2324756eedd7d103057718fc28587e7b57619f7eb077f57054a
[sample_user@ip-10-0-0-79 current] $ vim secrets.yml
----------------------------------------------
# Do not keep production secrets in the unencrypted secrets file.
# Instead, either read values from the environment.
# Or, use `bin/rails secrets:setup` to configure encrypted secrets
# and move the `production:` environment over there.
production:
secret_key_base: 81734ede2dfc8644523baabe7b8614081c53c43580feb5f9f23140d946040d22dfe2324756eedd7d103057718fc28587e7b57619f7eb077f57054a
----------------------------------------------
[sample_user@ip-10-0-0-79 ~] $ exit
#local
$ bundle exec cap production deploy
# 再度デプロイ
一度デプロイが成功すると後は変更があった時に
git push → cap production deploy を実行するだけでデプロイ先に内容が反映されるのでデプロイ作業が大幅に楽になります。
それではサーバーにアクセスしてみて、作ったAPPが存在するかを確認してみてください。
あったぁ!
日本語登録も大丈夫です。
まとめ
初めてAWSを利用したサーバー構築と自動デプロイを行ったのですが結構つまづくポイントが多く時間を費やしてしまったため、これを機にAWSやサーバー、データベースといったWebの基礎をもう一度学び直そうと思います。
長くなってしましましたがお読みいただきありがとうございました。
参考記事
こちらの記事を参考にデプロイと記事を書かせていただきました。ありがとうございました。