筆者が開発している Koyomi という、分散ジョブスケジューラのインストール、使用方法について解説するチュートリアル・ドキュメントです。
今回は Vagrant を使ってまっさらな CentOS 7 の環境に Koyomi をインストールし、systemd1の service として起動します。
その上で、ジョブを登録して実行するところまでやってみます。
このチュートリアルを通して、Koyomi が cron のように動作することがわかると思います。
本稿執筆時点の Koyomi のバージョンは 0.5.1 です。
Vagrant による CentOS 7 環境構築
http://www.vagrantbox.es/ で配布されている Vagrantbox を使います。
以下のコマンドは MacOS X 上で実行しました。環境に応じて、適宜読み替えて下さい。
vagrant box add centos7 https://github.com/holms/vagrant-centos7-box/releases/download/7.1.1503.001/CentOS-7.1.1503-x86_64-netboot.box
mkdir ~/Vagrant/centos7
cd ~/Vagrant/centos7
vagrant init centos7
vagrant up
vagrant ssh
で VM にログインできます。
CentOS 7 VM Setup
ここからは上で作成した Vagrant による CentOS 7 の環境で作業していきます。
vagrant ユーザで作業します。
plenv と Perl 5.22.0 インストール
VM に plenv2 と Perl 5.22.0 をインストールします。
git clone git://github.com/tokuhirom/plenv.git ~/.plenv
echo 'export PATH="$HOME/.plenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(plenv init -)"' >> ~/.bash_profile
exec $SHELL -l
git clone git://github.com/tokuhirom/Perl-Build.git ~/.plenv/plugins/perl-build/
plenv install 5.22.0
Koyomi インストール & セットアップ
インストールガイドでは、GitHub または CPAN からインストールする方法を紹介しています。
今回は GitHub 上の master ブランチの HEAD を用いますが、通常は最新の安定版を取得することを推奨します。
git clone git@github.com:key-amb/perl5-App-Koyomi.git ~/koyomi
cpanm, Carton を Perl 5.22.0 にインストールしておく
plenv を使って、~/koyomi
以下では Perl 5.22.0 を使うようにします。
また、下準備として cpanm3 と Carton
4 を Perl 5.22.0 にインストールしておきます。
cd ~/koyomi
plenv local 5.22.0
plenv install-cpanm
cpanm -v Carton
plenv rehash
依存モジュールのインストール
Carton を使って local/
に Koyomi の依存モジュールをインストールします。
依存モジュールが多いので、初回は少々時間が掛かるかと思います。
cd ~/koyomi
carton install
Configure
今回はデフォルトの config/default.toml
を使います。
設定ファイルを次のように編集します。
$ cd ~/koyomi
$ git diff config/default.toml
diff --git a/config/default.toml b/config/default.toml
index 1ef5b29..58c2ec0 100644
--- a/config/default.toml
+++ b/config/default.toml
@@ -4,7 +4,7 @@
#debug_mode = true
[log]
-#debug = true
+debug = true
console = true
file = true
# file_path = /path/to/log
@@ -27,13 +27,13 @@ lock_ttl_seconds = 25
[datasource.module]
job = "Teng"
-semaphore = "Teng"
-#semaphore = "None"
+#semaphore = "Teng"
+semaphore = "None"
[datasource.connector]
-dsn = "dbi:mysql:database=koyomi;host=127.0.0.1;port=3306"
-#dsn = "dbi:SQLite:tmp/koyomi.sqlite"
-user = "root"
+#dsn = "dbi:mysql:database=koyomi;host=127.0.0.1;port=3306"
+dsn = "dbi:SQLite:tmp/koyomi.sqlite"
+user = "" # "root"
password = ""
# Can override for each entity
設定ファイルの詳細については、ドキュメントを参照して下さい。
SQLite に DB 作成
今回は簡単のため、ジョブのデータストアとして SQLite を使います。
リポジトリに同梱している DDL を発行して、DB を作成します。
cat schema/sqlite/koyomi.ddl | sqlite3 tmp/koyomi.sqlite
sqlite3
コマンドが見つからない場合、yum install sqlite
などとしてインストールして下さい。
以上で、koyomi
を動かすための準備は完了です。
koyomi を動かす
ここでは Makefile
に定義したタスクを使って手動で worker を実行します。
$ make worker
carton exec perl -Ilib script/koyomi
2015-06-20T22:20:53 [DEBUG] bless( {'datasource' => {'connector' => {'dsn' => 'dbi:SQLite:tmp/koyomi.sqlite','password' => '','user' => ''},'module' => {'job' => 'Teng','semaphore' => 'None'}},'debug' => {'worker' => {'sleep_seconds' => 5}},'job' => {'lock_ttl_seconds' => 25},'log' => {'console' => 'true','debug' => 'true','file' => 'true'},'schedule' => {'update_interval_seconds' => 120},'worker' => {'interval_minutes' => 1,'minimum_interval_seconds' => 30}}, 'App::Koyomi::Config' ) at lib/App/Koyomi/Config.pm line 30
2015-06-20T22:20:53 [DEBUG] update schedule at lib/App/Koyomi/Schedule.pm line 46
2015-06-20T22:20:53 [DEBUG] 2015-06-20T22:20:53 Sat at lib/App/Koyomi/Schedule.pm line 67
無事に起動しました。
デバッグログを有効にしているので、出力が多めになっています。
この時点では、まだ1つもジョブを登録していません。
一旦、Ctrl-C で worker プロセスを中断しておいて下さい。
Koyomi を Systemd の Service として動かす
koyomi
は daemon として使われることを想定していますが、 koyomi
単体では自らを daemon 化する方法を提供していません。
daemontools など外部のツールを用いる必要があります。
今回は koyomi
を systemd1 の service として動かしてみます。
Unit 定義ファイル作成
次のような Unit 定義ファイルを作成しました。
$ cat /etc/systemd/system/koyomi.service
[Unit]
Description=koyomi daemon
[Service]
User=vagrant
Group=vagrant
ExecStart=/home/vagrant/koyomi/tmp/koyomi.sh
[Install]
WantedBy=multi-user.target
起動スクリプト作成
koyomi
を起動するため、次のようなシェルスクリプトを作成しました。
$ cat /home/vagrant/koyomi/tmp/koyomi.sh
# !/bin/sh
set -e
HOME=/home/vagrant
KOYOMI=${HOME}/koyomi
CARTON=${HOME}/.plenv/versions/5.22.0/bin/carton
eval "$(${HOME}/.plenv/bin/plenv init -)"
cd $KOYOMI && \
$CARTON exec perl -Ilib script/koyomi
以上で、koyomi
を systemd で動かすための準備は完了です。
Service の起動
systemctl コマンドを使って service を有効化し、起動します。
sudo systemctl enable koyomi
sudo systemctl start koyomi
systemctl status
で起動したことを確認できます。
$ sudo systemctl status koyomi
koyomi.service - koyomi daemon
Loaded: loaded (/etc/systemd/system/koyomi.service; enabled)
Active: active (running) since 土 2015-06-20 23:23:51 JST; 2min 55s ago
Main PID: 5129 (koyomi.sh)
CGroup: /system.slice/koyomi.service
├─5129 /bin/sh /home/vagrant/koyomi/tmp/koyomi.sh
└─5173 perl -I lib script/koyomi
6月 20 23:23:51 localhost.localdomain systemd[1]: Started koyomi daemon.
6月 20 23:23:52 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:23:52 [DEBUG] bless( {'datasource' => {'connector' => {'dsn' => 'dbi:SQLite:tm... {'conso
6月 20 23:23:52 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:23:52 [DEBUG] update schedule at lib/App/Koyomi/Schedule.pm line 46
6月 20 23:23:52 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:23:52 [DEBUG] 2015-06-20T23:23:52 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:24:22 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:24:22 [DEBUG] no need to update schedule at lib/App/Koyomi/Schedule.pm line 42
6月 20 23:24:22 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:24:22 [DEBUG] 2015-06-20T23:24:22 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:25:00 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:25:00 [DEBUG] no need to update schedule at lib/App/Koyomi/Schedule.pm line 42
6月 20 23:25:00 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:25:00 [DEBUG] 2015-06-20T23:25:00 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:26:00 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:26:00 [DEBUG] update schedule at lib/App/Koyomi/Schedule.pm line 46
6月 20 23:26:00 localhost.localdomain koyomi.sh[5129]: 2015-06-20T23:26:00 [DEBUG] 2015-06-20T23:26:00 Sat at lib/App/Koyomi/Schedule.pm line 67
Hint: Some lines were ellipsized, use -l to show in full.
koyomi-cli を用いたジョブの登録
せっかくなので、1つジョブを登録することにします。
koyomi-cli add
を実行するとエディタ(vi
)が起動し、予めフォーマットされた YAML を編集する画面になります。
YAML を編集して保存することで、ジョブを登録します。
今回は echo $(date) alive >> /tmp/tick.log
というコマンドを毎分実行するジョブを登録してみます。
$ cd ~/koyomi
$ carton exec perl -Ilib script/koyomi-cli add
:
# (エディタ起動)
---
command: 'echo $(date) alive >> /tmp/tick.log'
memo: ''
times:
- '*/*/* *:* (*)'
user: ''
# __EOF__
# Format and Description:
# "command": String. Job as shell command to execute.
# "memo": String. You can add comment about the job on this field.
# "times": Array. Each entry follows this format:
# - 'YYYY/mm/dd HH:MM (number of day in week)'
# Examples:
# - '2015/*/* 0:0 (7)' ... At 0:00 am every sunday in 2015
# - '*/*/* *:30 (*)' ... At 30 minutes after every o'clock
# "user": String. OS user to execute the command. Leave it blank to execute by the user of worker
:
"/tmp/Ekdf40ta3e" 17L, 612C written
---
command: echo $(date) alive >> /tmp/tick.log
memo: ''
times:
- '*/*/* *:* (*)'
user: ''
Add this job. OK? (y/n) [n] y
2015-06-20T23:55:48 [INFO] [add] Finished. at lib/App/Koyomi/CLI.pm line 103
koyomi-cli list
で登録されたジョブを確認できます。
$ koyomi-cli list
.-------------------------------------------------------------------------------.
| id | user | command | Y | m | d | H | M | weekday |
+----+------+-------------------------------------+---+---+---+---+---+---------+
| 1 | | echo $(date) alive >> /tmp/tick.log | * | * | * | * | * | * |
'----+------+-------------------------------------+---+---+---+---+---+---------'
デフォルトの設定ではジョブの登録・削除・変更は約2分後に daemon に反映されます。
数分後に journalctl
コマンドでログを確認してみます。
$ sudo journalctl -n 100
6月 20 23:55:16 localhost.localdomain sudo[5410]: vagrant : TTY=pts/1 ; PWD=/home/vagrant/koyomi ; USER=root ; COMMAND=/bin/systemctl restart koyomi
6月 20 23:55:16 localhost.localdomain systemd[1]: Stopping koyomi daemon...
6月 20 23:55:16 localhost.localdomain systemd[1]: Starting koyomi daemon...
6月 20 23:55:16 localhost.localdomain systemd[1]: Started koyomi daemon.
6月 20 23:55:17 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:55:17 [DEBUG] bless( {'datasource' => {'connector' => {'dsn' => 'dbi:SQLite:tmp/koyomi.sql
6月 20 23:55:17 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:55:17 [DEBUG] update schedule at lib/App/Koyomi/Schedule.pm line 46
6月 20 23:55:17 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:55:17 [DEBUG] 2015-06-20T23:55:17 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:56:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:56:00 [DEBUG] no need to update schedule at lib/App/Koyomi/Schedule.pm line 42
6月 20 23:56:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:56:00 [DEBUG] 2015-06-20T23:56:00 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:57:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:57:00 [DEBUG] no need to update schedule at lib/App/Koyomi/Schedule.pm line 42
6月 20 23:57:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:57:00 [DEBUG] 2015-06-20T23:57:00 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:58:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:58:00 [DEBUG] update schedule at lib/App/Koyomi/Schedule.pm line 46
6月 20 23:58:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:58:00 [DEBUG] (id,user,command) = (1,<NULL>,"echo $(date) alive >> /tmp/tick.log") at lib/
6月 20 23:58:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:58:00 [DEBUG] 2015-06-20T23:58:00 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:58:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:58:00 [INFO] 5589 1 USER=vagrant COMMAND="echo $(date) alive >> /tmp/tick.log" at lib/App/
6月 20 23:58:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:58:00 [INFO] 5589 1 Succeeded. at lib/App/Koyomi/Job.pm line 69
6月 20 23:59:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:59:00 [DEBUG] no need to update schedule at lib/App/Koyomi/Schedule.pm line 42
6月 20 23:59:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:59:00 [DEBUG] 2015-06-20T23:59:00 Sat at lib/App/Koyomi/Schedule.pm line 67
6月 20 23:59:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:59:00 [INFO] 5595 1 USER=vagrant COMMAND="echo $(date) alive >> /tmp/tick.log" at lib/App/
6月 20 23:59:00 localhost.localdomain koyomi.sh[5414]: 2015-06-20T23:59:00 [INFO] 5595 1 Succeeded. at lib/App/Koyomi/Job.pm line 69
登録されたジョブが読み込まれ、実行されている様子がわかります。
/tmp/tick.log
も見てみましょう。
$ cat /tmp/tick.log
Sat Jun 20 23:58:00 JST 2015 alive
Sat Jun 20 23:59:00 JST 2015 alive
Sun Jun 21 00:00:00 JST 2015 alive
Sun Jun 21 00:01:00 JST 2015 alive
Sun Jun 21 00:02:00 JST 2015 alive
Sun Jun 21 00:03:00 JST 2015 alive
:
まとめ
CentOS 7 の環境に Koyomi をインストールし、systemd の service として動かしてみました。
Koyomi が動くこと、cron のように使えることがわかった(わかる)のではないかと思います。
ここでは SQLite の例を示しましたが、ジョブのデータストアとしてリモートサーバの MySQL を用いれば、ジョブの実行プロセスを冗長化することも出来ます。
Koyomi はまだ生まれたばかりのプロダクトなので、機能の不足などあるかと思います。
引き続き開発していくつもりですが、何かフィードバックがあれば是非お寄せ下さい。
Have fun!!