Subscribed unsubscribe Subscribe Subscribe

詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!

シェルスクリプトで Go の簡易ベンダリング

Go

Heroku で Go がサポートされたのは良いニュースだったけど godep を使わなきゃいけないのが気に入らないところで、Go で Heroku に乗せたい Web アプリケーションを作る時は Docker を使う ことにした(参考)。その際にも Docker コンテナ中で go get をいちいち待つのはストレスなのでベンダリングはしておいたほうがよい。そこで簡単なベンダリングスクリプトを書いた。Go 1.5 で試験的に導入されたベンダリングには特に対応していない。

https://gist.github.com/motemen/bb1fca4a92a29bad78dc

このスクリプトは

  • プロジェクトの依存しているサードパーティーライブラリを特定のパス以下にコピーできる
  • 上記のパスを GOPATH に含めて go コマンドを実行できる
  • リビジョンロッキングは行わない

なので、複数人開発には向かないと思う。

使い方は簡単で、プロジェクトのトップで

% go-vendor.sh save

とすれば _vendor/src 以下に(既存の GOPATH から)ソースコードをコピーして、

% go-vendor.sh go build

として _vendorGOPATH に含めつつ go コマンドを実行する。ディレクトリ名が _ ではじまっているので ./... などとしてもソースコードとしては判定されない。

ちなみに依存ライブラリの列挙は go list で行っており、まさにこれはスイスアーミーナイフですのでおすすめの逸品です。

gobump で Go プロジェクトのバージョニングをおこなう

Go

Go に限らず、公開しているプロジェクトのバージョニングは必要だけれど面倒なタスクのひとつで、プロジェクトのメンテナンスを続けていくつもりがあるのなら、ほぼ必ず通らなければならない道でしょう。ここで話題にしているのは Git などによるソースコードのバージョン管理ではなく、たとえばバージョン 3.1.4 といった、リリースされるソフトウェアの公開バージョンをどう運用するか、という話です。

バイナリとして配布する前提のプロジェクトであればソース中で var version string と宣言した変数に、ビルド時に -ldflags '-X main.Version 3.1.4' などとしてバージョンを設定するという方法もありますが、go get による配布ができるのなら、提供側としては楽ができます。たとえば gore は開発者向けということでバイナリの配布をしていませんが、リリース作業がないとなると意識してバージョンを切るタイミングがないので、ここを自動化したいものです。

幸い Go はソースコードの操作がとても簡単に行えるので、version 変数に代入されている文字列リテラルを書き換える……というようなことの実現もたいした苦労ではありません。

gobump

そこで作ったのが gobump

go get github.com/motemen/gobump/cmd/gobump

Go プロジェクトのワークツリーで、以下のようにして使います:

gobump minor -w

バージョニングが Semantic Versioning に従っている前提で、ソースコード中のバージョン的な(/^version$/i)変数や定数に与えられている値を進めます。第一引数には "major"、"minor"、"patch" を与えることができて、それぞれバージョン番号の対応する箇所をインクリメントさせます。たとえば上の例だと、

package main

const version = "1.2.3"

みたいなコードが

package main

const version = "1.3.0"

に書き換えられる。

-w は gofmt や goimports など標準のツールにおなじみのオプションで、バージョンアップ後のコードを標準出力に印字する代わりに、対象のファイルの内容を書き換えます。 この際 -v オプションを与えると、書き換えられた名前と値が JSON で出力されるので、スクリプトからの利用に便利です。

% gobump minor -w -v
{"version":"1.3.0"}

motemen/gobump · GitHub

これを利用した自動化については後ほど紹介します。

Mackerel + peco + zsh でコマンドラインにホスト名を補完する

複数のサーバが関わっている環境では、ホストに人間が分かる名前を関連付けなければ運用がスケールしなくなるものです。その名前はホスト名だったり、ロールやタグのようなものだったりすると思いますが、仮にホスト名を利用するなら、DNS を用いて名前とホスト(の IP アドレス)の対応をつけるようなこともできるでしょう。DNS が利用できない場合は、/etc/hosts に書くというようなのもありですね。

しかしホスト名を直接利用した運用というのは意外と難儀なところがあって、とくに自分のように普段サーバを扱った作業をあまりしないアプリケーションエンジニアなどは、「前に接続したことあるあのホストは何だっけ……」といううろ覚え状態に弱い。名前の一部は覚えているわけなので、シェルの履歴を検索すればなんとかなるのですが、一度も接続したことがなければ目当てのホストを探し出すことはできません(この、接続したことがあるかどうかに確信が持てないのもストレス)。

Mackerel と mkr

さて、Mackerel ははてなが提供するサーバ管理・監視サービスで、私もふだん利用しているものなので、これを使うことを考えます。Mackerel ではサーバはホスト名だけでなくサービス/ロールにひも付きますから、たとえホスト名に意味のある名前をつけない運用であっても、サービスとロール("app" や "db" など)をたどることで目当てのサーバを見つけることができます。この側面を利用すると、とても人間にやさしい。ここで mkr というツールを用いて、関心のあるホストを簡単に見つけられるようにする方法を実現します。

mkr は Mackerel が提供する API の公式クライアントです。Go で実装されていて、go get またはバイナリのダウンロードで利用できます。

go get github.com/mackerelio/mkr

mkr では、

  • Mackerel へのホストの登録(mkr create
  • ホスト情報の更新(mkr update
  • メトリックの投稿(mkr throw
  • ホスト情報の一覧(mkr hosts

などの API がコマンドラインインターフェースで利用できます。基本的には MACKEREL_APIKEY 環境変数に Mackerel の API キーを設定して使いますが、標準的な構成で mackerel-agent を稼働させているホストで実行する場合にはその設定ファイルから API キーやホスト ID を再構成してくれるため、便利なことに追加の設定なしですぐ使えるようです(詳しくは README をご覧ください)。

ここではホスト情報の一覧(mkr hosts)を使うことになりますが、このコマンドには -f オプションが定義されていて、Go の text/template 形式で出力を加工できるようになっているので、これを利用します。

mkr + peco + zsh による実現

f:id:motemen:20150630233012g:plain

上のスクリーンキャストでは Mackerel に登録しているサーバをそのホスト名およびサービス/ロールとともに一覧し、peco であいまい検索を行って、選択したものをコマンドラインに補完する、ということをしています(というのを ^[o にマッピングしている)。コマンドラインには直接 IP アドレスを展開し、末尾にコメントとしてホスト名を記録しているので、シェルの履歴にもコンテキストが残りますね。

これは以下の zsh 関数とシェルスクリプトの組み合わせで実現しています。

complete-mackerel-host-ip

zsh 関数 complete-mackerel-host-ip がキモで、入力中の単語から Mackerel に登録しているホストのあいまい検索を行ない、入力中のバッファに展開します。環境変数を用いず第1引数に API キーを取るようにしているので、環境変数以外の場所でキーを管理しているような場合にもたぶん簡単に使えるはずです。ちなみにあまり用途はないかもしれませんが第2引数には API キーの名前を指定できて、 複数の Mackerel オーガニゼーションを並行して利用している場合にはこれでキャッシュを分離できるようになっています。

ここでは IP アドレス部分のマッチをおこなわないよう指定できる fzf を利用していますが、filter 変数を 'peco' に書き換えることで peco にもすぐ切り替えることができます。

https://gist.github.com/motemen/2b0656be9e2acf32b35d#file-complete-mackerel-host-ip-zsh

mkr-hosts-tsv

これはキャッシュしつつ Mackerel のホストを TSV で一覧するだけのシェルスクリプト。PATH の通るところに置いてください。ここで mkr hosts とその -f オプションを利用していいます。

https://gist.github.com/motemen/2b0656be9e2acf32b35d#file-mkr-hosts-tsv

参考資料