経緯
0.0.0.0:49168->8888/tcp
この 49168
を コンテナ内から 知りたかった
結論から言うと
Docker Remote API を Unix domain socket 経由で叩いて jq で json パースして port 番号をゲットしました
方法はいろいろあるはず
docker run の時に etcd か何かに port 番号を登録しておいてコンテナ内からアクセスするとか、それなら registrator を使えばいいじゃねとか、他にもいろいろあると思います。
ひとまず準備するものを最小限にしてみたつもりですが、更にシンプルな案があれば教えてください!
ポート番号ゲットまでの流れ
簡単にお試しできる環境書いていきます。
1. Dockerfile
FROM ubuntu:trusty
RUN apt-get update && apt-get install -y jq
2. ビルドします
$ docker build -t hoge .
3. 起動します
起動する時に Docker の Unix domain socket を volume オプションでコンテナ内にマウントします。
$ docker run -it --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 8888 hoge /bin/bash
docker ps
で確認するとこんな感じです。
7b4e590705e1 hoge:latest "/bin/bash" 17 hours ago Up 2 seconds 0.0.0.0:49168->8888/tcp sad_wright
ここで 0.0.0.0:49168->8888/tcp
となっているのを覚えていてください。
4. ポートをゲットしてみましょう
起動したコンテナ内で下記コマンドを実行してください。
$ echo -e "GET /containers/${HOSTNAME}/json HTTP/1.0\r\n" | \
nc -U /var/run/docker.sock | \
sed '1,/^\r$/d' | \
jq '.NetworkSettings.Ports[][0].HostPort | tonumber'
49168
取れた!!
コマンド解説
簡単に
1. Docker Remote API を叩く
$ echo -e "GET /containers/${HOSTNAME}/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock
Docker Remote API に対して GET /containers/コンテナID/json
を叩くと docker inspect
と同じ json が取得できます。
Docker Remote API v1.15 - Docker Documentation
Inspect a container
今回は Unix domain socket 経由で取得するので、 nc -U
で socket ファイルを指定してそいつに HTTP Request を投げる感じです。
ちなみに $HOSTNAME
は各コンテナに初期で定義されている環境変数で、コンテナID が格納されています。
root@7b4e590705e1:/# echo $HOSTNAME
7b4e590705e1
衝突の可能性を考え、より長いコンテナIDを取得したい場合は docker run
の --cidfile
オプションを使用すると良いでしょう。
$ docker run -it --rm --cidfile /tmp/host.txt -v /tmp/host.txt:/tmp/host.txt hoge /bin/bash
root@ad4eed179fa0:/# echo $HOSTNAME
ad4eed179fa0
root@ad4eed179fa0:/# cat /tmp/host.txt
ad4eed179fa00edb9b0c045822f882808e5c77bb4e2a2c61c9ac4e9fe0afed7e
2. HTTP Response で Body だけ取る
$ sed '1,/^\r$/d'
nc -U
で取れる HTTP Response はヘッダーもくっついています。今回はボディだけ欲しいので先頭からボディの開始前まで削除、みたいな感じです(多分)
3. json パースする
$ jq '.NetworkSettings.Ports[][0].HostPort | tonumber'
ここはそのままです。最後の tonumber
を付けないと "49168"
みたいな返り値になるので、まあそれでもいいけどとりあえず変換しておきました。
複数の Port Forwarding 設定している場合はこれだと駄目なので、そこらへんは各自がんばってください。
まとめ
- Docker Remote API 初めて使った
-
nc -U
で socket と遊べるのも初めて知った - やっぱり jq 便利
「docker daemon を tcp アクセス許可して curl でやればいいのでは?」とか jq 無くても sed でがんばるとかいろいろあると思いますが、それはそれで。
参考
- Docker Remote API v1.15 - Docker Documentation
-
regex - Bash: Remove headers from HTTP response - Stack Overflow
- body だけ取り出すやり方ググりました
-
Docker: How to get image size? - Unix & Linux Stack Exchange
- Docker の Unix domain socket +
nc -U
について知りました
- Docker の Unix domain socket +
-
Docker, how to get container information from within the container? - Stack Overflow
-
--cidfile
について知った記事です
-