weblog of key_amb

主にIT関連の技術メモ

ssh と rsync だけで Tree Deploy を実現する "grifork" を作った

はじめに〜fireap to grifork

約半年前に fireap というデプロイツール(タスクランナー)を作りました。

オンプレミスでも使えて、ノード数 N に対して O(log N) で動作する、というものです。
が、前提条件として、システム内の全ホストに fireap をデプロイし、また、全ホストで Consul の agent を動かす必要があります。
その辺りが導入障壁になる環境もあるかもしれないな、と思いました。

…で、少し工夫すれば、「デプロイサーバにだけプログラムがあればツリー状にデプロイできる」ものも作れるだろう、と思って作ってみたのが、今回の grifork になります。

Ruby で書いてます。

Tree Deploy とは

なんとなく言葉の雰囲気で意味が伝わる気もしますが、grifork のメカニズムの説明がてらに Cacoo で絵を描いてみました。

f:id:key_amb:20161002145457p:plain

対象のホストリストをツリー状のグラフにマッピングして、デプロイをキックするサーバ(以下、デプロイサーバ)から樹状にデプロイを伝播していくと、そういうデプロイのやり方を意図しています。*1

fireap 同様、実行時間は O(log N) になります。

grifork: standalone モード

grifork には2つ動作モードがありますが、"standaloneモード" が、デプロイサーバでだけ grifork が動けばいいというモードです。

上図のようなツリーに対して、このモードでデプロイを行うと、下の3段階でデプロイが進行します。

(1) デプロイサーバから子ノードに rsync

f:id:key_amb:20161002151648p:plain

(2) デプロイサーバから第1世代の子ノードに ssh して、第2世代の子ノードへの rsync をキック

f:id:key_amb:20161002151700p:plain

(3) 以下、グラフの葉に達するまで繰り返し

f:id:key_amb:20161002151712p:plain

各世代のジョブは全て Parallel *2 で並行に走らせることにしました。
ので、最大並列数が「最大のノードを持つ世代のノード数」になります。

※まだ最大14ノードでしか試してないのですが、ひょっとしたら並列数がすごく大きくなったら何か問題出てくるかも。

grifork: grifork モード

もう1つの動作モードは "griforkモード" と呼んでいます。
こちらは、全ノードで grifork プログラムが動作する前提になっています。

このモードでは、子ノードで grifork を実行することで、再帰的に葉に達するまでタスクを実行します。

こちらの仕組みについても、先ほどのツリーを使って図解します。

(1) デプロイサーバから子ノードに rsync

※ standalone モードと同じなので、図は割愛

(2) 子ノードに ssh して各サブツリーへの grifork をキック

f:id:key_amb:20161002152223p:plain

(3) 以下、再帰的にグラフの葉に達するまで繰り返し

f:id:key_amb:20161002152251p:plain

standalone モードで grifork や ruby を配布して、grifork モードでアプリケーションをデプロイする、というやり方もできます。
grifork モードの実験をやるときは、実際に standalone モードで全ホストに grifork を配布していました。

使い方

まだ gem にしてないので、今のところ github から clone して使う形になります。

git clone https://github.com/key-amb/grifork.git
cd grifork
bundle install
./bin/grifork [--[f]ile path/to/Griforkfile]

デプロイツールとして紹介してきましたが、デプロイに限らずリモートでタスクを実行させる用途でも使えます。

Griforkfile という DSL ファイルにタスクの設定を書きます。
デフォルトでカレントディレクトリの Griforkfile を参照します。

リポジトリexample ディレクトリに、各モードの Griforkfile のサンプルを置いておきました。

動作例と実行ログ

ちょっとしたサンプルとそのログを Gist に貼っておきました。もし、参考にしたい方はどうぞ。

https://gist.github.com/key-amb/94b8113e315ed1ea0e0d98dd6071a9a9

今後の展望

とりあえず動くものはできた、というレベルなので、まだまだ色々使いづらいところや、エラーケースの対処など漏れているところもありそうです。

gem 化した方が使いやすそうだなと思いつつ、まだやっていません。

また、Go で書き直したら、grifork モードのために grifork 自身を配布するのも楽だろうな、と思っています。やる気次第だけど、できれば、やりたい。

以上、 sshrsync だけでクラスタに対してツリー状にタスクを伝播するタスクランナー "grifork" を紹介しました。

ご興味ありましたら、お試し下さい。

もし何か要望やバグなどありましたら、GitHub Issue か Pull Request か、Twitter などでお知らせ下さい。

余談〜デプロイの未来について

そもそもの話になりますが、PaaS やコンテナの普及によって、サーバアプリケーションをデプロイする仕組みは変わりつつあるように思います。
単純にファイルツリーを配布するようなデプロイツールのニーズは、相対的に下がっていきそうな気もしています。

おまけ〜grifork の語源

graph + fork (+ griffin)