Skip to content

Why do we install dependencies during Docker’s final “CMD” command, in development?

I’m working through a book about bootstrapping microservices, and the author provides the following dockerfile, which is meant to be used in development.**

FROM node:12.18.1-alpine
WORKDIR /usr/src/app
COPY package*.json .
CMD npm config set cache-min 999999 && 
   npm install && 
   npm run start:dev

The CMD command here is obviously somewhat unusual. The rationale provided is as follows: By doing the npm install when the container starts, we can “make use of npm caching so it’s much faster to install at container startup than if we installed it during the build process.”

What is going on behind the scenes here with the CMD command? How is this different from having a RUN command that installs the dependencies prior to the CMD command? And relatedly, why do we need to set a cache-min policy?

**The source files are not copied over here because they are included in a mounted volume.

EDIT: Here is the docker compose file as well

version: '3'
services:
  history:
    image: history
    build:
      context: ./history
      dockerfile: Dockerfile-dev
    container_name: history
    volumes:
      - /tmp/history/npm-cache:/root/.npm:z
      - ./history/src:/usr/src/app/src/:z
    ports:
      - '4002:80'
    environment:
      - PORT=80
      - NODE_ENV=development
    restart: 'no'

    ...

Answer

When you develop, you often change the packages that are included in the project. By doing it this way, you don’t need to build a new image when you do that. You can just stop and start the container and it’ll install the new packages.

I am a little surprised by the copying of package*.json though. I’d assume that that would be passed into the image using a volume like you say the source code is. It can still be done like that and maybe it is. We’d need to see your docker run command do know if it is.