最近Dockerというものを勉強しており、理屈はどうあれ最低限業務で使えるようになることを目標に頑張っています。
で、ポートフォワーディングというものに引っかかってしまい、解決まで苦労したのでそれの備忘録的なものです。
「Dockerってそもそも何?」って方には全く訳が分からない記事ですので、ある程度Dockerが使え、Docker Toolboxでポートフォワーディングできなくなったときは参考にしてもらえればと思います。
- 環境
- ポートフォワーディングについて
- やりたかったこと
- 実行
- 試してみたこと1
- 試してみたこと2
- VirtualBoxの設定と、run時の-pのport番号とコンテナ内のsample.pyのポート番号の組み合わせ
- 結論
環境
Windows 10 Pro バージョン 1903 Docker Toolbox Dockerバージョン: 18.09.1 VirtualBox: 6.1.16
ポートフォワーディングについて
IPネットワーク上のある機器が、自らのIPアドレスのTCPやUDPの特定のポート番号への通信を、別のアドレスの特定のポートへ自動的に転送すること。また、ネットワーク機器などのもつそのような機能。
Dockerの場合、コンテナ内のサーバにコンテナ外部からアクセスするためには、このポートフォワーディングが必要で、これをしないとコンテナ外部からコンテナ内のサーバにアクセスすることはできません。
やりたかったこと
ひとまず、コンテナ内のサーバにコンテナ外部からアクセスできることを確かめられれば良かったので、サンプル程度のFlaskアプリを使いました。
用意したファイルは以下の3つです。
- sample.py
- Dockerfile
- requirements.txt
sample.pyの中身
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World! from Docker" if __name__ == "__main__": app.run(host='0.0.0.0', port=7000, debug=True)
Dockerfileの中身
FROM python:latest COPY requirements.txt /usr/src/app/ RUN pip install --upgrade pip RUN pip install -r /usr/src/app/requirements.txt COPY sample.py /usr/src/app/ CMD ["python", "/usr/src/app/sample.py"]
requirements.txt
click==6.6 Flask==0.11.1 itsdangerous==0.24 Jinja2==2.8 MarkupSafe==0.23 Werkzeug==0.11.10
実行
イメージの作成
docker build -t flaskimg .
-t:イメージ名とタグの指定。今回で言えば、flaskimgがイメージ名にあたり、タグはつけていません。
タグをつける場合は、
docker build -t イメージ名:タグ Dockerfileのパス
となります。
コンテナの起動
docker run -d --rm --name flaskcon -p 9000:7000 flaskimg
-d:バックグラウンドで起動
--rm:コンテナ停止後、そのコンテナを削除
--name:コンテナ名の指定。この場合はflaskconという名前を付けています。
-p:ポートの設定です。これを指定しないとコンテナ内部のサーバにコンテナ外部からアクセスすることが出来ません。
-p コンテナ外部からのポート番号:コンテナ内部のポート番号
で指定します。
つまり、コンテナ内部では7000番でアクセスでき、コンテナ外部からは9000番でアクセス(http://127.0.0.1:9000)すれば、コンテナ内部のサーバにアクセスできるわけですが....。
出来ない。なんでや?
試してみたこと1
調べてみると、Docker Toolboxでポートフォワーディングをやる場合、VirtualBoxの方でも設定をいじらないといけないようです。めんどくさい....。
以下の記事を参考にVirtualBoxで設定を変えます。
Docker Toolboxでポートフォワーディング!【Windows 10 Home】
ホストはコンテナ外部から、ゲストはコンテナ内部を指しているので、それぞれ以下のようにポート番号を指定します。
これでVirtualBoxを再起動し、再度buildし、runして、http://127.0.0.1:9000でアクセスすると、
出来ない。なんでや?(2度目)
ちなみに、http://127.0.0.1:7000でも無理でした。
試してみたこと2
今度は以下のようにしてみました。
そのうえで、VirtualBoxを再起動し、再度buildし、runして、http://127.0.0.1:7000でアクセスすると、
できた。謎。ちなみに、http://127.0.0.1:9000はアクセスできませんでした。
VirtualBoxの設定と、run時の-pのport番号とコンテナ内のsample.pyのポート番号の組み合わせ
上記3つに対し、いろいろ試した結果を下に記します。sample.pyのポート番号は7000で固定です。
表のVBはVirtualBoxの略記です。
No | VBのhostポート | VBのguestポート | -p | sample.pyのポート | コンテナ外部からのアクセス |
---|---|---|---|---|---|
1 | なし | なし | 9000:7000 | 7000 | 127.0.0.1:7000で不可 |
2 | なし | なし | 9000:7000 | 7000 | 127.0.0.1:7000で不可 |
3 | なし | なし | 7000:9000 | 7000 | 127.0.0.1:7000で不可 |
4 | なし | なし | 7000:9000 | 7000 | 127.0.0.1:7000で不可 |
5 | 7000 | 9000 | 9000:7000 | 7000 | 127.0.0.1:7000で可 |
6 | 7000 | 9000 | 9000:7000 | 7000 | 127.0.0.1:9000で不可 |
7 | 7000 | 9000 | 7000:9000 | 7000 | 127.0.0.1:7000で不可 |
8 | 7000 | 9000 | 7000:9000 | 7000 | 127.0.0.1:9000で不可 |
9 | 9000 | 7000 | 9000:7000 | 7000 | 127.0.0.1:7000で不可 |
10 | 9000 | 7000 | 9000:7000 | 7000 | 127.0.0.1:9000で不可 |
11 | 9000 | 7000 | 7000:9000 | 7000 | 127.0.0.1:7000で不可 |
12 | 9000 | 7000 | 7000:9000 | 7000 | 127.0.0.1:9000で不可 |
13 | 7000 | 8888 | 9000:7000 | 7000 | 127.0.0.1:7000で不可 |
14 | 7000 | 8888 | 9000:7000 | 7000 | 127.0.0.1:9000で不可 |
15 | 7000 | 8888 | 8888:7000 | 7000 | 127.0.0.1:7000で可 |
16 | 7000 | 8888 | 8888:7000 | 7000 | 127.0.0.1:9000で不可 |
17 | 7000 | 8888 | 8888:7000 | 7000 | 127.0.0.1:8888で不可 |
No1~No4を見る限り、VirtualBoxのポートの設定は絶対に必要と言えます。
それ以外で、アクセスできる設定の共通点を絞り出すと、
VBのhostと、-pの右側、コンテナ内のサーバのポート番号(今回で言えば、sample.pyのポート番号)、コンテナ外部からアクセスする場合のポート番号が同じもの
であることが必要そうです。
加えて、No13の結果も含めて考えると、上記の条件に、
VBのguestと-pの左側が同じ
じゃないといけないみたいです。
いろいろ面倒だなぁ...。
結論
上記をいろいろ考えるとめんどくさいことこの上ないので、以下のようにコンテナ外部からのポート番号をコンテナ内部のポート番号と同じにした方が楽ですね。
-pで指定するときにコンテナ内部のポート番号がどっちに来るかわからなくなりそうですが。
VBのhostポート | VBのguestポート | -p | sample.pyのポート | コンテナ外部からのアクセス |
---|---|---|---|---|
7000 | 7000 | 7000:7000 | 7000 | 127.0.0.1:7000 |
ちなみに、コンテナ内部のポート番号(今回で言えば、sample.pyのポート番号)を変更すると、いきなりつながらなくなるので注意です。
VBのhostポート | VBのguestポート | -p | sample.pyのポート | コンテナ外部からのアクセス |
---|---|---|---|---|
7000 | 7000 | 7000:7000 | 8888 | 127.0.0.1:7000で不可 |
7000 | 7000 | 7000:7000 | 8888 | 127.0.0.1:8888で不可 |
何にせよ、Docker Toolboxを使う場合は要注意です。