3

This is the package.json of my Node app:

{
    "name": "my-graphql-app",
    "version": "1.0.0",
    "description": "My Node GraphQL APP",
    "private": true,
    "license": "UNLICENSED",
    "scripts": {
        "start": "npm run run:watch",
        "build": "webpack",
        "build:watch": "webpack --watch",
        "run": "node ./dist/app.js",
        "run:watch": "nodemon ./dist/app.js"
    },
    "dependencies": {
        "@babel/core": "^7.8.4",
        "@babel/polyfill": "^7.8.3",
        "@babel/preset-env": "^7.8.4",
        "apollo-server-express": "^2.10.1",
        "babel-loader": "^8.0.6",
        "body-parser": "^1.19.0",
        "cors": "^2.8.5",
        "express": "^4.17.1",
        "graphql": "^14.6.0",
        "mysql2": "^2.1.0",
        "nodemon": "^2.0.2",
        "npm-run-all": "^4.1.5",
        "sequelize": "^5.21.5",
        "webpack-cli": "^3.3.11"
    },
    "devDependencies": {
        "webpack": "^4.41.6",
        "webpack-node-externals": "^1.7.2"
    }
}

This is working fine when I run npm install and npm start on my local machine (in case it matters, I am running it on Mac OS Catalina 10.15.3). My local node version is v11.10.1.

I am going crazy trying to make the same Node app work inside a docker container. I have made many different attempts, tweaking the package.json and Dockerfile, but I always end up with some npm install error or import error.

I am trying to spin up the containers (I also have a MySQL container) using docker-compose up --build.

This is my Dockerfile:

FROM node:12

EXPOSE 5000

WORKDIR /graphql_api

COPY package.json .
RUN npm install

COPY . /graphql_api

CMD npm start

This is my docker-compose.yml:

version: '3'
services:
    database:
        image: mysql:5.7
        environment:
            - 'MYSQL_ROOT_PASSWORD=pwd'
            - 'MYSQL_DATABASE=testdb'
            - 'MYSQL_USER=user'
            - 'MYSQL_PASSWORD=pwd'
        volumes:
            - ./db:/docker-entrypoint-initdb.d
        restart: always
        ports:
            - 8006:3306
    graphql_api:
        build: ./graphql_api
        container_name: graphql_api
        restart: always
        volumes:
            - ./graphql_api:/graphql_api
            - /graphql_api/node_modules
        ports:
            - "5000:5000"
        depends_on:
            - database

(The MySQL container starts up perfectly fine, by the way, and the database itself is correctly initialised with the all the tables I have defined in my init.sql file.)

As soon as the build process reaches the RUN npm install point, I always get this warning:

npm WARN deprecated core-js@2.6.11: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.

Then I get a bunch of messages like these ones

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.1.2 (node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/watchpack/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.11: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: abbrev@1.1.1 (node_modules/watchpack/node_modules/fsevents/node_modules/abbrev):
npm WARN enoent SKIPPING OPTIONAL DEPENDENCY: ENOENT: no such file or directory, rename '/graphql_api/node_modules/watchpack/node_modules/fsevents/node_modules/abbrev' -> '/graphql_api/node_modules/watchpack/node_modules/fsevents/node_modules/.abbrev.DELETE'
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: ansi-regex@2.1.1 (node_modules/watchpack/node_modules/fsevents/node_modules/ansi-regex):

(I didn't copypaste them all because there are really a lot.)

After those I get the message

added 785 packages from 486 contributors and audited 8930 packages in 26.85s

which makes me think that npm install did in fact have some effect despite the previous messages.

However, when the build process reaches the CMD npm start, this happens:

graphql_api    | > my-graphql-app@1.0.0 start /graphql_api
graphql_api    | > npm-run-all --parallel build:watch run:watch
graphql_api    |
graphql_api    | sh: 1: npm-run-all: not found
graphql_api    | npm ERR! code ELIFECYCLE
graphql_api    | npm ERR! syscall spawn
graphql_api    | npm ERR! file sh
graphql_api    | npm ERR! errno ENOENT
graphql_api    | npm ERR! my-graphql-app@1.0.0 start: `npm-run-all --parallel build:watch run:watch`
graphql_api    | npm ERR! spawn ENOENT
graphql_api    | npm ERR!
graphql_api    | npm ERR! Failed at the my-graphql-app@1.0.0 start script.
graphql_api    | npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

I have also tried building the container while starting from a node:11 image instead of a node:12 image, to match the Node version I have installed locally, but the result is the same.

I am really at a loss here: I have tried changing many things around after googling and looking at other StackOverflow answers (for example, the addition of "private": true in pacakge.json comes from an answer I found here to a similar question) but I still cannot get this container to run.

mrodo
  • 565
  • 5
  • 21
  • Do you have a `.dockerignore` file that keeps your host's `node_modules` tree out of the image? – David Maze Feb 26 '20 at 23:30
  • Also, the second set of messages you show looks like Docker Compose output; can you include the relevant fragment of your `docker-compose.yml` file in the question? (Are you overwriting all of the work from the Dockerfile with a `volumes:` bind mount?) – David Maze Feb 26 '20 at 23:32
  • @DavidMaze I don't have a `.dockerignore` file, just a `.gitignore` file. And yes, you are right, I am indeed launching the container though `docker-compose`, so now I will edit the question to include my `docker-compose.yml` in the question. Sorry, I forgot about that part. – mrodo Feb 26 '20 at 23:35
  • 1
    Does deleting the `volumes:` for your `graphql_api` container help? That's injecting the host (MacOS) `node_modules` directory into your (Linux) container. – David Maze Mar 05 '20 at 11:20
  • `sh: 1: npm-run-all: not found` ... so either `node_modules/.bin` is not included in the path variable (should not happen as it was started via npm), the module did not get installed (unlikely based on your log output) or the node_modules folder went missing like in https://stackoverflow.com/questions/30043872/docker-compose-node-modules-not-present-in-a-volume-after-npm-install-succeeds to test this you could change your `npm start` script in your `package.json` to something like `ls -la node_modules` to confirm that it's not empty for what every reason... – Fabian N. Mar 05 '20 at 11:30
  • @DavidMaze I tried commenting the `volumes` part in my `docker-compose.yml` and got this instead of the usual error about `npm-run-all `: `challenge_api | /graphql_api/app.js:1i mport '@babel/polyfill' SyntaxError: Cannot use import statement outside a module` – mrodo Mar 05 '20 at 13:31
  • @FabianN. I have put `RUN ls -la node_modules` in my Dockerfile right before `CMD npm start`, and something interesting happens: when the `volumes` part in the `docker-compose.yml` is commented, I see a list of folders. But when it's uncommented, I don't see them. So I think @DavidMaze might be on to something. – mrodo Mar 05 '20 at 14:32
  • @mrodo please take a look at the answer I linked in my last comment – Fabian N. Mar 05 '20 at 16:20
  • @mrodo. Can you check running this command `docker exec -it /bin/bash` to exec inside a docker container and see if node modules are present and check the logs? And also add `node_modules` in `.dockerignore` file. Not sure, you are installing packages then doing a copy from the root. will it override the node_modules in the container? – Abhishek Mar 06 '20 at 09:47
  • @mrodo try this removing volume path or change to a different valid path at the host side. – Abhishek Mar 06 '20 at 09:54
  • @FabianN. adding the line from that link to my docker-compose (which I have updated in the question) had an effect: now I get a different error `import '@babel/polyfill' SyntaxError: Cannot use import statement outside a module`. I have checked my local graphql_api folder and there is a node_modules folder in it. Besides, the `ls` during the build process also continues to show all the package folders. *But most importantly, with this configuration, if I stop and restart the containers with docker-compose up, the node app boots correctly!* Now, if I only could get that to work on the 1st try.. – mrodo Mar 06 '20 at 15:58
  • @mrodo I don't see any reason why you have used volumes here because you are copying everything inside container in your docker image. Also please use a dockerignore file that ignores node_modules and prevents it from being inside the docker container. So we are only left with main source code and no caches or npm modules, because it might need to be rebuilt according to the host OS which in your case is MacOS and Ubuntu which is in your container. – PrivateOmega Mar 10 '20 at 05:36
  • @PrivateOmega I always thought that volumes was needed to allow for my changes to be immediately available in the app. I want my Node app to notice every time I save changes in my editor as I am developing, just like it would if I was running it locally. I thought adding volumes in the docker-compose was necessary to achieve that because it maps my local folder to the container's folder. COPY only works at the startup, but then doesn't maintain the "mapping", or am I wrong here? – mrodo Mar 10 '20 at 14:37

4 Answers4

3

According to your error message, the package npm-run-all is missing. Inside dockerfile, install this package (globally) before the "npm install" line and try again.

Hope it helps!

  • This : `npm-run-all` is not a core part of Node or `npm`. You should add this to your `devDependencies`. As for all the OPTIONAL DEPENDENCY warnings ; this is because you're building a Docker container, which is Linux. You don't see these warnings on your Mac, because they're packages a Mac needs to compensate for features that Linux has by default, so they're not optional there. – Adrian Mar 11 '20 at 14:14
  • This is not the case. `npm-run-all` is included in my `package.json`. Also, as I wrote in a comment, I have put `RUN ls -la node_modules` in my Dockerfile right before `CMD npm start`, and I do see a list of all the packages, including `npm-run-all`. – mrodo Mar 11 '20 at 14:35
  • @mrodo What you see in node_modules are packages installed locally. You need to `RUN npm install -g npm-run-all && npm install`. It seems that one of the library causes this. – Alan Darmasaputra Mar 12 '20 at 09:34
0

You could try adding ./node_modules/.bin/ to your PATH in the dockerfile. That is likely where npm-run-all is located.

Seth Speaks
  • 153
  • 5
0

If you execute the command from ./graphql_api/node_modules/.bin/ then npm-run-all would work.

Then here you would have two options.

  1. You can export /graphql_api/node_modules/.bin/ to the PATH environment variable in your Dockerfile as follows; ENV PATH="/graphql_api/node_modules/.bin/:${PATH}"
  2. You can install npm-run-all as globally with executing command npm i -g npm-run-all.

Please see this particular issue created that I found while looking into your problem referenced below. https://github.com/mysticatea/npm-run-all/issues/96

Jacomus M
  • 74
  • 7
0

The only way is to export /graphql_api/node_modules/.bin/ to the PATH. Location can prevent from those repercussions