Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image without npm nor yarn #404

Open
rubennorte opened this issue May 16, 2017 · 39 comments
Open

Image without npm nor yarn #404

rubennorte opened this issue May 16, 2017 · 39 comments

Comments

@rubennorte
Copy link

Now that Docker supports multi-stage builds it'd be nice to have an official base image with just the Node.js binary. A build image could extend from the current images and a production image could extend from the standalone version (copying the built application with all installed dependencies from the build container).

@LaurentGoderre
Copy link
Member

I agree but we use the official distribution which include npm. The core node doesn't have a version of node without npm, as far as I am aware.

@chorrell
Copy link
Contributor

Yeah, that would be great. I think if we do that we'd have to somehow build node without npm. Or convince the build group that we need that as another option.

It might make sense to do more of a clean break and create a new node-minimal image that better fits this use case.

@rubennorte
Copy link
Author

I just saw that https://github.com/mhart/alpine-node provides that kind of image (with the Node binary only). Maybe you can get some ideas from there.

@chorrell
Copy link
Contributor

Yeah they build node with --without-npm. We could probably do the same thing but the build and release would take longer.

@pesho
Copy link
Contributor

pesho commented May 16, 2017

Well, theoretically we could just rm -rf /usr/local/lib/node_modules/npm/ /usr/local/bin/npm after extracting the Node tarball. I don't see much value in pursuing that though.

@rubennorte
Copy link
Author

rubennorte commented May 16, 2017

@pesho I do see the value. You'd be reducing the image size by 40% (22MB from 54MB belong to npm and yarn in the Node 6.10 image). In some environments that's important.

@pesho
Copy link
Contributor

pesho commented May 16, 2017

@rubennorte I spoke too soon before. Indeed, there is value in having a minimal image without package managers for production.

@Starefossen
Copy link
Member

I agree, a minimal image without npm nor yarn would be nice for production use cases. This only makes sens for the alpine variant (since the ones based on Debian are so huge anyways), and I think it can be solved as easy as rm -rf /path/to/npm.

Nice issue number #404 😜

@valeriangalliat
Copy link

I had something in mind when multi-stage builds got introduced to make the smallest possible Node image:

# Dockerfile-alpine-minimal.template
FROM node:0.0.0-alpine AS builder
FROM alpine:0.0

COPY --from=builder /usr/local/bin/node /usr/local/bin/
COPY --from=builder /usr/lib/ /usr/lib/

CMD [ "node" ]

I'm not sure if it's OK to use multi-stage builds in docker-node yet, but I like the idea of using the previously built alpine image and multi-stage builds to make the minimal version (instead of having to compile Node again).

@Daniel15
Copy link

Daniel15 commented Jul 14, 2017

The core node doesn't have a version of node without npm, as far as I am aware.

They used to have a statically-linked node binary that you could download just by itself with no other stuff. It looks like they only still have that for Windows (eg. https://nodejs.org/dist/v6.11.1/win-x64/node.exe), the only Linux downloads I could find still contain npm. Having said that, you could just use their Linux tarball and delete the npm directory and executable.

@chorrell
Copy link
Contributor

Is this worth revisiting as a variant? Doing rm -rf /usr/local/lib/node_modules/npm/ /usr/local/bin/npm is easy enough and it would be useful with multi-stage builds. And what would we call the variant?

@pesho
Copy link
Contributor

pesho commented May 25, 2018

And what would we call the variant?

A few suggestions: production, micro, tiny, nano

I like the idea in general.

@LaurentGoderre
Copy link
Member

The complexity this would bring kind of scares me.

@LaurentGoderre
Copy link
Member

@valeriangalliat I like your approach but in the current setup, that would mean building the alpine images twice because different images are not aware of each other.

@chorrell
Copy link
Contributor

chorrell commented May 25, 2018

I think we should only do this for Debian, something like:

FROM debian:jessie-slim

RUN groupadd --gid 1000 node \
  && useradd --uid 1000 --gid node --shell /bin/bash --create-home node

# gpg keys listed at https://github.com/nodejs/node#release-team
RUN set -ex \
  && for key in \
    94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
    FD3A5288F042B6850C66B31F09FE44734EB7990E \
    71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
    DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
    C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
    B9AE9905FFD7803F25714661B63B535A4C206CA9 \
    56730D5401028683275BD23C23EFEFE93C4CFFFE \
    77984A986EBC2AA786BC0F66B01FBB92821C587A \
  ; do \
    gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys "$key" || \
    gpg --keyserver hkp://ipv4.pool.sks-keyservers.net --recv-keys "$key" || \
    gpg --keyserver hkp://pgp.mit.edu:80 --recv-keys "$key" ; \
  done

ENV NODE_VERSION 10.2.0

RUN buildDeps='ca-certificates curl xz-utils' \
    && ARCH= && dpkgArch="$(dpkg --print-architecture)" \
    && case "${dpkgArch##*-}" in \
      amd64) ARCH='x64';; \
      ppc64el) ARCH='ppc64le';; \
      s390x) ARCH='s390x';; \
      arm64) ARCH='arm64';; \
      armhf) ARCH='armv7l';; \
      i386) ARCH='x86';; \
      *) echo "unsupported architecture"; exit 1 ;; \
    esac \
    && set -x \
    && apt-get update && apt-get install -y $buildDeps --no-install-recommends \
    && rm -rf /var/lib/apt/lists/* \
    && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz" \
    && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
    && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
    && grep " node-v$NODE_VERSION-linux-$ARCH.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
    && tar -xJf "node-v$NODE_VERSION-linux-$ARCH.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
    && rm -rf /usr/local/lib/node_modules/ \
    && rm -rf /usr/local/bin/npm \
    && rm -rf /usr/local/bin/npx \
    && rm "node-v$NODE_VERSION-linux-$ARCH.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
    && apt-get purge -y --auto-remove $buildDeps \
    && ln -s /usr/local/bin/node /usr/local/bin/nodejs

CMD [ "node" ]

The above image is about 125MB

(edit: updated to delete /usr/local/lib/node_modules/)

@chorrell
Copy link
Contributor

chorrell commented May 25, 2018

Also, for a variant name, I kind of like node:core, node:10-core etc.

@LaurentGoderre
Copy link
Member

How much space is saved on Debian?

@Daniel15
Copy link

Daniel15 commented May 25, 2018 via email

@chorrell
Copy link
Contributor

We're looking at a ~60MB difference using the rm -r approach:

[chorrell:~/GitHub/docker-node-main] master(+6/-6)* ± docker images | grep 10.2.0-slim
node                10.2.0-slim         c164ad185a38        20 hours ago        184MB

vs

[chorrell:~/GitHub/docker-node-main] master(+6/-6)* ± docker images | grep 10.2.0-core
node                10.2.0-core         68519b454a55        3 minutes ago       125MB

@chorrell
Copy link
Contributor

chorrell commented May 25, 2018

Note that I don't think the statically compiled versions are available, or at least I cannot find them at https://nodejs.org/dist/ for v10. And we would want versions for each of the architectures we support too.

chorrell added a commit that referenced this issue May 30, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Closes #404
chorrell added a commit that referenced this issue May 31, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Closes #404
chorrell added a commit that referenced this issue May 31, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Closes #404
chorrell added a commit that referenced this issue May 31, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Closes #404
chorrell added a commit that referenced this issue May 31, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Closes #404
chorrell added a commit that referenced this issue Jun 1, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Closes #404
@bobbui
Copy link

bobbui commented Jun 23, 2018

love this idea, @chorrell how soon this can be released?

@chorrell chorrell mentioned this issue Jul 4, 2018
3 tasks
@bnb
Copy link

bnb commented Jul 9, 2018

@SimenB definitely think it's worth it – the fact that y'all are getting the work done is super valuable if Node.js core were to do the same 💚

@addaleax
Copy link
Member

addaleax commented Jul 9, 2018

@bnb Feel free to put this on the TSC agenda by adding the label to it and/or mentioning it in the current TSC meeting issue (nodejs/TSC#565) – ideally with a short summary of the question you’d like to see answered, which decision you’d like to see made, or what you’d like to raise awareness about. (It’s not super-clear from this thread for me, so that’s why I’m mentioning it 🙂).

@hulkish
Copy link

hulkish commented Jul 15, 2018

Would really like to see this as well. It's actually far-preferred to not involve global dependencies at all for your production apps.

@mhdawson
Copy link
Member

A potentially related issue: nodejs/Release#341. The discussion is related to having different versions, some without extras.

@mhdawson
Copy link
Member

mhdawson commented Aug 1, 2018

Discussed in last TSC meeting, but this should not block this issue and ongoing discussion about whether we should do something on the release side will continue in: nodejs/Release#341. Removing from TSC agenda.

chorrell added a commit that referenced this issue Nov 27, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Also:

- Skip setting yarn version in core variant
- Skip npm and yarn tests for "core" variant

Closes #404
chorrell added a commit that referenced this issue Dec 6, 2018
This is an image without npm or yarn installed, suitable for multi-stage
builds.

Also:

- Skip setting yarn version in core variant
- Skip npm and yarn tests for "core" variant

Closes #404
@markmsmith
Copy link

FWIW, I would like to add a vote in favor of this work, including providing an alpine-based image without npm.

My needs are:

  1. For the 1st stage of the app build, I'm using yarn, so don't need npm (but it's not the end of the world if it's there).
  2. More importantly, when I'm creating the production docker image in the 2nd stage of the dockerfile, I don't need any package manager at all, and want the attack surface to be as small as possible. Making the image smaller is just a nice bonus.

I would really like to see an official image, since it's not obvious to someone like myself which things are necessary vs what can safely be deleted when pairing down a larger image, or which specific combination of flags need to be set to build it from source without npm, while still allowing native modules to work.

If one of the main obstacles is still the naming convention for the release, it would be nice if there could be a simple vote with github reactions by the maintainers so we could be unblocked. The suggestion of -nopm on the PR seemed pretty good to me.

Thanks.

@SkeLLLa
Copy link

SkeLLLa commented Aug 2, 2019

I've made some tests. Using multi-stage docker build and node static build I was able to reduce node alpine image size by two times. And upx-packed is four times less size.

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
node                alpine              d97a436daee9        8 days ago          79.3MB
mhart/alpine-node   slim                b8c1832fbf86        8 days ago          44.5MB
m03geek/alpine-node latest              4ed96bad5c6f        10 minutes ago      38.7MB
m03geek/alpine-node upx-latest          c3e52e2954ac        22 seconds ago      18.6MB

You can find dockerfile in my repo https://github.com/SkeLLLa/alpine-node, feel free to use it if needed.

@astefanutti
Copy link

FWIW, I'm maintaining scratch Node images at https://github.com/astefanutti/scratch-node. The compressed size is around 14MB for Node 12.

@SkeLLLa
Copy link

SkeLLLa commented Aug 5, 2019

@astefanutti that's very nice. I've created static built based on your idea with scratch. And with upx it became even smaller: ~12MB. You may apply upx packer in your repo as well.
Also I've created autobuild repo, so if anyone interested: https://hub.docker.com/r/m03geek/alpine-node. Those are not well tested, but they should work.

If anyone here is interested in porting that into official repo - feel free to take, test, enhance the code (repo link is in docker repo description).

@Rush
Copy link

Rush commented Jul 23, 2020

Agree it would be useful!

@chorrell
Copy link
Contributor

fwiw, I experimented a bit with this over here using GitHub Actions to build a statically compiled node: https://github.com/chorrell/docker-node-minimal

@hubgit
Copy link

hubgit commented Feb 24, 2021

Building the node:14-alpine image without npm or yarn reduces the image size from 116MB to 86MB, most of which is the 71MB node binary.

@gaby
Copy link

gaby commented Nov 28, 2021

Any news on this? Issue was created over 3 years ago :-S

@marinpurgar
Copy link

Almost one year in since last bump and still no info about minimal node base images suited for production workloads?

@mknj
Copy link

mknj commented Mar 6, 2024

We currently struggle because Microsoft Defender for Cloud flags all our Production builds because of an outdated dependency in npm (-> ip@2.0.0).

@LaurentGoderre
Copy link
Member

I created the debian core image in #2058

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.