Ryo9597
@Ryo9597

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

DockerでPrismaのマイグレーションが実行できない

前提・実現したいこと

DockerでExpressとMySQLの環境を構築しています。
ORMマッパーとして、Prismaを使用しています。

以下のコードで、Prismaのマイグレーションを行ったのですがエラーが発生します。

npx prisma migrate dev --name init

発生している問題・エラーメッセージ

エラーメッセージ

❯ docker-compose exec app ash
/node # npx prisma migrate dev --name init

Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "Nuxt-Express-TypeScript" at "db:6306"

Error: P1001: Can't reach database server at `db`:`6306`

Please make sure your database server is running at `db`:`6306`.

該当のソースコード

docker-compose.yml

version: '3.8'

volumes:
  db-data:

services:
  # MySQL
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: $MYSQL_DATABASE
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      TZ: $TZ
    volumes:
      - db-data:/var/lib/mysql
      - db-data:/etc/mysql/conf.d/my.cnf
    ports:
      - $DB_PORT:3306

  #【backend】Express
  app:
    build:
      context: ./docker/app
    environment:
      TZ: $TZ
      DEBUG: $BACKEND_DEBUG
      DATABASE_URL: $BACKEND_DATABASE_URL
    tty: true
    ports:
      - $BACKEND_PORT:18080
    restart: always
    volumes:
      - $BACKEND_DIR:$BACKEND_WORK_DIR
    working_dir: $BACKEND_WORK_DIR
    command: [sh, -c, npm install && npm run build && npm run start]

.env

# mysql
DB_PORT = "6306"

# backend
BACKEND_PORT = "18080"

# frontend
FRONT_PORT = "3000"
STORYBOOK_PORT = "6006"

# Dockerfile <mysql>
MYSQL_DATABASE = "Nuxt-Express-TypeScript"
MYSQL_ROOT_PASSWORD = "password"
TZ = "Asia/Tokyo"

# Dockerfile <backend>
BACKEND_DIR = "./api"
BACKEND_WORK_DIR = "/node"
BACKEND_DEBUG = "api:*"
BACKEND_DATABASE_URL = "mysql://root:password@db:6306/Nuxt-Express-TypeScript"

Dockerfile

FROM node:14.15.3-alpine
WORKDIR /node

RUN apk update && apk add bash

COPY package*.json ./

RUN npm install

EXPOSE 18080

CMD  npm run build && npm run start

prisma/schema.prisma

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
}

試したこと

Sequel ProでDBにアクセスできるかどうか確認

接続確認しました。

スクリーンショット 2021-08-25 20.24.31.png

無事接続でき、Nuxt-Express-TypeScriptというDBが作成できていることが確認できました。

スクリーンショット 2021-08-25 20.23.28.png

DBのホスト名を変更

今回のエラーは、DBへの接続が出来ていないというものかと思います。
なので、今回はホスト名がlocalhostではなく、dbになると思うので、そこの修正を行いました。

(修正前) mysql://root:password@localhost:6306/Nuxt-Express-TypeScript

(修正後) mysql://root:password@db:6306/Nuxt-Express-TypeScript

修正前も修正後もどちらもマイグレーションに失敗しました。

どこに問題があり、エラーが発生するかが分からないのでお教えいただけますと幸いです。
よろしくお願いいたします。

@bigen1925様のご指摘に対する補足

結論から書くと、マイグレーションは成功するのですが、DBへのアクセスができません

docker-compose.ymlを修正し、port3306で起動するように変更しました。

docker-compose.yml
version: '3.8'

volumes:
  db-data:

services:
  # MySQL
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: $MYSQL_DATABASE
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      TZ: $TZ
    volumes:
      - db-data:/var/lib/mysql
      - db-data:/etc/mysql/conf.d/my.cnf

  #【backend】Express
  app:
    build:
      context: ./docker/app
    environment:
      TZ: $TZ
      DEBUG: $BACKEND_DEBUG
      DATABASE_URL: $BACKEND_DATABASE_URL
    tty: true
    ports:
      - $BACKEND_PORT:18080
    restart: always
    volumes:
      - $BACKEND_DIR:$BACKEND_WORK_DIR
    working_dir: $BACKEND_WORK_DIR
    command: [sh, -c, npm install && npm run build && npm run start]

問題なく動作しています。

ターミナル
❯ docker-compose ps
         Name                   Command           State           Ports         
--------------------------------------------------------------------------------
docker-nuxt-             docker-entrypoint.sh     Up      0.0.0.0:18080->18080/t
typescript-              sh -c ...                        cp                    
express_app_1                                                                   
docker-nuxt-             docker-entrypoint.sh     Up      3306/tcp, 33060/tcp   
typescript-              mysqld                                                 
express_db_1  

.envの修正を行います。

.env
# mysql
DB_PORT = "6306"

# backend
BACKEND_PORT = "18080"

# frontend
FRONT_PORT = "3000"
STORYBOOK_PORT = "6006"

# Dockerfile <mysql>
MYSQL_DATABASE = "Nuxt-Express-TypeScript"
MYSQL_ROOT_PASSWORD = "password"
TZ = "Asia/Tokyo"

# Dockerfile <backend>
BACKEND_DIR = "./api"
BACKEND_WORK_DIR = "/node"
BACKEND_DEBUG = "api:*"
- BACKEND_DATABASE_URL = "mysql://root:password@db:6306/Nuxt-Express-TypeScript"
+ BACKEND_DATABASE_URL = "mysql://root:password@db:3306/Nuxt-Express-TypeScript"

マイグレーションの実行を行います。(マイグレーションを同様の方法で試したこともあるので、このまま続けていいかい?みたいなメッセージも出ています。)

ターミナル
❯ docker-compose exec app ash 
/node # npx prisma migrate dev --name init
Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "Nuxt-Express-TypeScript" at "db:3306"

✔ - Drift detected: Your database schema is not in sync with your migration history.

The following is a summary of the differences between the expected database schema given your migrations files, and the actual schema of the database.

It should be understood as the set of changes to get from the expected schema to the actual schema.

[+] Added tables
  - User

- The following migration(s) are applied to the database but missing from the local migrations directory: 20210826070628_init


We need to reset the MySQL database "Nuxt-Express-TypeScript" at "db:3306".
Do you want to continue? All data will be lost. … yes

The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20210826115115_init/
    └─ migration.sql

Your database is now in sync with your schema.

✔ Generated Prisma Client (2.30.0) to ./node_modules/@prisma/client in 69ms

prisma には、 GUI でデータベース上のデータを閲覧・編集できるprisma studioを使用する。

ターミナル
/node # npx prisma studio
Prisma schema loaded from prisma/schema.prisma
Prisma Studio is up on http://localhost:5555

アクセスすると、エラーとなります。

スクリーンショット 2021-08-26 21.02.28.png

また、Sequel Proでアクセスしてみます。
こちらも失敗しました。

スクリーンショット 2021-08-26 21.03.38.png

なので、マイグレーションは成功したと思うのですが、テーブルが確認できていません。。

解決

.envに追記を行う

.env
# mysql
DB_PORT = "6306"

# backend
BACKEND_PORT = "18080"
+ STUDIO_PORT = "5555"

# frontend
FRONT_PORT = "3000"
STORYBOOK_PORT = "6006"

# Dockerfile <mysql>
MYSQL_DATABASE = "Nuxt-Express-TypeScript"
MYSQL_ROOT_PASSWORD = "password"
TZ = "Asia/Tokyo"

# Dockerfile <backend>
BACKEND_DIR = "./api"
BACKEND_WORK_DIR = "/node"
BACKEND_DEBUG = "api:*"
BACKEND_DATABASE_URL = "mysql://root:password@db:3306/Nuxt-Express-TypeScript"

docker-compose.ymlで5555のポートを開放させる。

docker-compose.yml
version: '3.8'

volumes:
  db-data:

services:
  # MySQL
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: $MYSQL_DATABASE
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      TZ: $TZ
    volumes:
      - db-data:/var/lib/mysql
      - db-data:/etc/mysql/conf.d/my.cnf

  #【backend】Express
  app:
    build:
      context: ./docker/app
    environment:
      TZ: $TZ
      DEBUG: $BACKEND_DEBUG
      DATABASE_URL: $BACKEND_DATABASE_URL
    tty: true
    ports:
      - $BACKEND_PORT:18080
+     - $STUDIO_PORT:5555
    restart: always
    volumes:
      - $BACKEND_DIR:$BACKEND_WORK_DIR
    working_dir: $BACKEND_WORK_DIR
    command: [sh, -c, npm install && npm run build && npm run start]

これで接続できました。

スクリーンショット 2021-08-28 9.36.01.png

お答えいただきありがとうございました!

0

3Answer

そもそもdocker-composeを使っているのなら、デフォルトでサービス間は同じネットワークに居ると考えていいと思います。

# 特別なことをしていないのであれば、この設定はなくてもdefaultネットワークが
# 勝手に作られるし、サービス間で同じネットワークに入っている状態になる

networks:
  container-link: # これらは必要ないと思う

...
    networks:
      - container-link

...
    networks:
      - container-link

外した上で起動して、各サービスコンテナ内で

$ ping db
$ ping app

とかしてみると分かる。

なのでapp->db間は3306ポートで通信できるはず

# ホスト側でdbの内容を見るとかでなければ、わざわざホスト側にポートを開放する必要はないと思う
    ports:
      - $DB_PORT:3306 

mysqlのイメージについては別途Dockerfileはdocker-composeを使っているので書く必要がないような...

... via docker stack deploy or docker-compose

  db:
    image: mysql
...
...
    environment:
      MYSQL_ROOT_PASSWORD: example

environmentにEnvironment Variablesにある値は設定できる。
英語が難しければdeepL

そしてせっかく.envを用意しているのに、ここがベタ書きなのは気になる。
root:password@db:6306

datasource db {
  provider = "mysql"
  url      = "mysql://root:password@db:6306/Nuxt-Express-TypeScript"
}

.envの内容をコンテナ内で使うなら、

docker-compose.yml
...

    env_file:
      - .env
...

として、各サービスのコンテナ内に入って

$ printenv

とかしてみると分かる。

ホストからは開放した6306ポートで接続ができるということなので、サービス間のネットワーク、ポート、mysqlのDockerfile、mysqlパスワード辺りでなにか想定してないことが起きてて、接続ができていなさそう。

1Like

Comments

  1. @Ryo9597

    Questioner

    ご指摘ありがとうございます。
    ご指摘いただいた箇所に関しては修正いたしました。

    やはりサービス間のネットワークあたりが怪しいですよね。
    もう少し色々試してみます!

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

TL;DR

BACKEND_DATABASE_URL = "mysql://root:password@db:6306/Nuxt-Express-TypeScript"

BACKEND_DATABASE_URL = "mysql://root:password@db:3306/Nuxt-Express-TypeScript"

としてください。

補足

qiita_docker.jpg

==========

追記

TL; DR

prisma studioはappコンテナで起動した上で、docker-compose.ymlに

service:
  app:
    ports:
      - $BAKEND_PORT:18080
      - xxxx:5555

を追加して、ブラウザからは http://localhost:xxxx へアクセスしてみてください。

追加するxxxxは任意のポートで構わなく、5555でも構いません
また、 $BAKEND_PORT:18080 はexpressのポートだと思うので削除する必要はありません

追記補足1:

なぜ動くのかはこうです
qiita2.jpg

追記補足2:

現状では動かない理由はこうです
qiita3.jpg

1Like

Comments

  1. @Ryo9597

    Questioner

    ご指摘ありがとうございます。
    また資料まで用意していただき感謝いたします。
    すごくわかりやすく、なぜ3306を使用しなければならないかが理解できました。

    ただマイグレーションは成功しましたが、prisma studioへアクセスできないなど違う問題が発生いたしました。
    こちらはどのように考えればよろしいのでしょうか?
  2. 追記して回答しました
  3. @Ryo9597

    Questioner

    ありがとうございます。
    なぜ動かないか理解できました!

    図解していただき感謝いたします。
  4. Prisma2は非常によくできたツールですので、ぜひ楽しんでください :)
  5. @Ryo9597

    Questioner

    ありがとうございます!
    Prismaをマスターできるよう頑張ります^^

prisma studioは全くわかりませんが、

Prisma Studio is up on http://localhost:5555

    ports:
      - $BACKEND_PORT:18080

5555で起動してるのに、18080を開放しようとしてる?

あとあまり最初から$BACKEND_PORTみたいな変数をあちこちで使わないほうが見通しがいいと思います。よっぽど複数箇所で使うような変数でないならとりあえずベタ書きにしてしまって、疎通確認後に変更していったほうがいいような気がします。

1Like

Comments

  1. @Ryo9597

    Questioner

    ご指摘ありがとうございます。
    そうですね。
    5555のポート開放していないのが原因ですね。
    appコンテナのportsに5555を入れたら、prisma studioにもアクセスできました。

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

Your answer might help someone💌