Search code examples
node.jspostgresqldockersequelize.jslibpq

Using sequelize with Postgresql in Docker: Libpq dependency Exec format error


I'm trying to connect to a PostgreSQL database hosted on Azure from a Dockerized Node app with Sequelize. However, I'm getting an error that the libpq dependency can't be found when run in the container. It works fine on my local machine.

(node:40) UnhandledPromiseRejectionWarning: Error: Error loading shared library /usr/app/node_modules/libpq/build/Release/addon.node: Exec format error
    at Object.Module._extensions..node (internal/modules/cjs/loader.js:1122:18)

I've found a few similar errors out there and tried different methods in the Dockerfile to ensure the dependency is loaded with no success. I've also ensured that my Node version matches on my local machine and in the Docker container.

FROM node:14-alpine

WORKDIR /usr/app

COPY package*.json ./
RUN \
    apk add --no-cache g++ make python3 postgresql-libs

RUN \
    apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev && \
    npm install libpq && \
    apk --purge del .build-deps  

COPY . .

CMD ["npm", "start"]

Here is my docker-compose.yml

version: "3.8"
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - .:/usr/app
    ports:
      - "3000:3000"

docker-compose.dev.yml

version: "3.8"
services:
  api:
    command: npm run dev
    environment:
      - NODE_ENV=development

Running the following to build the image and start the container:

docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

The libpq dependency comes from the fact that I need to use native: true in the sequeqlgze connection to enforce SSH. Which requires the pg-native package.

// PostgreSQL connection
exports.connect = async () => {
  const sequelize = new Sequelize(
    config.DATABASE_NAME,
    config.DB_USERNAME,
    config.DB_PASSWORD,
    {
      host: config.DB_HOSTNAME,
      port: config.DB_PORT,
      dialect: "postgres",
      native: true, // enables ssl
    }
  );

Related Resources

https://github.com/nodejs/node-gyp/issues/1855

Using Docker with nodejs with node-gyp dependencies

Docker logs when building image

Step 5/7 : RUN     apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev &&     npm install libpq &&     apk --purge del .build-deps
 ---> Running in 20f7406e6abc
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
(1/4) Installing pkgconf (1.6.3-r0)
(2/4) Installing openssl-dev (1.1.1g-r0)
(3/4) Installing postgresql-dev (12.5-r0)
(4/4) Installing .build-deps (20201207.093711)
Executing busybox-1.31.1-r9.trigger
OK: 243 MiB in 47 packages

> [email protected] install /usr/app/node_modules/libpq
> node-gyp rebuild

make: Entering directory '/usr/app/node_modules/libpq/build'
  CXX(target) Release/obj.target/addon/src/connection.o
  CXX(target) Release/obj.target/addon/src/connect-async-worker.o
  CXX(target) Release/obj.target/addon/src/addon.o
In file included from ../../nan/nan.h:56,
                 from ../src/addon.h:4,
                 from ../src/addon.cc:1:
/root/.cache/node-gyp/14.15.1/include/node/node.h:758: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]
  758 |       (node::addon_register_func) (regfunc),                          \
      |                                           ^
/root/.cache/node-gyp/14.15.1/include/node/node.h:792:3: note: in expansion of macro 'NODE_MODULE_X'
  792 |   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
      |   ^~~~~~~~~~~~~
../src/addon.cc:76:1: note: in expansion of macro 'NODE_MODULE'
   76 | NODE_MODULE(addon, InitAddon)
      | ^~~~~~~~~~~
  SOLINK_MODULE(target) Release/obj.target/addon.node
  COPY Release/addon.node
make: Leaving directory '/usr/app/node_modules/libpq/build'

> [email protected] postinstall /usr/app/node_modules/nodemon
> node bin/postinstall || exit 0

Love nodemon? You can now support the project via the open collective:
 > https://opencollective.com/nodemon/donate

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

+ [email protected]
added 222 packages from 187 contributors and audited 224 packages in 13.185s

12 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

WARNING: Ignoring APKINDEX.70f61090.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.ca2fea5b.tar.gz: No such file or directory
(1/4) Purging .build-deps (20201207.093711)
(2/4) Purging postgresql-dev (12.5-r0)
(3/4) Purging openssl-dev (1.1.1g-r0)
(4/4) Purging pkgconf (1.6.3-r0)
Executing busybox-1.31.1-r9.trigger
OK: 233 MiB in 43 packages
Removing intermediate container 20f7406e6abc
 ---> 86a68c654898
Step 6/7 : COPY . .

Solution

  • Thank you David! Looks like I wasn't preserving node_modules in my docker-compose.yml file.

    Adding: - /usr/app/node_modules to the volumes did the trick!

    version: "3.8"
    services:
      api:
        build:
          context: .
          dockerfile: Dockerfile
        volumes:
          - .:/usr/app
          - /usr/app/node_modules
        ports:
          - "3000:3000"