見出し画像

Capistrano

自動デプロイツールの一種。デプロイ時に必要なコマンドが1回で済む。
手動デプロイ時に起こるコマンドの打ち間違い、手順間違いを解消。

Gemfile を編集

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

# Gemfileを読み込み、インストール
$ bundle install
$ bundle exec cap install

生成されたファイルの説明

Capfile
capistrano全体の設定ファイル。
Capistranoの機能を提供するコードは複数のライブラリ(Gem)に分かれるCapistranoを動かすにはいくつかのライブラリを読み込む必要がある。Capfileは、関連ライブラリのどれを読み込むかを指定できる。
デプロイについての設定を書くファイル。

deploy.rb ・ production.rb ・ staging.rb
Githubへの接続に必要なsshキーの指定、デプロイ先のサーバのドメイン、AWSサーバへのログインユーザー名、サーバにログインしてからデプロイのために何をするか、といった設定を記載する。

Capfile を編集

# requireで引数としておかれた文字列が指すディレクトリが読み込まれ、デプロイに必要な動作を記述。
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 }

デプロイの設定ファイルを編集

cap installコマンド
config/deploy下に production.rb と staging.rb の2種類のファイルを生成。
デプロイする環境別の設定を記述するファイル。
今回はproduction(本番環境のものだけ)を編集。
①サーバーホスト名
②AWSサーバーへのログインユーザー名
③サーバーロール
④SSHの設定
⑤その他サーバーに紐づく任意の設定

config/deploy/production.rb を編集

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

deploy.rb
production環境、staging環境どちらにも当てはまる設定を記述。
①アプリケーション名
②gitのレポジトリ
③利用するSCM
④タスクとそれぞれのタスクで実行するコマンド

config/deploy.rb を編集


# config valid only for current version of Capistrano
# capistranoのバージョンを記載。固定のバージョンを利用し、バージョン変更によるトラブルを防止。
lock '<Capistranoのバージョン>'

# Capistranoのログの表示に利用。
set :application, '<アプリケーション名>'

# どのリポジトリからアプリを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のバージョン>'

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

# PIDを記載したファイルの場所。
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っっj
gemfile.lock でCapistranoのバージョンを確認

capistrano (3.11.0)

DSL

特定の処理で効率をあげるために特化した形の文法を擬似的に用意した
プログラム。上記の(set :名前, 値)は言わば変数のようなもの。
例: set: Name, 'value' と定義した場合、fetch Name とすることで 'Value'が取り出せます。一度setした値はdeploy.rbやproduction.rbなどの
全域で取り出せる。ファイル内には、desc '◯◯'やtask:XX doといった記述が見受けられます。先ほどCapfileでrequireしたものに加えて追加のタスクを記述している形です。ここで記述したものもcap deploy時に実行される。

Capistranoによる自動デプロイ後のディレクトリ構成

一度Capistranoによる自動デプロイを実行すると、本番環境のアプリケーションのディレクトリが変化します。アプリのバックアップなど、複数のディレクトリが作成される。特に重要なのが、releases、current、sharedです。

・releasesディレクトリ

capistranoを通じてデプロイされたアプリは、releasesというフォルダに纏められる。ここに過去のアプリが残っていることにより、デプロイ時に問題が発生しても一つ前のバージョンに戻ることができます。
その過去の保存数を指定しているのがdeploy.rbの set :keep_releases
の記述です。今回は5つ、過去のバージョンを保存するよう設定しました。

・currentディレクトリ
releasesフォルダの中で一番新しいものが、自動的にcurrentフォルダ内に
コピーされているような状態になります。
current内に入っているアプリ内容が、現在デプロイされている内容になる。

・sharedディレクトリ
バージョンが変わっても共通で参照されるディレクトリが格納される。
具体的に、log、public、tmp、vendor ディレクトリが格納される。

手動でのUnicorn起動に比べ、Capistranoを使った場合は、Railsのアプリケーションのディレクトリが1段階深くなるので、数カ所変更を加えます。
capistranoでのデプロイ後は、アプリケーションのディレクトリ直下にあるcurrentディレクトリが動く。app_pathのディレクトリ指定も一段階追加。
また、実際に動くディレクトリであるworking_directoryの指定をcurrent
にしたり、ログやpidの指定をshared以下にするなどの変更を加えます。

config/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の設定ファイル

これまで /var/www/ 以下のアプリケーションに対して連携を設定していたので、/var/www/〇〇 以下のcurrent、sharedなどのディレクトリと連携するように設定を変更。

ターミナル(EC2サーバ)

$ sudo vim /etc/nginx/conf.d/rails.conf
rails.conf を編集

upstream app_server {
 # sharedの中を参照するよう変更
 server unix:/var/www/<アプリケーション名>/shared/tmp/sockets/unicorn.sock;
}

server {
 listen 80;
 server_name <Elastic IP>;

# アップロードされるファイルの容量上限を2ギガに設定。デフォルトは1メガ。
 client_max_body_size 2g;

 # currentの中を参照するよう変更
 root /var/www/<アプリケーション名>/current/public;

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

# 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-user@ip-172-31-25-189 ~]$ sudo service mysqld restart

# PID確認
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

# プロセスをkill
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <PID>

全てmasterにpush!!

自動デプロイ

ターミナル(ローカルPC)

$ bundle exec cap production deploy​

エラーが出た場合

・再度同じコマンドを実行
 bundle install の際、初めて自動デプロイを実行する場合はメモリ不足で
 落ちることがあります。
・記述ミスを確認
・bundle installなどのコマンド実行を確認

・Elastic IPでアクセス :3000 は付けない。

エラーが出る時

・ローカル側(localhost3000)にエラーが出ないか確認。
・サーバー側で /var/www/<レポジトリ名>/current/log/unicorn.stderr.log
 をless か cat コマンドでエラーを確認。
 (下に行くほど最新のログ。時刻表記がUTCであることに注意。)
・ローカルでの編集でpushやpullを実行しているか確認。
・EC2インスタンス、mysql、nginxの再起動。

アプリケーション更新

①アプリをローカルで更新し、リモートリポジトリにプッシュ。
②ローカルのプロジェクトのディレクトリで
bundle exec cap production deploy を実行。

次はS3の準備です!!

この記事が気に入ったらサポートをしてみませんか?