GWに一人さみしくDockerとSerfと戯れてみた(๑´ڡ`๑)



少しserfを触りたいなと思ったので、dockerを使って検証できる環境を作りました。  
なので、今回はcontainerないでsshdを立てたりしています（ここでは使いませんが）  
まだ`serf members` で検証できるレベルです。


## 今回の検証環境

### Dockerイメージ 

OS

Ubuntu:16.04 ltsが出ましたね。


入れたもの

* serf
* supervisor（理由は後ほど）


```Dockerfile
FROM ubuntu:16.04


RUN apt-get update -y \ 
    apt-get install -y wget unzip

# Install Serf
RUN wget -nv https://releases.hashicorp.com/serf/0.7.0/serf_0.7.0_linux_amd64.zip && \
    echo "b239fdcd1c15fd926ff0cd10bc32a31330d1c74aba9e4d49ff83d5707ef1ba4b  serf_0.7.0_linux_amd64.zip" | sha256sum -c - && \
    unzip serf_0.7.0_linux_amd64.zip -d /usr/bin && \
    rm serf_0.7.0_linux_amd64.zip

# Install supervisor
#   https://docs.docker.com/engine/admin/using_supervisord/
RUN apt-get install -y openssh-server apache2 supervisor
RUN mkdir -p /var/lock/apache2 /var/run/apache2 /var/run/sshd /var/log/supervisor

# Clean
RUN apt-get clean && \
    rm -rf /tmp/* /var/tmp/*

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

COPY serf.sh /usr/local/bin/serf.sh
RUN chmod a+x /usr/local/bin/serf.sh

EXPOSE 22 7946
CMD ["/usr/bin/supervisord"]
```

### Supervisor

以下のconfファイルを置くだけでいいはずが少しハマりました。。

```/etc/supervisor/conf.d/supervisord.conf
[program:serfagent]
command=/usr/local/bin/serf.sh
```

少し脱線します。ハマった理由は

```
supervisor: couldn't exec /usr/local/bin/serf.sh: ENOEXEC
supervisor: child process was not spawned
```

なんでやねん！ `RUN chmod a+x /usr/local/bin/serf.sh` ってしとるやないか  
と思いながら調べてたら

最初

```/usr/local/bin/serf.sh
#/bin/sh
set -u
```

このようなファイルになっていました。。。いつもハマる時は簡単なアレ  
だけどきづけない。。

修正後は次で記述

### Serf実行ファイル

最初に立ち上げるエージェントかどうかで `-join` をつけるかどうか変わるので  
supervisorがserfを直接実行しないように、ラップしたもの


```/usr/local/bin/serf.sh
#!/bin/sh
set -u

if [ -z "${NODE_PORT_7946_TCP_ADDR+x}" ]; then
    serf agent -bind 0.0.0.0:7946
else
    serf agent -bind 0.0.0.0:7946 -join $NODE_PORT_7946_TCP_ADDR:7946
fi
```

`NODE_PORT_7946_TCP_ADDR` はコンテナ起動時に設定しています。
link先があれば設定済みで、最初のコンテナには存在しません

## では実行

### コンテナを立ち上げるためのスクリプト（on mac)

```node.sh
#!/bin/sh

num=`docker ps | grep node | wc -l`
num=`echo $num | tr -d " "`
num=$(( num+1 ))
SSH_PORT=$(( 2220 + num ))
node_name=node$num
echo $node_name


SERF_PORT=7945
DOKCER_IMAGE_NAME=shinofara/serf:latest

cmd=""
if [[ $num -eq 1 ]]; then
cmd="docker run -d -t \
       --name ${node_name} \
       -p ${SERF_PORT} \
       -p ${SSH_PORT}:22 \
       ${DOKCER_IMAGE_NAME}"
else

cmd="docker run -d -t \
       --name ${node_name} \
       -p ${SERF_PORT} \
       -p ${SSH_PORT}:22 \
       --link node1:node \
       ${DOKCER_IMAGE_NAME}" 
fi

echo $cmd && $cmd

```

ps結果が0件なら最初のエージェントとして起動、それ以外はlinksさせて起動

### スクリプト実行（on mac)


```
$ sh node.sh 
node1
docker run -d -t --name node1 -p 7945 -p 2221:22 shinofara/serf:latest
f9abc288f29b1f32224b6f243c86062613c63f7727933f4891ca1e215ca32f58
$ sh node.sh 
node2
docker run -d -t --name node2 -p 7945 -p 2222:22 --link node1:node shinofara/serf:latest
299e5b7b4798cd609a806d23782e4851cfa592bf57870e6a638f7c947656cb11
$ sh node.sh 
node3
docker run -d -t --name node3 -p 7945 -p 2223:22 --link node1:node shinofara/serf:latest
07e327177cae0a27ecfaea854ad629111da2ffc24f9c403d7c181503dce03407
$ sh node.sh 
node4
docker run -d -t --name node4 -p 7945 -p 2224:22 --link node1:node shinofara/serf:latest
1a0e54ce5c54db404fe51e1cdcea67202ad064fe586a7e43a74bf2ae8aa1f907
$ sh node.sh 
node5
docker run -d -t --name node5 -p 7945 -p 2225:22 --link node1:node shinofara/serf:latest
b1477622be43fe3e9e05b05573321b67c66d6542674d5f7111f8242e52d8423f
$ sh node.sh 
node6
docker run -d -t --name node6 -p 7945 -p 2226:22 --link node1:node shinofara/serf:latest
f5b709c3b415b70b042c234df8b9c50d6dc679e5c976d4523b3f001cbc05bb04
$ sh node.sh 
node7
docker run -d -t --name node7 -p 7945 -p 2227:22 --link node1:node shinofara/serf:latest
6e7622d40e9bc367d4481412afaeb965a5bf42ba4dad4072079e1c33f5554b09
```

特にnode数に意味はありません、あきるまで実行しただけです

### ちゃんとクラスタネットワークが作成されているか確認

確認するためのコンテナを立ち上げます。


```
$ docker run --rm -it --name node8 -p 7945 -p 2228:22 --link node1:node shinofara/serf:latest /bin/bash
```

まだsupervisorが立ち上がってないので起動＆確認

```
root@e9305544dfab:/# /usr/bin/supervisord &
root@e9305544dfab:/# supervisorctl status
serfagent                        RUNNING   pid 13, uptime 0:00:06
sshd                             RUNNING   pid 12, uptime 0:00:06
```

`serf members` で確認

```
root@e9305544dfab:/# serf members
1a0e54ce5c54  172.17.0.5:7946  alive
07e327177cae  172.17.0.4:7946  alive
299e5b7b4798  172.17.0.3:7946  alive
e9305544dfab  172.17.0.9:7946  alive
f5b709c3b415  172.17.0.7:7946  alive
f9abc288f29b  172.17.0.2:7946  alive
6e7622d40e9b  172.17.0.8:7946  alive
b1477622be43  172.17.0.6:7946  alive
```

とりあえずクラスタネットワーク作成までは完了！

作業履歴はこちら
https://github.com/shinofara/serf/tree/b4b92da946d506695cbab3af8b32ee758fc32273