vercel / commerce

Next.js Commerce
https://demo.vercel.store
MIT License
11.46k stars 4.24k forks source link

Add dockerfile for hosting outside of vercel #481

Closed burn2delete closed 2 years ago

okbel commented 2 years ago

We're not planning on building a docker image.

Aryojaam commented 2 years ago

Here is a sample Dockerfile for running the project in docker. Just make sure before running, make sure:

NEXT_PUBLIC_VENDURE_SHOP_API_URL=http://localhost:3000/shop-api NEXT_PUBLIC_VENDURE_LOCAL_URL=/vendure-shop-api

*  secondly, your vendure backend is running and reachable

So, here is the `Dockerfile` which is located in the root of your project:

FROM node:latest EXPOSE 8000

WORKDIR /app/

COPY package.json /app/ COPY turbo.json /app/ COPY yarn.lock /app/ COPY site/ /app/site/ COPY packages/ /app/packages/

RUN yarn

remove comment for production

RUN yarn build

WORKDIR /app/site/

use for production instead of dev

CMD yarn next start -p 8000

CMD yarn next dev -p 8000


Additionally I use `docker-compose` for starting.
Here is a sample `docker-compose.yml` which should also be located in the root folder of the project as well.

version: '3.1'

services: server: build: ./ restart: always ports:

gnacoding commented 1 year ago

@Aryojaam

Hi Since this repo changed from using yarn to pnpm, did you by any chance figured out how to do this with pnpm? I adjusted your Dockerfile to use pnpm. But Cloud Run is throwing me errors.

I've taken a look at vercels official example: https://github.com/vercel/turbo/tree/main/examples/with-docker This uses yarn as well and places the Dockerfile inside the actual app-folder not the root.

EDIT: Happy new year!

Aryojaam commented 1 year ago

@gnacoding Happy new year! :) Unfortunately I do not have experience with either pnpm or Cloud Run. Maybe you can post the error you are getting here? But just a wild guess for a fix might be installing pnpm globally in your container with npm i -g pnpm and then using it in the next steps if you are not already not doing so?

gnacoding commented 1 year ago

@Aryojaam Thanks for the answer! This is the modified Dockerfile that I used to build the image:

FROM docker.io/node:16-alpine
# Set up pnpm
RUN apk add --no-cache libc6-compat
RUN npm install -g pnpm
RUN npm install -g turbo@1.4.6

WORKDIR /app/

COPY package.json /app/
COPY turbo.json /app/
COPY pnpm-lock.yaml /app/
COPY pnpm-workspace.yaml /app/
COPY packages/ /app/packages/
COPY site/ /app/site/

RUN pnpm install
RUN pnpm build

WORKDIR /app/site/

# use for production instead of dev
# CMD yarn next start -p 8000
CMD pnpm next start

When I ran this image locally it works just fine, but when I deploy it with Cloud Run it builds the image but when I open the URL it just says 'Service Unavailable'. I noticed with this Dockerfile the image is over 2GB large since it does no cleanup. What Cloud Build does is basically taking the Dockerfile from the GitHub Repo and attempts to build it with 'docker build...' and deploys it to its serverless instance Cloud Run (like AWS Lambda).


This was the beginning of my 2 day 'walking down the rabbit hole session' I ended up finding a few more hints from: https://github.com/vercel/next.js/discussions/39432 https://github.com/vercel/turbo/issues/534 https://github.com/pnpm/pnpm/issues/3114 https://github.com/pnpm/pnpm/discussions/4777 Yarn: https://github.com/Elvincth/turbo-strapi-nextjs/blob/main/dev.Dockerfile https://github.com/thmsmtylr/turborepo-starter/blob/main/Dockerfile https://github.com/vercel/turbo/tree/main/examples/with-docker


Based on the links above I created/modified the Dockerfile like this:

# Builder image
FROM docker.io/node:16-alpine AS build

RUN apk add --no-cache curl bash git

ARG PROJECT_NAME=site

WORKDIR /app

# Set up pnpm
RUN apk add --no-cache libc6-compat
RUN npm install -g pnpm
RUN npm install -g turbo@1.4.6
RUN pnpm config set store-dir .pnpm-store
COPY pnpm-lock.yaml  ./
RUN pnpm fetch

# Build
COPY . .
RUN pnpm install --frozen-lockfile --offline --ignore-scripts --workspace-root --filter ${PROJECT_NAME}...
RUN pnpm run build --filter=${PROJECT_NAME}...
# WORKAROUND FOR: https://github.com/vercel/next.js/discussions/39432
RUN pnpm install --prod --frozen-lockfile --offline --shamefully-hoist --ignore-scripts --workspace-root --filter ${PROJECT_NAME} && \
    cp -Lr ./node_modules ./node_modules_temp && \
    rm -rf ./node_modules_temp/.cache && \
    rm -rf ./node_modules_temp/.pnpm
# END WORKAROUND

# Runtime image
FROM docker.io/node:16-alpine AS release

ARG PROJECT_NAME=site

ENV NODE_ENV=production
ENV PORT=3000

WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=build --chown=nextjs:nodejs /app/${PROJECT_NAME}/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/${PROJECT_NAME}/.next/static* ./.next/static
COPY --from=build --chown=nextjs:nodejs /app/${PROJECT_NAME}/public* ./public

# WORKAROUND FOR: https://github.com/vercel/next.js/discussions/39432
RUN rm -rf ./node_modules
COPY --from=build /app/node_modules_temp ./node_modules
# END WORKAROUND

USER nextjs

EXPOSE 3000

CMD ["node", "server.js"]

This Dockerfile runs great and when I inspect the image the prod-build looks perfect but it gives me the same error created in this issue: https://github.com/vercel/next.js/discussions/39432

docker run -p 3000:3000 test5                                                                                                                                                               ─╯
node:internal/modules/cjs/loader:998
  throw err;
  ^

Error: Cannot find module 'next/dist/server/next-server'
Require stack:
- /app/server.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:995:15)
    at Function.Module._load (node:internal/modules/cjs/loader:841:27)
    at Module.require (node:internal/modules/cjs/loader:1067:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at Object.<anonymous> (/app/server.js:2:20)
    at Module._compile (node:internal/modules/cjs/loader:1165:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1219:10)
    at Module.load (node:internal/modules/cjs/loader:1043:32)
    at Function.Module._load (node:internal/modules/cjs/loader:878:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/app/server.js' ]

I started a discussion here and will Update it once I find a solution: https://github.com/vercel/commerce/discussions/928

brmk commented 1 year ago

Posting the Dockerfile that works for me. I had to upgrade next to 13.4 to get rid of the "Error: Cannot find module 'next/dist/server/next-server'" error and now it works perfectly

P.S. I'm using an old setup with packages/ and site/ folders since it has vendure provider.

# Builder image
FROM docker.io/node:16-alpine AS build

RUN apk add --no-cache curl bash git

ARG PROJECT_NAME=site

WORKDIR /app

# Set up pnpm
RUN apk add --no-cache libc6-compat
RUN npm install -g pnpm
RUN npm install -g turbo@1.4.6
RUN pnpm config set store-dir .pnpm-store
COPY pnpm-lock.yaml  ./
RUN pnpm fetch

# Build
COPY . .
RUN pnpm install --frozen-lockfile --offline --ignore-scripts --workspace-root --filter ${PROJECT_NAME}...
# Install sharp module
RUN cd site && pnpm add sharp
RUN pnpm run build --filter=${PROJECT_NAME}...

# Runtime image
FROM docker.io/node:16-alpine AS release

ENV NODE_ENV=production
ENV PORT=8000

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

COPY --from=build --chown=nextjs:nodejs /app/site/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/site/.next/static ./site/.next/static
COPY --from=build --chown=nextjs:nodejs /app/site/public ./site/public

# RUN ./node_modules/.bin/next telemetry disable

USER nextjs

CMD ["node", "site/server.js"]

EXPOSE 8000