Home >Web Front-end >JS Tutorial >Let's talk about how to choose the best Node.js Docker image?

Let's talk about how to choose the best Node.js Docker image?

青灯夜游
青灯夜游forward
2022-12-13 20:00:092513browse

Selecting a Node Docker image may seem like a small matter, but the size and potential vulnerabilities of the image can have a significant impact on your CI/CD process and security. So how do we choose the best Node.js Docker image?

Let's talk about how to choose the best Node.js Docker image?

When we use FROM node:latest or just FROM node, it is easy to ignore its potential risks. If you don't know the overall security risk and introduce it into the CI/CD process, it will undoubtedly exacerbate the risk. [Related tutorial recommendations: nodejs video tutorial, Programming teaching]

The following example is very typical. You can see this Node from many tutorials or blog posts. js Dockerfile configuration. However, there are big problems with the configuration of this Dockerfile, and it is highly not recommended to use it like this:

FROM node
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN npm install
CMD "npm" "start"

Translator’s Note: If you need to skip the analysis and see the conclusion directly, please slide directly to End of article.

A Node.js Docker image to choose from

When you build a Node.js image , there are actually many choices. These include official Docker images maintained by the Node.js core team, as well as special Node.js image versions selected from specific base images. You can also choose others, such as the Node.js application built by Google on the distroless project, or an image called scratch provided by the official Docker team.

Among these Node.js Docker images, which one is the most suitable for you?

Let’s analyze them one by one to learn more about their benefits and potential risks.

Author's Note: In this article, I will compare the Node.js image of version 18.2.0, which will be released around June 2022.

Default Node.js image

We start with the maintained node image. It is officially maintained by , and contains some basic image tags. These tags correspond to different underlying distributions (Debian, Ubuntu, Alpine) and different versions of the Node.js runtime itself. There are also specific version tags for different CPU architectures, such as amd64 and arm64x8 (new version of Apple's M1).

The most common node images in Debian distributions, such as bullseye or buster, they are based on that are maintained by another team ##buildpack-deps.
What happens when you build a Node.js Docker image based on this default node image?

FROM node

Use docker build --no-cache -f Dockerfile1 -t dockerfile1When building the image, the following will appear:

  • We did not specify Node .js runtime version, so node is an alias of node:last, and his version points to 18.2.0
  • this The Node.js Docker image size is 952MB

What are the dependencies and security vulnerability footprints of this latest Node.js image? We can use docker scan dockerfile1 to run a Synk-powered container, and we will get the following results:

  • There are 409 dependencies in total - these are Use open source libraries detected by the operating system's package manager, such as curl/libcurl4, git/git-man, imagemagick/imagemagick-6-common.
  • A total of 289 security issues were found in these dependencies, such as Buffer Overflows, use-after-free errors, out-of-bounds writeetc.
  • Node.js 18.2.0 runtime version is prone to 7 security issues. For example, DNS Rebinding, HTTP Request Smuggling, Configuration Hijacking
##Translator’s Note:

  • Buffer Overflows - 缓冲区溢出
  • Use After Free - 一种内存破坏漏洞,通常存在于浏览器中
  • out-of-bounds write - 越界写入
  • DNS Rebinding - DNS重绑定攻击
  • HTTP Request Smugglin - HTTP请求夹带攻击技术
  • Configuration Hijacking - 配置劫持

你真的需要在Node.js镜像中给你的应用提供wgetgitcurl吗?在Node.js Docker镜像中,有成百上千个依赖和工具,而这些依赖又对应着成百上千个漏洞。Node.js运行时的特性对应着7个不同的安全漏洞,给潜在攻击留下了很大的空间。总的来说,情况并不是很乐观。

Node.js Docker Hub选项node:buster vs node:bullseye

如果你在Node.js Docker Hub仓库上浏览可用tags,你将会发现有两个Node.js镜像tags - node:busternode:bullseye

这两个Docker镜像tags都基于Debian发行版。buster镜像tag对应着Debian10,将会在2022年8月到2024年进入到他的End of Life日期,所以buster不是一个很好的选择。bullseye镜像tag对应着Debian11,被当做Debian的当前稳定版本,预计EOL日期为2026年6月。

译者注:

  • End of Life。特指产品寿命的结束,通常缩写为EOL。

因此,十分建议你将所有新的和现有的Node.js Docker镜像从node:buster迁移到node:bullseye或者其他合适的可替代版本。
我们先构建一个新的Node.js Docker镜像基于:

FROM node:bullseye复制代码

如果你构建了这个Node.js Docker镜像tag并且与之前使用node:latest的结果进行比较,将会得到完全相同的大小、依赖数量和发现的漏洞。原因是nodenode:latestnode:bullseye全部指向了同一个正在构建的Node.js镜像tag。

Node.js镜像tag瘦身

官方的Node.js团队还维护了一个显式地针对功能性Node.js环境所需工具的镜像tag并且不会存在其他的东西。

这个Node.js镜像tags是通过slim镜像tag变量来引用的,比如node:bullseye-slim,或者带有Node.js指定版本,像node:14.19.2 -slim

我们再来基于Debian的当前稳定版本的bullseye构建一个Node.jsslim镜像:

FROM node:bullseye-slim
  • 镜像的大小已经急剧下降,从接近1GB的容器镜像降到246MB的镜像大小
  • 扫描他的内容也显示了整体软件足迹的大幅下降,只有97个依赖项和56个漏洞。

就容器镜像大小和安全状况而言,node:bullseye-slim已经是一个比较好的起点了。

一个LTS的Node.js Docker镜像

到目前为止,我们的Node.js Docker镜像基于当前版本的Node.js,即Node.js18。但是根据Node.js的发布时间表,这个版本直到2022年10月才进入正式的Active LTS状态。

译者注:LTS - Long-term support,即长期支持版本。

如果我们总是依赖于我们正在构建的Node.js Docker镜像中的LTS版本的话会怎么样?我们先更新这个Docker镜像tag并构建一个新的Node.js镜像:

FROM node:lts-bullseye-slim

瘦身后的Node.js LTS版本(16.15.0)在镜像上带来了相似数量的依赖、安全漏洞和一个略小的体积(188MB)。

因此,尽管你可能需要在LTS和当前Node.js运行时版本中选择,但他们都不会对Node.js镜像的软件占用空间有大的影响。

node:alpine对于Node.js镜像来说是一个更好的选择吗?

Node.js Docker团队维护了一个node:alpine镜像tag以及他的变体,以便将Alpine Linux发行版的特定版本与Node.js运行时的特定版本进行匹配。

Alpine Linux项目经常因为其非常小的镜像体积而被引用,小体积意味着更新的软件占用空间和更少的漏洞,确实十分不错。
下面的命令会让Dockerfile去生成一个node环境,这个将会增加未压缩的镜像体积:

FROM node:alpine

这个将会产生一个178MB大小的docker镜像,和slimNode.js镜像大小差不多,但是在alpine镜像tag中,只检测到了16个系统依赖漏洞和2个安全安全漏洞。这就意味着alpine镜像tag对于小体积和漏洞数量来说是一个比较好的选择。

alpine对Node.js镜像可能提供了一个较小的镜像体积和更少的漏洞数量。但是,我们必须意识到Alpine项目使用musl作为C标准库的实现。而Debian的Node.js镜像tag依赖于glibc实现,比如bullseyeslim。这些差异可以解释性能问题、功能性的bug或者是潜在的应用程序崩溃,这些都是由于底层C库的差异造成的。

选择一个alpine的Node.js镜像tag意味着你实际上是在选择一个非官方的Node.js运行时。Node.js Docker团队并不会正式支持基于alpine的容器镜像构建。因此,他声明基于Alpine的镜像tag是实验性的,并且可能和官方的构建不一致。

如果你正在选一个一个基于Alpine的Node.js Docker镜像,需要记住一点,Docker安全工具(例如Trivy或Snyk)目前无法检测到Alpine镜像中与运行时相关的漏洞的。虽然这种情况未来可能会改变,但是目前还不能找到Node.js18.2.0alpine基础镜像tag的安全漏洞,而18.2.0运行时本身实际上是容易受到攻击的。这与安全工具本身有关,而不是与Alpine基础镜像有关,但是也应该考虑到这一点。

Node.js的distroless(无损)Docker镜像

我们的基准测试的最后一个比较项目是谷歌的Distroless容器镜像。

什么是distroless容器镜像?

这种镜像甚至比slim的Node.js镜像更加小,因为distroless镜像只针对这个应用和应用运行时的依赖性而已。因此,一个distroless的docker镜像没有容器包管理器、shell、或者其他通用工具的依赖性,这使得它们的体积更小,漏洞也更少。

幸运的是,Distroless项目为Node.js维护了一个特殊运行时的distrolessdocker镜像,通过其完整的命名空间识别为grc.io/distroless/nodejs-debian11,并且可以在谷歌的容器注册表中找到(这个是gcr.io的部分)。

因为Distroless容器镜像没有软件,我们可以使用一个docker的多阶段工作流来为我们的容器安装依赖项,并且把它们复制到Distroless镜像:

FROM node:16-bullseye-slim AS build
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN npm install

FROM gcr.io/distroless/nodejs:16
COPY --from=build /usr/src/app /usr/src/app
WORKDIR /usr/src/app
CMD ["server.js"]

构建这个distrolessdocker镜像将产生112MB的文件,而在slimalpine镜像tag来说,这已经减小了很多文件的体积了。
如果你正在考虑使用distrolessdocker镜像,有一些重要的事项需要注意:

  • 好的一点是,它们是基于当前稳定的Debian发行版本,这意味着它们是最新的,很久才会到EOL的日期。
  • 因为它们是基于Debian的,所以它们依赖glibc实现,并且不太可能在生产环境出现一些奇怪的问题。
  • 你很快就会发现Distroless团队没有维护细粒度的Node.js运行时版本。这意味着你需要依赖于通用的nodejs:16的标记(该标记经常更新),或者在一个特定时间点根据镜像的SHA256哈希值进行安装。

Node.js Docker镜像tags的比较

我们可以参考下面的表格来总结不同Node.js Docker镜像tags之间的比较:

Image tag Node.js runtime version OS dependencies OS security vulnerabilities High and Critical vulnerabilities Medium vulnerabilities Low vulnerabilities Node.js runtime vulnerabilities Image size Yarn available
node 18.2.0 409 289 54 18 217 7 952MB Yes
node:bullseye 18.2.0 409 289 54 18 217 7 952MB Yes
node:bullseye-slim 18.2.0 97 56 4 8 44 7 246MB Yes
node:lts-bullseye-slim 16.15.0 97 55 4 7 44 6 188MB Yes
node:alpine 18.2.0 16 2 2 0 0 0 178MB Yes
gcr.io/distroless/nodejs:16 16.17.0 9 11 0 0 11 0 112MB No

Let’s go through the data and insights we learned about each of the different Node.js image tags and determine which one is ideal.

DEVELOPMENT-PARITY (development environment parity)

If you choose to use the Node.js image tag depends on the consistency of development (this means you want to optimize for the exact same environment as development and production), then this may already be a losing battle. In most cases, all 3 major operating systems use different C library implementations. Linux relies on glibc, Alpine relies on musl, and macOS has its own BSD libc implementation.

DOCKER Image Size

Sometimes, the image size is also important. To be more precise, our goal is not to have the smallest size, but to have the smallest overall software footprint. In this case, there is not much difference between slim image tags and alpine, and they average about 200MB for a container image. Of course, the software usage of the slim mirror is still quite high compared to alpine (slim97 VS alpine16), Therefore, the number of vulnerabilities is also higher for alipne (slime56 vs slpine2).

Security Vulnerabilities

Vulnerabilities are an important issue and have been at the center of many articles on why you should reduce container images size.

Ignore node and node:bullseye, which are images that increase security vulnerabilities due to larger software usage. We can pay more attention to slightly smaller image types. . Comparing between slim, alpine, and distroless, the absolute number of high-risk and critical security vulnerabilities is not high, ranging from 0 to 4. This is A controllable risk that won't affect your application.

Essential content?

The ideal Node.js Docker image should be a streamlined version of the operating system based on modern Debian OS. There is a stable and active long-term support version of Node.js.

The final analysis is to choose node:lts-bullseye-slimNode.js mirror tag. I'm in favor of using deterministic image tags, so the slight change I would make is to use the actual underlying version number instead of the lts alias.

The most ideal Node.js Docker image tag is **node:16.17.0-bullseye-slim**.

If you work on a mature development team that can support custom base images, my second best suggestion is to choose Google's distrolessimage tag , as it maintains glibc compatibility with official Node.js runtime versions. This workflow will require some maintenance, so I'm just suggesting it.

For more node-related knowledge, please visit: nodejs tutorial!

The above is the detailed content of Let's talk about how to choose the best Node.js Docker image?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete