Rundeck
ジョブスケジューラー
リモート管理
エージェントレス (ssh)
crond からの移行が容易
JVM ベース
RPM リポジトリの提供あり
ワークフローの概念があり、複雑なジョブを定義可能
柔軟すぎるので慣れが必要
認証
標準で realm ファイルの簡単な仕組みだけ
リバースプロキシで認証して資格情報を渡す機能はあり
導入
CentOS 7 向け
code:bash
yum install java-1.8.0
yum install rundeck
service rundeckd start
あっさり入った
各種設定
タイムゾーン
code:/etc/sysconfig/rundeckd
RDECK_JVM_OPTS=-Duser.timezone=Asia/Tokyo
セッションタイムアウト
ジョブ設定等で結構単画面に居座るため長めに
code:/etc/rundeck/rundeck-config.properties
server.session.timeout = 900
データベースを MariaDB にする
この手のは既定だとSQLite だったり HSQLDB だったりするので切り替える
データベースとユーザー作成
code:bash
mysql -p << '____________________'
CREATE DATABASE rundeck;
GRANT ALL ON rundeck.* TO 'rundeck'@'localhost' IDENTIFIED BY 'XYZXYZXYZ';
____________________
設定変更
code:/etc/rundeck/rundeck-config.properties
# MariaDB
dataSource.driverClassName = com.mysql.jdbc.Driver
dataSource.url = jdbc:mysql://localhost/rundeck?autoReconnect=true
dataSource.username = rundeck
dataSource.password = XYZXYZXYZ
この設定だけで全てデータベースになるわけではない
table:RDB に格納されてるっぽいもの
auth_token 発行した API トークン
base_report execution の結果
execution ジョブやコマンドの実行
node_filter 保存したノード絞り込みフィルタ
notification 通知の実行記録
plugin_meta プラグイン用。Git Export のコミットログなどがあった
rdoption ジョブのオプション設定
rdoption_values ジョブのオプションがリストの場合その候補値
rduser ユーザー。外部認証の場合動的に追加される
scheduled_execution ジョブ定義
workflow 実行時のジョブ情報
workflow_step 実行時のステップの情報
workflow_workflow_step 実行時ジョブがどのステップをどの順で実行したか
ストレージが入ってない
ノードソースが入ってない
管理者アカウントの変更
認証自体は JAAS を使っているのでデータベースとは無関係
既定では /etc/rundeck/realm.properties を使った認証
後で Google 認証に切り替えるので、ここでは Google 認証がダメな場合にログインできるように 1 ユーザーだけ登録する
/passwordUtility/index にアクセスしてハッシュパスワード生成
またはコマンドラインでハッシュパスワード生成
code:bash
java -jar /var/lib/rundeck/bootstrap/rundeck-3.0.7-20181008.war --encryptpwd Jetty
Required values are marked with: *
Username (Optional, but necessary for Crypt encoding):
super
*Value To Encrypt (The text you want to encrypt):
password
==ENCRYPTED OUTPUT==
obfuscate: OBF:xxxxxxxxxx
md5: MD5:yyyyyyyyyy
crypt: CRYPT:xxxxxxxxxx
ユーザーを追加し既定の admin を無効に
code:/etc/rundeck/realm.properties
super: MD5:yyyyyyyyyy,admin
code:bash
sudo systemctl restart rundeckd
SSH 接続用の秘密鍵を用意
ここに置かれているのは既定のキー
OpenSSH の既定のキー置き場になっているのでコマンド系との相性が良い
ただし、Rundeck は jsch-ssh を使うので、.ssh 系ディレクトリは既定でなく、known_hosts 等も参照していないようだ
code:bash
sudo -iu rundeck
ssh-keygen -t rsa -b 4096 -P ''
ssh-keygen -t ed25519 -P ''
ストレージ
Rundeck ではストレージファシリティ(コンテナ)とストレージプロバイダ(バックエンド)という概念がある
既定では Key Storage, Project Definition Storage の 2 種類のファシリティが定義されている
Key Storage
秘密鍵のストレージ
既定では file プロバイダなので、データはファイルとして格納される
Project Definition Storage
プロジェクト情報
既定では db プロバイダなので、データはデータベースに格納される(が……後述)
Key Storage
秘密鍵やパスワードを登録しておき別で参照する
特性上ファイルでもいいかな
Project Definition Storage
プロジェクトの設定情報
README
MOTD (Message of the day)
これだけっぽい
罠がある
既定では db プロバイダだが実際はファイルシステムに格納される
rundeck.projectsStorageType=db の設定もしないとデータベースに格納されない
プロジェクトが管理するファイルはストレージに格納するが、プロジェクト自体の存在情報はストレージにはない
データベースの場合 project に管理情報がある
ファイルベースの場合 project.etc.dir をスキャンして project.properties を見つけている
データベースに格納する場合 Project Description には英数字しか使えない
画面から日本語を入れるとよく分からない動作になる
初めて projectsStorageType=db に設定した際には file から自動移行されるが
Project Description に日本語が入っていると Validator のエラーで起動失敗する
Git Export の設定はインポートしてくれない
ジョブ定義はストレージの外
ノードソースの設定は入っている
ノードソースがファイル依存の場合はもちろんそのファイルは別途管理が必要
今回はファイルのままでよさそう
たいした情報量ではない
プロジェクトの説明に日本語入れたい
ノードソースがファイルなので、別途バックアップが必要で面倒
ノードの登録
仕組み
事前にノード定義 (XML, JSON, YAML) データ構造を用意する
ノード定義を一気に書く場合繰り返しが多いので YAML がお勧め
ノード定義を収集するプログラムがノードソース
Rundeck ではプロジェクトにノードソースを登録する
単一ファイルに全部書くなら File Source
それを Web に置くなら URL Source
ディレクトリ内に個別に書くなら Directory Source
収集するプログラムを書くなら Script Source
手早く
ファイルノードソースが使いやすそう
Add Source -> File
Format: resourceyaml
File Path: /var/rundeck/projects/${project.name}/nodes.yaml
/icons/check.icon Generate
/icons/check.icon Include Server Node
/icons/check.icon Require File Exists
/icons/check.icon Writeable
ファイルソースで登録したファイルは画面から編集可能になるので楽
ノードを絞り込む作業が頻発するので、役割に応じてうまく tags を設定しておくと楽になる
ローカルノードは Run Locally の際に使われるので、ローカルソースは残しておく(消してもノードは消えない)
ローカルはあくまでも管理ノードの位置づけ(実行ユーザーが rundeck になる)
ローカルノードとは別に Rundeck 自身をリモートノードとして追加しておくと便利
!hostname: localhost などの条件で All Remotes みたいなフィルタを既定として保存しておけばちょっと楽
code:nodes.yaml
foo.example.com: ¢os7
hostname: foo.example.com:port
username: rundeck
osArch: amd64
osFamily: unix
osName: Linux
osVersion: centos7
tags: update,httpd,mysql
bar.example.com:
<<: *centos7
hostname: foo.example.com:port
tags: update,nginx
baz.example.com: ¢os6
<<: *centos7
hostname: bar.example.com:port
osVersion: centos6
tags: update,httpd,mysql,letsencrypt
ノードに直接 ssh できない場合は結構困る
Rundeck は jssh なので、.ssh/config 等による制御が効かない
Rundeck に対して透過的に振る舞うためには、踏み台サーバーに専用アカウントを作りそこから ForceCommand が楽
将来この値によって処理が変わる可能性があるので unix にしておく
残りはRundeck が Java ベースなので Java のシステムプロパティに合わせておくと安全
code:java -XshowSettings:properties -version 2>&1 | grep os\\.`
os.arch = amd64
os.name = Linux
os.version = 3.10.0-862.14.4.el7.x86_64
sun.os.patch.level = unknown
とはいえ、osVersion は判定に使わないと思うので、ノード絞り込み用に OS の短い名前等登録しておくと便利
管理対象のサーバーにユーザーを作成
必要なコマンドはパスワード無しで sudo できるように
!requiretty も忘れずに
ジョブ
名前を持つ
プロジェクトに属する
起動単位で、処理の流れ(ワークフロー)を定義
起動引数(オプション)を定義可能
一度に複数のノードで実行可能(ノードフィルタ)
crond に似た記述で定期実行が可能
管理について
プロジェクト配下に作成するが、管理はプロジェクトとは独立して 既定のデータベースに格納されている
プロジェクトに Git Export プラグインを設定することでジョブ設定画面が Git に統合される。超便利
Git Export プラグインで外部 Git リポジトリの URL や認証情報を設定することで利用可能
内部で使われている jgit だと新形式の openssh PEM がデコードできないようだ。ed25519 キーが使えない
ノードフィルタ
ジョブが持つ処理対象となるノードを絞り込む条件式のこと
tags: httpd osFamily: unix のような式
Dispatch to Nodes の場合、ノードフィルタ式によって対象ノードが決まる
ジョブ起動の際に追加で絞り込んだりオーバーライドしたりすることも可能
Execute locally の場合、ノードフィルタは使われず、常に localhost ノード 1 つが対象となる
Execute locally だと後述の job.filter 変数の問題が生じる
ジョブステップ
処理単位
複数登録すると順に実行される
ステップには 2 種類ある
Node Steps は対象となるノード毎に実行される
Workflow Step はノードフィルタに関係なく 1 度だけ実行される
標準出力と標準エラーはキャプチャされログに記録される
ステップには Error Handler と Log Filter をオプションで登録可能
Error Handler はステップが失敗した際に実行する別のステップ
Log Filter はステップの標準出力を加工したり解析したりする
Highlight Output Filter で出力に色をつける
Key Value Data Filter で標準出力からコンテキスト変数を定義し、次のステップで参照可能
多彩なステップが用意されている
コンテキスト変数を参照して再利用性の高い設定が可能
大半の場所では ${} 記法が使える
${node.XXXX} 実行対象のノード情報
${job.XXXX} ジョブの情報
${option.XXXX} 起動オプション値(オプションを定義した場合のみ)
job.filter コンテキスト変数について
ジョブに設定されたノードフィルタ式が入っている
Dispatch to Nodes の場合はこの値が実効値となる
ジョブ起動の際に追加で絞り込んだりオーバーライドしたりした場合は、変更後の値が入る
Execute locally の場合もジョブに設定された値になっているが実行とは関係ない
この場合、この変数値を参照して処理を書くと不具合の元になるので注意を要する
job.filter 変数を使う場合、Execute locally はできるだけ使わないことをお勧めする
job.filter 変数が生きるのは、後述の Job reference Step
Command Step - Node Steps
指定したコマンドをシェルで実行
Rundeck がコマンドラインを構築してノード上でコマンドを実行する
sudo yum -y update とか
リモートの場合ノード定義を参照して透過的に SSH してくれる
コマンドが複雑になりそうなら次の Script の方が安心
コマンド定義のコンテキスト変数は ${} 記法
Script Step - Node Steps
直接スクリプトを書ける (Shebang 可)
Rundeck が転送して一時ファイルを生成しノード上で実行
Command Step より複雑なものが実行可能
スクリプト引数や処理系の指定も可能
管理しにくいが自由度が高い
スクリプト内部のコンテキスト変数参照は 2 種類の記法がある
@job.id@ 文字列としてファイル生成前に展開される
$RD_JOB_ID 文字列展開ではなく環境変数として参照できる(シェルの場合)
スクリプト内部では ${} 記法は認識しない。bash の展開と被っても安心
Script file or URL Step - Node Steps
Rundeck サーバー上のファイルか URL にあるスクリプトを指定
Rundeck が転送して一時ファイルを生成しノード上で実行
スクリプト引数や処理系の指定も可能
ファイル名や URL にコンテキスト変数が使える
Script Step と違ってファイルは書き換えずに転送されるため、スクリプト内では環境変数参照のみ使える
Job reference Step - Node Steps / Workflow Steps
他のジョブ参照をジョブステップに組み込める
ワクワクする(柔軟すぎて危険)
Node Steps / Workflow Steps どちらの実行でも可能
特に Node Steps に設定した場合は、現ジョブの対象ノードの回数 (M) 実行されることに注意
被参照ジョブが複数のノードを対象 (N)として実行する場合は M * N 回実行される
参照側の設定で被参照ジョブのノードフィルタを変更(オーバーライド)して実行することが可能
Job reference Step で実行した場合、job.filter コンテキスト変数について特別な制御がある
被参照ジョブ上の変数値は常に呼び出し元ジョブの job.filter 値になる
変数の値が変わるだけで、被参照ジョブ上のノードフィルタには影響しない
被参照ジョブに元々設定されたノードフィルタは機能する
参照側の設定でノードフィルタの設定をオーバーライドすることも可能
その場合でもフィルタは機能するが、変数値は呼び出し元ジョブの job.filter 値のまま
つまり、被参照ジョブ上においては例え Dispatch to Nodes モードであってもjob.filter が実効値とは限らない
被参照ジョブのノードフィルタと変数値を揃えない場合は、job.filter の値を使って処理してはいけない
参照定義において被参照ジョブのノードフィルタを ${job.filter} としてオーバーライドするか、被参照ジョブの元々の定義においてノードフィルタを ${job.filter} に設定して保存しておけば、変数値とノードフィルタが揃い、呼び出し元のノードフィルタを実効値として引き継ぐことができる
呼び出し側の対象ノードは可変だが、その状態で Workflow Steps の他のジョブに処理を委譲したい際に便利
特に後者の設定だとオーバーライド設定が不要になり再利用しやすい
ただしこのジョブは Editable filter を yes にしない限り直接起動できないジョブになってしまう
Copy File Step - Node Steps
Rundeck ローカルファイルをノードにコピー
ローカル側は rundeck.base 配下のパスしか書けない
ディレクトリごと転送も可能
ノードからローカルへの転送はできない
Local Command Step - Node Steps
例えリモートノードが実行対象であっても常に Rundeck ローカルでコマンドを実行する
実行結果を受けてデータ更新するなど
コンテキスト変数は環境変数として渡される
シェルではなくコマンド
スクリプトを書くには /bin/bash -c が必要
システム自体の環境変数がほぼ空っぽ。 HOME が必要なコマンドに注意
ノードからローカルに転送するためにはこれを使うしかない
ノードの変数 $RD_NODE_HOSTNAME は host:port なので対策が必要
Rundeck ローカルにヘルパースクリプトを書いておくと使いやすい
code:sh
set -euo pipefail
export HOME=/var/lib/rundeck
HOST="${RD_NODE_HOSTNAME%%:*}"
PORT="${RD_NODE_HOSTNAME:${#HOST} + 1}"
PORT="${PORT:-22}"
USER="$RD_NODE_USERNAME"
scp -P "$PORT" "$USER@$HOST:foo" "bar"
Slack 通知
雑多
ユーザーデータベース rduser は動的
前段で認可を通ったユーザーの情報が登録される
最初にログイン成功した段階で内部 ID が割り振られる
ユーザーレコードを勝手に削除すると不具合が出る(そりゃそうか)