いまさらDockerでズンドコキヨシ

ちょっと前にズンドコルータというものが流行っていました(http://qiita.com/kooshin/items/2e00cdeb53cf9cf4c51d).
いいなー私もDockerでやりたいとか思ってましたが,Dockerの機能を使ったいい感じのやり方が思いつかなかったのでやってませんでした.

しかし! Docker 1.12からDockerにもロードバランサが!!これでズンドコキヨシできるやん!!
となりました.
以下思いついてやってみたものの記録です.
※今回結論から言うと成功してません.可能なはずですが何度も何度も繰り返す強い心が必要でした.

Docker ロードバランサ

以前の記事に書いた通りです.内部でIPVSのラウンドロビンで飛ばしてくれます.
今回はIngressのロードバランサのみでやってみます(簡単なので)

設計

まず最も簡単な実装を考えるためDocker LB配下のコンテナがhttpリクエストを受けるとそのコンテナIDによってzun, doko, kyoshiのいずれかを返します.
これでアクセスを繰り返せばいつかzun zun zun doko kiyoshiが完成するはず!という目論見です.
dockerzundoko

サーバ側

Dockerイメージはこんな感じ
https://github.com/YujiOshima/dockerfiles/tree/master/zundoko

Dockerfile

FROM python
ADD files /app
WORKDIR /app
ENTRYPOINT python run.py

run.py

from http.server import HTTPServer, SimpleHTTPRequestHandler
import socket

hostname = socket.gethostname()

class MyHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        uri = self.path
        body = ""
        if uri == "/zun":
            body = b"zun"
        elif uri == "/doko":
            body = b"doko"
        elif uri == "/kiyoshi":
            body = b"__kiyoshi__"
        else :
            body = judge_reponce(hostname).encode('utf-8')

        self.send_response(200)
        self.end_headers()
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.send_header('Content-length', len(body))
        self.wfile.write(body)

def judge_reponce(cid):
    intid = int(hostname, 16)
    if intid % 5 == 0:
        return "**kiyoshi**"
    elif intid % 5 == 1:
        return "doko"
    else:
        return "zun"

host = '0.0.0.0'
port = 8000
httpd = HTTPServer((host, port), MyHandler)
print('serving at port', port)
httpd.serve_forever()

めっちゃ簡単です.
これをDockerクラスタ上にデプロイします.

docker service create --name=zundokokiyoshi -p 9000:8000 --replicas=30 zundoko

クライアント側

アクセスする側も今回Dockerイメージにします.
https://github.com/YujiOshima/dockerfiles/tree/master/getzundoko

import sys
import http.client
import time

DESIRE = b"zun zun zun doko **kiyoshi** "

def main(server, port, loopnum):
    conn = http.client.HTTPConnection(server, port)
    for i in range(0, loopnum):
        result = b""
        for i in range(0, 5):
            conn.request("GET", "/")
            result += conn.getresponse().read() + b" "
            print(result)
            if result not in DESIRE:
                print("faild...")
                break
            time.sleep(0.01)
        if result == DESIRE:
            print("done!!")
            return 

if __name__ == '__main__':
    args = sys.argv
    server = "localhost"
    port = 80
    loopnum = 10
    if len(args) > 1:
        server = args[1]
    if len(args) > 2:
        port = args[2]
    if len(args) > 3:
        loopnum = int(args[3])
    print("connect "+server+":"+str(port))
    main(server, port, loopnum)

うん,これでアクセスを繰り返してzun zun zun doko kiyoshiが完成すれば終了するはず,

動作!

レッツプレイ!

docker run -it --rm getzundoko 52.196.60.122 9000 100
connect 52.196.60.122:9000
b'**kiyoshi** '
b'**kiyoshi** zun '
faild...
b'zun '
b'zun doko '
b'zun doko zun '
faild...
b'zun '
b'zun zun '
b'zun zun doko '
b'zun zun doko **kiyoshi** '
b'zun zun doko **kiyoshi** doko '
faild...
b'**kiyoshi** '
b'**kiyoshi** zun '
faild...
b'zun '
b'zun doko '
b'zun doko **kiyoshi** '
b'zun doko **kiyoshi** zun '
faild...
b'zun '
b'zun doko '
b'zun doko zun '
faild...
b'zun '
b'zun zun '
b'zun zun doko '
b'zun zun doko **kiyoshi** '
b'zun zun doko **kiyoshi** doko '
faild...
b'**kiyoshi** '
b'**kiyoshi** zun '
faild...
b'zun '
b'zun doko '
b'zun doko **kiyoshi** '
b'zun doko **kiyoshi** zun '
faild...

お!動いてるっぽい...!

結果

ダメでした.
正確には何度繰り返してもzun zun zun doko kiyoshiが完成しませんでした.
理由としてDockerLBの内部ではIPVSのラウンドロビンなのでアクセスが均等になるように割り振られるんですよね.
なので今回私一人しかアクセスしてないので着弾するコンテナの順番が固定になってしまうわけですね...もっと早く気付けよ...

もちろん何度もservice createでコンテナを作りなおす,複数プロセスからアクセスして適当に着弾順序を変えるとかすれば完成すると思いますが.面倒なのでやめました.
コンテナ間アクセスのLBとか使ってもうチョット真面目に考えなおそう.