DockerでExpress APIサーバを立ち上げる


DockerでExpressを使うことが多いので、設定方法などをメモします。
ソースコードは[GitHub🐱](https://github.com/hinahinako/docker-sample/tree/master/express)でも公開しています。

## 🌱 環境
- MacOS: macOS Monterey 12.4
- node: 16.17.0

## 🗂 ディレクトリ構成

```
.
└── express
  ├── Dockerfile
  ├── docker-compose.yaml
  ├── index.js
  ├── node_modules
  ├── package-lock.json
  └── package.json
```

## 🐳 手順

### ① Expressプロジェクト作成

以下のコマンドを叩きます
```
mkdir express
cd express
npm init
npm i express
```

index.jsを作成します

```js:index.js
const express = require('express')
const app = express()

/**
 * サーバ起動
 */
const server = app.listen(8000, function () {
  console.log('🚀 app started. port:' + server.address().port)
})

/**
 * GET /test
 */
app.get('/test', async function (req, res, next) {
  console.log('/test called')
  res.send('/test called')
})
```

#### 解説

以下はexpressを開始しています

```js
const express = require('express')
const app = express()
```


以下はポート8000でAPIサーバを起動しています

```js
const server = app.listen(8000, function () {
  console.log('🚀 app started. port:' + server.address().port)
})
```


以下は `GET /test`でリクエストが来たら `/test called`を表示するAPIを定義しています

```js
app.get('/test', async function (req, res, next) {
  console.log('/test called')
  res.send('/test called')
})
```

サーバがちゃんと動くことを確認します
```
node index.js
```

以下が表示されればOKです
```
🚀 app started. port:8000
```

以下でサーバを停止します
```
exit
```

### ② イメージ作成
Dockerfileを作成します

```docker:Dockerfile
FROM node:16
WORKDIR /usr/src/app
COPY ./index.js .
COPY ./package*.json .
RUN npm install
EXPOSE 8000
CMD [ "node", "index.js" ]
```

イメージビルドします (しばらく待ちます)
```
docker build -t my-express-container .
```

できたイメージを確認します
```
docker images
```
以下が表示されればOKです
```
REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
my-express-container   latest    xxXXxxXXxx     9 seconds ago   915MB
```


#### 👩‍🏫 解説
Dockerファイルとは...

>一言で説明すると、Dockerイメージの設計図になります。
新規にDockerイメージを作成するための手順を記したテキストファイルになります

上から順に読むだけで動きが大体わかります。
```docker
FROM node:16               # ベースイメージです
WORKDIR /usr/src/app       # 命令実行時の作業ディレクトリです
COPY ./index.js .          # index.jsを /usr/src/app配下にコピーしています
COPY ./package*.json .     # package.jsonなどを/usr/src/app配下にコピーしています
RUN npm install            # npm installしています
EXPOSE 8000                # 8000番ポートを解放しています
CMD [ "node", "index.js" ] # node index.js`を実行しています
```

参考にさせていただきました
- [Dockerfileとは](https://aiacademy.jp/media/?p=1386)
- [Docker入門（第四回）～Dockerfileについて～](https://knowledge.sakura.ad.jp/15253/)

### ③ コンテナ立ち上げ

docker-compose.yamlを作成します

```yaml:docker-compose.yaml
version: "3.9"
services:
  my-express:
    image: my-express-container
    container_name: my-express-api
    build:
      context: .
    ports:
      - "8001:8000"
```

コンテナを立ち上げます 
```
docker compose up -d
```

立ち上がったことを確認します
```
docker ps
```

以下のように表示されればOKです

```
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                        NAMES
yyYYyyYYyy     xxXXxxXXxx     "docker-entrypoint.s…"   6 seconds ago   Up 4 seconds   0.0.0.0:8001->8000/tcp, :::8001->8000/tcp    my-express-api
```



#### 👩‍🏫 解説

```yaml:docker-compose.yaml
version: "3.9"
services: 
  my-express:                       # サービス名です
    image: my-express-container     # イメージ名です　※1
    container_name: my-express-api  # コンテナ名です
    build:
      context: .                    # ビルドを実行した場所(Dockerfileの場所)です
    ports:
      - "8001:8000"                 # ポートです ※2
```

**<font color="MediumVioletRed">※1</font> imageについて**
imageには前のステップで実行した `docker build -t <イメージ名>`のイメージ名を設定します

**<font color="MediumVioletRed">※2</font> portについて**
左側(8001) = Dockerで解放するポート(ホストPCからアクセスするポート)です
左側(8000) = expressサーバで設定しているポートです

参考にさせていただきました
- [docker-compose.ymlのbuild設定はとりあえずcontextもdockerfileも埋めとけって話](https://qiita.com/sam8helloworld/items/e7fffa9afc82aea68a7a)


## 🌐 アクセスしてみる


```
curl localhost:8001/test
```

以下が返って来ればOKです

```
/test called
```

## 📙 参考
- [Docker ドキュメント(日本語)](https://docs.docker.jp/index.html)