简体   繁体   中英

Dockerize NextJS Application with Prisma

I have created a NextJS application, to connect to the database I use Prisma. When I start the application on my computer everything works. Unfortunately, I get error messages when I try to run the application in a Docker container. The container can be created and started. The start page of the application can also be shown (there are no database queries there yet). However, when I click on the first page where there is a database query I get error code 500 - Initial Server Error and the following error message in the console:

PrismaClientInitializationError: Unknown PRISMA_QUERY_ENGINE_LIBRARY undefined. Possible binaryTargets: darwin, darwin-arm64, debian-openssl-1.0.x, debian-openssl-1.1.x, rhel-openssl-1.0.x, rhel-openssl-1.1.x, linux-arm64-openssl-1.1.x, linux-arm64-openssl-1.0.x, linux-arm-openssl-1.1.x, linux-arm-openssl-1.0.x, linux-musl, linux-nixos, windows, freebsd11, freebsd12, openbsd, netbsd, arm, native or a path to the query engine library.
You may have to run prisma generate for your changes to take effect.
    at cb (/usr/src/node_modules/@prisma/client/runtime/index.js:38689:17)
    at async getServerSideProps (/usr/src/.next/server/pages/admin/admin.js:199:20)
    at async Object.renderToHTML (/usr/src/node_modules/next/dist/server/render.js:428:24)
    at async doRender (/usr/src/node_modules/next/dist/server/next-server.js:1144:38)
    at async /usr/src/node_modules/next/dist/server/next-server.js:1236:28
    at async /usr/src/node_modules/next/dist/server/response-cache.js:64:36 {
  clientVersion: '3.6.0',
  errorCode: undefined
}

My Dockerfile:

# Dockerfile

# base image
FROM node:16-alpine3.12

# create & set working directory
RUN mkdir -p /usr/src
WORKDIR /usr/src

# copy source files
COPY . /usr/src

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

# install dependencies
RUN npm install

COPY . .

# start app
RUN npm run build
EXPOSE 3000
CMD npm run start

My docker-compose.yaml:

version: "3"

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: web
    restart: always
    volumes:
      - ./:/usr/src/app
    ports:
      - "3000:3000"
    env_file:
      - .env

My package.json:

{
    "name": "supermarket",
    "version": "0.1.0",
    "private": true,
    "scripts": {
        "dev": "next dev",
        "build": "next build",
        "start": "next start",
        "lint": "next lint"
    },
    "prisma": {
        "schema": "prisma/schema.prisma"
      },
    "dependencies": {
        "@prisma/client": "^3.6.0",
        "axios": "^0.22.0",
        "cookie": "^0.4.1",
        "next": "latest",
        "nodemailer": "^6.6.5",
        "react": "17.0.2",
        "react-cookie": "^4.1.1",
        "react-dom": "17.0.2"
    },
    "devDependencies": {
        "eslint": "7.32.0",
        "eslint-config-next": "11.1.2",
        "prisma": "^3.6.0"
    }
}

I have been having a similar issue, which I have just solved.

I think what you need to do is change the last block in your docker file to this

# start app
RUN npm run build
RUN npx prism generate
EXPOSE 3000
CMD npm run start

I think that will solve your issue.

I've found the error. I think it's a problem with the M1 Chip. I changed node:16-alpine3.12 to node:lts and added some commands to the Dockerfile which looks like this now:

# base image
FROM node:lts

# create & set working directory
RUN mkdir -p /usr/src
WORKDIR /usr/src

# copy source files
COPY . /usr/src

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

RUN apt-get -qy update && apt-get -qy install openssl

# install dependencies
RUN npm install

RUN npm install @prisma/client

COPY . .
RUN npx prisma generate --schema ./prisma/schema.prisma
# start app
RUN npm run build
EXPOSE 3000
CMD npm run start

I hope this can also help other people


I had a luck this way:

FROM node:17-slim as dependencies


# set working directory
WORKDIR /usr/src/app

# Copy package and lockfile
COPY package.json ./
COPY yarn.lock ./
COPY prisma ./prisma/
RUN apt-get -qy update && apt-get -qy install openssl

# install dependencies
RUN yarn --frozen-lockfile

COPY . .

# ---- Build ----
FROM dependencies as build
# install all dependencies

# build project
RUN yarn build

# ---- Release ----
FROM dependencies as release
# copy build
COPY --from=build /usr/src/app/.next ./.next
COPY --from=build /usr/src/app/public ./public

# dont run as root
USER node

# expose and set port number to 3000
EXPOSE 3000
ENV PORT 3000

# enable run as production
ENV NODE_ENV=production

# start app
CMD ["yarn", "start"]

I've found this solution with some workarounds: https://gist.github.com/malteneuss/a7fafae22ea81e778654f72c16fe58d3 In short:

# Dockerfile

...
FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx prisma generate                   # <---important to support Prisma query engine in Alpine Linux in final image
RUN npm run build

# Production image, copy all the files and run next
FROM node:16-alpine AS runner
WORKDIR /app
...
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --chown=nextjs:nodejs prisma ./prisma/                # <---important to support Prisma DB migrations in bootstrap.sh
COPY --chown=nextjs:nodejs bootstrap.sh ./
...
CMD ["./bootstrap.sh"]

This Dockerfile is based on the official Nextjs with Docker example project and adapted to include Prisma. To run migrations on app start we can add a bash script that does so:

# bootstrap.sh

#!/bin/sh
# Run migrations
DATABASE_URL="postgres://postgres:postgres@db:5432/appdb?sslmode=disable" npx prisma migrate deploy
# start app
DATABASE_URL="postgres://postgres:postgres@db:5432/workler?sslmode=disable" node server.js

Unfortunately, we need to explicitly set the DATABASE_URL here, otherwise migrations don't work, because Prisma can't find the environment variable (eg from a docker-compose file). And last but not least, because Alpine Linux base image uses a Musl C-library, the Prisma client has to be compiled in the builder image against that. So, to get the correct version, we need to add this info to Prisma's schema.prisma file:

# schema.prisma

generator client {
  provider = "prisma-client-js"
  binaryTargets = ["native", "linux-musl"] # <---- important to support Prisma Query engine in Alpine linux, otherwise "PrismaClientInitializationError2 [PrismaClientInitializationError]: Query engine binary for current platform "linux-musl" could not be found."
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM