やりたい事
ブラウザ(ホスト側)からのHTTPリクエストにより、Docker(コンテナ)上のアプリからのレスポンス「Hello World」をブラウザ(ホスト側)に出力したい
■前提
- DockerFileを利用すること
- WebサーバにはPythonのFlaskを利用
■補足
-
勝手に思っていることですが「ホスト」と「コンテナ」は別世界と捉えると理解しやすくなります
※違うかもしれませんが、現実世界とメタバース、みたいな関係? -
その別世界に対する「環境構築」までの手順は基本、ターミナルからのCUIベース。
アプリの実行はブラウザ経由です。
知りたい事
大きくは下記の点です
- DockerFileとアプリケーションファイルの関連性
- Dockerを利用したブラウザ経由の通信の仕組み
STEP1:アプリケーションファイルを作ろう!
まずは、Docker関係なく、ローカル(ホスト側)で「Hello World」が出力されるAPファイル(hello.py)を用意
from flask import Flask
#Flaskオブジェクトを生成、[__name__]はおまじない的なやつ
app = Flask(__name__)
#ブラウザで[localhost]の仮想ディレクトリルートが指定された場合の挙動(hello worldを出力)
@app.route('/')
def hello():
return 'hello world'
#webサーバを起動
if __name__ == '__main__':
app.run(debug='true',host='0.0.0.0',port='8888')
■ポイント
- Docker(コンテナ)上で動作させるためには、app.run の「host='0.0.0.0'」がめちゃポイント。
ローカル(ホスト側)だけの場合、これがなくても動作したのですが、Docker(コンテナ)上での場合は、これがわからず、躓きましたね。
そして、これが「知りたい事」に記載したDockerを利用したブラウザ経由の通信の仕組み
の部分の話になります。
<解説>
■「host='0.0.0.0'」がない場合
-
デフォルトは「host='127.0.0.1'」として動作するようです。
つまり、「127.0.0.1(ローカルホスト)」からのリクエストに対して処理する、ということ。 -
ホスト側からのリクエスト=127.0.0.1でしょ?という思ってしまうのですが、これが間違い。
-
「ホスト」と「コンテナ」は別世界(別ネットワーク)であり、ルータでつながっていると思ってください。
-
「ホスト」側からのリクエストは「ルータ」を経由するときには「127.0.0.1」ではなく、別に割り当てられたIPアドレスとなってしまいます。
そのため、「127.0.0.1(ローカルホスト)」からのリクエストではないため、処理できない、ということ。 -
「host='0.0.0.0'」を設定することで、どこからのリクエストでも処理しますよ、になるのでこれが大事、ということ。
STEP2:Dockerファイルを作ろう!
Dockerファイルとはアプリケーションを実行するための環境(※)をイメージとして作り出すための設計図のようなものです。
※今回は下記の3つの手順で構築
- Pythonモジュール(Flask含む)の「コンテナ」という別世界へのインストール
- アプリケーションファイル(hello.py)の「コンテナ」という別世界へのコピー
- アプリケーションファイル(hello.py)の「コンテナ」という別世界での実行(webサーバの起ち上げ)
この設計図をもとに「build」コマンドを実行すると「image」が作られます。
その「image」を「run」コマンドで実行すると「コンテナ」が作成・起動されます。
設計図 → イメージ → コンテナ
という流れですね。
from python:3.8
#ワークディレクトリを作成
workdir /var/www
#ホスト側のhello.pyをコンテナ側の[var/www]へコピー
copy ./src /var/www
run pip install flask
CMD python hello.py
STEP3:Dockerイメージの作成 および コンテナの作成・起動
powershellよりwslを起動し実行。
※本題ではないため、詳細は省略
<イメージの作成>
docker build -t hello .
<コンテナの作成・起動>
docker run -p 8888:8888 --name hello -v ${PWD}/src:/var/www hello:latest
■ポイント
- ポートの設定部分(-p)で、ローカル(ホスト側)の「8888番ポート」とDocker(コンテナ)上の「8888番ポート」をリンクせよという指示です
STEP4:ローカル(ホスト側)からブラウザ経由で実施
こんな感じでできました。
いかがでしたでしょうか。