Docker鏡像瘦身:從1.43G到22.4MB
在下方公眾號(hào)后臺(tái)回復(fù):面試手冊(cè),可獲取杰哥匯總的 3 份面試 PDF 手冊(cè)。
Docker 鏡像的大小對(duì)于系統(tǒng)的 CI/CD 等都有影響,尤其是云部署場(chǎng)景。我們?cè)谏a(chǎn)實(shí)踐中都會(huì)做瘦身的操作,盡最大的可能使用 Size 小的鏡像完成功能。
下文是一個(gè)簡(jiǎn)單的 ReactJS 程序上線的瘦身體驗(yàn),希望可以幫助大家找到鏡像瘦身的方向和靈感。
如果你正在做 Web 開(kāi)發(fā)相關(guān)工作,那么你可能已經(jīng)知道容器化的概念,以及知道它強(qiáng)大的功能等等。
但在使用 Docker 時(shí),鏡像大小至關(guān)重要。我們從 create-react-app (https://reactjs.org/docs/create-a-new-react-app.html)獲得的樣板項(xiàng)目通常都超過(guò) 1.43 GB。
今天,我們將容器化一個(gè) ReactJS 應(yīng)用程序,并學(xué)習(xí)一些關(guān)于如何減少鏡像大小并提高性能的技巧。
我們將以 ReactJS 為例,但它適用于任何類(lèi)型的 NodeJS 應(yīng)用程序。
步驟 1:創(chuàng)建項(xiàng)目
①借助腳手架通過(guò)命令行模式創(chuàng)建 React 項(xiàng)目:
npx?create-react-app?docker-image-test
②命令執(zhí)行成功后將生成一個(gè)基礎(chǔ) React 應(yīng)用程序架構(gòu)。
③我們可以進(jìn)入項(xiàng)目目錄安裝依賴(lài)并運(yùn)行項(xiàng)目:
cd?docker-image-test
yarn?install
yarn?start
④通過(guò)訪問(wèn) http://localhost:3000 可以訪問(wèn)已經(jīng)啟動(dòng)的應(yīng)用程序。

步驟 2:構(gòu)建第一個(gè)鏡像
①在項(xiàng)目的根目錄中創(chuàng)建一個(gè)名為 Dockerfile 的文件,并粘貼以下代碼:
FROM?node:12
WORKDIR?/app
COPY?package.json?./
RUN?yarn?install
COPY?.?.
EXPOSE?3000
CMD?["yarn",?"start"]
②注意,這里我們從 Docker 倉(cāng)庫(kù)獲得基礎(chǔ)鏡像 Node:12,然后安裝依賴(lài)項(xiàng)并運(yùn)行基本命令。
③現(xiàn)在可以通過(guò)終端為容器構(gòu)建鏡像:
docker?build?-t?docker-image-test?.
④Docker 構(gòu)建鏡像完成之后,你可以使用此命令查看已經(jīng)構(gòu)建的鏡像:
docker?images
在查詢(xún)結(jié)果列表的頂部,是我們新創(chuàng)建的圖像,在最右邊,我們可以看到圖像的大小。目前是 1.43GB。

⑤我們使用以下命令運(yùn)行鏡像:
docker?run?--rm?-it?-p?3000:3000/tcp?docker-image-test:latest
打開(kāi)瀏覽器并且刷新頁(yè)面驗(yàn)證其可以正常運(yùn)行。
步驟 3:修改基礎(chǔ)鏡像
①先前的配置中我們用 node:12 作為基礎(chǔ)鏡像。但是傳統(tǒng)的 Node 鏡像是基于 Ubuntu 的,對(duì)于我們簡(jiǎn)單的 React 應(yīng)用程序來(lái)說(shuō)這大可不必。
②從 DockerHub(官方 Docker 鏡像注冊(cè)表)中我們可以看到,基于 alpine-based 的 Node 鏡像比基于 Ubuntu 的鏡像小得多,而且它們的依賴(lài)程度非常低。
③下面顯示了這些基本圖像的大小比較:

現(xiàn)在我們將使用node:12-alpine作為我們的基礎(chǔ)鏡像,看看會(huì)發(fā)生什么。
FROM?node:12-alpine
WORKDIR?/app
COPY?package.json?./
RUN?yarn?install
COPY?.?.
EXPOSE?3000
CMD?["yarn",?"start"]
然后我們以此構(gòu)建我們的鏡像,并與之前做對(duì)比。

哇!我們的鏡像大小減少到只有 580MB,這是一個(gè)很大的進(jìn)步。但還能做得更好嗎?
步驟 4:多級(jí)構(gòu)建
①在之前的配置中,我們會(huì)將所有源代碼也復(fù)制到工作目錄中。
②但這大可不必,因?yàn)閺陌l(fā)布和運(yùn)行來(lái)看我們只需要構(gòu)建好的運(yùn)行目錄即可。因此,現(xiàn)在我們將引入多級(jí)構(gòu)建的概念,以減少不必要的代碼和依賴(lài)于我們的最終鏡像。
③配置是這樣的:
#?STAGE?1
FROM?node:12-alpine?AS?build
WORKDIR?/app
COPY?package.json?./
RUN?yarn??install
COPY?.?/app
RUN?yarn?build
#?STAGE?2
FROM?node:12-alpine
WORKDIR?/app
RUN?npm?install?-g?webserver.local
COPY?--from=build?/app/build?./build
EXPOSE?3000
CMD?webserver.local?-d?./build
④在第一階段,安裝依賴(lài)項(xiàng)并構(gòu)建我們的項(xiàng)目。
⑤在第二階段,我們復(fù)制上一階段構(gòu)建產(chǎn)物目錄,并使用它來(lái)運(yùn)行應(yīng)用程序。
⑥這樣我們?cè)谧罱K的鏡像中就不會(huì)有不必要的依賴(lài)和代碼。
接下來(lái),構(gòu)建鏡像成功后并從列表中查看鏡像:

現(xiàn)在我們的鏡像大小只有 97.5MB。這簡(jiǎn)直太棒了。
步驟 5:使用 Nginx
①我們正在使用 Node 服務(wù)器運(yùn)行 ReactJS 應(yīng)用程序的靜態(tài)資源,但這不是靜態(tài)資源運(yùn)行的最佳選擇。
②我們嘗試使用 Nginx 這類(lèi)更高效、更輕量級(jí)的服務(wù)器來(lái)運(yùn)行資源應(yīng)用程序,也可以盡可能提高其性能,并且減少鏡像的量。
③我們最終的 Docker 配置文件看起來(lái)像這樣:
#?STAGE?1
FROM?node:12-alpine?AS?build
WORKDIR?/app
COPY?package.json?./
RUN?yarn??install
COPY?.?/app
RUN?yarn?build
#?STAGE?2
FROM?nginx:stable-alpine
COPY?--from=build?/app/build?/usr/share/nginx/html
EXPOSE?80
CMD?["nginx",?"-g",?"daemon?off;"]
④我們正在改變 Docker 配置的第二階段,以使用 Nginx 來(lái)服務(wù)我們的應(yīng)用程序。
⑤然后使用當(dāng)前配置構(gòu)建鏡像。

⑥鏡像大小減少到只有 22.4MB!
⑦同時(shí),我們正在使用一個(gè)性能更好的服務(wù)器來(lái)服務(wù)我們出色的應(yīng)用程序。
⑧我們可以使用以下命令驗(yàn)證應(yīng)用程序是否仍在工作。
docker?run?--rm??-it?-p?3000:80/tcp?docker-image-test:latest
⑨注意,我們將容器的 80 端口暴露給外部,因?yàn)槟J(rèn)情況下,Nginx 將在容器內(nèi)部的 80 端口上可用。
所以這些是一些簡(jiǎn)單的技巧,你可以應(yīng)用到你的任何 NodeJS 項(xiàng)目,以大幅減少鏡像大小。
現(xiàn)在,您的容器確實(shí)更加便攜和高效了。今天就到這里。編碼快樂(lè)!
作者:張亞龍譯?
出處:轉(zhuǎn)載自公眾號(hào)分布式實(shí)驗(yàn)室(ID:dockerone)
推薦閱讀
史上講解最好的 Docker 教程,從入門(mén)到精通(建議收藏的教程)
Docker 極簡(jiǎn)入門(mén)指南,10 分鐘就能看懂~

