聊聊如何選擇一個最好的Node.js Docker映像?
選擇一個Node的Docker映像看起來像是一件小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?
我們在使用FROM node:latest
或只是FROM node
時,很容易忽略他潛在的風險。如果你不知道整體的安全風險並且把他引入了CI/CD的流程中,那無疑是加劇了這個風險。 【相關教學推薦:nodejs影片教學、程式設計教學】
#下面這個範例非常典型,你可以從很多教學或部落格文章看到這個Node. js Dockerfile的配置。 但是這個Dockerfile的配置存在很大的問題,非常不推薦這樣使用:
FROM node WORKDIR /usr/src/app COPY . /usr/src/app RUN npm install CMD "npm" "start"
譯者註:如果需要跳過分析直接看結論,請直接滑到文末。
一個可供選擇Node.js Docker映像
當你建立一個Node.js映像的時候,其實有很多選擇。其中就包含了Node.js核心團隊維護的官方Docker映像,以及從特定的基礎映像中選取的特殊Node.js映像版本。還可以選擇其他的,例如穀歌在distroless
專案上構建的Node.js應用程序,或者是Docker官方團隊提供的一個名為scratch
的鏡像。
在這些Node.js的Docker映像中,哪一個是最適合你的呢?
讓我們一個一個的去分析,了解更多他們的好處和潛在風險。
作者註:在這篇文章中,我將會比較18.2.0這個版本的Node.js鏡像,他的發佈時間是2022年6月左右。
預設的Node.js映像
我們先從維護的node映像開始。它是由進行正式地維護的,包含了一些基礎的鏡像tag。這些tag對應到不同的底層發行版(Debian、Ubuntu、Alpine)以及不同版本的Node.js運行時本身。還有針對不同CPU架構的特定版本tag,例如amd64
和arm64x8
(新版蘋果的M1)。
Debian發行版中最常見的node
鏡像,例如bullseye
或buster
,他們都是基於由另一個團隊維護的buildpack-deps
的。
當你基於這個預設的node
映像建立Node.js Docker映像時會發生什麼事?
FROM node
使用docker build --no-cache -f Dockerfile1 -t dockerfile1
建構映像時,就會出現下面這些:
- #我們沒有指定Node .js運行時版本,所以
node
是node:last
的一個別名,他的版本指向的是18.2.0
##這個Node.js Docker映像大小是952MB
docker scan dockerfile1來運行一個
Synk-powered容器,就會得到下面的結果:
- 共有409個依賴項- 這些是使用作業系統套件管理員偵測到的開源程式庫,例如
- curl/libcurl4
、
git/git-man、
imagemagick/imagemagick-6-common。
共有289個安全問題在這些依賴中被發現,例如, - Buffer Overflows
、
use-after-free errors、
out-of-bounds write等。
Node.js 18.2.0運行時版本容易出現7個安全問題。例如, - DNS Rebinding
、
HTTP Request Smuggling、
Configuration Hijacking
- Buffer Overflows - 缓冲区溢出
- Use After Free - 一种内存破坏漏洞,通常存在于浏览器中
- 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,你将会发现有两个Node.js镜像tags - node:buster
和node: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
的结果进行比较,将会得到完全相同的大小、依赖数量和发现的漏洞。原因是node
、node:latest
、node: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镜像,和slim
Node.js镜像大小差不多,但是在alpine
镜像tag中,只检测到了16个系统依赖漏洞和2个安全安全漏洞。这就意味着alpine
镜像tag对于小体积和漏洞数量来说是一个比较好的选择。
alpine
对Node.js镜像可能提供了一个较小的镜像体积和更少的漏洞数量。但是,我们必须意识到Alpine项目使用musl
作为C标准库的实现。而Debian的Node.js镜像tag依赖于glibc
实现,比如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镜像将产生112MB的文件,而在slim
和alpine
镜像tag来说,这已经减小了很多文件的体积了。
如果你正在考虑使用distroless
docker镜像,有一些重要的事项需要注意:
- 好的一点是,它们是基于当前稳定的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 | ##OS Critical vulnerabilitiesMedium vulnerabilities | Low vulnerabilities | Node.js runtime vulnerabilities | Image size | Yarn available |
---|---|---|---|---|---|---|---|---|---|
node | 18.2.0 | #409 | 289 | 54 | # 18 | 217 | 7 | ||
Yes | ##node:bullseye | 18.2.0 | 409 | 289 | #54 | 18 | 217 | 7 | 952MB |
node:bullseye-slim | #18.2.0 | 97 | 56 | 4 | 8 | 44 | 7 | #246MB | |
node:lts-bullseye-slim | 16.15.0 | 97 | 55 | 4 | #7 | 44 | 6 | 188MB | |
node:alpine | 18.2.0 | 16 | 2 | 2 | 0 | #0 | 0 | 178MB | |
gcr.io/distroless/nodejs:16 | 16.17.0 | 9 | #11 | 0 | 0 | 11 | 0 | #112MB |
如果你選擇使用的Node.js映像tag取決於開發的一致性(這意味著你希望為開發和生產完全相同的環境進行最佳化),那麼這可能已經是一場失敗的battle了。在大多數情況下,所有3個主要作業系統都使用不同的C庫實作。 Linux依賴glibc,Alpine依賴musl,而macOS有自己的BSD libc實作。
DOCKER鏡像大小有時候,鏡像大小也很重要。更準確地說,我們的目標不是擁有最小的體積,而是擁有最小的整體軟體佔用。在這種情況下,
slim鏡像tags和
alpine沒有太大的區別,而且它們對於一個容器鏡像來說平均大概是200MB。當然,
slim鏡像的軟體佔用相對於
alpine來說還是相當高的(
slim97個VS
alpine16個),因此,漏洞數量對於
alipne來說也更高(
slime56個VS slpine
安全漏洞
漏洞是一個重要的問題,並且一直是許多文章的中心——關於你為什麼應該減少容器鏡像的大小。
忽略
node和
node:bullseye這種由於較大的軟體佔用而跟著增加安全漏洞的鏡像,我們可以更關注稍微小一點的鏡像類型。在
slim、
alpine、distroless
本質內容?
最理想的Node.js Docker映像應該是基於現代Debian OS的作業系統的精簡版本,它有一個穩定且活躍的Node.js長期支援版本。
歸根究底就是選擇
node:lts-bullseye-slim
lts別名。 最理想的Node.js Docker映像tag是**node:16.17.0-bullseye-slim**
。 如果你在一個成熟的開發團隊工作,該團隊可以支援自訂基礎鏡像,那麼我的第二個最佳建議是選擇Google的
distroless
glibc對官方Node.js運行時版本的兼容性。這個工作流程會需要一些維護,所以我只是建議而已。
更多node相關知識,請造訪:###nodejs 教學###! ###以上是聊聊如何選擇一個最好的Node.js Docker映像?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

PHP與Vue:完美搭檔的前端開發利器在當今網路快速發展的時代,前端開發變得愈發重要。隨著使用者對網站和應用的體驗要求越來越高,前端開發人員需要使用更有效率和靈活的工具來創建響應式和互動式的介面。 PHP和Vue.js作為前端開發領域的兩個重要技術,搭配起來可以稱得上是完美的利器。本文將探討PHP和Vue的結合,以及詳細的程式碼範例,幫助讀者更好地理解和應用這兩

在前端開發面試中,常見問題涵蓋廣泛,包括HTML/CSS基礎、JavaScript基礎、框架和函式庫、專案經驗、演算法和資料結構、效能最佳化、跨域請求、前端工程化、設計模式以及新技術和趨勢。面試官的問題旨在評估候選人的技術技能、專案經驗以及對行業趨勢的理解。因此,應試者應充分準備這些方面,以展現自己的能力和專業知識。

Django是一個由Python編寫的web應用框架,它強調快速開發和乾淨方法。儘管Django是web框架,但要回答Django是前端還是後端這個問題,需要深入理解前後端的概念。前端是指使用者直接和互動的介面,後端是指伺服器端的程序,他們透過HTTP協定進行資料的互動。在前端和後端分離的情況下,前後端程式可以獨立開發,分別實現業務邏輯和互動效果,資料的交

身為C#開發者,我們的開發工作通常包括前端和後端的開發,而隨著技術的發展和專案的複雜性提高,前端與後端協同開發也變得越來越重要和複雜。本文將分享一些前端與後端協同開發的技巧,以幫助C#開發者更有效率地完成開發工作。確定好介面規範前後端的協同開發離不開API介面的交互。要確保前後端協同開發順利進行,最重要的是定義好介面規格。接口規範涉及到接口的命

什麼是JPA?它與JDBC有什麼不同? JPA(JavaPersistenceapi)是一個用於物件關係映射(ORM)的標準接口,它允許Java開發者使用熟悉的Java物件來操作資料庫,而無需編寫直接針對資料庫的sql查詢。而JDBC(JavaDatabaseConnectivity)是Java用來連接資料庫的標準API,它需要開發者使用SQL語句來操作資料庫。 JPA將JDBC封裝起來,為物件-關聯映射提供了更方便、更高層級的API,簡化了資料存取操作。在JPA中,什麼是實體(Entity)?實體

Go語言作為一種快速、高效的程式語言,在後端開發領域廣受歡迎。然而,很少有人將Go語言與前端開發聯繫起來。事實上,使用Go語言進行前端開發不僅可以提高效率,還能為開發者帶來全新的視野。本文將探討使用Go語言進行前端開發的可能性,並提供具體的程式碼範例,幫助讀者更了解這一領域。在傳統的前端開發中,通常會使用JavaScript、HTML和CSS來建立使用者介面

Golang與前端技術結合:探討Golang如何在前端領域發揮作用,需要具體程式碼範例隨著互聯網和行動應用的快速發展,前端技術也愈發重要。而在這個領域中,Golang作為一門強大的後端程式語言,也可以發揮重要作用。本文將探討Golang如何與前端技術結合,以及透過具體的程式碼範例來展示其在前端領域的潛力。 Golang在前端領域的角色作為一門高效、簡潔且易於學習的

Go框架是一組擴充Go內建程式庫的元件,提供預製功能(例如網路開發和資料庫操作)。受歡迎的Go框架包括Gin(Web開發)、GORM(資料庫操作)和RESTful(API管理)。中間件是HTTP請求處理鏈中的攔截器模式,用於在不修改處理程序的情況下新增身份驗證或請求日誌記錄等功能。 Session管理透過儲存使用者資料來保持會話狀態,可以使用gorilla/sessions管理session。
