Help us understand the problem. What is going on with this article?

capistranoとは?からインストール、自動デプロイまで(rails)【AWSを無料で独学勉強】

自動でデプロイさせて負担を軽減する

デプロイの作業は非常に手間です。
いちいちその作業をすれば、随分な時間が取られてしまいます。
煩わしいので、自動化させましょう

これまでのデプロイまでの流れを振り返る

ここまでデプロイするための作業をしましたが、簡単に流れを振り返りましょう
1. git push
2. git pull
3. SSH接続
4. アセットコンパイル
5. Unicorn再起動

この一連の流れをすれば、デプロイが完了されます。
なお、この一連の流れをまだしたことがない、自信がないという人は
詳しく解説している下記の記事を閲覧してください。

EC2インスタンスを立ち上げるまでの記事はシリーズ化しているので、こちらをどうぞ
独学ではじめてAWSのEC2にデプロイする方法①~⑩(インスタンスの作成)

capistranoとは

この一連のデプロイ作業を自動化させる、様々のツールの一つにcapistranoがあります。
capistranoを利用することでサーバーにログインしなくても"" コマンド一つで ””デプロイできちゃうのですから、非常に楽です。

一度Capistranoにデプロイが成功すれば、簡略してエラーなしにデプロイができます。

Capistranoの導入

Gemのインストール

ローカルのwebappにCapistranoのgemを追加しましょう

Gemfile(ローカル)
group :development, :test do
  gem 'capistrano'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-unicorn'
end

続いて、インストールします

$ bundle install

gemがインストールできたところで、Capistranoの下記のコマンドを実施

$ bundle exec cap install

するとファイルが作成されます。

railsルート
├─  Capfile
├─  config
│ ├─  deploy
│ │ ├─production.rb
│ │ └─staging.rb
│ └─deploy.rb
└─  lib
    └─capistrano
        └─tasks

これらのファイル説明は作業しながら学びましょう

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 }

production.rbを編集

production.rbですが2つファイルがあります

❌ config/environment/production.rb
⭕️ config/deploy/production.rb

今回作業はするのはconfig/deploy/production.rbです
実際に開くと下記の画面が出ます。
スクリーンショット 2020-01-19 23.44.01.png

このファイルを下記に編集しましょう!

config/deploy/production.rb
server '18.○○○.○○.○○○(Elastic IP)', user: 'ec2-user', roles: %w{app db web}

deploy.rbを編集

config/deploy.rbを開くと下記の画面が出ます
スクリーンショット 2020-01-19 23.54.26.png

deploy.rbの記述をすべて削除
スクリーンショット 2020-01-19 23.55.21.png

下記を追加します

config/deploy.rb
# config valid only for current version of Capistrano
# capistranoのバージョンを記載。固定のバージョンを利用し続け、バージョン変更によるトラブルを防止する
lock '○.○○.○(Capistranoのバージョン)'

# Capistranoのログの表示に利用する
set :application, '○○○(自身のアプリケーション名)'
set :deploy_to, '/var/○○○(アプリを入れているディレクトリ)/○○○(アプリ名)'

# どのリポジトリからアプリをpullするかを指定する
set :repo_url,  'git@github.com:○○○(Githubのユーザー名)/○○○(レポジトリ名.git'

# バージョンが変わっても共通で参照するディレクトリを指定
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, '○.○.○(rubyのバージョン)' #カリキュラム通りに進めた場合、2.5.1か2.3.1です

# どの公開鍵を利用してデプロイするか
set :ssh_options, auth_methods: ['publickey'],
                  keys: ['~/.ssh/○○○○○.pem(ローカルPCのEC2インスタンスのSSH鍵(pem)へのパス 例:~/.ssh/key_pem.pem))'] 

# プロセス番号を記載したファイルの場所
set :unicorn_pid, -> { "#{shared_path}/tmp/pids/unicorn.pid" }

# Unicornの設定ファイルの場所
set :unicorn_config_path, -> { "#{current_path}/config/unicorn.rb" }
set :keep_releases, 5

# デプロイ処理が終わった後、Unicornを再起動するための記述
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:restart'
  end
end

貼り付けたテンプレートの一部を修正しましょう

config/deploy.rb
lock '<Capistranoのバージョン>'

Capistranoのバージョンを確認するために、Gemfile.lockを開きましょう

Gemfile.lock
    capistrano (3.11.1)
      airbrussh (>= 1.0.0)
      i18n
      rake (>= 10.0.0)
      sshkit (>= 1.9.0)

これでCapistranoのバージョンが(3.11.1)とわかりました。
ではdeploy.rbを修正しましょう

config/deploy.rb
lock '3.11.1'

rubyのバージョン確認

set :rbenv_ruby, '○.○.○(rubyのバージョン)'

ターミナルで下記を実行しましょう

$ ruby -v

> ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]

○○○のところは、アプリ名などを入れる必要があるので、穴埋めしてください

deproy.rb
set :application, '○○○(自身のアプリケーション名)'
set :repo_url,  'git@github.com:○○○(Githubのユーザー名)/○○○(レポジトリ名.git'
keys: ['~/.ssh/○○○○○.pem(ローカルPCのEC2インスタンスのSSH鍵(pem)へのパス 例:~/.ssh/key_pem.pem))'] 

unicorn.rbを編集

unicorn.rb
app_path = File.expand_path('../../', __FILE__)

worker_processes 1

working_directory app_path
pid "#{app_path}/tmp/pids/unicorn.pid"
listen "#{app_path}/tmp/sockets/unicorn.sock"
stderr_path "#{app_path}/log/unicorn.stderr.log"
stdout_path "#{app_path}/log/unicorn.stdout.log"

上記のunicorn.rbの記述を下記に変更

unicorn.rb
# ../が一つ増えている
app_path = File.expand_path('../../../', __FILE__)

worker_processes 1
# currentを指定
working_directory "#{app_path}/current"

# それぞれ、sharedの中を参照するよう変更
listen "#{app_path}/shared/tmp/sockets/unicorn.sock"
pid "#{app_path}/shared/tmp/pids/unicorn.pid"
stderr_path "#{app_path}/shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/shared/log/unicorn.stdout.log"

Nginxの設定ファイルを編集

ターミナル(EC2)
$ sudo vim /etc/nginx/conf.d/rails.conf

するとrails.confが表示されるので、一旦すべて削除します

rails.conf
upstream app_server {
  server unix:/var/○○○(ディレクトリ)/○○○(アプリケーション名)/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name 18.○○.○○○.○○(Elastic IP);

  root /var/○○○(ディレクトリ/○○○○○○(アプリケーション名)/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control 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;
}

そして、下記にを貼り付けて〇〇〇〇を埋めてください

rails.conf
upstream app_server {
  # sharedの中を参照するよう変更
  server unix:/var/○○○(アプリをまとめているディレクトリ)/○○○○○(アプリケーション名)/shared/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name 18.○○○.○○(Elastic IP;

  # currentの中を参照するよう変更
  root /var/○○○(アプリをまとめているディレクトリ)/○○○○○(アプリケーション名)/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    # currentの中を参照するよう変更
    root   /var/○○○/○○○○○○(アプリケーション名)/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;
}

Nginxの設定を変更したら、忘れずに再読込・再起動

[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx reload
[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx restart

MySQLの起動を確認

ターミナル(EC2)
[ec2-user@ip-172-31-25-189 ~]$ sudo service mysqld restart

unicornのプロセスをkillしよう

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ 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

一番上のunicorn_rails masterをkillしたいので、下記を実施

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill 17877

ローカルでの修正を全てmasterにpushしてください

自動デプロイの実施

# アプリケーションのディレクトリで実行する
$ bundle exec cap production deploy

すると下記ん画像のように、徐々に処理が進み出す。
Image from Gyazo

エラーが発生する場合

ディレクトリ `/var/www' を作成できません: 許可がありません

Image from Gyazo

mkdir stdout: Nothing written
mkdir stderr: mkdir: ディレクトリ `/var/www' を作成できません: 許可がありません
mkdir: ディレクトリ `/var/www' を作成できません: 許可がありません

ヒヤリング:手動デプロイはできていたか?
・YES:Capistranoの設定の問題(ここまで進めている以上、できているはず)
・NO:もう一度手動デプロイを確認する必要があるかもしれません。

設定の見直し

rails.confとdeploy.rbのパスの確認をしてください。

var/www/アプリ名で設定しているか?
・ディレクトリはwwwの場合、入力間違いがないか???
・ディレクトリは"wwwでない"場合、capistranoのデフォルト設定を変更する必要がある。
EC2でのアプリの保存場所が『 var/www/アプリ名 』でない場合、、

[参考](https://capistranorb.com/documentation/getting-started/configuration/)

deplory.rbに下記を追加してください。

deploy.rb
set :deploy_to, '/var/○○○/アプリ名'

capistranoのデフォルト設定では、/var/www/アプリ名が設定されているため、これを変更する必要がある。
そのオプション設定がset :deploy_to, '/var/○○○/アプリ名'である。

Master.keyがないエラー( Missing encryption key to decrypt file with. Ask your team for your master key and write it to )

このエラーが表示されたということは、『 本番環境にあるmaster.keyをうまく読み込めていない 』ことを意味します。

rake stdout: Nothing written
rake stderr: Missing encryption key to decrypt file with. Ask your team for your master key and write it to /var/○○○(アプリを格納しているディレクトリ名)/○○○(アプリ名)/releases/20200121124714/config/master.key or put it in the ENV['RAILS_MASTER_KEY'].

なので現状として可能性は二つです。

  • master.keyを作成していない。
  • master.keyを作成する場所が間違っている。

ここまで作業を進めている人は,master.keyを作成しているはずです。
>つまり、master.keyの作成場所をまちがている可能性が高いです。

# 誤解が生まれやすいmaster.keyの作成場所

✖︎ アプリ名>config>master.key
○ アプリ名>shared>config>master.key

おそらく、上記のようにmaster.keyの作成場所に誤りがある可能性が高いです。
ですから、

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ cd shared 
[ec2-user@ip-172-31-23-189 shared ]$ cd config
[ec2-user@ip-172-31-23-189 config ]$ ls
>ここでmaster.keyがない場合、 master.keyを作成してください。

master.keyを作成する場合、、、

ターミナル(ローカル)
アプリ名 $ vi config/master.key
>master.keyを中身がわかります。
>間違っても編集しないようにしましょう

ローカル環境のmaster.keyをコピーしたら、EC2にmaster.keyを作成しましょう

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ cd shared/config
[ec2-user@ip-172-31-23-189 config ]$ vi master.key
>編集画面が出るので
>ローカルのmaster.keyをコピペします。
>:wpで保存しましょう

master.keyを読み込ませるために、deploy.rbに
下記を追加してください

deploy.rb
set :linked_files, fetch(:linked_files, []).push("config/master.key")

再度自動デプロイしましょう

# アプリケーションのディレクトリで実行する
$ bundle exec cap production deploy

今度はうまくいくはずです。

参考:Rails5.2から追加された credentials.yml.enc のキホン

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした