ARM版ConsulをAndroidスマートフォンなどで動作させる

概要
----

Serfには公式にarmバイナリがあるが、Consulにはない。
今回はConsulをarm向けにビルドし、raspberry piやandroidスマートフォンで動作させる。

その前に
------

仮にクラスタリングするとして、このあたりのツールを使ってやることですか？とか、特性的にSerfのほうがメリットが大きいのではないですか？といった疑問はあるかと思うが、一応できますよ、というメモ。

環境
----

consulをビルドする際にはcgoが動く必要がある。
何年も前の議論なので[ここ](https://code.google.com/p/go/issues/detail?id=1880)にある記述が今も正しいかはわからないが、「If you need cgo on arm, you will have to compile on arm directly」とあるとおり、cgoが必要なクロスコンパイル環境を作るととにかく動作しない事が多いようなので（実際動かなかった）、おとなしくqemu-system-arm等でarmのlinux環境を作るか、raspberry piなどで実施するほうが簡単。
android端末上に適当なlinux（arm）イメージを転送->mount->chrootしても（未存在syscallなどを踏まなければ多分）動作するが、面倒なのでお勧めできない。

今回はraspbery piにraspbianを入れて作業を行った。
goは1.4.2を利用し、consulのバージョンは0.5.0とした。

事前準備
--------

### mercurial

あとでconsul 0.5.0の依存関係にパッチを当てる際にmercurialが必要になるのでインストールしておく。

```bash
$ sudo apt-get install mercurial
```

### go

1.4.2をソースビルドして利用する。

```bash:goのインストール
$ mkdir /home/pi/work
$ cd /home/pi/work
$ wget https://storage.googleapis.com/golang/go1.4.2.src.tar.gz
$ tar zxvf go1.4.2.src.tar.gz 
$ cd go/src/
$ ./all.bash 
$ sudo mv go /usr/local/
$ sudo ln -s /usr/local/go/bin/go /usr/local/bin/go
$ sudo ln -s /usr/local/go/bin/gofmt /usr/local/bin/gofmt
$ export GOROOT=/usr/local/go/
$ echo "export GOROOT=/usr/local/go/" >> ~/.bashrc
$ mkdir /home/pi/go
$ export GOPATH=/home/pi/go/
$ echo "export GOPATH=/home/pi/go/" >> ~/.bashrc
```

consulのビルド
--------

consul 0.5.0は、ソースビルドしようとすると依存物のバージョンの関係でエラーが発生するので、[ここ](https://groups.google.com/forum/#!topic/consul-tool/HV_3-BcDUl8)に記載されているとおり、v0-5-0.jsonを使って解決する。

※masterで直っているのかもしれないが、kvsにputはできるがgetするとnullになるというよくわからない挙動が確認されたので、0.5.0にした。

```bash:consulのビルド準備
$ go get github.com/kr/godep
$ cd ${GOPATH}
$ mkdir -p src/github.com/hashicorp/
$ cd src/github.com/hashicorp/
$ git clone https://github.com/hashicorp/consul.git
$ cd consul/
$ git checkout refs/tags/v0.5.0
$ mkdir -p Godeps
$ wget -qOGodeps/Godeps.json https://raw.githubusercontent.com/hashicorp/consul/master/deps/v0-5-0.json
$ ${GOPATH}/bin/godep restore
```

また、consul 0.5.0のビルドにはgo 1.4以上が必要だが、go 1.4以上ではnetを利用した場合にdynamic linkの依存ができるのは有名な話なようで、そのままだとgo buildして出来上がったものをお手持ちのスマートフォンなどに転送しても動作しない。
static linkになるようにビルドしたいので、途中で少しconsulのscripts/build.shに手を加える。


```bash:consul/scripts/build.sh
...
# Build!
echo "--> Building..."
# add "-a", "-tags netgo", "-extldflags \"-static\""
go build \
    -a \
    -tags netgo \
    -ldflags "${CGO_LDFLAGS} -X main.GitCommit ${GIT_COMMIT}${GIT_DIRTY} -X main.GitDescribe ${GIT_DESCRIBE} -extldflags \"-static\"" \
    -v \
    -o bin/consul${EXTENSION}
...
```

あとはconsulのディレクトリでmake実行すればバイナリが出来上がる。ARMアーキテクチャバージョンを指定する場合はGOARM環境変数を設定する。

```bash
$ make
```

動作確認
--------

念の為、出来上がったバイナリの種別と、起動できるか、static linkできているかを確認する。

```bash
$ file bin/consul
bin/consul: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=0xcb73cd4edf8500c88e62470a73143e16a3cd2efb, not stripped
$ bin/consul --version
Consul v0.5.0
Consul Protocol: 2 (Understands back to: 1)
$ ldd bin/consul
	not a dynamic executable
```

あとは適当にandroidスマートフォンか何かに送って動作を確認する。

```bash
$ adb push bin/consul /data/local/tmp
$ adb shell
~ $ su
~ # cd /data/local/tmp
/data/local/tmp # chmod 755 consul
/data/local/tmp # ./consul --version
Consul v0.5.0
Consul Protocol: 2 (Understands back to: 1)
```

agentを動かしてみるとこんな感じ。

```bash
/data/local/tmp # mkdir test
/data/local/tmp # ./consul agent -data-dir=./test
==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1
==> Starting Consul agent...
==> Starting Consul agent RPC...
==> Consul agent running!
         Node name: 'localhost'
        Datacenter: 'dc1'
            Server: false (bootstrap: false)
       Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400)
      Cluster Addr: 192.168.2.100 (LAN: 8301, WAN: 8302)
    Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false
             Atlas: <disabled>

==> Log data will now stream in as it occurs:

    1980/01/06 10:31:11 [INFO] serf: EventMemberJoin: localhost 192.168.2.100
    1980/01/06 10:31:11 [ERR] agent: failed to sync remote state: No known Consul servers
```

※時間が狂っているのはお手持ちのスマートフォンのせいなので気にしなくて良い。