Less is Best

rubyが好き。技術の話とスタートアップに興味があります。

Capistrano3で快適デプロイ生活!!

Capistrano3で快適なデプロイ生活を目指しています。Railsで定数設定ファイルをgitから外して管理する方法。と組あわせれば、最高なデプロイ生活が待っていること間違い無しです。

が、Capistrano3のまとまった情報があまり手に入らず(Capistrano2とどっちかよくわからんし)、導入の際にかなり苦労したので、インストールから設定までをさらしておきます。

環境: Ruby 2.0.0-p247 Rails 4.0.0 Apache Passenger

Server:CentOS6.4 公開鍵認証設定済み

Capistranoとは

Rubyでできたソフトウェアデプロイメントツールです。 Capistranoは分散環境へのウェブアプリケーションのソフトウェアデプロイメントを簡素化および自動化するために設計されています。 アプリのデプロイの際に生じるいろいろな作業をコマンドで自動化することで、ミスを無くしたり、楽をしたりするためのツールです。

今回は分散環境ではないですが、勉強のため使って行きたいと思います。

公式サイト

github:capistrano / capistrano

Capistranoでデプロイしたアプリのディレクトリ構造は以下のようになっている。 shared以下のファイルからcurrentディレクトリに、linked_files,linked_dirsで指定した通りにシンボリックリンクが張られている。基本的にバージョン管理すると都合の悪いものをsharedにいれて運用するようです。 またディレクトリ構造から考えられる通り、過去のリリースに戻ることも可能です。(cap deploy:rollback) 詳細コマンドは cap -Tで確認してください。

    ├── current  #現在起動しているアプリケーションのディレクトリ
    │ └── app      #現在のアプリ
    ├── releases
    │   ├── app_02  #1つ前のアプリ
    │   └── app_01  #2つ前のアプリ
    ├── repo
    └── shared

サーバーの設定

何をすれば良いかというと、デプロイ用のユーザー作成 デプロイ用ユーザーに公開鍵でアクセス出来るようにする

ということを行います。 今回、こちらの設定は済んでいたので省略させて頂きます(スイマセン)

詳細:公式HP

Dotinstall:#5 作業用ユーザーを設定しよう

Dotinstall:#6 鍵認証を設定しよう (1)

こちらを見れば、だいたいどんなことをしなければいけないかわかると思います。

ローカルでの設定

設定ファイルをgit管理化から外しておきます

cp config/database.yml{,.example}
echo config/database.yml >> .gitignore

cd rails_dir
vim Gemfile 

Gemfile

    gem 'capistrano'
    gem 'capistrano-rails'
    gem 'capistrano-bundler'
    gem 'capistrano-rbenv'

インストール

bundle install
bundle exec cap install


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

詳しい図はこちらにCapistrano Version 3

まずはCapfileの編集

Capfile

    # Load DSL and Setup Up Stages
    require 'capistrano/setup'
    
    # Includes default deployment tasks
    require 'capistrano/deploy'
    
    # Includes tasks from other gems included in your Gemfile
    #
    # For documentation on these, see for example:
    #
    #   https://github.com/capistrano/rvm
    #   https://github.com/capistrano/rbenv
    #   https://github.com/capistrano/chruby
    #   https://github.com/capistrano/bundler
    #   https://github.com/capistrano/rails/tree/master/assets
    #   https://github.com/capistrano/rails/tree/master/migrations
    #
    
    # rbenvを使用しているので or 'capistrano/rvm'
    require 'capistrano/rbenv'
    
    #rbenvをシステムにインストールした or ユーザーローカルにインストールした
    set :rbenv_type, :user  # :user or :system
    # rubyのversion
    set :rbenv_ruby, '2.0.0-p247'
    
    # Rails,bundlerをデプロイするので必須
    require 'capistrano/bundler'
    require 'capistrano/rails'
    
    # Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
    Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

つづいてデプロイ先のサーバーの設定。 今回はweb,app,dbすべて1つのサーバーに詰め込みます。

config/deploy/production.rb

    set :stage, :production
    
    
    #サーバーのロールを指定.ついでにユーザーも指定しています。
    role :app, %w{deploy@yoshiso.net}
    role :web, %w{deploy@yoshiso.net}
    role :db,  %w{deploy@yoshiso.net}
    
    
    # you can set custom ssh options
    # it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options
    # you can see them in [net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start)
    # set it globally
    #> サーバーにアクセスするためのsshkeyを指定する.
    #> サーバーから直接githubのプライベートリポジトリにアクセスするためにforward_agentをtrueにしておく。
    set :ssh_options, {
      keys: [File.expand_path('~/.ssh/id_rsa')],
      forward_agent: true
    }
    
    #> サーバー個別の設定が多い場合は下記の方がいいかも。
    # and/or per server
    # server 'example.com',
    #   user: 'user_name',
    #   roles: %w{web app},
    #   ssh_options: {
    #     user: 'user_name', # overrides user setting above
    #     keys: %w(/home/user_name/.ssh/id_rsa),
    #     forward_agent: false,
    #     auth_methods: %w(publickey password)
    #     # password: 'please use keys'
    #   }
    # setting per server overrides global ssh_options
    
    #fetch(:default_env).merge!(rails_env: :production)

そして最後にデプロイ用のタスクを作ります。 Rails用のタスクに関してはcapistrano-railsが行っていてくれるので、その補完を行うタスクを作っていきます。

config/deploy.rb

    set :application, '<app_name>'
    #=> アプリケーション名
    
    set :repo_url, 'git@github.com:<username>/<repos_name>.git'
    #=> githubのurl。プロジェクトのgitホスティング先を指定する
    
    #ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }
    set :branch, 'master'
    #> デプロイするのはマスターブランチに固定
    
    set :deploy_to, '/var/www/<app_name>'
    #> デプロイ先のサーバーのディレクトリ。フルパスで指定した。
    
    set :scm, :git
    #> Version管理はgitですよ、と
    
    set :format, :pretty
    set :log_level, :debug # :info or :debug
    #> ログはたくさん見れるようにしておきます。
    
    # set :pty, true
    
    set :linked_files, %w{config/database.yml}
    #> デプロイ先のサーバーの :deploy_to/shared/config/database.yml のシンボリックリンクを
    #  :deploy_to/current/config/database.yml にはる。
    # 先にshared以下にファイルをアップロードする必要あり
    # 説明下記に
    
    set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/assets}
    #>同じくsharedに上記のディレクトリを生成し、currentにシンボリックリンクを張る
    
    
    # set :default_env, { path: "/opt/ruby/bin:$PATH" }
    
    set :keep_releases, 5
    #> 5リリース分保持しておく。
    
    namespace :deploy do
    
      #>アプリの再起動を行うタスク
      desc 'Restart application'
      task :restart do
        on roles(:app), in: :sequence, wait: 5 do
          execute :mkdir, '-p', release_path.join('tmp')
          execute :touch, release_path.join('tmp/restart.txt')
        end
      end
    
       #> 上記linked_filesで使用するファイルをアップロードするタスク 
       #  deployが行われる前に実行する必要がある。
      desc 'upload importabt files'
      task :upload do
        on roles(:app) do |host|
          upload!('config/database.yml',"#{shared_path}/config/database.yml")
        end
      end
    
      #> webサーバー再起動時にキャッシュを削除する
      after :restart, :clear_cache do
        on roles(:web), in: :groups, limit: 3, wait: 10 do
          # Here we can do anything such as:
          within release_path do
            execute :rmdir, '-rf', release_path.join('tmp/cache')
          end
        end
      end
    
      #> Flowのbefore,afterのタイミングで上記タスクを実行する.
      # 詳細のhookタイミングはここでcheck:http://www.capistranorb.com/documentation/getting-started/flow/
      before :started, 'deploy:upload'
    
      after :finishing, 'deploy:cleanup'
    
    end
    
    #> dbサーバーのデータベースを生成するタスク。
    #> デプロイ前に実行する必要がある。
    task :db_create do
      on roles(:db) do |host|
        q1 = 'CREATE DATABASE IF NOT EXISTS <app_name>;'
        q2 = 'GRANT ALL ON <app_name>.* TO <app_user>@localhost IDENTIFIED BY "<app_passsword>";'
        q3 = "FLUSH PRIVILEGES;"
        sql = "#{q1}#{q2}#{q3}"
        execute "mysql --user=<mysql_user> --password=<msql_password> -e '#{sql}' "
      end
    end

これで準備は完了。

タスクの実行

あとはタスクを実行するだけです。

bundle exec cap produciton db_create
bundle exec cap production deploy:update
bundle exec cap production deploy

以上でデプロイ完了! 自分はApache Passengerの環境が構築してあったので、virtualhostの設定を書いてあげれば、公開完了です。

参考文献

Capistrano3についてまとまっている順に

公式サイト

Upgrade to Capistrano 3.0

Capistrano 3への手引き

github:capistrano / capistrano

Capistrano Version 3

upload!メソッドについて