Closed25

Next.js, Prisma2, MySQL環境をdockerで作っていく

水瀬ひろ水瀬ひろ

まずはnvmをインストール
nodeとnpmのバージョン切り替えが楽になるみたい
(Rubyでいうrbenvみたいなものか)

export NVM_DIR="$HOME/.nvm" && (
  git clone https://github.com/nvm-sh/nvm.git "$NVM_DIR"
  cd "$NVM_DIR"
  git checkout `git describe --abbrev=0 --tags --match "v[0-9]*" $(git rev-list --tags --max-count=1)`
) && \. "$NVM_DIR/nvm.sh"

これを5行まとめてコピペ

インストール確認

command -v nvm
// nvm

nvm ls
// ->       system
// iojs -> N/A (default)
// node -> stable (-> N/A) (default)
// unstable -> N/A (default)

何も入ってないので安定バージョンをインストール

nvm install --lts --latest-npm

nvm ls
// ->     v14.15.4
//          system
// default -> lts/* (-> v14.15.4)
// iojs -> N/A (default)
// unstable -> N/A (default)
// node -> stable (-> v14.15.4) (default)
// stable -> 14.15 (-> v14.15.4) (default)
// lts/* -> lts/fermium (-> v14.15.4)
// lts/argon -> v4.9.1 (-> N/A)
// lts/boron -> v6.17.1 (-> N/A)
// lts/carbon -> v8.17.0 (-> N/A)
// lts/dubnium -> v10.23.2 (-> N/A)
// lts/erbium -> v12.20.1 (-> N/A)
// lts/fermium -> v14.15.4

色々入った。良さそうなので最新版を使っていきます。

nvm use 14.15.4
// Now using node v14.15.4 (npm v6.14.11)
水瀬ひろ水瀬ひろ

必要なファイルを作っていく

npm init -y
touch .gitignore

gitignoreにはgithubにあげる必要のない色々なファイルを書いていく
.gitignore

**/node_modules
.DS_Store
.next/
etc...
水瀬ひろ水瀬ひろ

次はフロントエンドであるNextの準備

mkdir frontend

cd frontend
npm init -y
npm install --save next react react-dom @zeit/next-css
npm install --save-dev @types/node @types/react @types/react-dom typescript
touch tsconfig.json

.tsconfig.json

{
  "compilerOptions": {
    "allowJs": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "lib": ["dom", "es2017"],
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "esnext"
  },
  "exclude": ["node_modules"],
  "include": ["**/*.ts", "**/*.tsx"]
}
touch next.config.js

next.config.js

const withCSS = require('@zeit/next-css')
module.exports = withCSS({})
touch next-env.d.ts

next-env.d.ts

/// <reference types="next" />
/// <reference types="next/types/global" />
水瀬ひろ水瀬ひろ
mkdir components
mkdir pages

cd pages
touch index.tsx

index.tsx

import * as React from 'react'
import { NextPage } from 'next'

const IndexPage: NextPage = () => {
  return <h1>Index Page</h1>
}

export default IndexPage
水瀬ひろ水瀬ひろ

Next.jsの起動するためのコマンドを追加
frontend/package.json

"scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "type-check": "tsc"
  },
水瀬ひろ水瀬ひろ

次はメインディレクトリに戻ってバックエンドを構築

cd ../

npm install -g @prisma/cli

mkdir backend
cd backend
prisma init
水瀬ひろ水瀬ひろ

続いてdocker-composeファイルの作成

touch docker-compose.yml
version: '3.7'
services:
  mysql:
    container_name: mysql
    ports:
      - '3306:3306'
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: prisma
      MYSQL_ROOT_PASSWORD: prisma
    volumes:
      - mysql:/var/lib/mysql
  prisma:
    links:
      - mysql
    depends_on:
      - mysql
    container_name: prisma
    ports:
      - '5555:5555'
    build:
      context: backend/prisma
      dockerfile: Dockerfile
    volumes:
      - /app/prisma
  backend:
    links:
      - mysql
    depends_on:
      - mysql
    container_name: backend
    ports:
      - '4000:4000'
    build:
      context: backend
      dockerfile: Dockerfile
    volumes:
      - ./backend:/app
      - /app/node_modules
      - /app/prisma
  frontend:
    container_name: frontend
    ports:
      - '3000:3000'
    build:
      context: frontend
      dockerfile: Dockerfile
    volumes:
      - ./frontend:/app
      - /app/node_modules
      - /app/.next

volumes: #define our mysql volume used above
  mysql:
水瀬ひろ水瀬ひろ

それぞれのディレクトリにDockerfileを用意する

cd frontend
touch Dockerfile
FROM node:14.15.4

RUN mkdir /app
WORKDIR /app

COPY package*.json ./
RUN npm install

CMD [ "npm", "run", "dev" ]
水瀬ひろ水瀬ひろ
cd ../backend
touch Dockerfile
FROM node:14.15.4
RUN npm install -g --unsafe-perm @prisma/cli

RUN mkdir /app
WORKDIR /app

COPY package*.json ./
COPY prisma ./prisma/

RUN npm install
RUN prisma generate

CMD [ "npm", "start" ]
水瀬ひろ水瀬ひろ
cd prisma
touch Dockerfile
FROM node:14.15.4
RUN npm install -g --unsafe-perm @prisma/cli

RUN mkdir /app
WORKDIR /app

COPY ./ ./prisma/

CMD [ "prisma", "dev"]
水瀬ひろ水瀬ひろ

prismaでMySQLを使うように変更

backend/prisma/schema.prisma

datasource db {
  provider = "mysql"
  url      = "mysql://root:prisma@mysql:3306/prisma"
}
水瀬ひろ水瀬ひろ

メインディレクトリにスクリプトを追加

package.json

"start": "docker-compose up",
"build": "docker-compose build",
"stop": "docker-compose down",
"clean": "docker system prune -af",
"clean:volumes": "docker volume prune -f",
"seed": "docker exec -it prisma npm run seed",
水瀬ひろ水瀬ひろ
npm run build

// mysql uses an image, skipping
// Building prisma

// Traceback (most recent call last):
//   File "compose/cli/main.py", line 67, in main
//   File "compose/cli/main.py", line 126, in perform_command
//   File "compose/cli/main.py", line 302, in build
//   File "compose/project.py", line 468, in build
//   File "compose/project.py", line 450, in build_service
//   File "compose/service.py", line 1147, in build
// compose.service.BuildError: (<Service: prisma>, {'message': 'Cannot locate specified Dockerfile: Dockerfile'})

// During handling of the above exception, another exception occurred:
水瀬ひろ水瀬ひろ

スクラップに追加しただけでまだDockerfile作ってなかった:sob:

水瀬ひろ水瀬ひろ

気を取り直してもう一度

npm run build

// ERROR: Service 'prisma' failed to build : The command '/bin/sh -c npm install -g --unsafe-perm prisma@cli' returned a non-zero code: 1

ライブラリ名の誤字。。

水瀬ひろ水瀬ひろ
You don't have any models defined in your schema.prisma, so nothing will be generated.
You can define a model like this:

スキーマ定義を一つも書いてないとダメみたい

prisma/schema.prisma

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
}
水瀬ひろ水瀬ひろ

たくさんワーニングが出ているので後で読むメモ

npm WARN backend@1.0.0 No description
npm WARN backend@1.0.0 No repository field.

npm WARN backend@1.0.0 No description
npm WARN backend@1.0.0 No repository field.

npm WARN backend@1.0.0 No description
npm WARN backend@1.0.0 No repository field.

npm WARN frontend@1.0.0 No description
npm WARN frontend@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules/watchpack-chokidar2/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
水瀬ひろ水瀬ひろ

ここが問題だった
backend/Dockerfile
as-is

FROM node:14.15.4
RUN npm install -g --unsafe-perm @prisma/cli

RUN mkdir /app
WORKDIR /app

COPY package*.json ./
COPY prisma ./prisma/

RUN npm install
RUN prisma generate

CMD [ "npm", "start" ]

to-be

FROM node:14.15.4
RUN npm install -g --unsafe-perm @prisma/cli

RUN mkdir /app
WORKDIR /app

COPY package*.json ./
COPY prisma ./prisma/

RUN npm install
RUN npx prisma generate

CMD [ "npm", "migrate:prisma" ]
CMD [ "npm", "start" ]
水瀬ひろ水瀬ひろ

image作成時にprismaをgenerateしていたのはよかったが、コンテナ立ち上げでMySQLと接続した後にmigrateを通す必要があった。

なのでコマンドを追加

CMD [ "npm", "migrate:prisma" ]

migrate:prismaはpackage.jsonにコマンド作成
package.json

"migrate:prisma": "prisma migrate dev --preview-feature --name init",
水瀬ひろ水瀬ひろ

https://zenn.dev/minasehiro/scraps/fbeff4f99771f9#comment-6b991396d58ec1
ワーニングを調べていく

これはgit管理すれば解決するみたい

npm WARN backend@1.0.0 No description
npm WARN backend@1.0.0 No repository field.

npm WARN backend@1.0.0 No description
npm WARN backend@1.0.0 No repository field.

npm WARN backend@1.0.0 No description
npm WARN backend@1.0.0 No repository field.

npm WARN frontend@1.0.0 No description
npm WARN frontend@1.0.0 No repository field.

これは関連するオプションが必要なければ --no-optional していい
npm install --no-optional

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules/watchpack-chokidar2/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
このスクラップは2021/01/30にクローズされました