はじめに

匠部の名状しがたい技術屋のようなもの、冨田です。

cronって知ってますよね?
Un*x系で昔からある決まった時間にバッチ処理を実行してくれるサービスです。
ある日最近構築されたサーバのcrontabを見てみたら

*/5 * * * * php ./hogehoge.php > /dev/null 2&>1

とか書いてあるんです。
これがまた突っ込みどころ満載で

  • ジョブの標準出力、標準エラー出力、終了ステータスが取れない
  • ジョブが終了せずに停止したケースが検知できない
  • 二重起動対策がない
  • 失敗時のリトライ機能がない

・・・・・・こんな気分です。

b

ではcronの使い方でどうにかなるかというとどうにもならず、本当に
「逃げるやつはただの運用担当者だ!」
「逃げないやつはよく訓練された運用担当者だ!」
「ホント、戦争運用は地獄だぜ!」
なわけです。

・・・そろそろネタはやめて本題に入りましょう。

Rundeckの紹介

商用の統合システム運用管理ツールJP1とは言わなくても、もう少し高機能なcronはないかと探し続けていたのですが、ようやくcronの代わりに入れようと思うジョブコントローラが見つかりました。

Rundeckを使うとcronでは難しいこんなことができます。

  • 複数のサーバをまたがるジョブ群の定義、実行が可能
  • ジョブの開始時間、終了時間、終了ステータス、標準出力、標準エラー出力の記録が可能
  • 終了しないジョブのタイムアウトの検知、二重起動の抑止が可能
  • 即時実行とcron的な定時実行が同じ環境で実行可能
  • 終了ステータスが0以外(ジョブの失敗)の際に実行されるエラー処理が可能
  • 異常終了時の自動リトライが可能

インストールしてみましょう

Redhat/CentOS系の場合はyumで簡単にインストール可能です。

# yum install java-1.6.0
# rpm -Uvh http://repo.rundeck.org/latest.rpm
# yum install rundeck
# service rundeckd start

初期設定

RundeckはGrails(Groovyのフレームワーク)で構築されていますので、Grailsの設定ファイルを編集します。RundeckのWebインタフェース用にRundeckサーバ自体のドメイン又はIPアドレスとSMTPサーバを設定します。

/etc/rundeck/rundeck-config.properties

grails.serverURL=RUNDECK_SERVER_FQDN:4440
grails.mail.host=SMTP_GATEWAY
grails.mail.port=25
grails.mail.default.from=mail_from@example.com

ログイン

http://(Rundeckのサーバ):4440にアクセスしてください。
デフォルトのID、パスワードはadmin:adminです。

プロジェクトの作成

ProjectName以外は特に変更する必要はありません。後で説明しますがこの画面に表示されている”SSH Key File Path”が重要ですので覚えておいてください。

project2

単純なジョブの登録と即時実行

では最初に単純なジョブを登録して実行してみましょう。先ほど作成したプロジェクトを開き、「create new job」を選択することでジョブの作成画面を開くことが出来ます。

newjob1_1

Add a stepからCommandかScriptを選んで、コマンドラインを入力してください。
ジョブはRundeckユーザの権限で実行されますので、他ユーザの権限が必要であればsudoする必要があります。まずは単純に現在日時を標準出力とファイルに出力してみます。

newjob1_5

Createボタンで保存したら早速 Run Job Now を押して実行してみましょう。

newjob1_3

ジョブの実行結果を確認します。
Log outputタブからView Optionsをクリックすると、コマンドライン実行時の標準出力、標準エラー出力を確認することができます。このログは保存されるため、後日、実行結果を確認することができます。

newjob1_6

失敗した場合は標準エラー出力に加えて、終了ステータスが表示されます。

newjob1_7

複数のステップから構成されるジョブを実行

例えば、MySQLの日次バックアップを取って、一週間以上たったダンプファイルを削除するジョブを定義するとこうなります。重要なのはIf a step failsの設定です。Stop at the failed stepに設定することで、Step1のmysqldumpが失敗(0以外の終了ステータス)した場合に、Step2のローテートを実行せずに終了させることができます。

newjob1_8

定時実行

即時実行してジョブの定義が正しいことを確認したら、定時実行してみましょう。Schedule to run repeatedly?をNoからYesに変更すると実行時刻、曜日、月を設定することができます。細かい制御が必要な場合はcrontabと同じ定義も設定できます。

newjob1_9

エラーの通知

実行時にこけるかもしれませんので、エラーの通知を設定しましょう。

newjob1_10

Send notificationをYesにすることで、ジョブの開始、成功、失敗の各イベント毎をトリガーにメール又はWebhookを送ることができます。

その他、cronでは難しい機能が簡単に設定できます。

並行起動の禁止

cron上で1分間隔など短周期で起動するバッチ処理を設定すると、前回起動した処理が終わる前に次の起動タイミングでバッチ処理が起動することがよくあります。その結果プロセスが大量に起動してロードアベレージがえらいことになったりするのですが、Rundeckではデフォルトで並行起動が禁止されています。Multiple Excutions?をYesに設定することで並行起動を許可することも可能です。

タイムアウト

データベースのロック、通信待ち等で起動したが終了しないジョブを検知することができます。ジョブ起動後設定したタイムアウト時間内に終了しない場合、失敗とみなされます。Send Notification設定を有効しておくことで、終了しない場合もエラーとして通知させることができます。

リトライ

ジョブが異常終了した際に指定した回数まで自動リトライします。デッドロック、通信エラー等の単純リトライで回避可能なエラーを回避することが出来ます。指定の回数リトライしても失敗し続けた場合はじめてジョブが失敗したとみなされます。

newjob1_11

親子型ジョブ

多数のステップを単一のジョブに設定してしまうと保守性がよくありません。ジョブの中から別のジョブを呼ぶ機能を使うことで、複数のステップをモジュール化することができます。

Add a stepする際にJob Referenceを選択すると他のジョブ名を設定することで、他のジョブを呼び出すことができます。ただしこの設定はジョブの名前をキーに呼び出します。呼び出される側のジョブ名を変更すると呼び出せなくなりますので注意してください。

newjob2_2

ホストをまたがったジョブの連携

ここまではRundeckがインストールされたサーバ上でジョブを実行していました。
次は複数のサーバ上のジョブを連動させてみましょう。

ホストの登録

まずプロジェクトにホストを登録します。
/var/rundeck/プロジェクト名/etc/resource.xml を作成し、以下の様なxmlファイルを配置します。

<?xml version="1.0" encoding="UTF-8"?>
<project>
<node name="name" type="Node" description="hostname-description" hostname="ip or hostname" username="root" tags="tag"/>
</project>

リモートホスト上のジョブは特にエージェント等は使用せずssh経由で実行します。リモートホストのusernameプロパティで指定したユーザに対して、プロジェクト作成時に設定した秘密鍵(/var/lib/rundeck/.ssh/id_rsa)でログインできるように設定してください。

ホストを登録することで、ジョブを登録する際に実行するホストが選択可能になります。
ジョブ登録時にNodesをExecute LocallyからDispatch to Nodesに変更し、Node Filterにホスト名又はホスト名のパターンを入力することで、ジョブが該当するホスト上で実行されます。

newjob2_3

実使用例

現在Rundeck上で稼働しているジョブがありますので紹介しておきましょう。

株式会社ロックオンが提供している各種Webサービス用の監視サーバ(VM)が社内にあるのですが、ESXi上のVMイメージをEC2上のストレージサーバへ定期バックアップするジョブの実行にRundeckを使用しています。

面倒なのは複数のサーバで決められた順序でバッチ処理を実行する必要があることです。Snapshotの取得やVMイメージの転送(rsync)はVSphereにSSHログインして実行していますが、ストレージサーバの操作はRundeckサーバからEC2 Cliを経由して行っています。全体構成と実行している内容は以下のとおりです。

newjob3_3

cronではなかなか難しい処理ですが今回はRundeckを使うことで、

  • 複数のサーバを連携させる
  • 失敗又は所定の時間内に終了しない場合の通知と以降の処理の停止
  • エラー時の自動リトライ
  • 処理中の標準出力、標準エラー、終了ステータスの保存

を簡単に実現することができました。

まとめ

他にもジョブスケジューラを検証したことがあるのですが、中途半端に機能不足だったり、逆に機能が多すぎたり、リソース消費が多すぎたりすることで簡単には導入できないものがほとんどでした。

Rundeckは機能的に過不足なく、また比較的設定も容易のため、今後のLinuxの標準的なジョブスケジューラとして使えるのではないでしょうか。インストールも簡単ですので、手近な環境で一度お試しください。

それでは本日はこの辺で。