ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

`soko(倉庫)` というサーバメタデータを取り扱うミドルウェアを作っている

github.com

みなさん、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つに対応している。

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なら二つとも楽そうだけど、その他はポーリングすることになるとか)、ぼちぼち作ろうと思っています。

あと、アレなんですよね。

自動テストが...(手記はそこで途切れている


ということで、ひとまず思った通り動いた記念にブログ記事を書くなどした。もっといいツールがあるかもしれないが、寡聞にして知らない。