Я пытаюсь закрепить приложение node.js (называемое «Хаб») в докере для Windows с контейнерами на базе Linux, но при создании/запуске контейнера не удается получить доступ к зависимости. Приложение является частью микросервисной архитектуры, в которой у меня есть несколько локальных общих модулей, которые используются различными службами. Hub-сервис не использует никаких томов.
В этом конкретном случае затронутая служба использует модуль аутентификации и вспомогательный модуль. Модуль аутентификации также включает в себя вспомогательный модуль. Кажется, в этом проблема.
Я получаю следующую ошибку:
hub-1 | Error: Cannot find module 'helper'
hub-1 | Require stack:
hub-1 | - /src/apps/Common/Authentication/index.js
hub-1 | - /src/apps/Hub/WS/eventhandler.js
hub-1 | - /src/apps/Hub/WS/initws.js
hub-1 | - /src/apps/Hub/index.js
hub-1 | requireStack: [
hub-1 | '/src/apps/Common/Authentication/index.js',
hub-1 | '/src/apps/Hub/WS/eventhandler.js',
hub-1 | '/src/apps/Hub/WS/initws.js',
hub-1 | '/src/apps/Hub/index.js'
hub-1 | ]
hub-1 | }
Структура папок соответствует предложению: Настройка приложения docker nodejs с локальными зависимостями npm
Это выглядит так:
Main Folder
|- <Dockerfiles for each service>-> "Dockerfile_Hub"
|- compose.yaml (Docker-compose)
|-apps
|-Hub
|- ...several other services
|-Common
|-Authentication
|-Helper
|- ... several other common modules
В файле docker я копирую ВСЕ часто используемые модули в контейнер, а затем запускаю команду установки npm. У меня есть другой сервис, где это работает безупречно, похоже, это как-то связано с путями к файлам во взаимозависимости между общими модулями (модуль аутентификации также зависит от вспомогательного модуля).
Package.json-файлы:
{
"name": "hub",
"version": "1.0.0",
"description": "Hub Service",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"authentication": "file:../Common/Authentication",
"axios": "^1.6.8",
"config": "file:../Common/Config",
"crypto": "^1.0.1",
"express": "^4.19.1",
"express-session": "^1.18.0",
"fs": "^0.0.1-security",
"helper": "file:../Common/Helper",
"http": "^0.0.1-security",
"jsonwebtoken": "^9.0.2",
"keycloak-connect": "^24.0.2",
"logger": "file:../Common/Logger",
"node-jose": "^2.2.0",
"socket.io": "^4.7.5",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0"
}
}
{
"name": "authentication",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"config": "file:../Config",
"helper": "file:../Helper",
"jsonwebtoken": "^9.0.2",
"jswt": "^1.4.4",
"logger": "file:../Logger"
}
}
Файлы Docker (как предложено в упомянутой статье):
ARG NODE_VERSION=20.12.0
FROM node:${NODE_VERSION}-alpine
ENV NODE_ENV development
WORKDIR /usr/src/app
RUN mkdir -p /src
COPY ./apps/Common /src/apps/Common
COPY ./apps/Hub /src/apps/Hub
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.npm to speed up subsequent builds.
# Leverage a bind mounts to package.json and package-lock.json to avoid having to copy them into
# into this layer.
RUN --mount=type=bind,source=/apps/Hub/package.json,target=package.json \
--mount=type=bind,source=/apps/Hub/package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci --omit=dev
RUN cd /src/apps/Hub && npm install
# Run the application as a non-root user.
USER node
# Expose the port that the application listens on.
EXPOSE 8000
# Run the application.
CMD node /src/apps/Hub/index.js
Docker-составьте:
version: "3"
#Hub
services:
hub:
build:
context: .
dockerfile: Dockerfile_Hub
environment:
NODE_ENV: development
APP_PATH: /src/apps/Hub
PINO_LOG_LEVEL: debug
ports:
- 3000:3000
Процесс сборки выполняется без каких-либо ошибок:
[+] Building 0.0s (0/0) docker:default
[+] Building 0.0s (0/0) docker:defaultr reading preface from client //./pipe/docker_engine: file has already been closed
[+] Building 3.2s (15/15) FINISHED
=> [hub internal] load build definition from Dockerfile_Hub
=> => transferring dockerfile: 1.38kB
=> [hub] resolve image config for docker.io/docker/dockerfile:1
=> CACHED [hub] docker-image://docker.io/docker/dockerfile:1@sha256:a57df69d0ea827fb7266491f2813635de6f17269be881f696fbfdf2d83dda33e
=> [hub internal] load metadata for docker.io/library/node:20.12.0-alpine
=> [hub internal] load .dockerignore
=> => transferring context: 2B
=> [hub stage-0 1/8] FROM docker.io/library/node:20.12.0-alpine@sha256:ef3f47741e161900ddd07addcaca7e76534a9205e4cd73b2ed091ba339004a75
=> [hub internal] load build context
=> => transferring context: 478.86kB
=> CACHED [hub stage-0 2/8] WORKDIR /usr/src/app
=> CACHED [hub stage-0 3/8] RUN mkdir -p /src
=> CACHED [hub stage-0 4/8] COPY ./apps/Common /src/apps/Common
=> CACHED [hub stage-0 5/8] COPY ./apps/Hub /src/apps/Hub
=> CACHED [hub stage-0 6/8] RUN --mount=type=bind,source=/apps/Hub/package.json,target=package.json --mount=type=bind,source=/apps/Hub/package-
=> CACHED [hub stage-0 7/8] RUN cd /src/apps/Hub && npm install
=> [hub stage-0 8/8] WORKDIR /src/apps/Hub
=> [hub] exporting to image
=> => exporting layers
=> => writing image sha256:4f2ce3b43d06485ec72da1c107df361e6b0a11d44785beea3baff85ff60170a3
=> => naming to docker.io/library/finslice-hub
[+] Running 2/2
✔ Container crazy_rosalind Removed
✔ Container finslice-hub-1 Recreated
Attaching to hub-1
hub-1 | node:internal/modules/cjs/loader:1146
hub-1 | throw err;
hub-1 | ^
hub-1 |
hub-1 | Error: Cannot find module 'helper'
hub-1 | Require stack:
hub-1 | - /src/apps/Common/Authentication/index.js
hub-1 | - /src/apps/Hub/WS/eventhandler.js
hub-1 | - /src/apps/Hub/WS/initws.js
hub-1 | - /src/apps/Hub/index.js
hub-1 | requireStack: [
hub-1 | '/src/apps/Common/Authentication/index.js',
hub-1 | '/src/apps/Hub/WS/eventhandler.js',
hub-1 | '/src/apps/Hub/WS/initws.js',
hub-1 | '/src/apps/Hub/index.js'
hub-1 | ]
hub-1 | }
hub-1 |
hub-1 | Node.js v20.12.0
hub-1 exited with code 1
Если я получу доступ к файловой системе контейнеров, я увижу, что все файлы/папки скопированы правильно.
Вероятно, это как-то связано с тем, как я установил команды WORKDIR/CD в файле docker. Я попытался изменить это на (последние 2 строки файла docker):
РАБОЧИЙ ПАРАМЕТР /src/apps/Hub Узел CMD index.js
с тем же результатом.
Запуск приложения только через node.js вне докера работает без каких-либо проблем.
Я наконец решил это. Попробовав совет Раиси и перейдя на файлы .dockerignore вместо выборочного копирования файлов, я внимательно изучил файловую систему в копии контейнера.
Что происходит: npm install для внутренних зависимостей (т. е. npm install ../Common/Authentication и т. д.) только создает символические ссылки на папку, но фактически не копирует модуль в папку. Вероятно, это сработало бы, если бы я работал на машине с Linux, но на машине с Windows символические ссылки относятся к каталогу в стиле Windows (т.е. d:\myApp\myModule), который, конечно, не будет работать в контейнере на базе Linux.
Что решило проблему, так это статья:
Установить каталог локального модуля npm без символических ссылок?
простое решение: «используйте npm install --install-links ../module» вместо «npm install ../module». Это скопирует весь исходный код, как если бы это был внешний пакет.
Почему вы начали свой путь с корня? Ставьте лайк
/src/apps/Common
. так и должно быть./src/apps/Common
. Его можно увидеть во всем файле докера. Гораздо лучше использоватьCOPY . .
и игнорировать ненужные файлы, используя файл .dockerignore.