Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next js output standalone - next:13.2.1, elastic-apm-node: 3.46.0 #3342

Open
2 of 3 tasks
mindyourlifeguide opened this issue May 11, 2023 · 7 comments
Open
2 of 3 tasks
Labels
agent-nodejs Make available for APM Agents project planning. community

Comments

@mindyourlifeguide
Copy link

mindyourlifeguide commented May 11, 2023

Describe the bug

To Reproduce
I have a monorepo with several applications. Package manager - pnpm v8.4.0.

my Dockerfile:

FROM node:16-alpine AS builder

ARG BUILD_ENV=prod
ARG PROJECT_NAME

WORKDIR /app

RUN apk add --no-cache build-base g++ cairo-dev jpeg-dev pango-dev giflib-dev
RUN npm install -g pnpm@8.4.0

COPY . .

RUN pnpm config set store-dir /app/.pnpm-store
RUN --mount=type=secret,id=npmrc,dst=/root/.npmrc \
    --mount=type=tmpfs,target=/app/node_modules/ \
    pnpm install && pnpm build:${BUILD_ENV} --filter=${PROJECT_NAME}

# Production image, copy the necessary files and run next
FROM node:16-alpine AS runner
WORKDIR /app

# args needed to build the docker image
ARG PATH_TO_PROJECT
ARG PROJECT_NAME

# service env variables
ENV PATH_TO_PROJECT $PATH_TO_PROJECT
ENV PROJECT_NAME $PROJECT_NAME
ENV RUN_ENV prod
ENV PORT 3000

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --chown=nextjs:nodejs  --from=builder /app/${PATH_TO_PROJECT}/.next/standalone .
COPY --chown=nextjs:nodejs  --from=builder /app/${PATH_TO_PROJECT}/public ./${PATH_TO_PROJECT}/public
COPY --chown=nextjs:nodejs  --from=builder /app/${PATH_TO_PROJECT}/.next/static ./${PATH_TO_PROJECT}/.next/static

USER nextjs

EXPOSE 3000

CMD node NODE_OPTIONS=--require=elastic-apm-node/start-next.js ./${PATH_TO_PROJECT}/server.js

I have a elastic-apm-node.js
In normal mode, everything worked - the Dockerfile was a little different. When I turned on output: standalone - apm stopped working.
You told me to import the api route package to include in the bundle. The package really dragged on and locally it seemed to even start. But when I build in ci - module not found at startup.

I solved this by removing the options for node NODE_OPTIONS=--require=elastic-apm-node/start-next.js from the Dockerfile and running apm agent manually in api routes. The agent worked, but now it says that the routes are unknown

Expected behavior

Working apm agent with output: standalone

Environment (please complete the following information)

  • OS: macOS 13.3.1 22E261 arm64
  • Node.js version: 18.16.0
  • "elastic-apm-node": "3.45.0",
  • "next": "13.2.1",

How are you starting the agent? (please tick one of the boxes)

  • Calling agent.start() directly (e.g. require('elastic-apm-node').start(...)) - work, but routes are unknown
  • Requiring elastic-apm-node/start from within the source code
  • Starting node with -r elastic-apm-node/start - module not found
@github-actions github-actions bot added agent-nodejs Make available for APM Agents project planning. community triage labels May 11, 2023
@trentm
Copy link
Member

trentm commented May 11, 2023

CMD node NODE_OPTIONS=--require=elastic-apm-node/start-next.js ./${PATH_TO_PROJECT}/server.js

That looks wrong. I think it should be either:

ENV NODE_OPTIONS=--require=elastic-apm-node/start-next.js
CMD node ./${PATH_TO_PROJECT}/server.js

or

CMD node --require=elastic-apm-node/start-next.js ./${PATH_TO_PROJECT}/server.js

I'm not sure this is the issue you are having, however.

@trentm
Copy link
Member

trentm commented May 11, 2023

Also, as I mentioned at #1611 (comment) I wonder if standalone mode is just completely broken in next@13.x.

Can you should a recursive directory listing of /app in your "runner" container? find /app

@trentm trentm removed the triage label May 11, 2023
@mindyourlifeguide
Copy link
Author

@trentm I tried:

CMD node --require=elastic-apm-node/start-next.js ./${PATH_TO_PROJECT}/server.js
CMD node NODE_OPTIONS=--require=elastic-apm-node/start-next.js ./${PATH_TO_PROJECT}/server.js
CMD node -r elastic-apm-node/start-next.js server.js

And always the result was the same.
image

Standalone mode itself works in "next": "13.2.1". Only elastic-apm-node does not work.
The same sentry works and doesn't require the api routes import hack.

@mindyourlifeguide
Copy link
Author

Can you should a recursive directory listing of /app in your "runner" container? find /app

what exactly are you interested in?
image

@mindyourlifeguide
Copy link
Author

@trentm in order for everything to work in nextjs in output standalone mode, you need:

  • import 'elastic-apm-node/start-next.js' - I do it in _document.tsx
  • COPY --chown=nextjs:nodejs --from=builder /app/${PATH_TO_PROJECT}/elastic-apm-node.* ./ - need to add to Dockerfile

Library versions:
"next": "13.2.1",
"elastic-apm-node": "3.46.0",

My final Dockerfile is more complicated since I don't run apm everywhere, but a simplified version would look like this:

FROM node:16-alpine AS builder

ARG BUILD_ENV=prod
ARG PROJECT_NAME

WORKDIR /app

RUN apk add --no-cache build-base g++ cairo-dev jpeg-dev pango-dev giflib-dev
RUN npm install -g pnpm@8.4.0

COPY . .

RUN pnpm config set store-dir /app/.pnpm-store
RUN --mount=type=secret,id=npmrc,dst=/root/.npmrc \
    --mount=type=tmpfs,target=/app/node_modules/ \
    pnpm install && pnpm build:${BUILD_ENV} --filter=${PROJECT_NAME}

# Production image, copy the necessary files and run next
FROM node:16-alpine AS runner
WORKDIR /app

# args needed to build the docker image
ARG PATH_TO_PROJECT
ARG PROJECT_NAME

# service env variables
ENV PATH_TO_PROJECT $PATH_TO_PROJECT
ENV PROJECT_NAME $PROJECT_NAME
ENV RUN_ENV prod
ENV PORT 3000

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --chown=nextjs:nodejs  --from=builder /app/${PATH_TO_PROJECT}/.next/standalone .
COPY --chown=nextjs:nodejs  --from=builder /app/${PATH_TO_PROJECT}/public ./${PATH_TO_PROJECT}/public
COPY --chown=nextjs:nodejs  --from=builder /app/${PATH_TO_PROJECT}/.next/static ./${PATH_TO_PROJECT}/.next/static
COPY --chown=nextjs:nodejs  --from=builder /app/${PATH_TO_PROJECT}/elastic-apm-node.* ./


USER nextjs

EXPOSE 3000

CMD node NODE_OPTIONS=--require=elastic-apm-node/start-next.js ./${PATH_TO_PROJECT}/server.js

@mindyourlifeguide mindyourlifeguide changed the title next js output standalone next js output standalone - next:13.2.1, elastic-apm-node: 3.46.0 May 22, 2023
@sjoukedv
Copy link

sjoukedv commented Jul 29, 2023

I am getting something similar with a more verbose error message below:

/app $ ELASTIC_APM_LOG_LEVEL=trace node --require=elastic-apm-node/start-next.js server.js
{"log.level":"debug","@timestamp":"2023-07-29T14:50:16.728Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"error":{"type":"Error","message":"Cannot find module './modules/next/dist/server/next.js'\nRequire stack:\n- /app/node_modules/elastic-apm-node/lib/instrumentation/index.js\n- /app/node_modules/elastic-apm-node/lib/agent.js\n- /app/node_modules/elastic-apm-node/index.js\n- /app/node_modules/elastic-apm-node/start.js\n- /app/node_modules/elastic-apm-node/start-next.js\n- internal/preload","stack_trace":"Error: Cannot find module './modules/next/dist/server/next.js'\nRequire stack:\n- /app/node_modules/elastic-apm-node/lib/instrumentation/index.js\n- /app/node_modules/elastic-apm-node/lib/agent.js\n- /app/node_modules/elastic-apm-node/index.js\n- /app/node_modules/elastic-apm-node/start.js\n- /app/node_modules/elastic-apm-node/start-next.js\n- internal/preload\n    at Module._resolveFilename (node:internal/modules/cjs/loader:1077:15)\n    at /app/node_modules/next/dist/server/require-hook.js:113:36\n    at Module._load (node:internal/modules/cjs/loader:922:27)\n    at Module.require (node:internal/modules/cjs/loader:1143:19)\n    at Hook._require.Module.require (/app/node_modules/require-in-the-middle/index.js:167:34)\n    at require (node:internal/modules/cjs/helpers:110:18)\n    at /app/node_modules/elastic-apm-node/lib/instrumentation/index.js:142:14\n    at Instrumentation._patchModule (/app/node_modules/elastic-apm-node/lib/instrumentation/index.js:433:20)\n    at /app/node_modules/elastic-apm-node/lib/instrumentation/index.js:358:17\n    at Hook._require.Module.require (/app/node_modules/require-in-the-middle/index.js:262:28)\n    at require (node:internal/modules/cjs/helpers:110:18)\n    at Object.<anonymous> (/app/node_modules/next/dist/server/lib/render-server.js:40:54)\n    at Module._compile (node:internal/modules/cjs/loader:1256:14)\n    at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)\n    at Module.load (node:internal/modules/cjs/loader:1119:32)\n    at Module._load (node:internal/modules/cjs/loader:960:12)\n    at Module.require (node:internal/modules/cjs/loader:1143:19)\n    at Hook._require.Module.require (/app/node_modules/require-in-the-middle/index.js:188:39)\n    at require (node:internal/modules/cjs/helpers:110:18)\n    at execMethod (/app/node_modules/next/dist/compiled/jest-worker/processChild.js:1:2366)\n    at process.messageListener (/app/node_modules/next/dist/compiled/jest-worker/processChild.js:1:1284)\n    at process.emit (node:events:514:28)\n    at emit (node:internal/child_process:937:14)\n    at process.processTicksAndRejections (node:internal/process/task_queues:83:21)"},"message":"Elastic APM caught unhandled exception"}
{"log.level":"trace","@timestamp":"2023-07-29T14:50:16.773Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"azure metadata server responded, but there was an error parsing the result: {}"}
{"log.level":"debug","@timestamp":"2023-07-29T14:50:16.793Z","log":{"logger":"elastic-apm-node"},"filename":"/app/node_modules/next/dist/server/require-hook.js","ecs":{"version":"1.6.0"},"error":{"type":"Error","message":"Error reading sourcemap for file \"/app/node_modules/next/dist/server/require-hook.js\":\nENOENT: no such file or directory, open '/app/node_modules/next/dist/server/require-hook.js.map'","stack_trace":"Error: Error reading sourcemap for file \"/app/node_modules/next/dist/server/require-hook.js\":\nENOENT: no such file or directory, open '/app/node_modules/next/dist/server/require-hook.js.map'"},"message":"could not process file source map"}
{"log.level":"debug","@timestamp":"2023-07-29T14:50:16.794Z","log":{"logger":"elastic-apm-node"},"filename":"/app/node_modules/next/dist/server/lib/render-server.js","ecs":{"version":"1.6.0"},"error":{"type":"Error","message":"Error reading sourcemap for file \"/app/node_modules/next/dist/server/lib/render-server.js\":\nENOENT: no such file or directory, open '/app/node_modules/next/dist/server/lib/render-server.js.map'","stack_trace":"Error: Error reading sourcemap for file \"/app/node_modules/next/dist/server/lib/render-server.js\":\nENOENT: no such file or directory, open '/app/node_modules/next/dist/server/lib/render-server.js.map'"},"message":"could not process file source map"}

These files are indeed not present in the traced output. Can we make sure to add the proper require/include statement such that they are picked up? I believe NextJS uses this tool to do the tracing https://github.com/vercel/nft.

Note; I think the scope is broader to framework that use output file tracing solutions

@snowman95
Copy link

snowman95 commented Feb 1, 2024

I had the same problem with this.
I am sharing my solution. (Caution: This is a trick.)

  • Issue : When using Next.js in standalone mode, an issue occurs in which the elastic-amp-node/start-next.js module cannot be found when built and run in Docker.

  • Cause : Next.js' standAlone mode includes only the dependencies absolutely necessary for production builds in the node_modules folder.
    elastic-amp-node only installs dependencies, but since it is not actually used anywhere in the code, it is judged to be an unnecessary dependency and is not included in node_modules of standAlone, so the module cannot be found.

  • Solution

    • By importing and using elastic-apm-node/start-next in the dummy API, you can include the start-next.js file in standalone/node_modules after building. It may not actually work, but it was imported.
      image
    • After building Next.js, elastic-apm-node is placed in the node_modules folder in the standAlone folder.
      image
    • If you change the path to the last line in DockerFile from node_modules → /app/node_modules, it will run successfully.
      image

my package version

 "next": "13.2.3"
 "elastic-apm-node": "^4.1.0",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
agent-nodejs Make available for APM Agents project planning. community
Projects
None yet
Development

No branches or pull requests

4 participants