デプロイのベストプラクティス
警告
この記事は古くなっており、更新版を投稿します。以下は既知のバグのリストです。もしよろしければご協力ください。
SM Framework Project を使用してください
SM Framework の拡張機能は、柔軟なサーバーサイドコードのデプロイに使用できます。以下のチュートリアルでは、1つの例で使用される手順を説明します。この例では、GitHubからRuby on Railsアプリケーションをデプロイします。デプロイ拡張機能は「ruby固有」ではないことに注意してください。任意のコードベースのデプロイに使用できます。
チュートリアル
rvmアプリケーションをデプロイする際は、いくつかの注意点があります。これらはすべて推奨されるプラクティスであり、通常は新しいマシンでセットアップするのが最適です。
アプリケーションをデプロイする最良の方法は、デプロイする各アプリケーション(プロジェクト/コードベース)に対して、ターゲットシステムに新しいユーザーを作成することです。その後、各アプリケーションを独自の*分離された*環境にデプロイします(例:ユーザーとして、ユーザーのホームパス内)。ユーザー名は、アプリケーションの「短縮名」と同じであることが望ましいです。
各アプリケーション(プロジェクト)にRVM gemsetを使用します
開発とデプロイの両方で、各プロジェクトにプロジェクトの.rvmrc を使用するようにしてください。
rvm_pathをユーザーに公開されるように設定します
appuser$ echo 'rvm_path="$HOME/.rvm"' >> ~/.rvmrc
次に、RVMをインストールします。
appuser$ \curl -sSL get.rvm.io | bash -s stable
curlの前にバックスラッシュがあることに注意してください。これは、他のオプションでエイリアスを設定している場合や、このために.curlrcファイルを使用している場合に、誤動作を防ぎます。ターゲットアプリケーションユーザー用にRVMをインストールしたら、デプロイをセットアップする準備ができました!
まず、デフォルトの〜/.smrcを生成します
appuser$ sm smrc
次に、環境、repository_url、およびデプロイ元のブランチなど、変更する必要がある設定を〜/.smrcファイルで更新します
appuser$ vim ~/.smrc
たとえば、Redmineインスタンスをデプロイするときは、〜/.smrcファイルに次の2つの変数を設定します
appuser$ grep -E '^repository_url=|^branch=' ~/.smrc repository_url="git://github.com/edavis10/redmine.git" branch="1.2-stable"
Rubyアプリケーションの場合、「rvm、unicorn、rails」などの拡張機能を含む「ruby」拡張機能セットをインストールして使用する必要があります
root# sm set install ruby
次に、Railsアプリケーションのセットアップ拡張アクションを実行します。これにより、アプリケーションユーザーの〜/sharedパス内にディレクトリと構成ファイルが作成され、セットアップされます。また、デフォルトのrubyでRVMをインストールします。
appuser$ sm rails setup
〜/shared/config/にunicorn構成ファイルを生成します。デフォルトで2つ以上のunicornワーカープロセスを実行する場合、およびunicorn設定を微調整する場合は、このファイルを編集します。
appuser$ sm unicorn setup
デフォルトで生成されたdatabase.ymlファイルを編集し、データベース接続情報を設定します
appuser$ vim ~/shared/config/database.yml
次に、デプロイ拡張機能をインストールします
root# sm ext install deploy
これで、デプロイ拡張機能を使用して、〜/.smrcで定義されたリポジトリとブランチ情報から最新のコードを使用して、〜/currentを新しいリリースで更新できます
appuser$ sm deploy
rvm gemsetファイルを使用する場合は、次の手順を実行します
appuser$ source ~/.rvm/scripts/rvm # load RVM into your current shell appuser$ rvm gemset import ~/current/production.gems
bundlerを使用する場合は、次のようにgemをブートストラップします(注:「gem "unicorn"」がGemfileに最初に*バージョンを指定せずに*記述されていることを確認してください)
appuser$ cd ~/current appuser$ gem install bundler && bundle install
Rubyアプリの環境をブートストラップしたら、unicornでアプリケーションを実行します
appuser$ sm unicorn start
特にアプリケーションのコードベースを変更および更新する場合は、常にすべてがうまくいくとは限りません。新しいコードベースが新しいrubygemを使用しており、それをアプリケーションのGemfileに追加するのを忘れていたために、アプリケーションのunicorn群を起動できず、数日間額にキーボードの跡が残ったことが何度もありました。コードベースの更新は成功したがunicornが再起動しない場合は、unicornログを確認することでこの状態を確認できます。たとえば、unicornログの最後の200行を確認するには、次のコマンドを発行します
appuser$ tail -n 200 ~/shared/log/unicorn.log
次に、エラーの内容を把握し、問題を修正して、再度デプロイします!!! そう、これは悪循環です;)
http/httpsトラフィックを処理し、アプリケーションサーバーにプロキシするために、Nginx Webサーバーを使用します。Nginx拡張機能は、「サーバー」拡張機能セットにあります
root# sm set install servers
Nginxを実行しているので、以下のように進めます。rootとして(sudoで)実行するように切り替えていることに注意してください
root# sm nginx install
次に、「システムを構成」します。これは、Nginx構成ディレクトリを/etc/nginxにコピーすることを意味します
root# sm nginx configure system
次に、各アプリケーションユーザーに対して、アプリケーションサーバー構成ファイル(/etc/nginx/servers/内)を生成します
root# sm nginx server add {{appuser}}
注:これにより、Unixドメインソケット(UDS)で実行されているunicornにプロキシするようにデフォルトで構成された/etc/nginx/servers/{{appuser}}.confファイルが作成されます。
次に、appuserのディレクトリがNginxによって読み取り可能であることを確認します
root# chmod go+rx /home/{{appuser}}
最後に、Nginxサービスを開始します
root# sm nginx service start
バックアップを忘れないでください!!!ほとんどの場合、これは、十分な準備ができていないイベントによってのみもたらされる後回しになっています。この痛みを回避してください。Rails拡張機能は、backup_databaseアクションを提供します。これにより、database.ymlファイルに基づいてデータベースが〜/shared/backups/ディレクトリにバックアップされます。(別の場所にバックアップしたい場合は、ファイルシステムのシンボリックリンクを使用してください。)
user$ sm rails backup_database
午前2時に毎晩実行するように、コマンドをcronに追加します
user$ crontab -e 0 2 * * * sm rails backup_database
注:これはまもなく「sm rails backup database」(スペースに注意してください)に変更されます
godなどのものを管理するためにラッパースクリプトを使用します
user$ rvm help wrapper
特定のブランチとリビジョンをデプロイする
BDSMデプロイ拡張機能では、アプリケーションのリポジトリで使用するブランチやリビジョンを指定することもできます。たとえば、gitを使用している場合は、〜/.smrcファイルに次のいずれかまたは両方を設定できます
branch="production" revision="asdf4269"
デプロイフック
上記のチュートリアルでは、いくつかのBDSMフレームワーク拡張機能を使用してRuby on Railsのデプロイを完了する方法を示しました。これで、ポート80でアプリケーションコードが提供される単一のサーバーが実行されています。UnicornとNginxのWebサーバーのスタックを実行しています。
デプロイに不慣れな方への注意:「Unicorn」は「アプリケーションサーバー」と呼ばれ、実際のRubyコードを実行するものです。「Webサーバー」であるNginxは、静的ファイル(css、画像、javascriptなど)の提供と、その他のすべてのリクエストをUnicorn群(アプリケーションサーバー)にプロキシするために使用されます。
コードをサーバー上の最新のものに更新するたびに、上記のいくつかの手順を実行する必要があります。ここでは、これらの手順をさらに自動化して、「sm deploy」と入力するだけで済むようにする方法を示します。インストールすると、拡張機能と拡張機能セットを新しいバージョンに更新する場合を除いて、再インストールまたは更新する必要はありません。プロジェクト、データベース、unicornの構成を再構成する必要もありません。これらはすべて1回限りのタスクです。
rvm gemsetおよび/またはbundlerを使用する場合(はい、私自身のように両方を一緒に使用できます)、アプリケーションの新しいバージョンをデプロイするたびに、gemが最新であることを確認する必要があります。
これは、デプロイプロセス中に自動的に実行できます。デプロイを完了するために、いくつかの手順が実行されます。これらの手順のほとんどは、ステージングロケーション($stage_path)で発生します。デプロイ拡張機能は、デプロイプロセスにおける各ステップの前後にフックを提供します。プロセスのこれらのフックポイントのいずれかでアクションを実行するには、config/deploy/に実行可能ファイルを作成します。
現在のアプリケーションのコードベースを置き換える前に、gemを更新して、アプリケーションが一時的に失敗しないようにする例を見てみましょう。アプリケーションのコードリポジトリ「config/deploy/before_replace_current」に次の実行可能ファイルを作成します
#!/bin/bash enter "${stage_path}" command_exists bundle || gem install bundler --no-rdoc --no-ri bundle --without development,test
このコンテンツを含むこのファイルがアプリケーションコードリポジトリにチェックインされると、次にサーバーで{{appuser}}として「sm deploy」が実行されると、このファイルはデプロイ拡張機能が現在デプロイされているコードディレクトリを置き換える直前に実行されます。
注意すべきことの1つは、このファイルはシェルスクリプトであるということです!つまり、サーバーで現在実行中のコードが置き換えられる前に必要なことを実行するために、任意のコマンドを実行できます。
Webサイトの実行中のコードベースを変更するために実行する必要がある別の手順は、アプリケーションサーバー(unicorn)を再起動して、新しいコードベースをリロードする必要があることです。unicorn拡張機能でこれを行う方法は次のとおりです
appuser$ sm unicorn restart
これは、現在のディレクトリが置き換えられた後に実行する必要があります。このために、after_replace_currentフックを使用できます。「config/deploy/after_replace_current」ファイルを作成し、次の内容を記述します
#!/bin/bash enter ${release_path} # Not necessary but it makes me feel warm and fuzzy. sm unicorn restart
unicornの再起動は、リクエストをドロップせずにコードベースをリロードするように、実行中のunicornプロセスに信号を送ります。unicorn群がまだ実行されていない場合は、これによりunicorn群が開始され、「sm unicorn start」と同じになります
私は個人的に、すべてのRubyアプリケーションでアプリケーションのランタイムエラー通知にairbrakeapp(旧:hoptoadapp)を使用しており、これは非常に便利な製品だと思います!したがって、アプリケーションには、「config/deploy/after_deploy」実行可能フックファイルもあり、これにより、airbrakeアプリケーションにデプロイ通知が送信されます
#!/bin/bash enter ${release_path} rake hoptoad:deploy TO="$environment" \ REVISION="$(cat "${release_path}/revision")"
今回は、「enter ${release_path}」が*必要*であることに注意してください。ここでのrakeコマンドは、アプリケーションのRakefileを見つけられるように、アプリケーションのデプロイされたコードベース内で実行する必要があるためです。