TL;DR;
- Node and Npm version should be updated to a more recent one, as we are mostly developing with newer node and npm versions, also because committed lockfiles are version 2.
Lockfile version 2 is available starting at npm v7, However I think we could update it even to a more recent version.
For example, Node v16, that includes npm v8).
npm install
command here should be replaced by npm ci
so we avoid side effects (no modification of package-lock.json).
Any strong reason to not do this?
Long version if you are not very convinced
The following is a real use case of a bug in the produced image. It took me like an hour to figure out the "bug" (thanks to @magicmatatjahu for pairing!).
The very first Docker image of server-api was built and pushed to Docker Hub by our GH workflow action if-nodejs-release.yml.
Unfortunately, after trying to deploy it to a K8s cluster, we found out that the container was failing due to a missing node module: Error: Cannot find module '@babel/core'
. By pulling the same image locally, we discarded the problem was in K8s but in the image itself.
The surprise is that, whenever that image is built locally (e.g. in my computer), the container works like a charm.
But why?
After diving (literally, using dive tool) into both Docker images (the one created by CI and the one created by myself locally), I noticed there was a big difference on a particular Docker layer. In particular, in the one created by COPY package* ./
.
As you can see, the package-lock.json
filesize differs. The one created by CI is much smaller (554 kB VS 1.2 MB).
After reading both files, I noticed that the package-lock.json
from the image created by CI was a version 1 ("lockfileVersion": 1
), however both the one created locally and the one available in the repository source code are version 2 ("lockfileVersion": 2
).
But how can be possible if dependencies are installed inside docker? See Dockerfile. Could be a bug with Docker? The answer is no.
Dependencies were not built at the time RUN npm ci
was executed, by way before. In particular, in the GH workflow action that precedes this. Inside Docker image we only run npm ci
, which is intended for just using the pacakge-lock.json
as the list of dependencies to install without modification.
This line is running a npm install
command, so all dependencies are installed. Is the GH action running an old npm
version that doesn't support lockfile version 2? Well, considering that the image where we run is ubuntu-latest
, the npm
version should be 8.1.2
(according to this). But we are not using that NPM (nor node) executable, but rather the one installed in the previous step, which is:
- Node v14.18.3
- NPM v6.14.15
.
The reason why the npm lockfile version is 1 in CI is because npm install
that ran in the workflow with NPM v6.14.15 doesn't understand lockfile version 2 fully, so it literally tries to do the best (which seems it's not the best for us). As the warning says:
❯ npm install
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion@1, but package-lock.json was generated for lockfileVersion@2. I'll try to do my best with it!
Due to that missing dependency (@babel/core
) that npm couldn't install, the app is broken.
Related issues