docker-node: node:7.9-alpine unable to build package due python is not installed

Latest solution https://github.com/nodejs/docker-node/issues/384#issuecomment-1097082551


Edit 2017: check this solution https://github.com/nodejs/docker-node/issues/384#issuecomment-305208112 Edit 2021: check this solution https://github.com/nodejs/docker-node/issues/384#issuecomment-856378530 Edit 2021: check note on required dependencies: https://github.com/nodejs/docker-node/issues/384#issuecomment-904804274 and https://github.com/nodejs/docker-node/issues/384#issuecomment-905048321 Edit 2022: the package python seems to have been deprecated/dropped a while ago in favor of python2 and python3, checkout this updated snippet https://github.com/nodejs/docker-node/issues/384#issuecomment-729038531


Recently I tried to dockerize a project which uses the bcrypt package. Everything works just fine on my mac but when I run it on Docker yarn throws a lot of errors related to gyp when trying to build the package during the installation process.

Here’s my Dockerfile:

FROM node:7.9-alpine
MAINTAINER Rafael Willians <me@rwillians.com>

RUN mkdir -p /usr/src/auth-service
WORKDIR /usr/src/auth-service

COPY package.json .
RUN yarn --no-emoji --prod

COPY . .

EXPOSE 3000

Here’s the output log:

$ docker-compose up --build
Building api
Step 1/8 : FROM node:7.9-alpine
 ---> 5e1532cfe1ea
Step 2/8 : MAINTAINER Rafael Willians <me@rwillians.com>
 ---> Using cache
 ---> 08fe67f74ce1
Step 3/8 : RUN mkdir -p /usr/src/auth-service
 ---> Using cache
 ---> df72f45a471a
Step 4/8 : WORKDIR /usr/src/auth-service
 ---> Using cache
 ---> 6ef48543f07e
Step 5/8 : COPY package.json .
 ---> Using cache
 ---> b8d993552d26
Step 6/8 : RUN yarn --no-emoji --prod
 ---> Running in c7927c31e1ce
yarn install v0.22.0
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
error /usr/src/auth-service/node_modules/bcrypt: Command failed.
Exit code: 1
Command: sh
Arguments: -c node-pre-gyp install --fallback-to-build
Directory: /usr/src/auth-service/node_modules/bcrypt
Output:
node-pre-gyp info it worked if it ends with ok
node-pre-gyp verb cli [ '/usr/local/bin/node',
node-pre-gyp verb cli   '/usr/src/auth-service/node_modules/bcrypt/node_modules/.bin/node-pre-gyp',
node-pre-gyp verb cli   'install',
node-pre-gyp verb cli   '--fallback-to-build' ]
node-pre-gyp info using node-pre-gyp@0.6.32
node-pre-gyp info using node@7.9.0 | linux | x64
node-pre-gyp verb command install []
node-pre-gyp info check checked for "/usr/src/auth-service/node_modules/bcrypt/lib/binding/bcrypt_lib.node" (not found)
node-pre-gyp http GET https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.2/bcrypt_lib-v1.0.2-node-v51-linux-x64.tar.gz
node-pre-gyp http 404 https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.2/bcrypt_lib-v1.0.2-node-v51-linux-x64.tar.gz
node-pre-gyp ERR! Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.2/bcrypt_lib-v1.0.2-node-v51-linux-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for bcrypt@1.0.2 and node@7.9.0 (node-v51 ABI) (falling back to source compile with node-gyp)
node-pre-gyp http 404 status code downloading tarball https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.2/bcrypt_lib-v1.0.2-node-v51-linux-x64.tar.gz
node-pre-gyp verb command build [ 'rebuild' ]
gyp info it worked if it ends with ok
gyp verb cli [ '/usr/local/bin/node',
gyp verb cli   '/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js',
gyp verb cli   'clean' ]
gyp info using node-gyp@3.5.0
gyp info using node@7.9.0 | linux | x64
gyp verb command clean []
gyp verb clean removing "build" directory
gyp info ok
gyp info it worked if it ends with ok
gyp verb cli [ '/usr/local/bin/node',
gyp verb cli   '/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js',
gyp verb cli   'configure',
gyp verb cli   '--fallback-to-build',
gyp verb cli   '--module=/usr/src/auth-service/node_modules/bcrypt/lib/binding/bcrypt_lib.node',
gyp verb cli   '--module_name=bcrypt_lib',
gyp verb cli   '--module_path=/usr/src/auth-service/node_modules/bcrypt/lib/binding' ]
gyp info using node-gyp@3.5.0
gyp info using node@7.9.0 | linux | x64
gyp verb command configure []
gyp verb check python checking for Python executable "python2" in the PATH
gyp verb `which` failed Error: not found: python2
gyp verb `which` failed     at getNotFoundError (/usr/local/lib/node_modules/npm/node_modules/which/which.js:13:12)
gyp verb `which` failed     at F (/usr/local/lib/node_modules/npm/node_modules/which/which.js:68:19)
gyp verb `which` failed     at E (/usr/local/lib/node_modules/npm/node_modules/which/which.js:80:29)
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/which.js:89:16
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/index.js:44:5
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/access.js:8:5
gyp verb `which` failed     at FSReqWrap.oncomplete (fs.js:114:15)
gyp verb `which` failed  python2 { Error: not found: python2
gyp verb `which` failed     at getNotFoundError (/usr/local/lib/node_modules/npm/node_modules/which/which.js:13:12)
gyp verb `which` failed     at F (/usr/local/lib/node_modules/npm/node_modules/which/which.js:68:19)
gyp verb `which` failed     at E (/usr/local/lib/node_modules/npm/node_modules/which/which.js:80:29)
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/which.js:89:16
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/index.js:44:5
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/access.js:8:5
gyp verb `which` failed     at FSReqWrap.oncomplete (fs.js:114:15) code: 'ENOENT' }
gyp verb check python checking for Python executable "python" in the PATH
gyp verb `which` failed Error: not found: python
gyp verb `which` failed     at getNotFoundError (/usr/local/lib/node_modules/npm/node_modules/which/which.js:13:12)
gyp verb `which` failed     at F (/usr/local/lib/node_modules/npm/node_modules/which/which.js:68:19)
gyp verb `which` failed     at E (/usr/local/lib/node_modules/npm/node_modules/which/which.js:80:29)
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/which.js:89:16
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/index.js:44:5
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/access.js:8:5
gyp verb `which` failed     at FSReqWrap.oncomplete (fs.js:114:15)
gyp verb `which` failed  python { Error: not found: python
gyp verb `which` failed     at getNotFoundError (/usr/local/lib/node_modules/npm/node_modules/which/which.js:13:12)
gyp verb `which` failed     at F (/usr/local/lib/node_modules/npm/node_modules/which/which.js:68:19)
gyp verb `which` failed     at E (/usr/local/lib/node_modules/npm/node_modules/which/which.js:80:29)
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/which.js:89:16
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/index.js:44:5
gyp verb `which` failed     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/access.js:8:5
gyp verb `which` failed     at FSReqWrap.oncomplete (fs.js:114:15) code: 'ENOENT' }
gyp ERR! configure error
gyp ERR! stack Error: Can't find Python executable "python", you can set the PYTHON env variable.
gyp ERR! stack     at PythonFinder.failNoPython (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:454:19)
gyp ERR! stack     at PythonFinder.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:368:16)
gyp ERR! stack     at F (/usr/local/lib/node_modules/npm/node_modules/which/which.js:68:16)
gyp ERR! stack     at E (/usr/local/lib/node_modules/npm/node_modules/which/which.js:80:29)
gyp ERR! stack     at /usr/local/lib/node_modules/npm/node_modules/which/which.js:89:16
gyp ERR! stack     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/index.js:44:5
gyp ERR! stack     at /usr/local/lib/node_modules/npm/node_modules/which/node_modules/isexe/access.js:8:5
gyp ERR! stack     at FSReqWrap.oncomplete (fs.js:114:15)
gyp ERR! System Linux 4.9.13-moby
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "configure" "--fallback-to-build" "--module=/usr/src/auth-service/node_modules/bcrypt/lib/binding/bcrypt_lib.node" "--module_name=bcrypt_lib" "--module_path=/usr/src/auth-service/node_modules/bcrypt/lib/binding"
gyp ERR! cwd /usr/src/auth-service/node_modules/bcrypt
gyp ERR! node -v v7.9.0
gyp ERR! node-gyp -v v3.5.0
gyp ERR! not ok
node-pre-gyp ERR! build error
node-pre-gyp ERR! stack Error: Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/usr/src/auth-service/node_modules/bcrypt/lib/binding/bcrypt_lib.node --module_name=bcrypt_lib --module_path=/usr/src/auth-service/node_modules/bcrypt/lib/binding' (1)
node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/usr/src/auth-service/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack     at emitTwo (events.js:106:13)
node-pre-gyp ERR! stack     at ChildProcess.emit (events.js:194:7)
node-pre-gyp ERR! stack     at maybeClose (internal/child_process.js:899:16)
node-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:226:5)
node-pre-gyp ERR! System Linux 4.9.13-moby
node-pre-gyp ERR! command "/usr/local/bin/node" "/usr/src/auth-service/node_modules/bcrypt/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /usr/src/auth-service/node_modules/bcrypt
node-pre-gyp ERR! node -v v7.9.0
node-pre-gyp ERR! node-pre-gyp -v v0.6.32
node-pre-gyp ERR! not ok
Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/usr/src/auth-service/node_modules/bcrypt/lib/binding/bcrypt_lib.node --module_name=bcrypt_lib --module_path=/usr/src/auth-service/node_modules/bcrypt/lib/binding' (1)
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
ERROR: Service 'api' failed to build: The command '/bin/sh -c yarn --no-emoji' returned a non-zero code: 1

I have opened this issue here because the error log mentioned that python wasn’t found in the PATH so this is probably some error in node’s 7.9-alpine Dockerfile, right?

I also ran sh against the built image and checked by myself that there was no python or python2 installed.

Not sure if those information are enough, I’m kinda new to Docker and Node. Please let me know if I should provide more information.

I got stuck here using node:15.1.0-alpine3.12 Continual fail until I replaced python with python3. Where?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 10
  • Comments: 45 (6 by maintainers)

Commits related to this issue

Most upvoted comments

@rwillians I have solved building native modules on alpine by adding the following to the Dockerfile

run apk --no-cache add --virtual native-deps \
  g++ gcc libgcc libstdc++ linux-headers make python && \
  npm install --quiet node-gyp -g &&\
  npm install --quiet && \
  apk del native-deps

This way the image size is not affected because it’s all in one layer.

Thanks @LaurentGoderre will look out for that!

I fixed the issue by adding these lines to my docker file

RUN apk --no-cache add g++ gcc libgcc libstdc++ linux-headers make python
RUN npm install --quiet node-gyp -g

If you are using the given snippet above, you should notice that python is been installed as a virtual dependency (which is a feature of alpine’s APK) and then it’s been removed right after npm install execution.

So in order to whatever command you are trying to run work, it should run before the “apk del native-deps” part.

If you arrived at the issue, it probably means you’re new at using Docker and/or Node.js, like I was when I opened this issue 5 years ago. And that’s alright, I’ll try making it easier for you 😃

We use alpine when we really care about that final image size (when you want it to be as small as possible), but that comes at a cost. If that’s not your case, please a try using a regular node image, such as node or node:17.8.0, and you should be good to go. If you really want that small image though, keep reading.

So what I mean by “cost” is that, in order to have a smaller image, you gotta remove unnecessary stuff from it — or better yet, never add the unnecessary stuff in the first place —. For example, alpine versions of node images, such as node:alpine and node:17.8.0-alpine, don’t come with python nor node-gyp installed, because they aren’t necessary in most cases. But some libs that you might use in your application, like the one I was using, requires to be built during their installation process using node-gyp, which requires python. Or, depending on your specific case, they might require something else.

Naturally, you’ll need to install those missing dependencies by yourself and once you don’t need them anymore, you gotta delete them. That’s the approach you’ll see on snippets throughout theses comments below. The most recent snippet is right below, just know that it might not fit your specific needs. It might be installing more stuff than you need or it might not be installing stuff that you actually need, in which case you’ll need to figure out the missing dependencies on your own by going through the logs. Of course you can ask for help here, me and a lot of the people participating in this discussion might be able to help you.

FROM node:17.8.0-alpine

WORKDIR /app

RUN apk --no-cache add --virtual virtual-deps \
    g++ gcc libgcc libstdc++ linux-headers make python2 && \
    npm install --quiet node-gyp -g

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

RUN npm ci && \
    apk del virtual-deps

COPY src/ src/

EXPOSE 3000
CMD ["npm", "start"]

If you’re new to Docker, you should know that there’s another approach to address this issue using what’s called Multi-Stage Builds. This approach, applied to this issue, consists of using a base image (such as thee regular node image) that most likely contains everything needed to build your application. And then, once it’s built, you copy those files (application along with dependencies — node_modules) to a brand new image based on alpine, as you can see below:

FROM node:17.8.0 AS build-stage

WORKDIR /app

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

RUN npm ci


FROM node:17.8.0-alpine

WORKDIR /app

COPY --from=build-stage /app ./
COPY src/ src/

EXPOSE 3000
CMD ["npm", "start"]

I’m not in a good position to tell you which approach is better for you. For example, the second approach might take longer to build if you don’t have cache but might be easier to work with while the first might be faster to build but it’s harder if you don’t know your way around finding the dependencies you need to install and also you gotta be more careful with how you cache the layers in order to get the optimal build time. So in my understanding, the best I can do is to tell you that you have these options and from here on, you can start exploring them on your own.

I fixed the issue by adding these lines to my docker file

RUN apk --no-cache add g++ gcc libgcc libstdc++ linux-headers make python
RUN npm install --quiet node-gyp -g

Thanks for sharing! this works for me.

Hey @zacharytyhacz, you gotta install python2 cuz the python package doesn’t seem to be available anymore.

FROM node:15.1.0-alpine3.12

RUN apk --no-cache add --virtual native-deps \
    g++ gcc libgcc libstdc++ linux-headers make python2 && \
    npm install --quiet node-gyp -g

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

RUN npm ci && \
    apk del native-deps

Btw I’m not sure if all those deps are required anymore

I fixed the issue by adding these lines to my docker file

RUN apk --no-cache add g++ gcc libgcc libstdc++ linux-headers make python
RUN npm install --quiet node-gyp -g

Thanks for sharing! this works for me.

Worked.

There is a recipe for node-gyp alpine in this repo, that works just fine:

FROM node:alpine

RUN apk add --no-cache --virtual .gyp python make g++ \
    && npm install \
    && apk del .gyp

@Macmee I suggest you to use JamesKyburz’s solution https://github.com/nodejs/docker-node/issues/384#issuecomment-305208112 in order to keep your image minimal.

I got stuck here using node:15.1.0-alpine3.12 Continual fail until I replaced python with python3.

I am struggling to see how having both npm and yarn is acceptable while node-gyp is out of question?

@rwillians My full Dockerfile is a mix of above recipe and Layer Caching from docker/getting-started repo:

FROM node:14-alpine
RUN apk add --no-cache --virtual .gyp python make g++

ENV NODE_ENV=production

WORKDIR /home/node/app

COPY package.json package-lock.json ./

RUN npm install && \
    apk del .gyp

COPY . .

EXPOSE 3000

CMD ["node", "src/index.js"]

~Image created this way grew quite large (367MB) when compared to node:14-alpine (117MB) with app taking 72MB, however it’s for another discussion.~ (after setting up mutli-stage build it’s 149MB)

I guess best option is to avoid dependencies which require node-gyp when possible.

@rwillians Yes, I will do that also. Thanks for pointing out.

Hey @malavshah9 👋
I’m glad that worked for you. If your using the alpine version of node image that means you care about your image size, so don’t forget the delete all dependencies and files that you don’t need during runtime. That’s why the recomended solution is longer than the one you used.

I fixed the issue by adding these lines to my docker file

RUN apk --no-cache add g++ gcc libgcc libstdc++ linux-headers make python
RUN npm install --quiet node-gyp -g

Thanks @macmee . This helped me a lot.

This can be closed, right?

We could probably put some caveats in the readme about using the alpine image, as well as some examples for using multi-stage builds.

The point of the alpine image is to be as small as possible so it doesn’t include python. See #282 on how to do it.