読者です 読者をやめる 読者になる 読者になる

weblog of key_amb

主にIT関連の技術メモ

Rundeck によるバッチ実行サーバの冗長化について考えてみた、試してみた #Rundeck

ここ数日ジョブスケジューラ熱が高まっていますが、少し前に下の記事で知った Rundeck も気になっていました。

Rundeck - cronから移行しやすいジョブスケジューラを使ってみよう - インフラエンジニアway - Powered by HEARTBEATS

Rundeck の仕組みと冗長化ポイント

Rundeck はある1台のサーバ上で動作し、Web UI からジョブを登録したり実行したりできます。
ジョブは Rundeck が稼働するサーバのローカル上で実行することも、Rundeck が管理するノード(群)に対してリモートで実行させることもできます。

冗長化ポイントは以下2点です。

  • ジョブ実行ノード
  • Rundeck 稼働サーバ

この記事ではまず、前者のジョブ実行ノードの冗長化について考えます。

Rundeck ジョブ実行ノードの冗長化

(1) ジョブ実行ノードをHAクラスタ化する

シンプルに複数台のジョブ実行ノードを HAProxy や Keepalived などの高可用システムにぶら下げて、Rundeck はHAシステム経由でジョブを実行するようにします。

このやり方の場合、Rundeck の Job の対象ノードにはHAシステムのホスト名または仮想IPを指定するようにします。

(2) ジョブを複数台で実行し、各ジョブの最初でミューテックスを取得するようにする

ジョブは複数台で実行するが、各ジョブの最初の処理でジョブの UUID ごとにユニークなミューテックス(ロック)を取得する、というやり方です。
ミューテックスの取得に成功したジョブは継続処理しますが、失敗した場合は即座に終了するようにします。

アプリケーションフレームワークにこうした機構が実装されていれば、比較的手軽に実現できそうです。

実は Rundeck の Job 設定を工夫すれば、同じようなことは「一応」実現できました。

以下は、Vagrant で動かすことができる GitHub - rundeck/anvils-demo: A simple example showing off rundeck's basic features を使って試しに設定してみた例になります。

Rundeck の Workflow による Job のミューテックス制御

手元の Macリポジトリを git clone し、vagrant up すると、box のダウンロード => 起動 => provision による Rundeck のインストールとセットアップが実行され、およそ 20〜30分ほどで Rundeck の WebUI に http://192.168.50.2:4440 でアクセスできるようになりました。

ログイン画面が出るので admin/admin でログインし、anvils プロジェクトの「Jobs」画面から、以下のような Job を作成します。

f:id:key_amb:20150228134004p:plain

Rundeck では単一ステップのジョブだけでなく、複数ステップから成る Workflow を作成することもできます。

各ステップには名前をつけることができます。
わかりやすいように "get lock", "procedure", "clean up" としました。
それぞれ中身はシェルコマンドです。

ここで、"get lock" は Rundeck 稼働サーバ上で mkdir /tmp/lockdir を実行することで、簡易的なミューテックス取得処理となるように意図しています。

"procedure" は任意のリモートプロセスなのですが、今回は単にローカルサーバ上で success を標準出力するだけです。

この Job を実行してみます。
tag:app にマッチするノード2台が実行対象です。

f:id:key_amb:20150228134026p:plain

Fail してしまいました。
ただし、Summary 表の "FAILED" は失敗したノード数を表しています。
数字は1なので、もう1台では成功しています。

Report タブで各ノードのステップ実行結果を見てみます。

f:id:key_amb:20150228134021p:plain

app1.anvils.com では "All Steps OK" となっており、Workflow が最後まで正常に実行されたことがわかります。
他方、app2.anvils.com では "get lock" ステップで失敗して、以降の処理を中断しました。

これはミューテックスによる排他制御であり、狙い通りの挙動です。

最後に出力である Log Output を確認しておきます。

f:id:key_amb:20150228134016p:plain

app1.anvils.com でのみ実際の処理(=successの表示)が行われたことがわかります。

以上で、Rundeck によって、バッチジョブを複数台にディスパッチし、かつその内1台でのみ実行されるように設定可能なことがわかりました。

ただ、ジョブ全体の結果が Failed になってしまうのが少々残念なところです。
調べた限りでは、「1台でも実行成功したら成功とする」ような設定は見つからなかったので、仕方なさそうです。

おわりに

この記事では Rundeck によるバッチ実行ノードの冗長化について考えてみました。
また、Rundeck の機能を使うことで冗長化が「一応」実現可能なことを確認しました。

しかし、少々トリッキーなやり方になってしまいました。
Rundeck 自体に「対象ノード群のどれか1台でのみジョブを実行する」ような機能があったら便利ですね!

GitHub を覗いてみたら、そういう Issue が既に挙げられていました。(ので、"+1" してみました :D)

How to execute a job on only a single node · Issue #729 · rundeck/rundeck · GitHub

2つめの Rundeck サーバの冗長化についても書こうと思ったのですが、長くなったのでこのエントリはここまでにしておきます。