みなさん、userdata書いてますか(挨拶)。
今日は、細々と書いてきた、自作ツールの紹介をしてみます。
どういうものか
たとえば、同じPuppetのマニフェスト、同じアプリをデプロイするけれど、サーバAはweb向けのロードバランサー、サーバBはAPI向けのロードバランサーの配下にいて欲しくて、それぞれ固有の動きをさせたいような場合があるかもしれない。
そういうとき、まず、サーバAの起動時に、EC2のタグ機能を使って
aws ec2 run-instances ......... # インスタンスIDを控えるか変数に入れる aws ec2 create-tags --resources i-XXXXXXX --tags Key=LoadBalancerName,Value=www
とやることが考えられる。サーバBなら Key=LoadBalancerName,Value=api
とでもなるだろう。ここで大事なのは、サーバAとサーバBは構成もサーバに上がっているアプリケーションも 同じ なのだが、EC2のタグでのみ役割が 区別されている 、という状態になる。
このアプリケーションサーバについて、いざ起動させて、www配下にいるときとAPI配下にいるときとで別々の挙動をさせたい場合には、たとえばアプリケーション内部で aws ec2 describe-tags
を発行すると確認はできるが、複雑怪奇なJSONをパースする羽目になる...。
soko
コマンドを用いると、以下の1行で確認できる。
lb = `soko get LoadBalancerName` #=> "www"
あるいは、Puppet的に大体一緒だけど少し違う構成にしたいときもあるだろう。以下のような方法でfacter変数を切り替えてハンドルすることが考えられる(Itamaeの run_command なんかと組み合わせてもとてもクールかもしれない)。
FACTER_LB_NAME=$(soko get LoadBalancerName) puppet agent --test --server puppet.example.lan
ここで、LoadBalancerNameは 動的に変更できる ので、たとえばwwwからAPIのサーバに転用したい場合には、
soko put LoadBalancerName api
を実行して、Puppetを再実行あるいはアプリケーションサーバを再起動するだけで完了する。
サーバのメタデータがあると便利
「ほぼ同じようなサーバなんだけど少しだけ違う」、たとえばwwwアプリケーションサーバとAPIアプリケーションサーバであったり、MySQLやSolrなどのマスターとスレーブであったりするような、ロール以下の小さな違いを扱う上で、このようなサーバメタデータのインベントリがあると便利な場合がある。
soko(1)
はこのような小さな違いをなるべく簡潔に、透過的に扱うべく開発した、単純なコマンドである。
具体的にsokoがやっていることは
- 個々のサーバに割り振られたサーバIDを読み取り、
- インベントリ(信頼できるKVS)に値をセーブ、あるいはロードする
これだけである。
サーバIDは、クラウド系のプラットフォームなら必ずインストールされているはずの cloud-init の、 /var/lib/cloud/data/instance-id
というファイルから取得している。AWSやOpenStackのようなプラットフォームでいう「インスタンスID」と同じものになる。
バックデータを溜め込むKVSとしては、以下の3つに対応している。
- Consul KV
- Amazon EC2 API
- OpenStack compute API v2 (Nova)
READMEにある通り、サーバ起動時の一番最初に以下のようなワンライナーを発行して設定することができる。
$ soko open aws \ access_key_id=$AWS_ACCESS_KEY_ID \ secret_access_key=$AWS_SECRET_ACCESS_KEY \ region=ap-northeast-1
soko を挟むメリット
以下のようなことは言えるんじゃないだろうか。
- コマンドが短く明示的になること。 aws-cliは複雑なJSONを扱ったり、nova clientもシェルで組み合わせて実行するには難しいインタフェースだったりするけど、sokoを使えば決められた作業を簡潔なコマンドで行える。
- バックエンドが透過的になること。 AWSからOpenStackに移設する場合、あるいは逆でも、sokoコマンドで抽象化することで設定変更のみで移設準備が済む。
ちなみに「コマンドが短く明示的」はクラウド自動化パーソンにとってはかなり重要で、要するにコマンドが短いと、実質シェルで戦うしかないcloud-initのuserdata内部で、簡単にメタデータが扱えるようになってくれる。
userdataで日々消耗している人たちなら、この便利そうな感覚わかってくれると思うんだけど......どうだろう。
FAQ
soko とはどういう意味?
サーバのメタデータが溜まっているところを「倉庫」に例えたイメージ。個人的にメタデータのたまり先をバックエンドとかインベントリと呼んでいる。インベントリだと倉庫というか在庫になるけど...。
役に立つの?
正直 まだよくわかっていない 。もともと別の方法で似たようなことをしていたのを、いろいろなプラットフォーム、バックエンドで透過的になるように実装し直しただけなので。少なくとも今僕が直面している問題を解決することはできるはず。
soko
自体非常に単純なツールので、僕の考えつかないような用途もあると思う。むしろこういう使い方もあるんじゃね? みたいな提案があれば是非聞いてみたい。
他のプラットフォームに対応してくれないの?
プルリクをお願いします... :bow: とりいそぎ、Google Cloud Platformには対応してもいいかなと思うけど、今ぼくが使ってないので検証ができない。
あと、バックエンドに無限に対応していても、バイナリサイズがかさむので、プラグイン機構を作ることは考えている。
今後の開発は?
soko watch LoadBalancerName
で、外部からLoadBalancerNameの変更がされたらフックしてなんかしてくれたりsoko find IP --where Role=www
で IP 一覧が取れたり
するとカッコ良さそうですね... 前者はすごくGoらしいですし。
バックエンドによって実装難易度が異なることもあり(Consul KVなら二つとも楽そうだけど、その他はポーリングすることになるとか)、ぼちぼち作ろうと思っています。
あと、アレなんですよね。
自動テストが...(手記はそこで途切れている
ということで、ひとまず思った通り動いた記念にブログ記事を書くなどした。もっといいツールがあるかもしれないが、寡聞にして知らない。