Search code examples
dockernginxpm2nuxt.js

Docker CMD doesn't recognize pm2-runtime


I'm trying to build a docker image that combines nginx & pm2 but when I'm trying to execute pm2 like this, But when I execute it like that I get following error:

/bin/sh: [pm2-runtime,: not found

The weird thing is that if I override the CMD and use it like this:

sudo docker run -it -p 80:80 frontend-test pm2-runtime

It DOES recognize that pm2(-runtime) is installed. Anyone has an idea how this black magic can happen? The previous version I was generating the nuxt pages, and serve them statically via Nginx, but now I want to convert that to using the SSR mode of nuxt. My goal is to run the app and than reverseproxy via Nginx (what seems to work, except that pm2 doesn't want to run). Thanks in advance!

Below is a (little bit simplified) version of my Dockerfile:

### BUILD STAGE ###

FROM node:10-alpine as build-stage
WORKDIR /app

# Copy only package(-lock).json to enable docker caching
COPY /index/package*.json /app/index/

# Install packages before copying source code to use cache where possible
WORKDIR /app/index
RUN npm install

# Copy source code
WORKDIR /app
COPY . .

# Build source code
WORKDIR /app/index
RUN npm run build

### END BUILD STAGE ###

### PRODUCTION STAGE ###

FROM nginx:1.17-alpine as production-stage
ARG env_name=dev

# Install system dependencies (nodejs to run pm2)
RUN apk add --update nodejs nodejs-npm

# Copy transpiled sourcecode to production image
COPY --from=build-stage /app/index/.nuxt /app/index

# Copy config files to production image
WORKDIR /app
COPY deployment/pm2.js ./ecosystem.config.js
COPY deployment/nginx.${env_name}.conf /etc/nginx/nginx.conf

# Install pm2 globally
RUN npm install pm2 -g
RUN pm2 list

EXPOSE 80
CMD ["pm2-runtime", "start", "--env", ${env_name}, "&&", "nginx", "-g", "daemon off;"]

### END PRODUCTION STAGE

Solution

  • The problem was that the CMD directive can't handle multiple commands out of the box.

    Changing the CMD to following line fixed my issue:

    CMD ["sh", "-c", "nginx && pm2-runtime start ecosystem.config.js --env $env_name"]
    

    Docker CMD & ENTRYPOINT runs the commands implicitly with sh -c, but to chain commands and/or inject environment variables, you need to "nest" the sh -c from docker with your own.