エンジニア管理ツールでも作る④Nginx環境用意

# 前回
Next.jsとFlaskのアプリを用意しました。

https://qiita.com/k-jimon/items/34becb7bd9aabdae6d10

https://qiita.com/k-jimon/items/2179afaa50d0df1cde9a

# 今回の目標
DockerでNginxの環境を作る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537927/7df64820-0759-a204-a4ec-3ae34321e2e9.png)

こんな感じでリクエストを振り分けます。

# Dockerfileの用意
```dockerfile
# web/Dockerfile
FROM  nginx:latest
```

「Dockerfileいらないやん」と思うでしょう。その通りです。
まあいつかカスタムしたくなるかもしれませんし...

# docker-compose.ymlの用意
```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`というエラーになってしまいました。
こんな罠があるんですね。知りませんでした。

https://qiita.com/tomo__x_/items/21cf774eb7d8ac0f337e


# Nginxの設定ファイル
```config
# 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/ にアクセスしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537927/0ea929d9-ba42-e318-2209-1c5fac6a456d.png)

frontコンテナにつながってますね。

---

http://localhost:10101/api にアクセスしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537927/e2281275-f788-e1e0-4669-b4288530a027.png)

apiコンテナにつながってますね。

## CORS問題の解消
CORS (オリジン間リソース共有、Cross-Origin Resource Sharing) という仕組みがあります。
XSS (Cross Site Scripting)攻撃などを防ぐ目的で、
ブラウザが今開いているURLとは違うURLのAPIを使おうとすると怒られます。

https://qiita.com/att55/items/2154a8aad8bf1409db2b

今回設定したnginxがない場合、
フロントの`localhost:8001`からバックの`localhost:3001`に対してリクエストを送るので、このCORS問題で怒られます。
解決するにはバック側でCORSの許可をしてやる必要があります。

今回、フロントもバックも`localhost:10101`という同じURLになったので、CORSを考えなくてよくなります。


# docker-compsoe.ymlの修正
apiコンテナとfrontコンテナのポートを解放してありましたが、Nginxを経由することでその必要は無くなりました。
なので、`ports`を削除してやって設定完了です。

```yml
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)の用意