LoginSignup
22
25

More than 5 years have passed since last update.

Docker コンテナに bind (PortForward) されたポート番号をコンテナ内から取得する方法

Posted at

経緯

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 設定している場合はこれだと駄目なので、そこらへんは各自がんばってください。

まとめ

  1. Docker Remote API 初めて使った
  2. nc -U で socket と遊べるのも初めて知った
  3. やっぱり jq 便利

「docker daemon を tcp アクセス許可して curl でやればいいのでは?」とか jq 無くても sed でがんばるとかいろいろあると思いますが、それはそれで。

参考

22
25
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
25