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側に任せる事ができるので、管理が楽になります。