5

If I'm building microservices using Node on Docker images - it's necessary to keep an idea of what version of Node I'm using.

The idea is - I'm going to be running Node locally in development - and then it still needs to work when running on a container.

If my Dockerfile looks like this:

FROM node:10.10-alpine

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm install --only=production

# Bundle app source
COPY . .

EXPOSE 3001
CMD [ "npm", "start" ]

This is fine - except my local environment doesn't know which version of node I'm using.

Now I could just put 10.10 in my .nvmrc file.

But then I have to remember to keep these in sync. Is there a better way to do it? Is there a node:alpine that respects .nvmrc?

3
  • 1
    Why aren’t your running your local environment from Docker? Sep 17, 2018 at 20:38
  • 1
    @JamesFenwick - I can do that? - The idea is - I want to be using nodemon in development, running tests, etc.
    – dwjohnston
    Sep 18, 2018 at 7:36
  • Found this because I was also looking for a solution. There's probably a way to add an nvm stage to the build, but seems like a waste of time because it would add so much complexity. Maybe keeping the two versions in sync is best handled with a CI or Git hook.
    – Codebling
    Apr 10, 2022 at 20:12

2 Answers 2

3

The primary point of Docker is isolating what happens inside a container from what happens outside (be that other running programs, other containers, or in your .nvmrc). Docker images tend to be extremely spare, containing just the components and data they need, explicitly specified in the Dockerfile. Any configurations required need to be explicitly set, say by environment variables or copied-over config files. An isolated environment with all requirements bundled / encapsulated—that's how Docker gets workloads with different (even highly incompatible) requirements running side-by-side.

Node Version Manager comes from a very different worldview. One that believes you might have multiple versions of node installed, and might freely switch back and forth between them. There's nothing wrong with that per se, especially for a developer workstation, but it's almost inimical to the Docker philosophy. The number of Docker configs that have >1 node version installed is going to be vanishingly small, and they'd be extremely unusual, especially those built on the minimalistic Alpine Linux or for the minimalist strategy of microservices.

If you need to switch between node versions on your development station, so be it. But recommend you do not attempt to map that workflow / multiple installed versions strategy into your Docker images. It's going to be a force-fit at best, and will rob you of the very precision and minimalism that makes Docker work so well. Instead, consider your Docker images the targeted, specific outcome of your build process. The specific versions of node or other resources can be "burned into" the image as environment variables or config files if you need to query the current version at runtime. If you need to build several variants, each targeting a separate node version, that's quite doable. Docker has a rich tagging ability; it's commonly used for just that purpose.

2
  • I'm not talking about running multiple versions of node on my Docker container. In my development environment, I'm going to have different projects running different versions of node, and for that NVM is helpful. If another is working on the project, then it's helpful for them to know which version of node to be using. For that dropping a .nvmrc in the project folder is helpful. I'm concerned that I'm declaring the node version in two places, once in the dockerfile, and the other in the .nvmrc. It could lead to a headache if one were forgotten if the version was later updated.
    – dwjohnston
    Sep 18, 2018 at 8:19
  • No question that NVM is handy. Fine for the dev world. But Docker images, once built, are immutable. Docker images, by design, lock or pin versions down in way NVM environments try to keep dynamic. That circle can't be directly squared. You can construct a Dockerfile based on your .nvmrc, but Dockerfiles are themselves static. No way to have the Dockerfile "take the current version of the local .nvmrc, build with that." Sep 18, 2018 at 9:24
0

You can define the node.version which should be used in a specific project using the package.json file, i.e:

{ "private": true, "engineStrict": true, "engines": { "node": "10.x" }, "devEngines": { "node": "10.x" }

When you run npm install and you are using a node version different than 10.* you would get an error and it won't let you install the packages. This would guarantee other developers don't use a different node version and commit the package-lock.json file with this version which could maybe cause issues down the road. See https://docs.npmjs.com/files/package.json the engines section for more information about this.

You can also leave the .nvmrc file in the repo as well which would be relevant for the local development environment so you can add in the .bashrc file the code to automatically switch node version when cd'ing into your different projects.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.