Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node-gyp compilation fails in node alpine image for docker #1855

Closed
Nosherwan opened this issue Aug 14, 2019 · 14 comments
Closed

Node-gyp compilation fails in node alpine image for docker #1855

Nosherwan opened this issue Aug 14, 2019 · 14 comments

Comments

@Nosherwan
Copy link

Hi,
My bcrypt module install fails in docker.
I am using docker for a node application the following is my docker file:

FROM node:10.16.2-alpine
# Create app directory
WORKDIR /app

COPY package*.json /app/
# Installs everything from package.json
# RUN npm install
# Will copy all files except node_modules
COPY . .

RUN apk --no-cache --update --virtual build-dependencies add \
    tzdata \
    build-base python \
    && npm install \
    && apk del build-dependencies
ENV TZ Australia/Sydney

# even though port is being exposed it will
# be overridden by docker-compose port
EXPOSE 4000 

CMD [ "npm", "start" ]

I have followed instructions in some other threads, mainly this one:
nodejs/docker-node#282

However I get a huge dump as soon as source compilation starts during docker-compose up.
Below is the dump for reference:

> bcrypt@3.0.6 install /app/node_modules/bcrypt
> node-pre-gyp install --fallback-to-build

node-pre-gyp WARN Using request for node-pre-gyp https download 
node-pre-gyp WARN Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v3.0.6/bcrypt_lib-v3.0.6-node-v64-linux-x64-musl.tar.gz 
node-pre-gyp WARN Pre-built binaries not found for bcrypt@3.0.6 and node@10.16.2 (node-v64 ABI, musl) (falling back to source compile with node-gyp) 
make: Entering directory '/app/node_modules/bcrypt/build'
  CXX(target) Release/obj.target/bcrypt_lib/src/blowfish.o
  CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt.o
  CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt_node.o
In file included from ../src/bcrypt_node.cc:1:
../node_modules/nan/nan.h: In function 'void Nan::AsyncQueueWorker(Nan::AsyncWorker*)':
../node_modules/nan/nan.h:2232:62: warning: cast between incompatible function types from 'void (*)(uv_work_t*)' {aka 'void (*)(uv_work_s*)'} to 'uv_after_work_cb' {aka 'void (*)(uv_work_s*, int)'} [-Wcast-function-type]
     , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
                                                              ^
In file included from ../node_modules/nan/nan.h:53,
                 from ../src/bcrypt_node.cc:1:
../src/bcrypt_node.cc: At global scope:
/root/.node-gyp/10.16.2/include/node/node.h:573:43: warning: cast between incompatible function types from 'void (*)(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)' {aka 'void (*)(v8::Local<v8::Object>)'} to 'node::addon_register_func' {aka 'void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)'} [-Wcast-function-type]
       (node::addon_register_func) (regfunc),                          \
                                           ^
/root/.node-gyp/10.16.2/include/node/node.h:607:3: note: in expansion of macro 'NODE_MODULE_X'
   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
   ^~~~~~~~~~~~~
../src/bcrypt_node.cc:378:1: note: in expansion of macro 'NODE_MODULE'
 NODE_MODULE(bcrypt_lib, init);
 ^~~~~~~~~~~
In file included from /root/.node-gyp/10.16.2/include/node/node.h:63,
                 from ../node_modules/nan/nan.h:53,
                 from ../src/bcrypt_node.cc:1:
/root/.node-gyp/10.16.2/include/node/v8.h: In instantiation of 'void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = node::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)]':
/root/.node-gyp/10.16.2/include/node/node_object_wrap.h:84:78:   required from here
/root/.node-gyp/10.16.2/include/node/v8.h:9502:16: warning: cast between incompatible function types from 'v8::WeakCallbackInfo<node::ObjectWrap>::Callback' {aka 'void (*)(const v8::WeakCallbackInfo<node::ObjectWrap>&)'} to 'Callback' {aka 'void (*)(const v8::WeakCallbackInfo<void>&)'} [-Wcast-function-type]
                reinterpret_cast<Callback>(callback), type);
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/root/.node-gyp/10.16.2/include/node/v8.h: In instantiation of 'void v8::PersistentBase<T>::SetWeak(P*, typename v8::WeakCallbackInfo<P>::Callback, v8::WeakCallbackType) [with P = Nan::ObjectWrap; T = v8::Object; typename v8::WeakCallbackInfo<P>::Callback = void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)]':
../node_modules/nan/nan_object_wrap.h:65:61:   required from here
/root/.node-gyp/10.16.2/include/node/v8.h:9502:16: warning: cast between incompatible function types from 'v8::WeakCallbackInfo<Nan::ObjectWrap>::Callback' {aka 'void (*)(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)'} to 'Callback' {aka 'void (*)(const v8::WeakCallbackInfo<void>&)'} [-Wcast-function-type]
  SOLINK_MODULE(target) Release/obj.target/bcrypt_lib.node
  COPY Release/bcrypt_lib.node
  COPY /app/node_modules/bcrypt/lib/binding/bcrypt_lib.node
  TOUCH Release/obj.target/action_after_build.stamp
make: Leaving directory '/app/node_modules/bcrypt/build'

I would appreciate any help.

@rvagg
Copy link
Member

rvagg commented Aug 20, 2019

These are all just compile warnings, not errors, at the bottom you have a successful bcrypt_lib.node that can be loaded as an addon. If you need the warnings to go away then you'll have to take that up with the node-bcrypt folks (or redirect the output to /dev/null if you really don't want to see it).

@rvagg rvagg closed this as completed Aug 20, 2019
@Nosherwan
Copy link
Author

Thanks for the reply @rvagg however bcrypt import doesnt work in koa.js even after the successful bcrypt_lib.node compilation. For the time I am using an all javascript version of bcrypt with zero dependancies called bcryptjs to get past the issue.

@rvagg
Copy link
Member

rvagg commented Aug 20, 2019

so, try running your container with bash and do a node -e require("/app/node_modules/bcrypt/lib/binding/bcrypt_lib.node") and what does it say? And what does node -e require("/app/node_modules/bcrypt/") say? do these return errors?

@Nosherwan
Copy link
Author

@rvagg I have given the commands below and they dont give any error:

node -e 'require("./node_modules/bcrypt/lib/binding/bcrypt_lib.node")'

and

node -e 'require("./node_modules/bcrypt/")'

However when the actual node app runs ( which by the way is in typescript) the follwing shows up:

web_1  | 
web_1  | > app-gql-server@0.0.1 start /app
web_1  | > npm run build:live
web_1  | 
web_1  | 
web_1  | > app-gql-server@0.0.1 build:live /app
web_1  | > nodemon --inspect=0.0.0.0:9229 -r ts-node/register -P ./tsconfig.json ./src/index.ts
web_1  | 
web_1  | [nodemon] 1.18.11
web_1  | [nodemon] to restart at any time, enter `rs`
web_1  | [nodemon] watching: *.*
web_1  | [nodemon] starting `node --inspect=0.0.0.0:9229 -r ts-node/register ./src/index.ts`
web_1  | Debugger listening on ws://0.0.0.0:9229/13799f3e-3aa8-47fa-aae3-532657c50c7d
web_1  | For help, see: https://nodejs.org/en/docs/inspector
web_1  | createStore executed once
web_1  | Error: Error loading shared library /app/node_modules/bcrypt/lib/binding/bcrypt_lib.node: Exec format error
web_1  |     at Object.Module._extensions..node (internal/modules/cjs/loader.js:807:18)
web_1  |     at Module.load (internal/modules/cjs/loader.js:653:32)
web_1  |     at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
web_1  |     at Function.Module._load (internal/modules/cjs/loader.js:585:3)
web_1  |     at Module.require (internal/modules/cjs/loader.js:692:17)
web_1  |     at require (internal/modules/cjs/helpers.js:25:18)
web_1  |     at Object.<anonymous> (/app/node_modules/bcrypt/bcrypt.js:6:16)
web_1  |     at Module._compile (internal/modules/cjs/loader.js:778:30)
web_1  |     at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
web_1  |     at Module.load (internal/modules/cjs/loader.js:653:32)
web_1  |     at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
web_1  |     at Function.Module._load (internal/modules/cjs/loader.js:585:3)
web_1  |     at Module.require (internal/modules/cjs/loader.js:692:17)
web_1  |     at require (internal/modules/cjs/helpers.js:25:18)
web_1  |     at Object.<anonymous> (/app/src/db/userApi.ts:5:16)
web_1  |     at Module._compile (internal/modules/cjs/loader.js:778:30)
web_1  | [nodemon] app crashed - waiting for file changes before starting...

I do additionally install "@types/bcrypt" for type definitions as dev dependencies.

@rvagg
Copy link
Member

rvagg commented Aug 20, 2019

Yeah, that is a bit weird. Is it possible that you have multiple versions of node installed on this image? do you know what node that nodemon is finding?
If you run this manually inside the container: node -p 'process.execPath + "@" + process.version' it'll give you the path and the version of the executable. Perhaps you could change the nodemon startup command to nodemon -p 'process.execPath + "@" + process.version' and start your app and see if it prints the same thing? (I'm not sure nodemon will be happy with that, but you could try).

@Nosherwan
Copy link
Author

nodemon is not happy as you already suspected. I have however tried to make sure the version of node is the same in all places:
1 - my local machine. Using latest nvm and using 10.16.2 as default.
2 - docker file
3 - ran node -p 'process.execPath + "@" + process.version' in my app's docker image running in an interactive shell, and it does give me the same node.js version

So still on square one.

@rvagg
Copy link
Member

rvagg commented Aug 20, 2019

Unfortunately version isn't the only compatibility vector. Alpine uses musl libc, not glibc. Presumably you're using an official Alpine Docker image (from nodejs/docker-node, published as the official node images). They are using proper musl builds, so glibc isn't involved at all. But it's possible to install glibc and compile against it, or use standard Linux x64 binaries on Alpine that are compiled against glibc. If you compile an addon with a glibc node and load it in a musl node I think you'll see the problem you're experiencing. Same with the reverse. Hence the need to determine that the node invoking node-gyp for building the addon is the same that loads it.

Is it possible another node is getting installed on the image? Perhaps via nvm or some other means? afaik nodemon just finds whatever is in PATH but maybe it's getting it from somewhere else.

https://github.com/remy/nodemon#default-executables nodemon has the ability to manually specify the executable to be used. I also notice in https://github.com/remy/nodemon/blob/master/lib/config/defaults.js it has a ts default. Is it possible that it's invoking ts-node and this is a binary? I don't know enough about ts-node, maybe it's just a wrapper or maybe it's pulling in its own node binary?

@rvagg
Copy link
Member

rvagg commented Aug 20, 2019

Ping @nodejs/docker - this might be interesting for you and maybe someone's dealt with this before and has a better answer than me. Summary: compiling an addon inside a container isn't being loaded when the app is started Error: Error loading shared library. nodemon and TypeScript are involved here.

@rvagg rvagg reopened this Aug 20, 2019
@LaurentGoderre
Copy link
Member

I will take a look! I seem to remember an issue with alpine and bcrypt though.

@bnoordhuis
Copy link
Member

Closing due to inactivity, can reopen if necessary.

@vicrazumov
Copy link

I'm running into the same issue while trying to build an image with https://github.com/laverdet/isolated-vm

@dancrtis
Copy link

I'm running into the same issue for npm dependencies that rely on node-gyp. Here's my current Dockerfile (I've configured it many different ways to no avail):

FROM node:alpine

WORKDIR "/app"
COPY ./package.json ./

RUN apk add python make gcc g++
RUN npm install

COPY . .
CMD ["npm", "run", "start"]

@lewislbr
Copy link

@DanielCurtis Try using a specific Node.js version. I've been able to resolve it with:

FROM node:14-alpine
RUN apk add --no-cache g++ make python
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . ./
CMD ["npm", "run", "start"]

@chlumpchatkupt
Copy link

chlumpchatkupt commented Nov 3, 2020

There seems to be an issue with Node 15: #2245

Edit: Using
FROM node:15.1-alpine RUN apk add --nocache python make g++
fixes it for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants