docker run時にコンテナ内の特定のポートに、host上のランダムなポートをbindさせる方法をまとめます。
簡単なwebサーバの実装とDockerコンテナ用のDockerfileの記述
今回、下記のような構成で簡単なwebサーバを作るとする。
$ tree
.
├── Dockerfile # webサーバ用コンテナのDockerfile
└── app
└── identidock.py # Flask webサーバの実装
今回は本筋でないので説明しませんが、pythonのwebフレームワークであるFlaskを使って、localhost の/に対してhttpリクエストしたときに Hello Worldを返す簡単なサーバを作ります。
./app/identidock.py に下記のように実装します。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World\n'
if __name__ == '__main__':
app.run(debug = True, host = '0.0.0.0')
続いて肝心なDockerfileの説明をします。
uwsgiというユーザ・グループを作成した上で、
コンテナ内の9090番ポートにwebサーバ、9191番にサーバパフォーマンス統計用のサーバを立ち上げる設定を記述します
FROM python:3.4
# uswgiというグループ・ユーザを作成
RUN groupadd -r uwsgi && useradd -r -g uwsgi uwsgi
# Flask uWSGI pip install
RUN pip install Flask==0.10.1 uWSGI==2.0.8
# コマンド実行時の作業ディレクトリ指定
WORKDIR /app
# ./appをコンテナ内にあるファイルシステムの/appにコピーする
COPY app /app
# 解放するポートを明示的に指定
EXPOSE 9090 9191
# これ以降のすべての行の実行ユーザをuwsgiに設定する
USER uwsgi
# uWSGIを実行する新たなコマンドを生成する
# uWSGIに対して、9090ポートで待ち受けるhttpサーバを起動させる。 /app/identidock.pyからappというアプリを実行させる
# 9191でstatsサーバも起動する
CMD ["uwsgi", "--http", "0.0.0.0:9090", "--wsgi-file", "/app/identidock.py", "--callable", "app", "--stats", "0.0.0.0:9191"]
これで、ひとまずwebサーバ用のDockerコンテナの準備ができたので、buildしていきます。
webappという名前でDockerコンテナのbuildを行います。
$ docker build -t webapp .
Dockerコンテナを指定したホスト上のポートにbindさせる
まずは、Dockerコンテナ内の 9090, 9191番ポートをホスト上の指定したポートにbindさせます。
方法としては、docker runコマンド実行時に、オプションで設定させるだけです。
コンテナ内の9090,9191を下記のポートにbindさせることとします。
- 9090番ポート → host上の9090番ポート 9090:9090
- 9191番ポート → host上の9191番ポート 9191:9191
上記のように、 ${host上のポート}:${コンテナ内のポート}という形式で、docker run時に -pオプションで追加してあげればbindすることができます。
同時に、コンテナ名を webapp-testとします
$ docker run -d -p 9090:9090 -p 9191:9191 --name webapp-test
docker runが完了したら、実際にポートがbind されているか、 docker portで確認します。
# docker port確認
$ docker port webapp-test
9191/tcp -> 0.0.0.0:9191
9090/tcp -> 0.0.0.0:9090
# 疎通確認
$ curl localhost:9090
Hello World
これで、指定したホスト上のポートにDockerコンテナをbindさせることができました。
Dockerコンテナにホスト上のポートをランダムにbindさせる。
今度は、Dockerコンテナの9090, 9191に対して、ホスト上の大きな番号のポートを自動的に割り当てます。
この方法は非常に簡単で、 docker run 時に -P を引数として使うことで、実現できます。
docker run –helpでは、-Pオプションは以下のように説明されています。
-P, --publish-all Publish all exposed ports to random ports
やることはこれだけです。
# ホスト上のランダムなポートにコンテナを割り当てる
$ docker run -d -P --name webapp-test webapp
# ポート確認
$ docker port webapp-test
9090/tcp -> 0.0.0.0:32769
9191/tcp -> 0.0.0.0:32768
Dockerコンテナへのランダムなポートbindの利点
このランダムなポートbindの利点としては、ある1台のホスト上に複数のコンテナを実行する際に、使われていないポートを自分で管理して明示的にしていするよりも、ポートのbindを全部Docker側に任せる事ができるので、管理が楽になります。