初学者によるDocker理解まとめ③　〜nginxを使ってAPIをproxyするまで〜

# はじめに
ようやくDockerを学び始めたので自分の理解をまとめておく。
前回 => https://qiita.com/theFirstPenguin/items/58e6bc5acf90dc497cb0
次回 => https://qiita.com/theFirstPenguin/items/b5f6ed253bed95fbec5a

#  今日の学びをメモ
ローカルPC上でnode.jsでexpressを実行するコンテナとnginxを実行するコンテナを立ち上げる。そしてnginxを経由してexpressのAPIを叩く。たったこれだけをdocker-composeを使ってやってみた。

## 前回までと今回の違い
[前回](https://qiita.com/theFirstPenguin/items/58e6bc5acf90dc497cb0)ではexpressのコンテナにアクセスするためにportを指定する必要があった。

```
curl http://localhost:3000
Hello
```
![スクリーンショット 2020-10-22 22.22.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/c692cc05-dde9-eb97-e013-cc0a5f354b87.png)

今回はnginxのproxy機能を用いて、portを指定せずexpressのコンテナにアクセスできるようにした。

```
curl http://:localhost
Hello
```
![スクリーンショット 2020-10-23 8.32.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/f3c84f6b-a823-ccec-71be-a0887489c489.png)


## 開発の全体像

```
ｃd ~
mkdir sample
```
sampleディレクトリの中で開発する。ディレクトリの中身はこんな感じになる。
appディレクトリとwebディレクトリがそれぞれexpressとnginxのコンテナとなる。
![スクリーンショット 2020-10-23 8.24.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/13332f7c-5e04-b50f-eb9d-7f09f5c9eb03.png)


```index.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
  res.send('Hello').status(200);
});

app.listen(3000, () => {
  console.log('Listening on port 3000');
});
```
## expressバックエンドのDockerfileの準備

```Dockerfile
FROM node:alpine

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm ci --only=production

# Bundle app source
COPY . .
# package.jsonをコピー後にnpm installするという作業をビルドの度に毎回やりたくない。
# そのため、上記を終わらせてから COPY. .をやる。
# そうすればコードを変えた部分だけビルドが実行される。

EXPOSE 3000
CMD [ "node", "index.js" ]
```

## nginx.confの準備
nginxコンテナの中の、localhostの80port（つまりhttpのデフォルトport）の全てのエンドポイント(/)に来たリクエストを`http://app:3000`にproxyする。
Dockerの管理下において、appコンテナのドメインがappになっていることに注目。
ちなみに、この設定ファイル名は`nginx.conf`で固定とのこと。配置場所はwebディレクトリ以下であれば特に気にしない。

```nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
	worker_connections 1024;
}

http {
	# Weather Report Reverse Proxy
         server {
            listen 80;
            server_name localhost 127.0.0.1;

            location / {
                proxy_pass          http://app:3000;
                proxy_set_header    X-Forwarded-For $remote_addr;
            }

        }
}
```

## docker-compose.ymlの準備
```docker-compose.yml
version: '3'
# 何も考えず３を指定
services:
  app:
    build:
      context: ./app
      # docker-compose.ymlから見て./appにあるDockerfileにしたがってビルドする
    container_name: express-app
    # 一応コンテナ名をつける
    ports:
      - '3000:3000'
      # docker run -p 3000:3000 app と一緒
    volumes:
      - './app:/usr/src/app'
      # ローカルPCの./appフォルダと、コンテナ内の ~/usr/src/appフォルダを同期させる。
      # docker exec -it express-app sh で確認できる

  web:
    image: nginx:latest 
    #nginx:alpilneだとエラーが起きるので、一応最新版で対応。
    container_name: nginx-web
    ports:
      - '80:80'
    volumes:
      - './web/reverse_proxy/nginx.conf:/etc/nginx/nginx.conf'
      # ローカルPCの./web/reverse_proxy/nginx.confと、コンテナ内の ~/etc/nginx/nginx.confを同期させる。
      # ~/etc/nginx/nginx.confは場所指定。
    links:
      - app
    depends_on:
      - app
      # appコンテナが起動しないと機能しない、という依存関係を明記。

```

## docker-compose up して終わり
`docker-compose up`すればコンテナが立ち上がります。
ローカルPCからcurlコマンドを打てばappコンテナから返事が帰ってきます。最初の図の通りです。

```
curl http://localhost
Hello
```

ちなみに直接appコンテナにもアクセスできます。当然ですが。

```
curl http://localhost:3000
Hello
```


# 最後に
初歩中の初歩をまとめました。
ちなみに、自分は何度やってもnginxがうまく起動せず絶望しかけましたが、`docker ps`をすると`k8s_controller_ingress-nginx-controller`という謎のコンテナ（というかkubernetesのingressだと思われる）が`docker stop`しても止まらないことに気付きました。kubernetesを再起動すると直ったので、仮にそんな状況があれば試すのもいいかと思います。

![スクリーンショット 2020-10-23 9.33.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/57e88526-bb98-0356-52f2-f9aaf26510db.png)


ありがとうございました。