如何優雅地將Docker鏡像從1.43G瘦身到22.4MB?
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:創建項目
1)借助腳手架通過命令行模式創建React項目:
npx create-react-app docker-image-test
2)命令執行成功后將生成一個基礎React應用程序架構。
3)我們可以進入項目目錄安裝依賴并運行項目:
cd docker-image-test
yarn install
yarn start
4)通過訪問http://localhost:3000可以訪問已經啟動的應用程序:
步驟2:構建第一個鏡像
1)在項目的根目錄中創建一個名為Dockerfile的文件,并粘貼以下代碼:
FROM node:12
WORKDIR /app
COPY package.json ./
RUN yarn install
COPY . .
EXPOSE 3000
CMD ["yarn", "start"]
2)注意,這里我們從Docker倉庫獲得基礎鏡像Node:12,然后安裝依賴項并運行基本命令。(我們不會在這里討論Docker命令的細節)
3)現在可以通過終端為容器構建鏡像:
docker build -t docker-image-test .
4)Docker構建鏡像完成之后,你可以使用此命令查看已經構建的鏡像:
docker images
在查詢結果列表的頂部,是我們新創建的圖像,在最右邊,我們可以看到圖像的大小。目前是1.43GB。
5)我們使用以下命令運行鏡像:
docker run --rm -it -p 3000:3000/tcp docker-image-test:latest
打開瀏覽器并且刷新頁面驗證其可以正常運行。
步驟3:修改基礎鏡像
1)先前的配置中我們用node:12作為基礎鏡像。但是傳統的Node鏡像是基于Ubuntu的,對于我們簡單的React應用程序來說這大可不必。
2)從DockerHub(官方Docker鏡像注冊表)中我們可以看到,基于alpine-based的Node鏡像比基于Ubuntu的鏡像小得多,而且它們的依賴程度非常低。
3)下面顯示了這些基本圖像的大小比較:
現在我們將使用node:12-alpine作為我們的基礎鏡像,看看會發生什么。
FROM node:12-alpine
WORKDIR /app
COPY package.json ./
RUN yarn install
COPY . .
EXPOSE 3000
CMD ["yarn", "start"]
然后我們以此構建我們的鏡像,并與之前做對比。
哇!我們的鏡像大小減少到只有580MB,這是一個很大的進步。但還能做得更好嗎?
步驟4:多級構建
1)在之前的配置中,我們會將所有源代碼也復制到工作目錄中。
2)但這大可不必,因為從發布和運行來看我們只需要構建好的運行目錄即可。因此,現在我們將引入多級構建的概念,以減少不必要的代碼和依賴于我們的最終鏡像。
3)配置是這樣的:
# 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
4)在第一階段,安裝依賴項并構建我們的項目。
5)在第二階段,我們復制上一階段構建產物目錄,并使用它來運行應用程序。
6)這樣我們在最終的鏡像中就不會有不必要的依賴和代碼。
接下來,構建鏡像成功后并從列表中查看鏡像:
現在我們的鏡像大小只有97.5MB。這簡直太棒了。
步驟5:使用Nginx
1)我們正在使用Node服務器運行ReactJS應用程序的靜態資源,但這不是靜態資源運行的最佳選擇。
2)我們嘗試使用Nginx這類更高效、更輕量級的服務器來運行資源應用程序,也可以盡可能提高其性能,并且減少鏡像的量。
3)我們最終的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;"]
4)我們正在改變Docker配置的第二階段,以使用Nginx來服務我們的應用程序。
5)然后使用當前配置構建鏡像。
6)鏡像大小減少到只有22.4MB!
7)同時,我們正在使用一個性能更好的服務器來服務我們出色的應用程序。
8)我們可以使用以下命令驗證應用程序是否仍在工作。
docker run --rm -it -p 3000:80/tcp docker-image-test:latest
9)注意,我們將容器的80端口暴露給外部,因為默認情況下,Nginx將在容器內部的80端口上可用。
所以這些是一些簡單的技巧,你可以應用到你的任何NodeJS項目,以大幅減少鏡像大小。
現在,您的容器確實更加便攜和高效了。