Docker鏡像瘦身:從1.43G到22.4MB

python部落 發佈 2021-09-18T14:25:54+00:00

作者:張亞龍譯出處:轉載自公眾號分布式實驗室(ID:dockerone)「Docker 鏡像的大小對於系統的 CI/CD 等都有影響,尤其是雲部署場景。我們在生產實踐中都會做瘦身的操作,盡最大的可能使用 Size 小的鏡像完成功能。

作者:張亞龍譯

出處:轉載自公眾號分布式實驗室(ID:dockerone)

Docker 鏡像的大小對於系統的 CI/CD 等都有影響,尤其是雲部署場景。我們在生產實踐中都會做瘦身的操作,盡最大的可能使用 Size 小的鏡像完成功能。

下文是一個簡單的 ReactJS 程序上線的瘦身體驗,希望可以幫助大家找到鏡像瘦身的方向和靈感。

如果你正在做 Web 開發相關工作,那麼你可能已經知道容器化的概念,以及知道它強大的功能等等。

但在使用 Docker 時,鏡像大小至關重要。我們從 create-react-app (https://reactjs.org/docs/create-a-new-react-app.html)獲得的樣板項目通常都超過 1.43 GB。

今天,我們將容器化一個 ReactJS 應用程式,並學習一些關於如何減少鏡像大小並提高性能的技巧。

我們將以 ReactJS 為例,但它適用於任何類型的 NodeJS 應用程式。

步驟 1:創建項目

藉助腳手架通過命令行模式創建 React 項目:

npx create-react-app docker-image-test

命令執行成功後將生成一個基礎 React 應用程式架構。

我們可以進入項目目錄安裝依賴並運行項目:

cd docker-image-test
yarn install
yarn start

通過訪問 http://localhost:3000 可以訪問已經啟動的應用程式。

步驟 2:構建第一個鏡像

在項目的根目錄中創建一個名為 Dockerfile 的文件,並粘貼以下代碼:

FROM node:12

WORKDIR /app

COPY package.json ./

RUN yarn install

COPY . .

EXPOSE 3000

CMD ["yarn", "start"]

注意,這裡我們從 Docker 倉庫獲得基礎鏡像 Node:12,然後安裝依賴項並運行基本命令。(我們不會在這裡討論 Docker 命令的細節)

現在可以通過終端為容器構建鏡像:

docker build -t docker-image-test .

Docker 構建鏡像完成之後,你可以使用此命令查看已經構建的鏡像:

docker images

在查詢結果列表的頂部,是我們新創建的圖像,在最右邊,我們可以看到圖像的大小。目前是 1.43GB。

我們使用以下命令運行鏡像:

docker run --rm -it -p 3000:3000/tcp docker-image-test:latest

打開瀏覽器並且刷新頁面驗證其可以正常運行。

步驟 3:修改基礎鏡像

先前的配置中我們用 node:12 作為基礎鏡像。但是傳統的 Node 鏡像是基於 Ubuntu 的,對於我們簡單的 React 應用程式來說這大可不必。

從 DockerHub(官方 Docker 鏡像註冊表)中我們可以看到,基於 alpine-based 的 Node 鏡像比基於 Ubuntu 的鏡像小得多,而且它們的依賴程度非常低。

下面顯示了這些基本圖像的大小比較:

現在我們將使用node:12-alpine作為我們的基礎鏡像,看看會發生什麼。

FROM node:12-alpine

WORKDIR /app

COPY package.json ./

RUN yarn install

COPY . .

EXPOSE 3000

CMD ["yarn", "start"]

然後我們以此構建我們的鏡像,並與之前做對比。

哇!我們的鏡像大小減少到只有 580MB,這是一個很大的進步。但還能做得更好嗎?

步驟 4:多級構建

在之前的配置中,我們會將所有原始碼也複製到工作目錄中。

但這大可不必,因為從發布和運行來看我們只需要構建好的運行目錄即可。因此,現在我們將引入多級構建的概念,以減少不必要的代碼和依賴於我們的最終鏡像。

配置是這樣的:

# 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

在第一階段,安裝依賴項並構建我們的項目。

在第二階段,我們複製上一階段構建產物目錄,並使用它來運行應用程式。

這樣我們在最終的鏡像中就不會有不必要的依賴和代碼。

接下來,構建鏡像成功後並從列表中查看鏡像:

現在我們的鏡像大小只有 97.5MB。這簡直太棒了。

步驟 5:使用 Nginx

我們正在使用 Node 伺服器運行 ReactJS 應用程式的靜態資源,但這不是靜態資源運行的最佳選擇。

我們嘗試使用 Nginx 這類更高效、更輕量級的伺服器來運行資源應用程式,也可以儘可能提高其性能,並且減少鏡像的量。

我們最終的 Docker 配置文件看起來像這樣:

# 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 來服務我們的應用程式。

然後使用當前配置構建鏡像。

鏡像大小減少到只有 22.4MB!

同時,我們正在使用一個性能更好的伺服器來服務我們出色的應用程式。

我們可以使用以下命令驗證應用程式是否仍在工作。

docker run --rm -it -p 3000:80/tcp docker-image-test:latest

注意,我們將容器的 80 埠暴露給外部,因為默認情況下,Nginx 將在容器內部的 80 埠上可用。

所以這些是一些簡單的技巧,你可以應用到你的任何 NodeJS 項目,以大幅減少鏡像大小。

現在,您的容器確實更加便攜和高效了。今天就到這裡。編碼快樂!

關鍵字: