I have a NestJS project that uses TypeORM with a MySQL database. I dockerized it using docker compose, and everything works fine on my machine (Mac). But when I run it from my remote instance (Ubuntu 22.04) I got the following error:
server | yarn run v1.22.19
server | $ node dist/main
server | node:internal/modules/cjs/loader:998
server | throw err;
server | ^
server |
server | Error: Cannot find module '/usr/src/app/dist/main'
server | at Module._resolveFilename (node:internal/modules/cjs/loader:995:15)
server | at Module._load (node:internal/modules/cjs/loader:841:27)
server | at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
server | at node:internal/main/run_main_module:23:47 {
server | code: 'MODULE_NOT_FOUND',
server | requireStack: []
server | }
server |
server | Node.js v18.12.0
server | error Command failed with exit code 1.
server | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
server exited with code 1
Here is my Dockerfile
:
FROM node:18-alpine AS development
# Create app directory
WORKDIR /usr/src/app
# Copy files needed for dependencies installation
COPY package.json yarn.lock ./
# Disable postinstall script that tries to install husky
RUN npx --quiet pinst --disable
# Install app dependencies
RUN yarn install --pure-lockfile
# Copy all files
COPY . .
# Increase the memory limit to be able to build
ENV NODE_OPTIONS=--max_old_space_size=4096
ENV GENERATE_SOURCEMAP=false
# Entrypoint command
RUN yarn build
FROM node:18-alpine AS production
# Set env to production
ENV NODE_ENV=production
# Create app directory
WORKDIR /usr/src/app
# Copy files needed for dependencies installation
COPY package.json yarn.lock ./
# Disable postinstall script that tries to install husky
RUN npx --quiet pinst --disable
# Install app dependencies
RUN yarn install --production --pure-lockfile
# Copy all files
COPY . .
# Copy dist folder generated in development stage
COPY --from=development /usr/src/app/dist ./dist
# Entrypoint command
CMD ["node", "dist/main"]
And here is my docker-compose.yml
file:
version: "3.9"
services:
server:
container_name: blognote_server
image: bladx/blognote-server:latest
build:
context: .
dockerfile: ./Dockerfile
target: production
environment:
RDS_HOSTNAME: ${MYSQL_HOST}
RDS_USERNAME: ${MYSQL_USER}
RDS_PASSWORD: ${MYSQL_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
command: yarn start:prod
ports:
- "3000:3000"
networks:
- blognote-network
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
links:
- mysql
depends_on:
- mysql
restart: unless-stopped
mysql:
container_name: blognote_database
image: mysql:8.0
command: mysqld --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
ports:
- "3306:3306"
networks:
- blognote-network
volumes:
- blognote_mysql_data:/var/lib/mysql
restart: unless-stopped
networks:
blognote-network:
external: true
volumes:
blognote_mysql_data:
Here is what I tried to do:
- I cleaned everything on my machine and then run
docker compose --env-file .env.docker up
but this did work. - I run my server image using docker (not docker compose) and it did work too.
- I tried to make a snapshot then connect to it and run
node dist/main
manually, but this also worked.
So I don't know why I'm still getting this error.
And why do I have a different behavior using docker compose
(on my remote instance)?
Am I missing something?
CodePudding user response:
Your docker-compose.yml
contains two lines that hide everything the image does:
volumes:
# Replace the image's `/usr/src/app`, including the built
# files, with content from the host.
- .:/usr/src/app
# But: the `node_modules` directory is user-provided content
# that and needs to be persisted separately from the container
# lifecycle. Keep that tree in an anonymous volume and never
# update it, even if it changes in the image or the host.
- /usr/src/app/node_modules
You should delete this entire block.
You will see volumes:
blocks like that that try to simulate a local-development environment in an otherwise isolated Docker container. This will work only if the Dockerfile only COPY
s the source code into the image without modifying it at all, and the node_modules
library tree never changes.
In your case, the Dockerfile produces a /usr/src/app/dist
directory in the image which may not be present on the host. Since the first bind mount hides everything in the image's /usr/src/app
directory, you don't get to see this built tree; and your image is directly running node
on that built application and not trying to simulate a local development environment. The volumes:
don't make sense here and cause problems.