カテゴリー: BackEnd

Capistrano3でRailsアプリケーションをデプロイする

はじめに

最近、現在開発中のアプリケーションのステージング環境の構築を行なっています。
それにあたり、初めてCapistranoの設定を行いましたので、ここに設定した内容をまとめます。

注意点としては、DBスキーマの管理にMigrationではなくridgepoleというGemを利用しています。
興味がある方はこちらの記事をご覧ください。

また、OctopusというGemを利用しています。
https://github.com/thiagopradi/octopus

前提条件

ruby 2.4.1
rails 5.1.0
capistrano 3.8.1
unicorn 5.3.0
ar-octops (GitHubからインストール)
ridgepole 0.6.5

 

Cpistranoについて

Capistranoはデプロイを自動化するフレームワークです。
Railsのほか、JavaやPHPで書かれたアプリケーションのデプロイにも使われます。
https://github.com/capistrano/capistrano

 

導入

Gemのインストール

Gemfileに下記のgemを追加してbundle installします。

gem 'dotenv-rails' #環境変数を簡単に扱える
group :development, :test do
  gem 'capistrano'
  gem 'capistrano-rails'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano3-ridgepole' # Capistranoでridgepoleを扱う
  gem 'capistrano3-unicorn' # Unicornの起動を簡単に行える
end

設定ファイルの準備

下記のコマンドを実行してCapistranoの設定ファイルを作成します。

$ bundle exec cap install

 

このコマンドを実行すると、下記の通り設定ファイルが作成されます。

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks

 

デプロイ設定

Capfileを修正する

生成されたCapfileを下記の通り修正します。

# Load DSL and set up stages
require 'capistrano/setup'

# Include default deployment tasks
require 'capistrano/deploy'
require 'capistrano/rbenv'

set :rbenv_type, :my_app_name
set :rbenv_ruby, '2.4.1'

require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'

# ridgepoleの動作に必要
require 'capistrano3/ridgepole'

# unicornの起動を簡単に行える
require 'capistrano3/unicorn'

# リポジトリにGitを利用する
require 'capistrano/scm/git'
install_plugin Capistrano::SCM::Git

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

各環境で共通のデプロイ設定を記述する

共通の設定はdeploy.rbに記述します。

# config valid only for current version of Capistrano
lock '3.8.1'

set :application, 'my-app-name'
set :repo_url, 'git@github.com:aaaa/my-app-name.git'

# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, '/home/engines/www/my-app-name'

# You can configure the Airbrussh format using :format_options.
# These are the defaults.
# set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto
set :format, :pretty
set :log_level, :debug

# Default value for :pty is false
set :pty, true

# Default value for linked_dirs is []
# append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets vendor/bundle}
set :unicorn_pid, "#{shared_path}/tmp/pids/unicorn.pid"

# ridgepole関連の設定
set :ridgepole_roles, :db
set :ridgepole_schema_file, File.join(current_path, 'db/schemas', 'Schemafile')
set :ridgepole_config_file, File.join(current_path, 'config', 'database.yml')

# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

# Default value for keep_releases is 5
set :keep_releases, 3

# rbenvをシステムにインストールしたか? or ユーザーローカルにインストールしたか?
set :rbenv_type, :user # :system or :user
# rubyのversion
set :rbenv_ruby, '2.4.1'
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 # default value

# bundle installの並列実行数
set :bundle_jobs, 4

# ridgepole関連のタスク
after 'deploy:publishing', 'deploy:restart'
after 'deploy:publishing', 'ridgepole:ridgepole_apply'
namespace :ridgepole do
  desc 'ridgepole apply'
  task :ridgepole_apply do
    invoke 'ridgepole:apply'
  end
end

#octopus関連のタスク
namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app) do
      if fetch(:stage).to_sym == :staging
        execute "cd #{current_path}/config; mv staging_shards.yml shards.yml"
      else
        execute "cd #{current_path}/config; mv production_shards.yml shards.yml"
      end
    end
    invoke 'unicorn:restart'
  end
end

環境ごとのデプロイ設定を記述する

今回は開発環境の構築ですので、staging.rbを修正します。

set :stage, :staging
set :rails_env, 'staging'
set :ridgepole_env, fetch(:rails_env)
set :unicorn_rack_env, 'deployment'

set :branch, ENV['BRANCH_NAME'] || 'develop'

set :migration_role, 'db'

# xxx.xxx.xxx.xxx: サーバのIPアドレス
# yyyy: 実行する際のユーザ
server 'xxx.xxx.xxx.xxx', user: 'yyyy', roles: %w{web app db}

# sshでログインする際の設定
# config/deploy/staging_deploy.keyでログインする
set :ssh_options, {
    keys: ["#{File.dirname(__FILE__)}/../deploy/staging_deploy.key"],
    forward_agent: false,
    auth_methods: %w(publickey)
}

Unicornの設定

下記の通り、config/unicorn/staging.rbを作成します。

app_path = '/home/engines/www/my-app-name'

worker_processes 2
working_directory "#{app_path}/current"

# This loads the application in the master process before forking
# worker processes
# Read more about it here:
# http://unicorn.bogomips.org/Unicorn/Configurator.html
preload_app true

timeout 30

# This is where we specify the socket.
# We will point the upstream Nginx module to this socket later on
#listen "#{app_path}/tmp/sockets/unicorn.sock", :backlog => 64
listen '/tmp/unicorn.sock', :backlog => 64

pid "#{app_path}/shared/tmp/pids/unicorn.pid"

# Set the path of the log files inside the log folder of the testapp
stderr_path "#{app_path}/current/log/unicorn.stderr.log"

before_exec do |server|
  ENV['BUNDLE_GEMFILE'] = "#{app_path}/current/Gemfile"
end

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
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end

  sleep 1
end

after_fork do |server, worker|
  # https://github.com/thiagopradi/octopus/issues/59(octopus + unicorn)
  defined?(ActiveRecord::Base) and
      ActiveRecord::Base.connection_proxy.instance_variable_get(:@shards).each {|k,v| v.clear_reloadable_connections! }
end

 

実行

ターミナルで下記のコマンドを実行します。

$ bundle exec cap staging deploy

 

さいごに

ステージング環境の構築にあたり、Capistranoによるデプロイの設定をまとめました。

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: RubyRails

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

4週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前