yarnpkg – yarn install doesn’t work with docker-compose

docker-compose version: docker-compose version 1.29.2, build 5becea4c

I have a create-react-app project with the following Dockerfile:

FROM node:lts-alpine as dev
WORKDIR /app
COPY . ./
RUN yarn --ignore-scripts
RUN find ./node_modules | grep 'node_modules/react-scripts$'
ENTRYPOINT ["yarn", "start"]

If I build it using docker build -t my_ui . and run using docker run -p 3333:3333 my_ui the image is built and runs as expected.

The problem occurs when using docker-compose with the following docker-compose.yml :

version: '3.8'
services:
    
    backend_service:
        SOME_STUFF

    ui:
        build:
            context: ./my-ui
            dockerfile: Dockerfile
            target: dev
        expose:
            - "3333"
        ports:
            - "3333:3333"
        volumes:
            - ./my-ui:/app
        depends_on: 
            - backend_service
 

Running docker-compose up ui returns:

Building ui
Sending build context to Docker daemon  1.288MB
Step 1/6 : FROM node:lts-alpine as dev
lts-alpine: Pulling from library/node
df9b9388f04a: Already exists 
70c90f7de7cb: Pull complete 
f83937c3ce37: Pull complete 
98b78bba1d70: Pull complete 
Digest: sha256:1a9a71ea86aad332aa7740316d4111ee1bd4e890df47d3b5eff3e5bded3b3d10
Status: Downloaded newer image for node:lts-alpine
 ---> e5065cc78074
Step 2/6 : WORKDIR /app
 ---> Running in 1199bb03835e
Removing intermediate container 1199bb03835e
 ---> 2ab98218756b
Step 3/6 : COPY . ./
 ---> b977d7fb20c0
Step 4/6 : RUN yarn --ignore-scripts
 ---> Running in b340ea955865
yarn install v1.22.18
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
warning " > @testing-library/user-event@12.8.3" has unmet peer dependency "@testing-library/dom@>=7.21.4".
warning " > styled-components@5.3.5" has unmet peer dependency "react-is@>= 16.8.0".
warning " > eslint-config-prettier@8.3.0" has unmet peer dependency "eslint@>=7.0.0".
warning " > eslint-plugin-prettier@3.4.0" has unmet peer dependency "eslint@>=5.0.0".
[4/4] Building fresh packages...
warning Ignored scripts due to flag.
Done in 66.47s.
Removing intermediate container b340ea955865
 ---> c1accc64799b
Step 5/6 : RUN find ./node_modules | grep 'node_modules/react-scripts$'
 ---> Running in a7fc4fca473b
./node_modules/react-scripts
Removing intermediate container a7fc4fca473b
 ---> 7bd1e48b30a8
Step 6/6 : ENTRYPOINT ["yarn", "start"]
 ---> Running in 9911f244b95c
Removing intermediate container 9911f244b95c
 ---> 9eaa7e004f2e
Successfully built 9eaa7e004f2e
Successfully tagged my_ui:latest
WARNING: Image for service ui was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Recreating my_postgres_1 ... done
backend_service_1 is up-to-date
Creating my_ui_1         ... done
Attaching to my_ui_1
ui_1        | yarn run v1.22.18
ui_1        | $ react-scripts start
ui_1        | /bin/sh: react-scripts: not found
ui_1        | error Command failed with exit code 127.
ui_1        | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
my_ui_1 exited with code 127

Apparently react-scrips is missing even though there is a node_modules/react-scrips directory.

A strange observation: if I run yarn --ignore-scripts LOCALY and then run docker-compose up ui it will build and run successfully even though .dockerignore file has a node_modules line so local dependencies should not be copied into the container.

WORKAROUND ATTEMPT #1:

Update Dockerfile to:

FROM node:lts-alpine as dev
WORKDIR /app
COPY . ./
RUN yarn --ignore-scripts
RUN ls -l ./node_modules | grep react-scripts
ENTRYPOINT npx react-scripts start

results in:

[[[ steps 1-4, same output as previouly ]]]
Step 5/6 : RUN ls -l ./node_modules | grep react-scripts
 ---> Running in f059d27886f0
drwxr-xr-x    9 root     root          4096 May 10 07:58 react-scripts
Removing intermediate container f059d27886f0
 ---> 189aaee8d944
Step 6/6 : ENTRYPOINT npx react-scripts start
 ---> Running in 2437134103a0
Removing intermediate container 2437134103a0
 ---> 04a6af0a2a49
Successfully built 04a6af0a2a49
Successfully tagged my_ui:latest
WARNING: Image for service ui was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
postgres_1 is up-to-date
backend_service_1 is up-to-date
Creating my_ui_1 ... done
Attaching to my_ui_1
ui_1        | npm WARN exec The following package was not found and will be installed: react-scripts
ui_1        | npm WARN deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x.
ui_1        | sh: react-scripts: Permission denied
ui_1        | npm notice 
ui_1        | npm notice New minor version of npm available! 8.5.5 -> 8.9.0
ui_1        | npm notice Changelog: <https://github.com/npm/cli/releases/tag/v8.9.0>
ui_1        | npm notice Run `npm install -g npm@8.9.0` to update!
ui_1        | npm notice 
my_ui_1 exited with code 127

Step 5 show that node_modules/react-scripts exists and belongs to root:root and yet sh: react-scripts: Permission denied.

WORKAROUND ATTEMPT #2:

Update Dockerfile to:

FROM node:lts-alpine as dev
WORKDIR /app
COPY . ./
RUN yarn --ignore-scripts
RUN ls -l ./node_modules/react-scripts/bin/react-scripts.js
RUN cat ./node_modules/react-scripts/bin/react-scripts.js
ENTRYPOINT node node_modules/react-scripts/bin/react-scripts.js start

results in:

[[[ steps 1-4, same output as previouly ]]]
Step 5/7 : RUN ls -l ./node_modules/react-scripts/bin/react-scripts.js
 ---> Running in f569f983cf86
-rwxr-xr-x    1 root     root          1895 May 10 08:13 ./node_modules/react-scripts/bin/react-scripts.js
Removing intermediate container f569f983cf86
 ---> 7aceda033266
Step 6/7 : RUN cat ./node_modules/react-scripts/bin/react-scripts.js
 ---> Running in 11fd19d9871c
#!/usr/bin/env node
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
  throw err;
});

const spawn = require('react-dev-utils/crossSpawn');
const args = process.argv.slice(2);

const scriptIndex = args.findIndex(
  x => x === 'build' || x === 'eject' || x === 'start' || x === 'test'
);
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [];

if (['build', 'eject', 'start', 'test'].includes(script)) {
  const result = spawn.sync(
    process.execPath,
    nodeArgs
      .concat(require.resolve('../scripts/' + script))
      .concat(args.slice(scriptIndex + 1)),
    { stdio: 'inherit' }
  );
  if (result.signal) {
    if (result.signal === 'SIGKILL') {
      console.log(
        'The build failed because the process exited too early. ' +
          'This probably means the system ran out of memory or someone called ' +
          '`kill -9` on the process.'
      );
    } else if (result.signal === 'SIGTERM') {
      console.log(
        'The build failed because the process exited too early. ' +
          'Someone might have called `kill` or `killall`, or the system could ' +
          'be shutting down.'
      );
    }
    process.exit(1);
  }
  process.exit(result.status);
} else {
  console.log('Unknown script "' + script + '".');
  console.log('Perhaps you need to update react-scripts?');
  console.log(
    'See: https://facebook.github.io/create-react-app/docs/updating-to-new-releases'
  );
}
Removing intermediate container 11fd19d9871c
 ---> a76c2d131538
Step 7/7 : ENTRYPOINT node node_modules/react-scripts/bin/react-scripts.js start
 ---> Running in efa73918a6b0
Removing intermediate container efa73918a6b0
 ---> db710c0193ac
Successfully built db710c0193ac
Successfully tagged my_ui:latest
WARNING: Image for service ui was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
postgres_1 is up-to-date
backend_service_1 is up-to-date
Creating my_ui_1 ... done
Attaching to my_ui_1
ui_1        | node:internal/modules/cjs/loader:936
ui_1        |   throw err;
ui_1        |   ^
ui_1        | 
ui_1        | Error: Cannot find module '/app/node_modules/react-scripts/bin/react-scripts.js'
ui_1        |     at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
ui_1        |     at Function.Module._load (node:internal/modules/cjs/loader:778:27)
ui_1        |     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
ui_1        |     at node:internal/main/run_main_module:17:47 {
ui_1        |   code: 'MODULE_NOT_FOUND',
ui_1        |   requireStack: []
ui_1        | }
my_ui_1 exited with code 1

So node_modules/react-scripts/bin/react-scripts.js is there, it belongs to root:root and the error says Cannot find module '/app/node_modules/react-scripts/bin/react-scripts.js'

Any help would be greatly appreciated.

Leave a Comment