Bcrypt error when creating a docker container with x86 architecture on a Mac M1

I’m using a Mac M1 (arm processor) and want to deploy my app containerizing it. I’m able to create the container, but when running npm start the app throws an error:

Error loading shared library /usr/app/programs/server/npm/node_modules/meteor/accounts-password/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node: Exec format error

This is the script I’m using to create the container, I run it at the root folder of my meteor project:

#!/bin/bash
# Source: https://blog.mvp-space.com/how-to-dockerize-a-meteor-app-with-just-one-script-4bccb26f6ff0
APP_NAME=someappname
APP_DOMAIN=https://www.example.com
APP_PORT=80
SETTINGS_PATH=settings-production.json
METEOR_VERSION=2.7.3
MONGO_URL="mongo url..."

echo "=> Removing /tmp/${APP_NAME}"
rm -rf /tmp/${APP_NAME}

echo "=> Executing Meteor Build..."
meteor build \
--architecture os.linux.x86_64 \
--allow-superuser \
--directory /tmp/${APP_NAME} \
--server=${APP_DOMAIN}/

echo "=> Copying settings file..."
cp ${SETTINGS_PATH} /tmp/${APP_NAME}/bundle/settings.json

echo "=> Moving to /tmp/${APP_NAME}/bundle"
cd /tmp/${APP_NAME}/bundle

# Create package.json
echo "=> Creating package.json..."
cat > package.json <<- "EOF"
{
  "name": "app",
  "version": "1.0.0",
  "scripts": {
    "start": "METEOR_SETTINGS=$(cat settings.json) node main.js"
  }
}
EOF

# Create the Dockerfile
echo "=> Creating Dockerfile..."
cat > Dockerfile <<EOF
# Pull base image.
FROM mhart/alpine-node:14
# Install build tools to compile native npm modules
RUN apk add --update build-base python
# Create app directory
RUN mkdir -p /usr/app
COPY . /usr/app
RUN cd /usr/app/programs/server && npm install --production
WORKDIR /usr/app
ENV PORT=3000
ENV MONGO_URL=${MONGO_URL}
ENV ROOT_URL=${APP_DOMAIN}/
CMD [ "npm", "start" ]
EXPOSE 3000
EOF

# Build the docker image
echo "=> Building docker image..."
docker stop ${APP_NAME}
docker rm -f ${APP_NAME}
docker rmi -f ${APP_NAME}
# Once everything is out of the way we can build the image
docker buildx build \
          --platform linux/amd64 \
          -t ${APP_NAME} .

# Start the container
# echo "=> Starting ${APP_NAME} container..."
docker run --rm -it --platform linux/amd64 --entrypoint sh ${APP_NAME}

It seems like:

meteor build \
--architecture os.linux.x86_64 \

is not creating the right bcrypt package for amd64. Is this a bug, am I doing something wrong… or is there a workaround?
Thank you!

The solution here is to run npm install from within the Dockerfile script so that native npm packages are built for x64. Here’s some sample code from disney/meteor-base:

(build-meteor-npm-dependencies.sh)

Our Dockerfile looks very similar (we also build on ARM sometimes)

...top rows omitted...

# Install OS build dependencies, which we remove later after we’ve compiled native Node extensions
RUN apk --no-cache --virtual .node-gyp-compilation-dependencies add \
		g++ \
		make \
		python3 \
	# And runtime dependencies, which we keep
	&& apk --no-cache add \
		bash \
		ca-certificates

# Copy in scripts and supporting files
COPY ./.docker/scripts/ $SCRIPTS_FOLDER/

# prep for the entrypoint script
RUN cd $SCRIPTS_FOLDER && npm install --production

# Copy in app bundle from tarball
ADD $BUNDLE_PATH $APP_BUNDLE_FOLDER/bundle

# Build native extensions
RUN bash $SCRIPTS_FOLDER/build-meteor-npm-dependencies.sh \
	&& apk del .node-gyp-compilation-dependencies

ENV NODE_ENV production

# Start app
ENTRYPOINT ["/docker/entrypoint.sh"] 

CMD ["node", "main.js"]
1 Like

Thank you, I’ll give it a try!