Automattic / node-canvas

Node canvas is a Cairo backed Canvas implementation for NodeJS.
10.09k stars 1.16k forks source link

Canvas won't run in a docker container #2413

Open Vigintillionn opened 1 month ago

Vigintillionn commented 1 month ago

Issue or Feature

I've been trying to get canvas to work in a docker container, running a discord bot. I can install canvas without issues, the problem is canvas won't run. Nor on node:20 nor node:20-alpine. Has anyone had this happen to them and possibly knows a solution to this? Here's the error I'm getting

obsidian-dev  | Error: libjpeg.so.8: cannot open shared object file: No such file or directory
obsidian-dev  |     at Module._extensions..node (node:internal/modules/cjs/loader:1454:18)
obsidian-dev  |     at Object.nodeDevHook [as .node] (/usr/src/node_modules/ts-node-dev/lib/hook.js:63:13)
obsidian-dev  |     at Module.load (node:internal/modules/cjs/loader:1208:32)
obsidian-dev  |     at Function.Module._load (node:internal/modules/cjs/loader:1024:12)
obsidian-dev  |     at Module.require (node:internal/modules/cjs/loader:1233:19)
obsidian-dev  |     at require (node:internal/modules/helpers:179:18)
obsidian-dev  |     at Object.<anonymous> (/usr/src/node_modules/canvas/lib/bindings.js:3:18)
obsidian-dev  |     at Module._compile (node:internal/modules/cjs/loader:1358:14)
obsidian-dev  |     at Module._compile (/usr/src/node_modules/source-map-support/source-map-support.js:568:25)
obsidian-dev  |     at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
obsidian-dev  | [ERROR] 14:04:23 Error: libjpeg.so.8: cannot open shared object file: No such file or directory

libjpeg8 is no longer part of debian nor alpine. I tried installing it but that didn't work either. Then I tried installing libjpeg62-turbo and create a symlink, but that didn't work either.

The code runs fine outside of my container (on my arch machine).

Steps to Reproduce

Here's my docker container:

# Base image with Node.js
FROM node:20 as base

# Create and set the working directory
RUN mkdir -p /usr/src
WORKDIR /usr/src

RUN apt-get update && apt-get install -y build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev

# Copy package.json and install dependencies
COPY package*.json ./
RUN npm install

# Copy the rest of the application code
COPY . .

# Production build
FROM base as production
ENV NODE_ENV=production
CMD ["npm", "run", "start"]

# Development build
FROM base as development
ENV NODE_ENV=development
CMD ["npm", "run", "dev"]

Your Environment

igorrogi1603 commented 1 month ago

I'm facing the same issue. If you manage to solve it, let me know.

igorrogi1603 commented 1 month ago

I managed to solve the problem. The issue lies in the node_modules folder. Once Canvas is installed in node_modules on the local machine (in my case, Windows), and you try to create the Docker image from your local machine, for some reason, Canvas throws an error. I believe it signs something in its package specific to that environment, and when the Docker image is generated, it tries to use the node_modules from the PC, causing an issue. Either you delete the node_modules folder from the project before generating the Docker image, or you add a .dockerignore file and ignore node_modules, similar to how .gitignore works.

Vigintillionn commented 1 month ago

I already have a dockerignore file with node_modules in. Would you mind sharing your dockerfile?

igorrogi1603 commented 1 month ago

Use the Node.js base image

FROM node:20

Install system dependencies necessary for native modules like canvas

RUN apt-get update && apt-get install -y \ build-essential \ libcairo2-dev \ libpango1.0-dev \ libjpeg-dev \ libgif-dev \ librsvg2-dev \ libtool \ autoconf \ automake \ && rm -rf /var/lib/apt/lists/*

Set the working directory

WORKDIR /app

Copy "package.json" and "yarn.lock" before other files

Use Docker cache to avoid reinstalling dependencies if they haven't changed

COPY package.json yarn.lock ./

Install dependencies using Yarn

RUN yarn

Reinstall canvas separately - sometimes needed locally

RUN yarn add canvas

Copy all files

COPY . .

Build the application (if necessary)

RUN yarn build

Install PM2 globally

RUN yarn global add pm2

Expose the listening port

EXPOSE 3333

Run migrations before starting the application with PM2

RUN ./node_modules/.bin/typeorm migration:run

Use PM2 to start the application in cluster mode

CMD ["pm2-runtime", "start", "ecosystem.config.js"]

Vigintillionn commented 1 month ago

This unfortunately did not resolve my issue. I still am receiving the same error.

igorrogi1603 commented 1 month ago

Access the node-canvas documentation -> https://www.npmjs.com/package/canvas Sometimes you might be using methods that are only supported in the browser and not in the backend.

Vigintillionn commented 1 month ago

I'm only using the createCanvas method.