【Node.js】 Dockerを用いてNode.js Express MySQLの環境を構築するまでの道のり

本記事で作ったdockerfileを整理したものをまとめた記事は⬇️
https://qiita.com/sho_U/items/52e221877a271146ce84



完成イメージ構成
nodoDocker(rootディレクトリ)
![a03c9651ffb5bba1c53532460a232639.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/c8bc6f40-6a48-c333-2fe3-dc296c2e2127.png)

###Dockerfile:
アプリケーション用(node.js)コンテナを作るためのfile

###app.env:
mysqlとの接続設定を記載したファイル

###docker-compose.yml:
node.jsコンテナとmysqlコンテナを管理するyml

###src:
アプリケーション本体

##アプリケーション用のコンテナを作成する
まずはアプリケーション用の仮コンテナを作成し、アプリの雛形を作成する。そのアプリの雛形はホスト側にマウントしておき、その雛形を利用してdocker-composeを作成していく。

nodeDocker配下に
docker-compose.ymlを作成

```docker-compose.yml
version: '3'
services:
  app:
    # dockerimageのファイルを指定
    build: .

    # コンテナ名
    container_name: node_docker_app

    # 環境変数を設定
    environment:
      - DEBUG=app:*

    tty: true

    # ホスト側のポート:コンテナのポート
    ports:
      - '3000:3000'

    # ソースコードを格納するフォルダをマウント
    #（ホスト側の./srcをコンテナの/appにマウント）
    volumes:
      - ./src:/app

    # 起動時のカレントフォルダを指定
    working_dir: /app

    # 起動後に実行するコマンドを指定(起動確認用）
    command: npm start


```

node をプルする。

```dockrefile.
FROM node:12
```

```ホスト.
#コンテナを一時的に起動（--rmで停止後削除する。コンテナ起動後、bashに入る）
docker-compose run --rm app /bin/bash
```

```コンテナ.
# express-generatorでアプリケーションのひな形を生成
npx express-generator

# 依存パッケージをインストール
npm install

#コンテナを抜ける（この仮コンテナは削除される)
exit
```
※この時、コンテナは削除されるが

```docker-compose.yml
    volumes:
      - ./src:/app
```
この記述により、.(docker-compose.ymlがあるディレクトリ。つまりnodoDockerディレクトリの配下のsrcディレクトリにマウントされているため、ホスト側のsrcディレクトリに作成した雛形は残っている。

コンテナを起動させる

```host.
docker-compose up
```

```docker-compose.yml
    command: npm start
```
の記載により、コンテナ起動後、自動的にExpress.jsのアプリケーションが起動する。
http://localhost:3000/
で確認。

コンテナを停止

```host.
#再度コンテナを一時的に起動
docker-compose run --rm app /bin/bash

#ソースコードの変更を検知して必要な時にアプリケーションを再起動してくれる、「nodemon」というツールをインストール。
#変更のたびにコンテナの停止・再起動することしなくてよくする。
npm install -D nodemon
```

package.jsonを修正

```src/package.json
"scripts": {
  "dev": "nodemon ./bin/www",
  "start": "node ./bin/www"
},
```

docker-compose.ymlファイルを編集

```docker-compose.yml
（変更前）
command: npm start

（変更後）
command: npm run dev
```

##MySQL用コンテナを追加

docker-compose.ymlにmysqlの設定を追加

```docker-compose.yml
version: '3'
services:
  mysql:
    image: mysql:5.7
    env_file: ./mysql/mysql.env
    #環境変数設定。タイムゾーンを日本時間に設定。
    environment:
      - TZ=Asia/Tokyo
    ports:
      - '3306:3306'
    volumes:
      #mysqlのデフォルト設定ファイルを上書き。:roでコンテナ側からは読み取り専用設定。
      - ./mysql/conf:/etc/mysql/conf.d/:ro
      #mysqldataにマウントすることで、コンテナを削除してもデーターは残るように設定。
      - mysqldata:/var/lib/mysql
    networks:
      - backend

  app:
    image: node:12
    env_file: ./app.env
    #環境変数設定。タイムゾーンを日本時間に設定。
    environment:
      - TZ=Asia/Tokyo
      - DEBUG=app:*
    tty: true
    ports:
      - '3000:3000'
    volumes:
      - ./src:/app
    working_dir: /app
    command: npm run dev
    networks:
      - backend
    #mysqlに依存しているので、mysqlコンテナ作成後、appコンテナが作られる。
    depends_on:
      - mysql

networks:
  backend:

volumes:
  mysqldata:
```
my.confを作成（コンテナ側の/etc/mysql/conf.d/に配置される。)

```mysql/conf/my.conf
[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mysqldump]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin
lower_case_table_names=1

# Enable access from the host machine.
bind-address=0.0.0.0
```

mysqlフォルダにmysql.envファイルを作成。(env_file: ./mysql/mysql.envの記載により、内容がコンテナ側のmysqlの環境変数に設定される)

```mysql/mysql.env
MYSQL_ROOT_HOST=%
MYSQL_ROOT_PASSWORD=（ルートパスワード）
MYSQL_USER=（ユーザー名）
MYSQL_PASSWORD=（パスワード）
MYSQL_DATABASE=todo
```

app.envファイルを作成(アプリケーションコンテナの環境変数設定)

```app.env
MYSQL_SERVER=mysql
MYSQL_USER=（ユーザー名）
MYSQL_PASSWORD=（パスワード）
MYSQL_DATABASE=todo
```

```docker-compose.yml
version: '3'
services:
  mysql:
    image: mysql:5.7
    container_name: node_docker_db
    env_file: ./mysql/mysql.env
    environment:
      - TZ=Asia/Tokyo
    ports:
      - '3306:3306'
    volumes:
      - ./mysql/conf:/etc/mysql/conf.d/:ro
      - mysqldata:/var/lib/mysql
    networks:
      - backend

  app:
    image: node:12
    container_name: node_docker_app
    env_file: ./app.env
    environment:
      - TZ=Asia/Tokyo
      - DEBUG=app:*
    tty: true
    ports:
      - '3000:3000'
    volumes:
      - ./src:/app
    working_dir: /app
    command: npm run dev
    networks:
      - backend
    depends_on:
      - mysql

#使用するネットワークを作成。docker-composeの場合service以下の名前を使って名前解決されるため、appとmysqlが自動的に接続される。
networks:
  backend:

volumes:
  mysqldata:
```

mysqlにログイン

```host.
docker-compose exec mysql mysql -uroot -p
```
できない、、、

```
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
```
いろいろ試した結果

```host.
docker-compose down --volumes
```
volumeを削除したら、ログインできた。原因は不明。

ejsをテンプレートエンジンに使用するためインストールを記載したdockerfileをルート直下に配置。

```Dockerfile
#node.jsのイメージをプル。
FROM node:12
#作業ディレクトリをアプリケーションディレクトリにする。
WORKDIR /app
ejsをインストール。
RUN npm install ejs
```
アプリ件ーションコンテナはDockerfileでビルドするようにしたため（元々はnode:12イメージをプルしてた）修正

```docker-compose.yml
（変更前）
image: node:12

（変更後）
build: .
```


ひとまず完了。