Let's talk about how to choose the best Node.js Docker image?
Dec 13, 2022 pm 08:00 PMSelecting 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?
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 dockerfile1
When building the image, the following will appear:
- We did not specify Node .js runtime version, so
node
is an alias ofnode:last
, and his version points to18.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 write
etc. - 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 - 緩沖區(qū)溢出
- Use After Free - 一種內(nèi)存破壞漏洞,通常存在于瀏覽器中
- out-of-bounds write - 越界寫入
- DNS Rebinding - DNS重綁定攻擊
- HTTP Request Smugglin - HTTP請求夾帶攻擊技術
- Configuration Hijacking - 配置劫持
你真的需要在Node.js鏡像中給你的應用提供wget
、git
、curl
嗎?在Node.js Docker鏡像中,有成百上千個依賴和工具,而這些依賴又對應著成百上千個漏洞。Node.js運行時的特性對應著7個不同的安全漏洞,給潛在攻擊留下了很大的空間。總的來說,情況并不是很樂觀。
Node.js Docker Hub選項node:buster vs node:bullseye
如果你在Node.js Docker Hub倉庫上瀏覽可用tags,你將會發(fā)現(xiàn)有兩個Node.js鏡像tags - node:buster
和node:bullseye
。
這兩個Docker鏡像tags都基于Debian發(fā)行版。buster
鏡像tag對應著Debian10,將會在2022年8月到2024年進入到他的End of Life日期,所以buster
不是一個很好的選擇。bullseye
鏡像tag對應著Debian11,被當做Debian的當前穩(wěn)定版本,預計EOL日期為2026年6月。
譯者注:
- End of Life。特指產(chǎn)品壽命的結束,通??s寫為EOL。
因此,十分建議你將所有新的和現(xiàn)有的Node.js Docker鏡像從node:buster
遷移到node:bullseye
或者其他合適的可替代版本。
我們先構建一個新的Node.js Docker鏡像基于:
FROM node:bullseye復制代碼
如果你構建了這個Node.js Docker鏡像tag并且與之前使用node:latest
的結果進行比較,將會得到完全相同的大小、依賴數(shù)量和發(fā)現(xiàn)的漏洞。原因是node
、node:latest
、node:bullseye
全部指向了同一個正在構建的Node.js鏡像tag。
Node.js鏡像tag瘦身
官方的Node.js團隊還維護了一個顯式地針對功能性Node.js環(huán)境所需工具的鏡像tag并且不會存在其他的東西。
這個Node.js鏡像tags是通過slim
鏡像tag變量來引用的,比如node:bullseye-slim
,或者帶有Node.js指定版本,像node:14.19.2 -slim
。
我們再來基于Debian的當前穩(wěn)定版本的bullseye
構建一個Node.jsslim
鏡像:
FROM node:bullseye-slim
- 鏡像的大小已經(jīng)急劇下降,從接近1GB的容器鏡像降到246MB的鏡像大小
- 掃描他的內(nèi)容也顯示了整體軟件足跡的大幅下降,只有97個依賴項和56個漏洞。
就容器鏡像大小和安全狀況而言,node:bullseye-slim
已經(jīng)是一個比較好的起點了。
一個LTS的Node.js Docker鏡像
到目前為止,我們的Node.js Docker鏡像基于當前版本的Node.js,即Node.js18。但是根據(jù)Node.js的發(fā)布時間表,這個版本直到2022年10月才進入正式的Active LTS
狀態(tài)。
譯者注:LTS - Long-term support,即長期支持版本。
如果我們總是依賴于我們正在構建的Node.js Docker鏡像中的LTS版本的話會怎么樣?我們先更新這個Docker鏡像tag并構建一個新的Node.js鏡像:
FROM node:lts-bullseye-slim
瘦身后的Node.js LTS版本(16.15.0)在鏡像上帶來了相似數(shù)量的依賴、安全漏洞和一個略小的體積(188MB)。
因此,盡管你可能需要在LTS和當前Node.js運行時版本中選擇,但他們都不會對Node.js鏡像的軟件占用空間有大的影響。
node:alpine對于Node.js鏡像來說是一個更好的選擇嗎?
Node.js Docker團隊維護了一個node:alpine
鏡像tag以及他的變體,以便將Alpine Linux發(fā)行版的特定版本與Node.js運行時的特定版本進行匹配。
Alpine Linux項目經(jīng)常因為其非常小的鏡像體積而被引用,小體積意味著更新的軟件占用空間和更少的漏洞,確實十分不錯。
下面的命令會讓Dockerfile去生成一個node環(huán)境,這個將會增加未壓縮的鏡像體積:
FROM node:alpine
這個將會產(chǎn)生一個178MB大小的docker鏡像,和slim
Node.js鏡像大小差不多,但是在alpine
鏡像tag中,只檢測到了16個系統(tǒng)依賴漏洞和2個安全安全漏洞。這就意味著alpine
鏡像tag對于小體積和漏洞數(shù)量來說是一個比較好的選擇。
alpine
對Node.js鏡像可能提供了一個較小的鏡像體積和更少的漏洞數(shù)量。但是,我們必須意識到Alpine項目使用musl
作為C標準庫的實現(xiàn)。而Debian的Node.js鏡像tag依賴于glibc
實現(xiàn),比如bullseye
和slim
。這些差異可以解釋性能問題、功能性的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維護了一個特殊運行時的distroless
docker鏡像,通過其完整的命名空間識別為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"]
構建這個distroless
docker鏡像將產(chǎn)生112MB的文件,而在slim
和alpine
鏡像tag來說,這已經(jīng)減小了很多文件的體積了。
如果你正在考慮使用distroless
docker鏡像,有一些重要的事項需要注意:
- 好的一點是,它們是基于當前穩(wěn)定的Debian發(fā)行版本,這意味著它們是最新的,很久才會到EOL的日期。
- 因為它們是基于Debian的,所以它們依賴
glibc
實現(xiàn),并且不太可能在生產(chǎn)環(huán)境出現(xiàn)一些奇怪的問題。 - 你很快就會發(fā)現(xiàn)Distroless團隊沒有維護細粒度的Node.js運行時版本。這意味著你需要依賴于通用的
nodejs:16
的標記(該標記經(jīng)常更新),或者在一個特定時間點根據(jù)鏡像的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
(slim
97 VS alpine
16), Therefore, the number of vulnerabilities is also higher for alipne
(slime
56 vs slpine
2).
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-slim
Node.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 distroless
image 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!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

PHP and Vue: a perfect pairing of front-end development tools. In today's era of rapid development of the Internet, front-end development has become increasingly important. As users have higher and higher requirements for the experience of websites and applications, front-end developers need to use more efficient and flexible tools to create responsive and interactive interfaces. As two important technologies in the field of front-end development, PHP and Vue.js can be regarded as perfect tools when paired together. This article will explore the combination of PHP and Vue, as well as detailed code examples to help readers better understand and apply these two

As a fast and efficient programming language, Go language is widely popular in the field of back-end development. However, few people associate Go language with front-end development. In fact, using Go language for front-end development can not only improve efficiency, but also bring new horizons to developers. This article will explore the possibility of using the Go language for front-end development and provide specific code examples to help readers better understand this area. In traditional front-end development, JavaScript, HTML, and CSS are often used to build user interfaces

Django is a web application framework written in Python that emphasizes rapid development and clean methods. Although Django is a web framework, to answer the question whether Django is a front-end or a back-end, you need to have a deep understanding of the concepts of front-end and back-end. The front end refers to the interface that users directly interact with, and the back end refers to server-side programs. They interact with data through the HTTP protocol. When the front-end and back-end are separated, the front-end and back-end programs can be developed independently to implement business logic and interactive effects respectively, and data exchange.

As a C# developer, our development work usually includes front-end and back-end development. As technology develops and the complexity of projects increases, the collaborative development of front-end and back-end has become more and more important and complex. This article will share some front-end and back-end collaborative development techniques to help C# developers complete development work more efficiently. After determining the interface specifications, collaborative development of the front-end and back-end is inseparable from the interaction of API interfaces. To ensure the smooth progress of front-end and back-end collaborative development, the most important thing is to define good interface specifications. Interface specification involves the name of the interface

In front-end development interviews, common questions cover a wide range of topics, including HTML/CSS basics, JavaScript basics, frameworks and libraries, project experience, algorithms and data structures, performance optimization, cross-domain requests, front-end engineering, design patterns, and new technologies and trends. . Interviewer questions are designed to assess the candidate's technical skills, project experience, and understanding of industry trends. Therefore, candidates should be fully prepared in these areas to demonstrate their abilities and expertise.

Methods for implementing instant messaging include WebSocket, Long Polling, Server-Sent Events, WebRTC, etc. Detailed introduction: 1. WebSocket, which can establish a persistent connection between the client and the server to achieve real-time two-way communication. The front end can use the WebSocket API to create a WebSocket connection and achieve instant messaging by sending and receiving messages; 2. Long Polling, a technology that simulates real-time communication, etc.

Django: A magical framework that can handle both front-end and back-end development! Django is an efficient and scalable web application framework. It is able to support multiple web development models, including MVC and MTV, and can easily develop high-quality web applications. Django not only supports back-end development, but can also quickly build front-end interfaces and achieve flexible view display through template language. Django combines front-end development and back-end development into a seamless integration, so developers don’t have to specialize in learning

Combination of Golang and front-end technology: To explore how Golang plays a role in the front-end field, specific code examples are needed. With the rapid development of the Internet and mobile applications, front-end technology has become increasingly important. In this field, Golang, as a powerful back-end programming language, can also play an important role. This article will explore how Golang is combined with front-end technology and demonstrate its potential in the front-end field through specific code examples. The role of Golang in the front-end field is as an efficient, concise and easy-to-learn
