Docker鏡像優化:從1.16GB到22.4MB

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Docker是一個供軟件開發人員和系統管理員使用容器構建、運行和與分享應用程序的平臺。容器是在獨立環境中運行的進程,它運行在自己的文件系統上,該文件系統是使用docker鏡像構建的。鏡像中包含運行應用程序所需的一切(編譯後的代碼、依賴項、庫等等)。鏡像使用Dockerfile文件定義。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"術語dockerization或containerization通常用於定義創建Docker容器的過程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲容器具備如下優點,所以"},{"type":"text","text":"很受歡迎"},{"type":"text","text":":"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"靈活性:即使是最複雜的應用程序也可以容器化。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"輕量化:容器共享主機內核,使得它們遠比虛擬機高效。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"便攜性:可以做到本地編譯,到處運行。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"松耦合:容器自我封裝,一個容器被替換或升級不會打斷別的容器。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"安全性:容器對進程進行了嚴格的限制和隔離,而無需用戶進行任何配置。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這篇文章中,我將重點討論如何優化Docker鏡像以使其輕量化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"讓我們從一個示例開始,在該示例中,我們構建了一個React應用程序並將其容器化。運行npx命令並創建Dockerfile之後,我們得到了如圖1所示的文件結構。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"npx create-react-app app --template typescript"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5a\/5a814d807e239c52887d1de76629e99b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖1:文件結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果我們構建一個基礎的Dockerfile(如下所示),我們最終會得到一個1.16 GB的鏡像:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10

 

WORKDIR \/app

COPY app \/app

RUN npm install -g webserver.local

RUN npm install && npm run build

 

EXPOSE 3000

CMD webserver.local -d .\/build"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/0b\/0bc747430757de34de72748a511f05b8.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖2:鏡像的初始大小爲1.16GB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第一步優化:使用輕量化基礎鏡像"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/","title":"","type":null},"content":[{"type":"text","text":"Docker Hub"}]},{"type":"text","text":"(公共Docker倉庫)中,有一些鏡像可供下載,每個鏡像都有不同的特徵和大小。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通常,相較於基於其他Linux發行版(例如"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/_\/ubuntu","title":"","type":null},"content":[{"type":"text","text":"Ubuntu"}]},{"type":"text","text":")的鏡像,基於"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/_\/alpine","title":"","type":null},"content":[{"type":"text","text":"Alpine"}]},{"type":"text","text":"或"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/_\/busybox","title":"","type":null},"content":[{"type":"text","text":"BusyBox"}]},{"type":"text","text":"的鏡像非常小。這是因爲Alpine鏡像和類似的其他鏡像都經過了優化,其中僅包含最少的必須的軟件包。在下面的圖片中,你可以看到Ubuntu、Alpine、Node和基於Alpine的Node鏡像之間的大小比較。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/86\/8636fe5ac03b51740ed84bc2d8de4990.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖3:基礎鏡像的不同大小"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過修改Dockerfile並使用Alpine作爲基礎鏡像,我們的鏡像最終大小爲330MB:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10-alpine

 

WORKDIR \/app

COPY app \/app

RUN npm install -g webserver.local

RUN npm install && npm run build

 

EXPOSE 3000

CMD webserver.local -d .\/build"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/b0\/b0c525a22c2b853edc10853e58bc385b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖4:經過第一步優化後鏡像大小爲330MB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第二步優化:多階段構建"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過多階段構建,我們可以在Dockerfile中使用多個基礎鏡像,並將編譯成品、配置文件等從一個階段複製到另一個階段,這樣我們就可以丟棄不需要的東西。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本例中,我們部署React應用程序需要的是編譯後的代碼,我們不需要源文件,也不需要node_modules目錄和package.json文件等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過將Dockerfile修改爲如下內容,我們最終得到的鏡像大小爲91.5MB。請記住,來自第一階段(第1-4行)的鏡像不會被自動刪除,Docker將它保存在cache中,如果我們在另一個構建鏡像過程中執行了相同的階段,就可以使鏡像構建更快。所以你必須手動刪除第一階段鏡像。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10-alpine AS build

WORKDIR \/app

COPY app \/app

RUN npm install && npm run build

 

 

FROM node:10-alpine

WORKDIR \/app

RUN npm install -g webserver.local

COPY --from=build \/app\/build .\/build

EXPOSE 3000

CMD webserver.local -d .\/build"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/de\/defd6ffdfe16ec546d5a5b083c94a322.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖5:第二步優化後的鏡像大小爲91.5MB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在我們有了一個Dockerfile,它有兩個階段:在第一個階段中,我們編譯項目,在第二個階段中,我們在web服務器上部署應用程序。然而,Node容器並不是提供網頁(HTML、CSS和JavaScript文件、圖片等)服務的最佳選擇,最好的選擇是使用像Nginx或Apache這樣的服務。在本例中,我將使用Nginx。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過將Dockerfile修改爲如下內容,我們的鏡像最終大小是22.4MB,如果我們運行這個容器,我們可以看到網頁"},{"type":"text","text":"可以正常工作,沒有任何問題"},{"type":"text","text":"(圖7)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10-alpine AS build

WORKDIR \/app

COPY app \/app

RUN npm install && npm run build

 

 

FROM nginx:stable-alpine

COPY --from=build \/app\/build \/usr\/share\/nginx\/html

EXPOSE 80

CMD [\"nginx\", \"-g\", \"daemon off;\"]"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a5\/a5679d4a483b0592976dff51e625a40b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖6:第三步優化後的鏡像大小爲22.4MB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5a\/5aea754a91e0157bf3503daca2a5337a.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"圖7:最終容器的運行結果"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"參考"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/docs.docker.com\/get-started\/","title":"","type":null},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"https:\/\/docs.docker.com\/get-started\/"}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/","title":"","type":null},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https:\/\/medium.com\/the-agile-crafter\/docker-image-optimization-from-1-16gb-to-22-4mb-53fdb4c53311"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章