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

Masteries

技術的なことや仕事に関することを書いていきます.

「Walter」を試していたのでまとめた

Walterは, Goで書かれた「ビルドパイプライン」ツールです.

JenkinsなどでCIを行う場合, 複数のジョブを連携して, 一連の処理の流れを作ることがあります. これを「ビルドパイプライン」と呼び, Jenkinsにはビルドパイプラインを作る為のプラグインが幾つか提供されています.

Walterは, Jenkinsに依存しない形で, 「ビルドパイプライン」をよりシンプルに, かつコードで指定出来るようにしたツールです(Jenkinsで「ビルドパイプライン」を設定する場合, 大抵ブラウザでJenkinsをポチポチする必要があります...).

詳しくは,

などなど参考にしながら, 実際に手を動かしながら試してみるのが良さそうです.

インストール

というわけで早速インストールしましょう. WalterはGo製のツールであり, ワンバイナリで動作します.

バイナリは, Walterのリポジトリ配布されているので, ここからダウンロードするのが手っ取り早いでしょう. Linux系の64bit OSであれば, 「walter_x.x.x_linux_amd64.tar.gz」でOKです.

また, Homebrewでインストールすることも可能です:

$ brew tap higanworks/homebrew-walter-binary 
$ brew install walter

問題なくインストールできれば, walterというコマンドが利用可能になります. これで準備OKです.

設定ファイル: pipeline.yml

Walterは, pipeline.ymlという設定ファイルを利用します.

pipeline:
  - name: command_stage_1
    type: command
    command: echo "hello, world"

pipeline.ymlを設置したディレクトリで, walterコマンドを実行すると, この設定に従って処理を実行してくれます(-cオプションで, 任意のYAMLファイルを利用することもできます).

$ walter
11:34:30  INFO Pipeline file path: "./pipeline.yml"
11:34:30  INFO not found "require" block
11:34:30  INFO not found "service" block
11:34:30  INFO local client was created
11:34:30  INFO not found messenger block
11:34:30  INFO not found cleanup block in the input file
11:34:30  INFO running Walter
11:34:30  INFO Starting Walter in local mode
11:34:30  INFO Preparing to run pipeline process...
11:34:30  INFO [command] exec: command_stage_1
11:34:30  INFO [command_stage_1][command] exec output: hello, world
11:34:30  INFO Finished running pipeline process...
11:34:30  INFO Preparing to run cleanup process...
11:34:30  INFO Finished running cleanup process...
11:34:30  INFO succeded to finish Walter

pipeline.ymlで指定したコマンド(単なるechoですが...)が, ここで実行されていることがわかります.

11:34:30  INFO [command] exec: command_stage_1
11:34:30  INFO [command_stage_1][command] exec output: hello, world

処理の逐次実行

次のように記述すれば, 処理を逐次(上から順番に)実行することができます.

pipeline:
  - name: command_stage_1
    type: command
    command: echo "hello, world"
  - name: command_stage_2
    type: command
    command: echo "こんにちは世界"

実行すると, 次のようになります:

11:37:53  INFO Pipeline file path: "./pipeline.yml"
11:37:53  INFO not found "require" block
11:37:53  INFO not found "service" block
11:37:53  INFO local client was created
11:37:53  INFO not found messenger block
11:37:53  INFO not found cleanup block in the input file
11:37:53  INFO running Walter
11:37:53  INFO Starting Walter in local mode
11:37:53  INFO Preparing to run pipeline process...
11:37:53  INFO [command] exec: command_stage_1
11:37:53  INFO [command_stage_1][command] exec output: hello, world
11:37:53  INFO [command] exec: command_stage_2
11:37:53  INFO [command_stage_2][command] exec output: こんにちは世界
11:37:53  INFO Finished running pipeline process...
11:37:53  INFO Preparing to run cleanup process...
11:37:53  INFO Finished running cleanup process...
11:37:53  INFO succeded to finish Walter

command_stage_1の後に, command_stage_2が実行されていることがわかります.

処理の並列実行

次のように記述すると, 幾つかの処理を並列に実行することができます.

pipeline:
  - name: parallel command
    parallel:
      - name: parallel 1
        type: command
        command: sleep 1
      - name: parallel 2
        type: command
        command: sleep 2
      - name: parallel 3
        type: command
        command: sleep 3

こうすると, parallel下に設定した3つの処理が, 同時に実行されます. もし, これを逐次実行した場合は6秒(1 + 2 + 3)のスリープになりますが, 並列に実行した場合は3秒で終了するはずです. というわけで, timeコマンドを使って処理時間を確認してみます.

$ time walter
11:39:04  INFO Pipeline file path: "./pipeline.yml"
11:39:04  INFO not found "require" block
11:39:04  INFO not found "service" block
11:39:04  INFO local client was created
11:39:04  INFO not found messenger block
11:39:04  INFO not found cleanup block in the input file
11:39:04  INFO running Walter
11:39:04  INFO Starting Walter in local mode
11:39:04  INFO Preparing to run pipeline process...
11:39:04  INFO [command] exec: parallel command
11:39:04  INFO [command] exec: parallel 1
11:39:04  INFO [command] exec: parallel 2
11:39:04  INFO [command] exec: parallel 3
11:39:07  INFO Finished running pipeline process...
11:39:07  INFO Preparing to run cleanup process...
11:39:07  INFO Finished running cleanup process...
11:39:07  INFO succeded to finish Walter
walter  0.01s user 0.03s system 1% cpu 3.043 total

3.043 totalということで, 確かに3秒で処理が終わっていることがわかります.

この並列処理の利用シーンですが, 例えば, carton installによるCPANモジュールのインストールと, npm installによるJavaScriptのライブラリのインストールを並列実行して, ビルドにかかる時間を節約する, といった使い方が出来ると思います.

コマンド実行時のオプション

1つの処理(Walterでは「ステージ」と言うそうです)の設定には, 次のようにオプションを指定することができます:

pipeline:
  - name: command_stage_1
    type: command
    only_if: test -e file.txt
    directory: dir
    command: cat file.txt

directoryは, そのステージで設定されたコマンドを実行するディレクトリを, only_ifはそのステージで設定されたコマンドを実行する条件(前提条件)を意味します.

例えばこの場合, only_if及びcommandで設定されたコマンドは, directoryで指定したdirというディレクトリをカレントディレクトリとして実行されます.

そして, only_iftest -e file.txtをしているので, このタスクはdirディレクトリ内にfile.txtが存在する場合のみ実行されるようになります.

まず, 失敗例から.

$ walter
11:46:49  INFO Pipeline file path: "./pipeline.yml"
11:46:49  INFO not found "require" block
11:46:49  INFO not found "service" block
11:46:49  INFO local client was created
11:46:49  INFO not found messenger block
11:46:49  INFO not found cleanup block in the input file
11:46:49  INFO running Walter
11:46:49  INFO Starting Walter in local mode
11:46:49  INFO Preparing to run pipeline process...
11:46:49  INFO [command] only_if: found "only_if" attribute in stage "command_stage_1"
11:46:49  INFO [command] only_if: command_stage_1
11:46:49  WARN [command] only_if err: exit status 1
11:46:49  WARN [command] exec: skipped this stage "command_stage_1", since only_if condition failed
11:46:49  INFO Finished running pipeline process...
11:46:49  INFO Preparing to run cleanup process...
11:46:49  INFO Finished running cleanup process...
11:46:49  INFO succeded to finish Walter

only_iferr: exit status 1になっており, これによってexec: skipped this stage "command_stage_1", since only_if condition failedとなっていることがわかります.

次に, 「Hello, walter!」という内容のファイルをdirディレクトリ内部にfile.txtとして設置して実行してみます.

$ walter
11:51:36  INFO Pipeline file path: "./pipeline.yml"
11:51:36  INFO not found "require" block
11:51:36  INFO not found "service" block
11:51:36  INFO local client was created
11:51:36  INFO not found messenger block
11:51:36  INFO not found cleanup block in the input file
11:51:36  INFO running Walter
11:51:36  INFO Starting Walter in local mode
11:51:36  INFO Preparing to run pipeline process...
11:51:36  INFO [command] only_if: found "only_if" attribute in stage "command_stage_1"
11:51:36  INFO [command] only_if: command_stage_1
11:51:36  INFO [command] exec: command_stage_1
11:51:36  INFO [command_stage_1][command] exec output: Hello, walter!
11:51:36  INFO Finished running pipeline process...
11:51:36  INFO Preparing to run cleanup process...
11:51:36  INFO Finished running cleanup process...
11:51:36  INFO succeded to finish Walter

先ほどと異なり, only_ifでエラーになっておらず, 正しくコマンド(cat file.txt)が実行され, それによってexec output: Hello, walter!になっていることがわかります.

「ステージ」が失敗した場合

もし, ステージで設定されたコマンドが失敗した場合, その時点で全ての処理が中断します.

例えば, 次のpipeline.ymlでは, 最初のステージで存在しないfailed_commandというコマンドを実行しようとしています.

pipeline:
  - name: command_stage_1
    type: command
    command: failed_command
  - name: command_stage_2
    type: command
    command: echo "hi!"
  - name: command_stage_3
    type: command
    command: echo "hi! hi!"

これを実行すると,

$ walter
11:55:09  INFO Pipeline file path: "./pipeline.yml"
11:55:09  INFO not found "require" block
11:55:09  INFO not found "service" block
11:55:09  INFO local client was created
11:55:09  INFO not found messenger block
11:55:09  INFO not found cleanup block in the input file
11:55:09  INFO running Walter
11:55:09  INFO Starting Walter in local mode
11:55:09  INFO Preparing to run pipeline process...
11:55:09  INFO [command] exec: command_stage_1
11:55:09  INFO [command_stage_1][command] exec output: sh: failed_command: command not found
11:55:09  WARN [command] exec err: exit status 127
11:55:09 ERROR [command] exec: failed stage "command_stage_1"
11:55:09  WARN Execution is skipped: command_stage_2
11:55:09  WARN Execution is skipped: command_stage_3
11:55:09  INFO Finished running pipeline process...
11:55:09  INFO Preparing to run cleanup process...
11:55:09  INFO Finished running cleanup process...
11:55:09  INFO more than one failures were detected running Walter

このように, exec output: sh: failed_command: command not foundでステージの実行が失敗していて, これによってExecution is skipped: command_stage_2そしてExecution is skipped: command_stage_3になっていることがわかります.

クリーンアップ

パイプラインの一番最後(処理が最後まで終了したか, そうでないかに関わらず)に行う処理は, cleanupで指定できます.

pipeline:
  - name: command_stage_1
    type: command
    command: touch file.txt
  - name: command_stage_2
    type: command
    command: ls
  - name: command_stage_3
    type: command
    command: echo "hi!"
cleanup:
  - name: cleanup
    command: rm file.txt

このように記述すると, command_stage_1で作成したfile.txtというファイルを, 一番最後に削除してくれます.

$ walter
11:57:30  INFO Pipeline file path: "./pipeline.yml"
11:57:30  INFO not found "require" block
11:57:30  INFO not found "service" block
11:57:30  INFO local client was created
11:57:30  INFO not found messenger block
11:57:30  INFO found cleanup block
11:57:30  INFO running Walter
11:57:30  INFO Starting Walter in local mode
11:57:30  INFO Preparing to run pipeline process...
11:57:30  INFO [command] exec: command_stage_1
11:57:30  INFO [command] exec: command_stage_1
11:57:30  INFO [command_stage_1][command] exec output: file.txt
pipeline.yml
11:57:30  INFO [command] exec: command_stage_2
11:57:30  INFO [command_stage_2][command] exec output: hi!
11:57:30  INFO [command] exec: command_stage_3
11:57:30  INFO [command_stage_3][command] exec output: hi! hi!
11:57:30  INFO Finished running pipeline process...
11:57:30  INFO Preparing to run cleanup process...
11:57:30  INFO [command] exec: cleanup
11:57:30  INFO Finished running cleanup process...
11:57:30  INFO succeded to finish Walter
$ ls
pipeline.yml

command_stage_1lsを実行したタイミングでは, file.txtが存在しますが, walterコマンドによる処理が終了した後にlsで確認すると, cleanupfile.txtを削除しているので, pipeline.ymlしか残っていないことがわかります.

まとめ

Walter, 他にもHipChatやSlack, Githubとの連携などなど, いろいろ機能があるのでこちらも試してみたいなーと思っています.