とあるお兄さんの雑記

基本的に技術系の内容を書きますが、何を書くかは私の気分です。

Docker Toolboxでポートフォワーディングできない!場合の対処法

最近Dockerというものを勉強しており、理屈はどうあれ最低限業務で使えるようになることを目標に頑張っています。

で、ポートフォワーディングというものに引っかかってしまい、解決まで苦労したのでそれの備忘録的なものです。

「Dockerってそもそも何?」って方には全く訳が分からない記事ですので、ある程度Dockerが使え、Docker Toolboxでポートフォワーディングできなくなったときは参考にしてもらえればと思います。

環境

Windows 10 Pro バージョン 1903
Docker Toolbox
Dockerバージョン: 18.09.1
VirtualBox: 6.1.16

ポートフォワーディングについて

IPネットワーク上のある機器が、自らのIPアドレスTCPUDPの特定のポート番号への通信を、別のアドレスの特定のポートへ自動的に転送すること。また、ネットワーク機器などのもつそのような機能。

IT用語辞典 e-Wordsより

Dockerの場合、コンテナ内のサーバにコンテナ外部からアクセスするためには、このポートフォワーディングが必要で、これをしないとコンテナ外部からコンテナ内のサーバにアクセスすることはできません。

やりたかったこと

ひとまず、コンテナ内のサーバにコンテナ外部からアクセスできることを確かめられれば良かったので、サンプル程度のFlaskアプリを使いました。

用意したファイルは以下の3つです。

  1. sample.py
  2. Dockerfile
  3. 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)すれば、コンテナ内部のサーバにアクセスできるわけですが....。

f:id:kurasher:20201108114209p:plain


出来ない。なんでや?

試してみたこと1

調べてみると、Docker Toolboxでポートフォワーディングをやる場合、VirtualBoxの方でも設定をいじらないといけないようです。めんどくさい....。
以下の記事を参考にVirtualBoxで設定を変えます。

Docker Toolboxでポートフォワーディング!【Windows 10 Home】

ホストはコンテナ外部から、ゲストはコンテナ内部を指しているので、それぞれ以下のようにポート番号を指定します。

f:id:kurasher:20201108115625p:plain

これでVirtualBoxを再起動し、再度buildし、runして、http://127.0.0.1:9000でアクセスすると、

f:id:kurasher:20201108114209p:plain

出来ない。なんでや?(2度目)

ちなみに、http://127.0.0.1:7000でも無理でした。

試してみたこと2

今度は以下のようにしてみました。

f:id:kurasher:20201108114901p:plain

そのうえで、VirtualBoxを再起動し、再度buildし、runして、http://127.0.0.1:7000でアクセスすると、

f:id:kurasher:20201108121433p:plain

できた。謎。ちなみに、http://127.0.0.1:9000はアクセスできませんでした。

VirtualBoxの設定と、run時の-pのport番号とコンテナ内のsample.pyのポート番号の組み合わせ

上記3つに対し、いろいろ試した結果を下に記します。sample.pyのポート番号は7000で固定です。

表のVBVirtualBoxの略記です。

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のポートの設定は絶対に必要と言えます。

それ以外で、アクセスできる設定の共通点を絞り出すと、
VBhostと、-pの右側コンテナ内のサーバのポート番号(今回で言えば、sample.pyのポート番号)、コンテナ外部からアクセスする場合のポート番号同じもの
であることが必要そうです。

加えて、No13の結果も含めて考えると、上記の条件に、
VBguest-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を使う場合は要注意です。