Не работают тома (volumes ) в Docker. Точнее не работает отслеживание изменений файлов в проекте на Nest.js

Я использую Docker version 20.10.21, build baeda1f. Операционная система Windows 11. Решил сделать "докеризацию" приложения на Nest.js. Создал пустой проект через nest cli и установил nodemon, хотя он тут по сути и не нужен, отслеживание работало из бе него. Приложение работает, всё хорошо. Потом я решил создать Docker image и на основе него контейнер. Вот мой Dockerfile

FROM node:latest

WORKDIR /app

RUN npm install -g nodemon

COPY package.json .

RUN npm install

COPY . .

EXPOSE 3030

CMD ["npm", "run", "start:dev"]

Вот мой package.json

{
  "name": "nest_docker_setup",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nodemon --config nodemon.json",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@nestjs/common": "^11.0.1",
    "@nestjs/core": "^11.0.1",
    "@nestjs/platform-express": "^11.0.1",
    "reflect-metadata": "^0.2.2",
    "rxjs": "^7.8.1"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3.2.0",
    "@eslint/js": "^9.18.0",
    "@nestjs/cli": "^11.0.0",
    "@nestjs/schematics": "^11.0.0",
    "@nestjs/testing": "^11.0.1",
    "@swc/cli": "^0.6.0",
    "@swc/core": "^1.10.7",
    "@types/express": "^5.0.0",
    "@types/jest": "^29.5.14",
    "@types/node": "^22.10.7",
    "@types/supertest": "^6.0.2",
    "eslint": "^9.18.0",
    "eslint-config-prettier": "^10.0.1",
    "eslint-plugin-prettier": "^5.2.2",
    "globals": "^15.14.0",
    "jest": "^29.7.0",
    "nodemon": "^3.1.9",
    "prettier": "^3.4.2",
    "source-map-support": "^0.5.21",
    "supertest": "^7.0.0",
    "ts-jest": "^29.2.5",
    "ts-loader": "^9.5.2",
    "ts-node": "^10.9.2",
    "tsconfig-paths": "^4.2.0",
    "typescript": "^5.7.3",
    "typescript-eslint": "^8.20.0"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

Вот так выглядит main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT ?? 3030);
}
bootstrap();

Вот так выглядит мой файл app.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!2';
  }
}

Вот так я создаю образ

docker build -t server-nest:v1.0 .

Вот так я создаю контейнер

docker run --name test-nest2 -p 3002:3030 --rm -v C:\Users\Dmitrij\work\nest_docker_setup:/app -v /app/node_modules server-nest:v1.0

абсолютные пути правильные. Вот файловая структура приложения Скриншот проекта

В чём собственно проблема. Образ и контейнер создается, но не работает отслеживание изменений. Т.е. если я в файле app.service.ts меняю строку return 'Hello World!2'; то по GET запросу http://localhost:3002 я получаю предыдущее значение. Но без Docker всё работает. Думал попробовать поставить nodemon и с ним получится, но не получилось. Я попробовал при запущенном контейнере проверить установился ли nodemon во таким образом. Внутри Docker контейнера запустил команду, чтобы проверить, что nodemon видит изменения:

docker exec -it test-nest2 sh
nodemon --watch src --exec "nest start --watch"

И получил в консоли такой ответ

[2:08:59 PM] Starting compilation in watch mode...

[2:09:01 PM] Found 0 errors. Watching for file changes.

[Nest] 99  - 02/23/2025, 2:09:01 PM     LOG [NestFactory] Starting Nest application...
[Nest] 99  - 02/23/2025, 2:09:01 PM     LOG [InstanceLoader] AppModule dependencies initialized +8ms
[Nest] 99  - 02/23/2025, 2:09:01 PM     LOG [RoutesResolver] AppController {/}: +3ms
[Nest] 99  - 02/23/2025, 2:09:01 PM     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 99  - 02/23/2025, 2:09:01 PM     LOG [NestApplication] Nest application successfully started +1ms
[Nest] 99  - 02/23/2025, 2:09:01 PM   ERROR [NestApplication] Error: listen EADDRINUSE: address already in use :::3030 +2ms
node:net:1937
    const ex = new UVExceptionWithHostPort(err, 'listen', address, port);
               ^

Error: listen EADDRINUSE: address already in use :::3030
    at Server.setupListenHandle [as _listen2] (node:net:1937:16)
    at listenInCluster (node:net:1994:12)
    at Server.listen (node:net:2099:7)
    at ExpressAdapter.listen (/app/node_modules/@nestjs/platform-express/adapters/express-adapter.js:109:32)
    at /app/node_modules/@nestjs/core/nest-application.js:183:30
    at new Promise (<anonymous>)
    at NestApplication.listen (/app/node_modules/@nestjs/core/nest-application.js:173:16)
    at async bootstrap (/app/src/main.ts:6:3) {
  code: 'EADDRINUSE',
  errno: -98,
  syscall: 'listen',
  address: '::',
  port: 3030
}

Node.js v23.8.0
PS C:\Users\Dmitrij\work\nest_docker_setup> 

Пробовал менять порты, но что-то не помогло. Надеюсь кто-нибудь что-нибудь подскажет.


Ответы (1 шт):

Автор решения: Streammer

В общем разобрался в чём проблема. Добавил в nodemon.json устаревший режим отслеживания

{
    "watch": ["src"],
    "ext": "ts,js,json",
    "exec": "nest start --watch",
    "legacyWatch": true
}  

Немного доработал Dockerfile Теперь мой Dockerfile выглядит вот так

FROM node:latest

WORKDIR /app

RUN npm install -g nodemon

COPY package.json .
COPY package-lock.json .

RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "run", "start:dev"]

Образ создаю такой командой

docker build -t server-nest:v1.0 .

А вот сам контейнер уже такой

docker run --name test-nest2 -p 3002:3000 --rm -v C:\Users\Dmitrij\work\nest_docker_setup:/app -v /app/node_modules -e CHOKIDAR_USEPOLLING=true server-nest:v1.0

Я добавил конструкцию

CHOKIDAR_USEPOLLING=true

chokidar — это библиотека для отслеживания изменений файлов в Node.js. Она используется многими инструментами, включая nodemon, webpack, jest и даже nest start --watch. chokidar позволяет этим инструментам автоматически перезапускать процессы при изменении файлов. В итоге всё заработало.

→ Ссылка