前回
Next.jsとFlaskのアプリを用意しました。
今回の目標
DockerでNginxの環境を作る
こんな感じでリクエストを振り分けます。
Dockerfileの用意
# web/Dockerfile
FROM nginx:latest
「Dockerfileいらないやん」と思うでしょう。その通りです。
まあいつかカスタムしたくなるかもしれませんし...
docker-compose.ymlの用意
version: '3'
services:
api:
build: api
image: sk-api
volumes:
- ./api:/app
ports:
- "8001:8000"
command: 'gunicorn'
front:
build: front
image: sk-front
volumes:
- ./front:/app
ports:
- "3001:3000"
command: 'npm run dev'
web:
build: web
image: sk-web
volumes:
- ./web/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "10101:80"
/etc/nginx/conf.d/default.conf
を上書きして設定を反映させます。
ポートは適当に10101
です。
最初10080
に設定してたんですが、ブラウザから見ようとするとERR_UNSAFE_PORT
というエラーになってしまいました。
こんな罠があるんですね。知りませんでした。
Nginxの設定ファイル
# web/default.conf
server {
listen 80;
location / {
proxy_pass http://front:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://api:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
listen 80;
は80番ポートで受け付けるという意味です。
location /
はhttp://localhost/
の設定で、
location /api
はhttp://localhost/api
の設定です。
proxy_pass
はどこに飛ばすかの設定です。
http://localhost/
はhttp://front:3000
に
http://localhost/api
はhttp://api:8000
に飛ばします。
proxy_set_header
で色々書いてありますが、
どれもクライアントの情報(IP情報など)をそのまま裏に受け流しています。
この設定がないと、裏のNext.jsから見たクライアント情報が全てこのnginxになってしまします。
Dockerコンテナ同士の疎通
Dockerコンテナは独自のネットワーク空間を持っています。
なのでdocker-compose.yml
のports: "10101:80"
などを設定しないとホストPCからコンテナへの通信ができません。
コンテナ同士の通信では、コンテナたちが同じネットワークに属していないといけません。
素のDockerを使う場合、ネットワークを作成して、そのネットワークにコンテナを属させて...みたいな操作が必要になります。
Docker Composeを使う場合、この手間がなくなります。
同じdocker-compose.yml
に書かれたservice
(コンテナ)たちは勝手に同じネットワークに属してくれます。
docker network ls
を打つと
NETWORK ID NAME DRIVER SCOPE
330f30e92154 host host local
16d9e5f32225 skill_default bridge local
ディレクトリ名_default
というネットワークが作成されているのが分かります。
(skill
とかいう適当な名前をつけていた事がバレる)
さらに細かい情報を見る場合は以下のようなコマンドを打ってみてください。
docker network inspect { NETWORK ID }
割り当てられているIPアドレスやら所属しているコンテナやらが見えると思います。
コンテナが同じネットワークに属している場合、「service名」で対象コンテナにアクセスできます。
なので
proxy_pass http://front:3000;
proxy_pass http://api:8000;
みたいに書くことができるわけです。
動作確認
webコンテナを立ち上げる
docker compose up -d
http://localhost:10101/ にアクセスしてみましょう。
frontコンテナにつながってますね。
http://localhost:10101/api にアクセスしてみましょう。
apiコンテナにつながってますね。
CORS問題の解消
CORS (オリジン間リソース共有、Cross-Origin Resource Sharing) という仕組みがあります。
XSS (Cross Site Scripting)攻撃などを防ぐ目的で、
ブラウザが今開いているURLとは違うURLのAPIを使おうとすると怒られます。
今回設定したnginxがない場合、
フロントのlocalhost:8001
からバックのlocalhost:3001
に対してリクエストを送るので、このCORS問題で怒られます。
解決するにはバック側でCORSの許可をしてやる必要があります。
今回、フロントもバックもlocalhost:10101
という同じURLになったので、CORSを考えなくてよくなります。
docker-compsoe.ymlの修正
apiコンテナとfrontコンテナのポートを解放してありましたが、Nginxを経由することでその必要は無くなりました。
なので、ports
を削除してやって設定完了です。
version: '3'
services:
api:
build: api
image: sk-api
volumes:
- ./api:/app
command: 'gunicorn'
front:
build: front
image: sk-front
volumes:
- ./front:/app
command: 'npm run dev'
web:
build: web
image: sk-web
volumes:
- ./web/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "10101:80"
コンテナを再作成しても動作に問題ないことを確認しておきます。
docker compose down
docker compose up -d
次回
DB(MySQL)の用意