モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

目次目次を開く/閉じる

Capistrano 3 で複数のサーバーを同時に SSH 経由で操作する

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2016/07/03
最終更新最終更新
2018/10/09
記事区分記事区分
一般公開

目次

    3Dモデリングとゲームエンジンに興味があります。Blenderも活用!

    Capistrano は複数のサーバーに ssh して何らかの処理を実行するための汎用ツールです。Rails のデプロイに関しては Capistrano の設定が gem で提供されているため、独自に Capistrano の設定をする必要はありませんでした。ここでは Rails に限定されない一般的な使用方法をまとめます。

    参考ページ

    インストール

    bundler はインストール済みであるとします。Gemfile で capistrano をインストールします。

    Gemfile

    source 'https://rubygems.org'
    
    group :development do
      gem "capistrano", "~> 3.4"
    end
    

    現在有効な ruby に対して bundler で capistrano を vendor/bundle にインストールします。

    bundle install --path vendor/bundle
    

    以下のファイルが生成されました。git プロジェクトの場合は必要に応じて .gitignore に追記します。

    • Gemfile.lock (git レポジトリに含めます)
    • .bundle (.gitignore で除外します)
    • vendor/bundle (.gitignore で除外します)

    Gemfile.lock はレポジトリに含めるようにしてください。

    It is recommended to fix the version number when using Capistrano, and is therefore recommended to use an appropriate bundler.
    http://capistranorb.com/documentation/getting-started/installation/

    .gitignore

    .bundle
    bundle
    

    以下のコマンドで動作確認できます。実行可能なタスク一覧が表示されます。

    bundle exec cap -T
    

    設定の雛形を生成

    以下のコマンドで設定ファイルの雛形を生成します。公式ドキュメントではこれを "Capify" と表現しています。

    $ bundle exec cap install
    

    不要ですので "no" としました。

    Enhance Capistrano with awesome collaboration and
    automation features? (Yes/no): no

    以下のファイルが生成されました。すべて git レポジトリに含めます。

    Capfile
    lib/capistrano/tasks/
    config/deploy.rb
    config/deploy/staging.rb
    config/deploy/production.rb
    

    複数サーバーに SSH ログインしてコマンドを発行

    Consolerequire すると console タスクが利用できるようになります。Capfile に以下の一行を追記します。

    require 'capistrano/console'
    

    複数サーバーに対して一括して同じコマンドを発行できます。

    config/deploy/staging.rb

    server 'xxx.xxx.xxx.xxx', user: 'ec2-user'
    server 'yyy.yyy.yyy.yyy', user: 'ec2-user'
    

    実行例

    $ bundle exec cap staging console
    
    staging> uptime
          03 uptime
          03  22:50:13 up  2:12,  1 user,  load average: 0.03, 0.02, 0.00
        ✔ 03 ec2-user@xxx.xxx.xxx.xxx 0.632s
          03  22:50:13 up  2:12,  1 user,  load average: 0.03, 0.02, 0.00
        ✔ 03 ec2-user@yyy.yyy.yyy.yyy 0.669s
    

    任意のタスクを定義して実行するサンプル

    Capify すると deploy タスクに関してのみ予め定義されたタスク群が利用できるようになります。

    Capfile

    # Include default deployment tasks
    require "capistrano/deploy"
    

    デプロイとは関係のない任意のタスクを用意するためには以下のようにします。

    lib/capistrano/tasks/my_task.rake

    # ユーザー入力を求めます。パスワード等については echo: false として内容が表示されないようにします。
    set :my_variable, ask('Enter something:', '既定値', echo: false)
    set :my_variable2, "you typed #{fetch(:my_variable)}"
    
    # 設定が前後する場合はラムダ `{}` を利用して遅延評価します。
    set :my_variable4, -> { "my_variable3 == #{fetch(:my_variable3)}" }
    set :my_variable3, 123
    
    desc "\"desc\" を記載すると cap -T に表示されるようになります。"
    task :my_task do
    
      run_locally do
        execute "hostname"
      end
    
      on roles(:all) do |host|
        execute "echo \"#{fetch(:my_variable2)}\""
        execute "echo \"#{fetch(:my_variable4)}\""
      end
      on roles(:my_role1) do |host|
        execute "echo \"#{host} has my_role1\""
      end
      on roles(:my_role2) do |host|
        execute "echo \"#{host} has my_role2\""
      end
    
    end
    

    config/deploy/staging.rb

    server '127.0.0.1', user: 'user1', roles: [:my_role1]
    server 'localhost', user: 'user2', roles: [:my_role1, :my_role2]
    

    実行例

    $ bundle exec cap staging my_task
    Please enter Enter something: (既定値): 
    00:00 my_task
          01 hostname  ← 実行コマンド
          01 vagrant  ← 実行結果
        ✔ 01 vagrant@localhost 0.004s  ← run_locally が完了
          02 echo "you typed abc"  ← on roles(:all) 開始
          02 you typed abc
        ✔ 02 user1@127.0.0.1 0.570s
          03 echo "my_variable3 == 123"
          02 you typed abc
        ✔ 02 user2@localhost 0.617s
          03 my_variable3 == 123
        ✔ 03 user1@127.0.0.1 0.622s
          03 my_variable3 == 123
        ✔ 03 user2@localhost 0.611s  ← on roles(:all) 完了
          04 echo "localhost has my_role1"  ← on roles(:my_role1) 開始
          05 echo "127.0.0.1 has my_role1"
          04 localhost has my_role1
        ✔ 04 user2@localhost 0.100s
          05 127.0.0.1 has my_role1
        ✔ 05 user1@127.0.0.1 0.100s  ← on roles(:my_role1) 完了
          06 echo "localhost has my_role2"  ← on roles(:my_role2) 開始
          06 localhost has my_role2
        ✔ 06 user2@localhost 0.045s  ← on roles(:my_role2) 完了
    

    ファイルアップロード

    upload! でローカルマシンのファイルを各リモートホストにアップロードできます。

    task :my_task do
      on roles(:all) do |host|
        upload! 'Capfile', "/tmp/Capfile_#{host}"
      end
    end
    

    コマンド実行結果の取得およびログへの出力

    capture でコマンド実行結果を変数に格納できます。info, warn, error でログ出力できます。

    task :my_task do
      run_locally do
        output = capture "whoami"
        info output
        warn output
        error output
      end
    end
    

    タスク間の連携

    invoke による連携

    lib/capistrano/tasks/my_task.rake

    task :my_task01 do
      on roles(:all) do |host|
        info "my_task01"
      end
    end
    
    task :my_task02 do
      on roles(:all) do |host|
        invoke 'my_task01' # 他のタスクを実行
        info "my_task02"
      end
    end
    

    実行例

    $ bundle exec cap staging my_task01
    00:00 my_task01
          my_task01
    $ bundle exec cap staging my_task02
    00:00 my_task01
          my_task01
          my_task02
    

    before, after による連携

    lib/capistrano/tasks/my_task.rake

    task :my_task01 do
      on roles(:all) do |host|
        info "my_task01"
      end
    end
    
    task :my_task02 do
      on roles(:all) do |host|
        info "my_task02"
      end
    end
    
    before :my_task02, :my_task01
    # after :my_task02, :my_task01
    

    before, after による連携 (ブロック形式)

    lib/capistrano/tasks/my_task.rake

    task :my_task02 do
      on roles(:all) do |host|
        info "my_task02"
      end
    end
    
    before :my_task02, :my_task03 do
      on roles(:all) do |host|
        info "my_task03"
      end
    end
    

    実行例

    $ bundle exec cap staging my_task03
    00:00 my_task03
          my_task03
          my_task03
    $ bundle exec cap staging my_task02
    00:00 my_task03
          my_task03
          my_task03
    00:00 my_task02
          my_task02
          my_task02
    

    並列処理数の制御

    サーバー数が多い場合、例えば git pull などが同時に実行されるとホスティングサーバーに負荷がかかります。また、デプロイ後のプロセス再起動を全ホストで一斉に行うとダウンタイムが発生するため 1 ホストずつプロセス再起動 (rolling restarts) するのが好ましいです。これを実現するためには以下の設定を利用します

    on(in: :sequence, wait: 5) { ... }
    on(in: :groups, limit: 2, wait: 5) { ... }
    

    無制限の並列処理

    デフォルト値です。parallel 実行されます。

    task :my_task do
      on roles(:all), in: :parallel do |host|
        execute "whoami && date"
        execute "whoami && date"
      end
    end
    

    実行例

    $ bundle exec cap staging my_task
    00:00 my_task
          01 whoami && date
          01 user1  ← リモートサーバー1
          01 user2  ← リモートサーバー2
          01 2016年  7月  4日 月曜日 01:33:55 JST
          01 2016年  7月  4日 月曜日 01:33:55 JST
        ✔ 01 user2@localhost 0.630s
        ✔ 01 user1@127.0.0.1 0.614s
          01 user2  ← リモートサーバー2
          01 user1  ← リモートサーバー1
          01 2016年  7月  4日 月曜日 01:33:56 JST
        ✔ 01 user2@localhost 0.661s
          01 2016年  7月  4日 月曜日 01:33:56 JST
        ✔ 01 user1@127.0.0.1 0.643s
    

    一台ずつの直列処理

    task :my_task do
      on roles(:all), in: :sequence, wait: 5 do |host|
        execute "whoami && date"
        execute "whoami && date"
      end
    end
    

    実行例

    $ bundle exec cap staging my_task
    00:00 my_task
          01 whoami && date
          01 user1  ← リモートサーバー1
          01 2016年  7月  4日 月曜日 01:35:01 JST
        ✔ 01 user1@127.0.0.1 0.546s
          01 user1  ← リモートサーバー1
          01 2016年  7月  4日 月曜日 01:35:02 JST
        ✔ 01 user1@127.0.0.1 0.579s  ← ここで `wait: 5` (秒) が始まります。
          01 user2  ← リモートサーバー2
          01 2016年  7月  4日 月曜日 01:35:07 JST
        ✔ 01 user2@localhost 0.531s
          01 user2  ← リモートサーバー2
          01 2016年  7月  4日 月曜日 01:35:08 JST
        ✔ 01 user2@localhost 0.557s  ← このあとすぐに終了します。
    

    数台までに限定した並列処理

    limit: 1 とすると、ほぼ sequence の場合と同じ処理方法になります。

    task :my_task do
      on roles(:all), in: :groups, limit: 1, wait: 5 do |host|
        execute "whoami && date"
        execute "whoami && date"
      end
    end
    

    実行例

    $ bundle exec cap staging my_task
    00:00 my_task
          01 whoami && date
          01 user1  ← リモートサーバー1
          01 2016年  7月  4日 月曜日 01:38:53 JST
        ✔ 01 user1@127.0.0.1 0.541s
          01 user1  ← リモートサーバー1
          01 2016年  7月  4日 月曜日 01:38:54 JST
        ✔ 01 user1@127.0.0.1 0.593s  ← ここで `wait: 5` (秒) が始まります。
          01 user2  ← リモートサーバー2
          01 2016年  7月  4日 月曜日 01:38:59 JST
        ✔ 01 user2@localhost 0.526s
          01 user2  ← リモートサーバー2
          01 2016年  7月  4日 月曜日 01:39:00 JST
        ✔ 01 user2@localhost 0.541s  ← ここで `wait: 5` (秒) が始まります (sequence との違い)
    

    タスク間の連携がある場合の例

    task :my_task01 do
      on roles(:all), in: :groups, limit: 1, wait: 5 do |host|
        execute "whoami && date"
        execute "whoami && date"
      end
    end
    
    task :my_task02 do
      on roles(:all) do |host|
        execute "whoami && date"
        execute "whoami && date"
      end
    end
    
    after :my_task01, :my_task02
    

    実行例

    $ bundle exec cap staging my_task01
    00:00 my_task01
          01 whoami && date
          01 user1  ← リモートサーバー1
          01 2016年  7月  4日 月曜日 01:58:28 JST
        ✔ 01 user1@127.0.0.1 0.661s
          01 user1  ← リモートサーバー1
          01 2016年  7月  4日 月曜日 01:58:28 JST
        ✔ 01 user1@127.0.0.1 0.606s  ← ここで `wait: 5` (秒) が始まります。
          01 user2  ← リモートサーバー2
          01 2016年  7月  4日 月曜日 01:58:34 JST
        ✔ 01 user2@localhost 0.482s
          01 user2  ← リモートサーバー2
          01 2016年  7月  4日 月曜日 01:58:34 JST
        ✔ 01 user2@localhost 0.501s  ← ここで `wait: 5` (秒) が始まります。
    00:12 my_task02  ← my_task01 が完了してから、my_task02 は全サーバーでほぼ同時に実行されます↓
          01 whoami && date
          01 user2
          01 2016年  7月  4日 月曜日 01:58:39 JST
        ✔ 01 user2@localhost 0.103s
          01 user2
          01 2016年  7月  4日 月曜日 01:58:40 JST
        ✔ 01 user2@localhost 0.326s
          01 user1
          01 2016年  7月  4日 月曜日 01:58:40 JST
        ✔ 01 user1@127.0.0.1 0.630s
          01 user1
          01 2016年  7月  4日 月曜日 01:58:40 JST
        ✔ 01 user1@127.0.0.1 0.054s
    
    Likeボタン(off)0
    詳細設定を開く/閉じる
    アカウント プロフィール画像

    3Dモデリングとゲームエンジンに興味があります。Blenderも活用!

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事

      • レイアウトおよび部分テンプレートに関するまとめ (Rails4)
        レイアウトおよび部分テンプレートはどちらもテンプレート (*.html.erb) に共通の要素をまとめておき、任意のテンプレートから利用できるようにしておくための仕組みです。フッターやヘッダーといった大枠はレイアウト、小さなパーツは部分テンプレートというイメージで使い分けましょう。 レイアウトの使用方法 クラス毎に指定する方法と、アクション毎に指定する方法があります。 app/views/layo...
        taro三世taro三世9/21/2016に更新
        いいねアイコン画像0
      • Ruby コードスニペット (正規表現)
        sample.rb str = "001: This is a string." var1,var2 = 2,3 # 'EOS'とすると#{}による変数展開がなされない (%03dは展開される) doc = (<<"EOS" % var1) # 括弧は省略可。要は<<"EOS"の次の行からEOSまで。(参: <<-"EOS"とすると前に空白...
        だいふくうさぎだいふくうさぎ4/13/2018に更新
        いいねアイコン画像0
      • OAuthを用いずにTwitterに自動投稿する (回数制限あり, Selenium with Ruby)
        Seleniumを用いて、OAuthを用いずにTwitterに自動投稿するRubyスクリプトを記述してみます。連続で複数回実行すると、ボット判定としてキャプチャ認証が発生します。その認証までは通過できませんので悪しからず。また、Twitterの仕様変更次第ではDOMの構造が変化するため、下記サンプルは機能しなくなる恐れが有ります。 twitter_post.rb #!/usr/bin/ruby r...
      • Ruby における日本語のエンコーディング
        日本語を含めて多言語対応する際には、Asciiコード以外の文字コードセットが必要になります。日本語が主となる場合、よく使われる文字セットにはUnicode, Shift_JIS, EUC-JPがあります。このうち Unicode だけは特殊であり、世界中のあらゆる文字を収録しようとしていることから 1 文字を表現するために必要なバイト数が大きくなってしまっています。そのため Unicode のうち...
        だいふくうさぎだいふくうさぎ3/21/2017に更新
        いいねアイコン画像0
      • Rails3ビューテンプレートの基本的な使用方法 (Ruby)
        Railsでは、ERB (eRuby (テキストファイルにRubyスクリプトを埋込む書式の仕様) をRubyで実装したもの) を用いてHTML内にRubyスクリプトを埋込むことができます。 <% %> で囲むと出力されません (if-elseなど制御構文を記述します) <%= %> で囲むとエスケープ出力されます <%== %> で囲むとエスケープされずに...