密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

41
密密 ! Niboshi 密密密密密密 13:00 13:05 2012/10/31 Niboshi::Version #=> 1.1.0.1 DocumentVersion #=> 1.2 密密 密密HiganWorks 密密密密

description

普通のRailsデプロイ事例として読んでもらっても大丈夫だと思います。 Z Cloudのコンパネをデプロイする様子をそのままスライドにしました、一部で普段の作業内容をシェアして欲しいという要望があったので。

Transcript of 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Page 1: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

密着 ! Niboshi 更新デプロイ13:00 ~ 13:05

2012/10/31Niboshi::Version #=> 1.1.0.1DocumentVersion #=> 1.2

制作・著作: HiganWorks 合同会社

Page 2: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Niboshi とは• Z Cloud のコンパネです• Rails + resque で構成– Nginx + unicorn– Rescure worker, scheduler

• 外部サービスとの連携多し– Joyent SmartDatacenter (SDC)– Giraffi ( モニタリング SaaS)– ペイメント代行サービス

開発は Team Shinobi

密着! Niboshi デプロイ 2

"sinobi".scan(/[niboshi]/) #=> ["s", "i", "n", "o", "b", "i"]

Page 3: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

注意• このスライドは 2012 年 10 月 31 に行った

Niboshi デプロイ 1.1.0.1 の作業ログです

• 作業の視点はデプロイ担当者、アプリのコードには関与していない

• 手法、コマンドなどは作業記録当時のものであり、最新とは限りません

密着! Niboshi デプロイ 3

Page 4: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

デプロイは FEATUREの把握から

密着! Niboshi デプロイ 4

Page 5: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

前提知識:一般的な Rails アプリの更新デプロイ

• 開発情報– Git のタグ– Changelog

• マイグレーションタスク抽出– DB マイグレーション– コンフィグディレクティブ

• 運用情報– 起動終了スクリプト– モニタリング– ワーカなどのデーモン管理

密着! Niboshi デプロイ 5

Page 6: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

New Feature, changelog の聞き込みQ A Do

タグは何? 1.1.0.1 • リリース対象として認識

• Git log , diff のチェック

どういうリリース? 管理システムとキュー連携してタスクを実行する機能の実装あとバグ Fix

サーバで必要なタスクの洗い出し=> 次ページへつづく

Config 変更は? ない デプロイ時の Structureチェックのみで OK

DB マイグレーション あったっけ。。?

お互い確認⇒ あった。

デプロイ時、リスタート前に rake db:migrate:status で確認後 db:migrateが必要になる密着! Niboshi デプロイ 6

Page 7: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

なぜ聞き込みがいるのでしょう。

アプリが何の機能を提供するかを知ることで、インフラやミドルウェアがどういう状態であるべきかの判断材料とするためです。その情報をもとにデプロイ先の動作環境を事前に調整します。

また、更新時に不必要なダウンタイムを発生させないためでもあります、 DB のマイグレーション・コンフィグのディレクティブ追加の通知を忘れるとアプリケーションが正常にリスタートできずダウンします。

密着! Niboshi デプロイ 7

Page 8: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

掘り下げて把握& Tododig Dug Todo / result

Feature:管理システムキュー連携

メッセージングは Resqueで行う実行は Resque でやるエンキューは社内の管理システムから

• 新規 resque worker! の設置

• Fail のチェックタスク• 管理サーバからの Redis

ポートの Open

- ( 運用 ) 新規 resque worker 起動方法のMonit でストップ / スタート

• Capistrano スクリプト修正

Bugfix:あれこれ

詳細後述 本番稼働とリリース対象のタグで log と diff を見る

Migration:データベース

DB:migrate:status で確認しつつdb/migrate/ を見る

メッセージキューを受けて叩くタスク用のカラムが 2つ追加される模様密着! Niboshi デプロイ 8

Page 9: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

今回の掘り下げの成果は。

訳あってスプリント (※) の期間が空いたため、大いにありました。DB のマイグレートと Config ファイルは見逃した際の本番環境へのインパクトが特に大きいため、自動チェックの仕組みを幾つか用意した上で直前にも口頭で確認しています。

開発側は普段がそれぞれの development 環境で行っているため、 Production との差をあまり意識しません。期間が空くとどこまで適用済みかなんて自分も含めてみんな忘れていますから。

密着! Niboshi デプロイ 9

(※) リリースのこと

Page 10: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

ミドルウェアの設定変更がありますね。

Feature を引っさげてのリリースですから。連携側のシステムも私が環境構築しているので色々とスムースです。

密着! Niboshi デプロイ 10

Page 11: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

テスト通ってる?

密着! Niboshi デプロイ 11

Page 12: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

自動実行の結果をチェック

密着! Niboshi デプロイ 12

Page 13: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

この時点での Jenkins 実行内容• Bundler 実行可否– .lock から生成する “– deployment” モードで

• Config.sample と development の構造チェック– 更新や階層変更、 Syntax エラーの検出

• Rake から unit, functional, integration テストの実行

課題: Jenkins サーバからデプロイできそうだが、まだ心配&デプロイコードのリファクタしたいので据え置き

密着! Niboshi デプロイ 13

Page 14: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Jenkins の役割はなんでしょう。

まず結合テストの実行と実行結果のシェア&通知です。導入前に比べ、単体の Ruby(rails) アプリケーションとしてのテスト効率は飛躍的に向上しました。

本番デプロイを想定した流れをジョブ化しており、テストもその環境で行われます。 DB や Config の構成変更は特に周知せずともここで検出できるようにしています。

密着! Niboshi デプロイ 14

Page 15: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

アプリケーションのコンフィグはどの様に運用していますか。

Niboshi では関係者が値を確認しやすいよう、 staging, production のコンフィグコピーを WEB で閲覧&編集できるようなツールを作っています。編集したコンフィグのみそのままデプロイできますが、書式が変なら警告して止まる仕組みです。

ほか、デプロイ用のサーバでは git の post-merge フックにて config.yml(sample) の diff を毎回出力させるなど、対応不要ならスルーし、要対応はどこかで止められるようにしています。

密着! Niboshi デプロイ 15

Page 16: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

デプロイの準備

密着! Niboshi デプロイ 16

Page 17: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Git log で雰囲気を把握• 本番稼働中のタグ確認

• cap production deploy:version– #=> ( 略 )/current/VER_1.1.0b

– Log みる• git log --oneline 1.1.0b..1.1.0.1

– 5e4e605 Update Gemfile.lock by doing bundle update– fd20c2e Update the Email template for update payment information– 21d8ab3 Comment-in newrelic gem in Gemfile– 3529ba2 Add resque worker for run notification queue– (中略)– b972edc Set default value for path of HTTP monitoring

– コメントで気になったらコードみる• git show 21d8ab3

– +gem “newrelic_rpm“ # なるほど

密着! Niboshi デプロイ 17

Page 18: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

コード見るの?

見ないことも多い、趣味で。もはや Ruby は必修科目なので参考にしたり。

密着! Niboshi デプロイ 18

Page 19: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Resque worker ++の対応• 普通のワーカーなので Capistrano にセット– Production.rb

-set :resque_workers, %w{reap_free_machines}+set :resque_workers, %w{reap_free_machines run_notification_queue}

• テンプレートから起動&終了スクリプトの設置とmonit 登録用コンフィグを生成するための配列

• DryRun (-n) でチェック• cap production -n deploy:create_ctl_scrpts

– ====Start preview config ==resque_run_notification_queue_start.sh==– #!/usr/local/rvm/bin/rvm-shell 1.9.3-p125– ( 中略 )– ====End preview config ==resque_run_notification_queue_start.sh==

– 内容問題無さそう ( ってか Staging で稼働の確認済み )

密着! Niboshi デプロイ 19

Page 20: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Capistrano とは。

コードベースからアプリケーションをデプロイするためのツールです。デフォルトでは Rails プロジェクト向けのタスクが組まれていますが、 Ruby の内部 DSL でタスクを定義できるので便利です。どちらかと言うと開発者が自分で自由にデプロイするために使うツールだと思いますが、最近は DevOps とか言うしそこだけ特定の誰かがやるのもあまり不自然ではないかも。

今回 Resque-worker がテンプレ通りだったので追加も楽でした。

密着! Niboshi デプロイ 20

Page 21: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Redis の対応• 先日立てた管理アプリとの連携のためポート開放• デプロイ前

– Listen が localhost– Iptables は余計なものを開けてはいないが社内 IP は通して

いる ⇒ bind address を変更すれば OK

-bind 127.0.0.1+bind 0.0.0.0

• Redis をリスタート– # service redis-server restart– # netstat -naplt | grep redis– tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 3553/redis-server

密着! Niboshi デプロイ 21

Page 22: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

CAPでのデプロイをおこなう

密着! Niboshi デプロイ 22

Page 23: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

と思ったけど 毎時 30 分に行うタスクが“Resque scheduler” にエンキューされる寸前だったので完了まで待つ

密着! Niboshi デプロイ 23

Page 24: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

適当に見届ける

密着! Niboshi デプロイ 24

Page 25: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

今回のデプロイ段取りをおさらい• Cap で 1.1.0.1 をデプロイする

– Bundler が複数ベンダのプライベートリポジトリをまたぐので多段 ssh-agent環境で行う

– Gemset も“ ruby-1.9.2-p290@capistrano” を固定で使用– migrate:status にて down 検出、リスタートしない

• db:migrate する– Cap の deploy:migrate も使えるはずだが、導入時に rvm との連携を作ってな

かったのでそのまま

• Rack アプリをリスタート• Resque-* (worker, scheduler, resque-web) を

リスタート• 新 worker 用の Monit スクリプトのロード

密着! Niboshi デプロイ 25

Page 26: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

“ 今回の“段取り?

ただの Bugfix などのケースだと、 Deploy&Restart でオシマイですからね。

密着! Niboshi デプロイ 26

Page 27: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Cap deploy でコードを• コマンド

– # cap production deploy– ( 中略 )– Tag to deploy (make sure to push the tag first): [1.1.0rc4] 1.1.0.1

– やること(普通にカスタマイズ可)• まずMysql のダンプ• 新規 Dirに Git clone & checkout & rm –rf .git• bundle install –deployment( ほかオプションも )• current リンクの付け替え• コンフィグの設置• 本来ならアプリのリスタート (※ 無効化済み )

代わりに db:migrate:status を表示させている。密着! Niboshi デプロイ 27

Page 28: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Capistrano にカスタマイズで追加したタスクは?

今回出てくるのでは、 DB のバックアップ、コンフィグ /管理スクリプト設置 (Dryrun プレビュー込 ) 、リビジョン確認くらいです。

あとはリバースプロキシ用の Nginx の操作をテンプレート&タスクにしてます。

密着! Niboshi デプロイ 28

Page 29: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

管理スクリプトも設置• 各種起動&停止スクリプトの設置– 毎回上書き設置• # cap production deploy:create_ctl_scrpts

– *_start.sh, *_stop.sh と monit_*.conf ファイルの作成と設置• deploy.rb でタスク、 staging.rb, production.rb で環境別

attribute をセット!( path とか resque-worker とか)

• {# deploy_to} の shared/system に設置

密着! Niboshi デプロイ 29

Page 30: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

DB:migrate

• アプリのサーバで migrate– 普通の rails 的更新– アプリの“ Current” は symlink なので、毎回 CD し

ないといつのまにか古いディレクトリにいる– ↓確認– bundle exec rake db:migrate:status RAILS_ENV=production

» down 20121012075801 Add status and executed at to notification queues

– ↓更新– bundle exec rake db:migrate RAILS_ENV=production

密着! Niboshi デプロイ 30

Page 31: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

なぜ” Current” は実体でなくシンボリックリンクなのですか。

Capistrano のやり方ですが、リンクの付け替えだけでアプリケーションのロールバックができるからです。Rails の DB マイグレーションの仕組みはロールバックもサポートしており (※) 、だいたい可逆です。

繰り返しになりますがデプロイ直後はカレントディレクトリに注意しないと古いものを見てしまいます。

密着! Niboshi デプロイ 31

(※) 特定のマイグレーションを DOWN にできる。マイグレーション内容によっては保証しかねるので流石にダンプの取得は必須

Page 32: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

アプリのリスタートをしていく

密着! Niboshi デプロイ 32

Page 33: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Rack アプリ( Rails )• Monit に管理させている– Cap で deploy:stop & deploy:start か– Monit で restart のどちらでも OK

– とりあえず– monit restart niboshi_unicorn_production

• デプロイを asset_pipeline にちゃんと対応してないので、リスタート後一発目の表示が遅い

密着! Niboshi デプロイ 33

Page 34: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

なぜ Monit なのですか。

いろいろやった結果、起動終了をスクリプトにしておいてmonit経由でデーモンをコントロールするのが分かりやすさや互換性、可搬性に優れていると思いました。

コントローラとしても、自動リスタートの内部監視としても優秀です。

密着! Niboshi デプロイ 34

Page 35: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Rack アプリのリビジョンチェック• 過去、再起動失敗でプロセス古いままという事例があったのでチェックするようにしている

• # cap production deploy:version• “Current” にあるファイル群の表示

– ** [out :: **.**.**.***] /opt/deploy/niboshi/current/VER_1.1.0.1– ** [out :: **.**.**.***] 5e4e605fd2731d0f0a30a8e83ecc567d1bb55e65

• 起動中の unicorn_master プロセスの proc/*/cwd の下– ====– ==== Revision of unicorn ========– ====– ** [out :: **.**.**.***] /proc/8639/cwd/VER_1.1.0.1– ** [out :: **.**.**.***] 5e4e605fd2731d0f0a30a8e83ecc567d1bb55e65

密着! Niboshi デプロイ 35

Page 36: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

リスタート失敗してた?

いろんな要因の失敗があった。CI してない頃は、もう何も信用出来なかった。

最近は少なくとも Staging に上げる頃にはコケる要素がほぼ駆除されている。

密着! Niboshi デプロイ 36

Page 37: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Worker の monit への追加• Capistrano で作ったコンフィグを Monit の

include_dir へ• ln -s / (略) /shared/system/monit_resque_run_notification_queue_production.conf \

/etc/monit/enable-conf.d/

• # monit –t> Control file syntax OK• # monit reload• # monit summary # ほっとくと起動してくれる

– Process 'resque_run_notification_queue' Initializing– Process 'resque_run_notification_queue' Does not exist– Process 'resque_run_notification_queue' Running

密着! Niboshi デプロイ 37

Page 38: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

Resque 関連リスタート• CWD が古いので、すべて一旦リスタートする。– Resque-(worker, scheduler, web)

– Monit でグループにしているのでまとめてリスタート命令

– cap production deploy:restart2 #deploy.rb で定義– * executing "monit restart -g resque_workers“

– cap production deploy:version で CWD のリビジヨンチェック

– 全プロセスが VER_1.1.0.1

密着! Niboshi デプロイ 38

Page 39: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

作業にはどのくらいの時間がかかりましたか。

聞きこみ&把握はテンプレなので事前の準備などには 20 分、実際にデプロイ&新ワーカーの稼働はタイトル通り、 5 分で終わりました。

密着! Niboshi デプロイ 39

Page 40: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

最後に何か。

当初は各段階でその場の対応をよくしていたが、最近はほとんどのデプロイが目視確認&そのまま次へとなってきています。

聞きこみの部分だけ何とかなれば、ワンクリック /完全自動化が次のステップになるでしょう。

密着! Niboshi デプロイ 40

Page 41: 密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -

密着 !Niboshi 更新デプロイ13:00 ~ 13:05

制作・著作: HiganWorks 合同会社

END