Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

経緯

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 でがんばるとかいろいろあると思いますが、それはそれで。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away