オープンソースのPaaSソフトウェア CloudFoundry の技術情報やイベント告知などを掲載します

2015-11-09

Rundeck を Cloud Foundry で動かす

「Cloud Foundry 百日行」第95日目,今日は最近注目されているジョブ・スケジューラー Rundeck です。Webベースのジョブ・スケジューラーといえば, 92日目に webcrontab を紹介 しましたが,Rundeck はこれと比べるとずっと本格派で,最近はインフラ周りの管理に使われることも増えているようです。

基本情報

手順の概要は以下の通りです。

  • 1) Buildpack の修正
  • 2) 各種設定ファイル/スクリプトの作成
  • 3) サービスの作成とバインド及び接続設定
  • 4) アプリのデプロイ
  • 5) 動作確認

1. Buildpack の修正

JAR ファイルを使っていることからもわかるように,このアプリは Java で書かれているのですが,

という理由から, Cloud Foundry 標準の java-buildpack は使えないことがわかりました。

そこで JAR ファイルを直接起動できる buildpack を探した結果, energizedwork/heroku-buildpack-runnable-jar を見つけました。

この buildpack は,アプリケーションの JAR ファイルをステージング時にダウンロードすることが前提なので,今回はコードの取得も不要になりました。

ただ,1つだけ問題が。

この buildpack にはデプロイの事前処理を行う機能があり,さらにそれをオプションでスキップできるようになっているのですが,バグ(と思われる問題)があってスキップが正常に行えず,Rundeck の場合ステージングが正常終了しません。

そこで,スキップが正常に行えるようにコードの修正を行いました。オリジナルのバージョンは検証時点の master ブランチのヘッド ( https://github.com/energizedwork/heroku-buildpack-runnable-jar/tree/a736a0571ab050815c287cef5bdf74a3a6e59152 ) で,それとの差分は以下の(実質)1行です。

$ git diff a736a05
diff --git a/bin/compile b/bin/compile
index f729d59..fa327fb 100755
--- a/bin/compile
+++ b/bin/compile
@@ -17,6 +17,8 @@ BUILD_DIR=$1
 CACHE_DIR=$2
 ENV_DIR=$3

+source ${BUILD_DIR}/manifest.sh
+
 GRADLE_TASK=${GRADLE_TASK-stage}

 export_env_dir $ENV_DIR

この修正を施した buildpack を,

に push しました。

2. 各種設定ファイル/スクリプトの作成

2.1. Buildpack用設定ファイルの作成

前節で述べた通り,今回の buildpack では

  • アプリの JAR ファイルをダウンロードするので,その URL を指定
  • デプロイの事前処理をスキップするように設定

する必要があります。

これらの設定は manifest.sh という shell スクリプト・ファイルに書くことになっているので,最終的に以下の内容の manifest.sh ファイルを作成しました(この辺りの説明は README.md には書かれていなかったので, bin/ 下のスクリプト から直接読み解きました)。

$ cat manifest.sh
export ARTIFACT_URL=http://download.rundeck.org/jar/rundeck-launcher-2.6.1.jar
export NO_PRE_DEPLOY=true

2.2. 起動スクリプトの作成

今回使う buildpack はデフォルトの起動スクリプトを持たないので,Procfile もしくはコマンドで起動方法を指定する必要があります。

単に java コマンドに -jar で JAR ファイルを渡せば済む,のであればよかったのですが,残念ながらそれではメモリ設定が固定値になってしまうので,割り当てられたメモリに合わせて起動スクリプト側でメモリ設定を計算するようにしました。

計算は Cloud Foundry 標準の java-buildpack のやりかたをベースにしました。

最終的に出来上がった起動スクリプトは以下の通りです。

$ cat start.sh
#!/bin/bash

set -x

## Calculate memory actually assigned to Java process
## '* 75 / 110' comes from:
##   - https://github.com/cloudfoundry/java-buildpack-memory-calculator/blob/6a7690ba8d6ae97b0c87209f22a2ad09d6098504/memory/allocator.go#L179-L181
##   - https://github.com/cloudfoundry/java-buildpack/blob/485c4552f9465b7e4dcf0acb0bdab43087e4637b/config/open_jdk_jre.yml#L32-L37
mem=$(echo $MEMORY_LIMIT | perl -ne '/(\d+)([gmk])/; $mx = $1; $factor = $2; if ($factor eq "g") { $mx = $mx * 1024 * 1024 } elsif ($factor eq "m") { $mx = $mx * 1024 }; print (int($mx))')
heap=$(($mem * 75 / 110))
stack=$(($mem * 5 / 110))

export JAVA_TOOL_OPTIONS="-Xmx${heap} -Xss${stack} -Dfile.encoding=UTF-8"

java -Dserver.http.port=$PORT -jar application.jar

なお,このメモリ設定の計算は,本来なら buildpack 側で行うべき処理ですが,試してみたものの環境変数の引き渡しがうまくいかなかったため,今回は諦めて起動スクリプト側で計算/設定を行うことにしました。

2.3. アプリケーション・マニフェストの作成

必須ではありませんが,push 時の指定オプションが多いので,アプリケーションの各種設定をまとめたマニフェスト・ファイルも作りました。内容は以下の通りです。

$ cat manifest.yml
applications:
  - name: rundeck
    command: "./start.sh"
    buildpack: "https://github.com/nota-ja/heroku-buildpack-runnable-jar.git#cf-100-day-challenge-095"
    memory: 1536m
    services:
      - mysql-rundeck

Buildpack として1節で修正したものを,起動スクリプトとして2.2節で作成したものを指定しています。またメモリ容量は試行錯誤の結果1.5GBとしました。サービスについては,次の節で述べます。

3. サービスの作成とバインド及び接続設定

本アプリはデータの永続化に DBMS を使います。DBMS については, 公式のマニュアル で MySQL について詳しく述べてあることから,今回は MySQL を使うことにしました。

3.1. MySQLサービスの作成

manifest.yml に指定したのと同じ名前でサービスを作成します。

$ cf create-service p-mysql 100mb mysql-rundeck
Creating service instance mysql-rundeck in org nota-ja / space 100 as nota-ja...
OK

3.2. アプリのアップロード及びバインド

アプリを非起動状態で push します。manifest.yml があるので,自動的に bind まで行われます。

$ cf push --no-start
Using manifest file /home/nota-ja/repos/rundecks/rundeck-jar/manifest.yml

Creating app rundeck in org nota-ja / space 100 as nota-ja...
OK

Using route rundeck.10.244.0.34.xip.io
Binding rundeck.10.244.0.34.xip.io to rundeck...
OK

Uploading rundeck...
Uploading app files from: /home/nota-ja/repos/rundecks/rundeck-jar
Uploading 2K, 7 files
Done uploading
OK
Binding service mysql-rundeck to app rundeck in org nota-ja / space 100 as nota-ja...
OK

3.3. DBMS接続及びその他の設定ファイルの作成

本アプリは DBMS の接続情報を環境変数から取得する機能がないため,通常どおり設定ファイルから読み込めるよう,ファイルを作成する必要があります。 公式サイトのマニュアル の記述に沿って,server/config/rundeck-config.properties というファイルを作成し,そこに設定を記述します。

接続情報は cf env を使って取得します。

$ cf env rundeck
..
 "VCAP_SERVICES": {
  "p-mysql": [
   {
    "credentials": {
     "hostname": "10.244.7.6",
     "jdbcUrl": "jdbc:mysql://10.244.7.6:3306/cf_fefc58cd_f912_4324_9117_caa3aefb5fe1?user=32KOFnad6F1BmBJU\u0026password=77Fi15F6RNbggaKj",
     "name": "cf_fefc58cd_f912_4324_9117_caa3aefb5fe1",
     "password": "77Fi15F6RNbggaKj",
     "port": 3306,
     "uri": "mysql://32KOFnad6F1BmBJU:77Fi15F6RNbggaKj@10.244.7.6:3306/cf_fefc58cd_f912_4324_9117_caa3aefb5fe1?reconnect=true",
     "username": "32KOFnad6F1BmBJU"
    },
    "label": "p-mysql",
    "name": "mysql-rundeck",
    "plan": "100mb",
    "tags": [
     "mysql"
    ]
   }
  ]
 }
}
..

併せて,アプリの正常な動作に必要と思われるサーバーURL (grails.serverURL) の設定もこのファイルで行います。

最終的に server/config/rundeck-config.properties は以下のようになりました。

$ cat server/config/rundeck-config.properties
grails.serverURL = http://rundeck.10.244.0.34.xip.io

dataSource.url = jdbc:mysql://10.244.7.6:3306/cf_fefc58cd_f912_4324_9117_caa3aefb5fe1?user=32KOFnad6F1BmBJU&password=77Fi15F6RNbggaKj
dataSource.username = 32KOFnad6F1BmBJU
dataSource.password = 77Fi15F6RNbggaKj
dataSource.dbCreate = update
rundeck.projectsStorageType = db

VCAP_SERVICESjdbcUrl 内にあった \u0026 は,設定ファイルの dataSource.url では & に置き換えています。

4. アプリのデプロイ

準備が整ったので,アプリをデプロイします。アプリケーション・マニフェストがあるので, cf push のみでOKです。

$ cf push
Using manifest file /home/nota-ja/repos/rundecks/rundeck-jar/manifest.yml

Updating app rundeck in org nota-ja / space 100 as nota-ja...
OK
..
0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK

App rundeck was started using this command `./start.sh`

Showing health and status for app rundeck in org nota-ja / space 100 as nota-ja...
OK

requested state: started
instances: 1/1
usage: 1.5G x 1 instances
urls: rundeck.10.244.0.34.xip.io
last uploaded: Mon Nov 9 10:34:42 UTC 2015
stack: cflinuxfs2
buildpack: https://github.com/nota-ja/heroku-buildpack-runnable-jar.git#cf-100-day-challenge-095

     state     since                    cpu    memory           disk      details
#0   running   2015-11-09 07:36:04 PM   1.1%   920.2M of 1.5G   0 of 1G

起動しました。

5. 動作確認

アプリ起動後,ブラウザーでアプリのURLにアクセスすると,ログイン画面に遷移するので,ユーザー名とパスワードを入力してログインします。デフォルトのユーザー名/パスワードは, 公式マニュアル によると admin / admin です:

ログインに成功するとホーム画面に遷移します:

【New Project+】をクリックして,プロジェクトを作成してみます。

とりあえず【Project Name】と【Description】以外はデフォルトのままです:

【Create】ボタンをクリックするとプロジェクトが作成され,プロジェクトのジョブ一覧画面に遷移します:

【Create a new Job…】をクリックして,ジョブを作成してみます。

【Job Name】と【Description】を適当に入力します:

【Add a Step】で【Command】を選択し,

echodate を使ったコマンドを入力して【Save】します:

残りの設定は全てスキップして【Create】ボタンをクリックします:

ジョブが作成されました:

【Run Job Now】をクリックしてジョブを実行してみます。

成功しました:

【Log Output】タブをクリックすると,出力が表示されます:

想定通りの出力になっていました。

以上で動作確認は終わりです。多機能すぎるのでこれ以上の確認は時間的に無理でしたが,試した範囲での動作に問題はありませんでした。

このアプリは,基本的にデータを DBMS に格納するようなので, Jenkins と違って Cloud Foundry 上でも本格利用ができるかもしれません。また当然ながら,Jenkins と同様に,簡単に試して捨てられるジョブの試験環境としても使うことができると思います。

今回使用したソフトウェア