こんにちは。MonotaROで商品管理や受発注システムの開発を担当している中尾です。
この度、これまでcronで実行していたジョブに対してRundeckを導入し、ジョブのスケジュール管理を効率化することができましたので、導入にあたって苦労した点とその解消方法を中心に紹介いたします。
Rundeck導入の背景
Cronの限界を感じた
MonotaROでは「注文を倉庫に連携する」、「商品の発注を自動で行う」といった様々なバッチ処理が、細かいものも含めると1日数千回近く実行されています。 これまでは、これらのバッチ処理はCronを使ってスケジューリングしていましたが、下記の理由から、いよいよCronでの運用に限界を感じました。
複数サーバーで動かしているバッチを一元管理ができないから。
- 負荷分散のため、バッチを動かすサーバーの数も以前より増えており、Crontabではこれらのサーバーのバッチを一元管理することが難しくなってきていました。
バッチ数が多くなり、管理が煩雑化してきたから。
- 常時十数本のバッチが稼働している状態になっており、バッチ間の依存関係もCron上では判断できないため、メンテナンス時に特定のバッチを停止するといった運用が難しくなってきていました。
バッチ間で連携を取る機会が増えたため、バッチの実行順をジョブフローで管理したいから。
- 外部のアプリケーションの導入や処理の疎結合化により、バッチ間やバッチと外部システム間での連携が多くなっていました。それに伴い、バッチAのあとにバッチBを動かすといったバッチ間の依存関係を管理したいと思う機会が増えていました。
今後も増大するだろうバッチ数のことや、依存関係が複雑化していくことを考えると、いまのうちにジョブスケジューラを導入したほうがよいと考え導入を決めました。
過去にも導入しようとしたが・・・
実は以前にもRundeckを導入しようと、検証までは行ったことがありましたが、当時の組織変更や他案件の増加により現在まで正式な導入には至っていませんでした。
今回は当時の検証結果を活かしつつ、改めて現状のあるべき姿を追求したうえでの再チャレンジになります。ジョブコントローラーの中からRundeckを選定した経緯などはこちらの記事をご覧ください。
cron から Rundeck に乗り換えると決めた話 - MonotaRO Tech Blog
Rundeck導入において苦労した点
Rundeckの導入に当たっては、導入前にいくつか懸念事項が出ており、その中でも対応に苦労したものを紹介します。
Rundeckが落ちた場合の対応の検討
今回全てのバッチ処理をRundeckに移行するため、万が一、Rundeckサーバーが落ちてしてしまうと、全てのバッチが実行できなくなり、大きな障害に繋がってしまいます。そこで、Rundeckサーバーを2台用意し、どちらかが落ちていても、もう一方からバッチ実行ができるような冗長構成を構築しました。
Rundeckには冗長構成の機能があらかじめ用意されており、その機能を利用することで上記を実現することができました。ただし、Community版では冗長構成の機能が利用できないため、冗長構成を利用したい場合はEnterprise版を導入する必要があります。
今回はEnterprise版の推奨構成を参考に、Rundeckサーバーを2台構成に、設定保存用のDBをそれぞれマスター/スレーブ構成にしました。また、ALBを使ってアクセスを振り分けることで、共通のURLからRundeck画面にアクセスできるようにしています。ログはS3に保存することで2台のRundeckサーバーから同じログが参照できるようにしています。
GitでのRundeckジョブのバージョン管理
MonotaROではプログラムのバージョン管理に主にGitを活用しており、Rundeckに登録されるジョブについても他のプログラムに合わせ、バージョン管理を行いたいという話になりました。
Rundeckには標準でGitとの連携プラグインが用意されているのですが、これはもともとバックアップとしての用途が主であり、ブランチを頻繁に切り替えて使うようなものとは異なっていました。例えば、IntelliJのような統合開発環境では、ブランチの切替は機能として用意されており開発者は簡単に扱う事ができますが、Rundeckで同じことしようと思うと毎回プラグインの設定画面に入り、設定を手動で変更する必要がありました。
毎回、プラグインの設定を変更してブランチ切替を行うのは開発者の負担になりますし、変更されたくない設定をうっかり変更してしまう可能性もあるため、デフォルトの機能だけでブランチを切り替える運用は難しいと判断しました。
なんとか簡単にできる方法はないか調査したところ、RundeckのAPIからプラグインの設定ができることがわかりました。そこで、RundeckのAPIを活用し、Gitプラグインの設定変更用のジョブをRundeckに登録することで、簡単なブランチ切替を実現しました。APIの使い方の例として今回使用したAPIを読者の皆様に紹介します。
- ブランチ名とコミッター名をジョブのオプションで渡しジョブを起動
APIでGitプラグインの現在の設定値を取得
SCM(Source Code Management) Pluginの設定を取得するAPI
curl -s \ -H "X-RunDeck-Auth-Token:{Api token}" \ -H "Content-Type: application/xml" -d '' \ -X GET {RundeckURL}/api/15/project/{PROJECT}/scm/{INTEGRATION}/config
{PROJECT}には対象のプロジェクトの名称を指定します。
- {INTEGRATION}には対象のプラグインに応じてexportかimportを指定します。
- importプラグインの場合:import
- Exportプラグインの場合:export
取得した設定値から、ブランチ名とコミッター名を置換し、新しい設定を作成
3で作成した設定値をAPIで反映
SCM(Source Code Management) Pluginの設定内容を変更するAPI
curl -s \ -H "X-RunDeck-Auth-Token:{Api token}" \ -H "Content-Type: application/xml" \ -d @{設定ファイルのパス} \ -X POST {RundeckURL}/api/15/project/{PROJECT}/scm/{INTEGRATION}/scm/export/plugin/{TYPE}/setup
{TYPE}には設定を変更したいプラグインを指定します。
- Gitからのimportプラグインを設定する場合:git-import
- Gitへのexportプラグインを設定する場合:git-export
(参考)API Reference | Rundeck Docs
導入してよかったこと
上記のようにいくつかの課題はありましたが、無事導入まで辿り着くことができ、現在、絶賛運用中です。最後に実際に使ってみて特に良かったと思う点をいくつか紹介いたします。
複数のサーバーに跨ってジョブフローが組めること
これまで、「サーバー①のバッチAのあとにサーバー②のバッチBを動かす」といった処理はCronの実行時刻をずらすことで実現していました。しかし、Rundeckではジョブフローで表現できるので、2つのバッチの関連が明確になり、また、バッチAが遅延した場合にバッチBが不具合を起こすといった心配をする必要がなくなりました。
Cron式が使えること
Cronでスケジューリングしている全バッチをRundeckに移行するのは大変な作業になる想定でしたが、RundeckでCron式が使えたため、Crontabを機械的にRundeckのジョブ定義ファイルに変換することが容易にできました。
重複起動制御ができること
Cronでは重複起動制御をすることはできないため、これまではプログラム側で重複起動しないよう排他制御を実装していましたが、Rundeckでは重複起動の制御を設定一つで切り替えられるため、今後のプログラム実装コストを少しですが削減できそうです。
まとめ
今回はRundeckの導入に至るまでの課題とその解消方法について紹介しました。 ここに書いていない細かいノウハウもまだまだありますが、そちらはまた機会があれば紹介したいと思います。
まとめとして、Rundeck自体は目新しい製品ではありませんが、その分信頼性が高く、機能もシンプルで使い勝手が良いと感じました! 同じようにCronでの運用に限界を感じている方は是非導入を検討してみてはいかがでしょうか。
モノタロウでは随時エンジニアの採用募集をしております。この記事に興味を持っていただけた方や、モノタロウのエンジニアと話してみたい!という方はカジュアル面談フォームからご応募お待ちしております。