How to create a Dockerfile for Nextjs and graphql? - docker

I tried to deploy my Nextjs project to Heroku via Docker, so i follow docs on internet,then i get a Dockerfile like this
# Install dependencies only when needed
FROM node:alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# COPY package.json yarn.lock ./
COPY package.json package-lock.json ./
# RUN yarn install --frozen-lockfile
RUN npm ci
# Rebuild the source code only when needed
FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
# RUN yarn build && yarn install --production --ignore-scripts --prefer-offline
RUN npm run build && npm install --production --ignore-scripts --prefer-offline
# Production image, copy all the files and run next
FROM node:alpine AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# You only need to copy next.config.js if you are NOT using the default configuration
# COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
ENV NEXT_TELEMETRY_DISABLED 1
# CMD ["yarn", "start"]
CMD ["npm", "run", "start"]
and .dockerignore
node_modules
.next
But i get this error when building
ERROR [runner 5/8] COPY --from=builder /app/public ./public
I think this error right because i don't see public folder in my project, maybe my project missing it
Then i go to learn basic about docker, i dont know so much , but i can create a simple Dockerfile like this
FROM node
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . .
# RUN npm run build
# ENV NODE_ENV=production
EXPOSE 3000
USER node
CMD [ "npm","run","dev"]
with .dockerignore above,I test it with dev enviroment, if it can run I'll edit to production, I run my project by command
docker run -it -p 3000:3000 --name run-my-client my-client
But i get this error
[Error: EACCES: permission denied, unlink '/usr/src/app/.next/build-manifest.json'] {
errno: -13,
code: 'EACCES',
syscall: 'unlink',
path: '/usr/src/app/.next/build-manifest.json'
}
I still see build-manifest.json file in .next folder, but i don't know why this error is appear.Am i missing something and How can i fix it?

Related

Is there a reason why yarn build takes long inside Docker?

I'm trying to build a nextjs app (yarn build) inside docker but it's taking extremely long 1hr+ to generate static pages.
Outside docker, it doesn't take long. I've also noticed it doesn't take this long inside github actions so I'm suspecting it might be something related to my Docker?
I'm using Docker version 20.10.14, build a224086 on Mac-OS
Here is My Dockerfile just incase
# Install dependencies only when needed
FROM node:16 AS deps
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:16 AS builder
ARG API_KEY \
API_BASE \
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
NEXT_TELEMETRY_DISABLED=1
ENV API_KEY=${API_KEY} \
API_BASE=${API_BASE} \
NEXT_TELEMETRY_DISABLED=${NEXT_TELEMETRY_DISABLED}
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build
# Production image, copy all the files and run next
FROM node:16 AS runner
ENV NODE_ENV production \
NEXT_TELEMETRY_DISABLED=1
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/scripts ./scripts
COPY --from=builder --chown=nextjs:nodejs /app/src/data ./src/data
USER nextjs
EXPOSE 3000
CMD ["yarn", "start"]
For me, I didn't have a .dockerignore thus all my nodemodules were being copied over to Docker which was taking extremely long.
So, create a .dockerignore file and add what you want ignored by docker in it e.g nodemodules

Next JS App Dockerfile build locally but fails in Cloud Run when CI/CD

While trying to implement CI/CD in Cloud Run using a Dockerfile, it fails as if some fail were not found. I have built the same container locally with no issues. Here is my Dockerfile:
NextJS version: 12.0.1
Docker: 4.4.2
# Install dependencies only when needed
FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:16-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build
# Production image, copy all the files and run next
FROM node:16-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
ENV PORT 3000
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
# ENV NEXT_TELEMETRY_DISABLED 1
CMD ["node", "server.js"]
The error displayed is the following:
enter image description here
Does anyone know what could be the problem here?
Are you on MacOS ? I had a similar issue a few weeks ago. The issue was casing : APFS is case insensitive by default. So everything worked on my local machine but failed when running on Linux.

Docker : Cannot find module when running NextJS app in a docker-compose

So I am trying to run a NextJS app inside a docker-compose.
In order to have a NextJS boilerplate + a Docker image to build the container, I followed the steps provided in the docker example of the NextJS official repo.
Here is the provided Dockerfile :
# Install dependencies only when needed
FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
# Production image, copy all the files and run next
FROM node:16-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# You only need to copy next.config.js if you are NOT using the default configuration
# COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
# ENV NEXT_TELEMETRY_DISABLED 1
CMD ["node", "server.js"]
From there, I created a docker-compose.yml file at the root of the app, and try to write it myself so that it starts the NextJS app :
version: "3"
services:
web:
build:
context: .
dockerfile: Dockerfile
container_name: web
restart: always
volumes:
- ./:/app
- /app/node_modules
- /app/.next
ports:
- 3004:3000
However, when running sudo docker-compose up --build, I get the following error :
node:internal/modules/cjs/loader:936
throw err;
^
Error: Cannot find module '/app/server.js'
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
at Function.Module._load (node:internal/modules/cjs/loader:778:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Why is it not able to find the node modules? What am I doing wrong exactly?
Here is my docker file from the same boiler plate which is working for me.
# Install dependencies only when needed
FROM node:alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN export NODE_OPTIONS=--openssl-legacy-provider && yarn build && yarn install --production --ignore-scripts --prefer-offline
# Production image, copy all the files and run next
FROM node:alpine AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# You only need to copy next.config.js if you are NOT using the default configuration
# COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
# USER nextjs
ENV PORT=80
EXPOSE 80
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
ENV NEXT_TELEMETRY_DISABLED 1
CMD ["yarn", "start"]
I have commented # USER nextjs as nextjs user was not working.
And this is my dockerignore file
**/.classpath
**/.dockerignore
**/.env.development
**/.git
**/.github
**/.husky
**/.idea
**/.next
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-d

Dockerizing Nextjs

I need to publish my Next js project on a server. For that, by request of admin, I need to dockerize it (because SWC compiler is not available on the server).
I set up Docker Desktop, created Dockerfile (content below) and docker-compose.yml (content below)
Then I successfully ran "docker-compose build"
and then "docker-compose up" - after that website is successfully work on my localhost:3000
What is my next steps? What should I provide to admin? I can push those 2 files on Github, but I guess, it's not enough. I can see in my docker app, that it created image of 723.88 Mb. Maybe I need to sent this one? But how and where it located?
I'm a noob in Docker, any advice is highly welcomed.
My Dockerfile:
# Install dependencies only when needed
FROM node:alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build && yarn install --production --ignore-scripts --prefer-offline
# Production image, copy all the files and run next
FROM node:alpine AS runner
WORKDIR /app
RUN npm install --global pm2
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
ENV NEXT_TELEMETRY_DISABLED 1
# Run npm start script with PM2 when container starts
CMD [ "pm2-runtime", "npm", "--", "start" ]
My docker-compose.yml file:
version: '3'
services:
next:
build: ./frontend
image: dockerhubid/project-webui:latest
ports:
- '3000:3000'

Next JS DockerFile for Cloud Build in GCP

This is the recommended Dockerfile from the official documentation
# Install dependencies only when needed
FROM node:alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build && yarn install --production --ignore-scripts --prefer-offline
# Production image, copy all the files and run next
FROM node:alpine AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# You only need to copy next.config.js if you are NOT using the default configuration
# COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
ENV PORT 3000
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
# ENV NEXT_TELEMETRY_DISABLED 1
CMD ["node_modules/.bin/next", "start"]
It takes about 8min to build right now, it was 6 plus something at the beginning.
I'm deploying it into GCP using a Cloud Build pipeline which trigger is a push to a given branch and just wondering the reason to add three different runs of node:alpine.
At the end it will be triggered anytime some push happen in the given branch so it will need to re-create everything.
Shouldn't something like this work better for those building it outside Vercel or similar?
FROM node:14.17-alpine AS deps
RUN apk update
RUN apk add --no-cache libc6-compat
WORKDIR /app
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
COPY package.json ./
RUN yarn build && yarn install --production
COPY /app/next.config.js ./
COPY /app/public ./public
COPY --chown=nextjs:nodejs /app/.next ./.next
COPY /app/node_modules ./node_modules
COPY /app/package.json ./package.json
RUN npx next telemetry disable
USER nextjs
EXPOSE 3000
CMD ["yarn", "start"]
It's not working and I'm trying to make it work like that to see results but in the meantime I would like to get help on figuring out if there's any issue in my mental workaround about that, I'm not an expert on that so I may be missing something.
The reason it's faster is because at the point where you do your yarn build, the only file you've copied into the image is package.json. The original Dockerfile has copied everything, so it can actually build your app.
As for the multi-stage nature of the first Dockerfile, I think its main advantage is that the final image only contains the output of the build. With a single-stage build like the latter file, the image will contain both the source files and the built files.

Resources