国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - 編程技術 - 如何優化 Node 項目的 Docker 鏡像

如何優化 Node 項目的 Docker 鏡像

2021-08-09 00:03掘金imac 編程技術

本文將以 Node 程序展示如何優化 Docker 鏡像(優化思想是通用的,不分程序),主要解決鏡像大小過大、CI/CD 構建鏡像速度,本文演示如何一步步優化 Dockerfile 文件。

如何優化 Node 項目的 Docker 鏡像

本文將以 Node 程序展示如何優化 Docker 鏡像(優化思想是通用的,不分程序),主要解決鏡像大小過大、CI/CD 構建鏡像速度,本文演示如何一步步優化 Dockerfile 文件,優化的結果如下:

  • 大小從 1.06G 到 73.4M
  • 構建速度從 29.6 秒到 1.3 秒(對比的是第二次構建的速度)

Node 項目

簡單寫了一個自己用的 wechat-bot,接下來就以這個項目演示怎么去優化 Docker 鏡像。

以下是我沒有仔細研究 Docker 剛開始寫的 Dockerfile 文件。

  1. FROM node:14.17.3 
  2.  
  3. # 設置環境變量 
  4. ENV NODE_ENV=production 
  5. ENV APP_PATH=/node/app 
  6.  
  7. # 設置工作目錄 
  8. WORKDIR $APP_PATH 
  9.  
  10. # 把當前目錄下的所有文件拷貝到鏡像的工作目錄下 .dockerignore 指定的文件不會拷貝 
  11. COPY . $APP_PATH 
  12.  
  13. # 安裝依賴 
  14. RUN yarn 
  15.  
  16. # 暴露端口 
  17. EXPOSE 4300 
  18.  
  19. CMD yarn start 

build 之后,如下圖,我這個簡單的 Node 程序鏡像竟然有 1G 多,接下來我們將逐步去優化減少這個大小。

如何優化 Node 項目的 Docker 鏡像

優化前言

在優化之前,有些東西我們必須了解,解決問題的第一步就是先找出導致問題的原因。

Dockerfile 文件,其內包含了一條條的指令,每一條指令構建一層,因此每一條指令的內容,就是描述該層如何構建。

Docker 鏡像并非只是一個文件,而是由一堆文件組成,最主要的文件是層(Layers)

  • 鏡像構建時,會一層層構建,前一層是后一層的基礎每一層構建完就不會再發生改變,后一層上的任何改變只發生在自己這一層。比如,刪除前一層文件的操作,實際不是真的刪除前一層的文件,而是僅在當前層標記為該文件已刪除。在最終容器運行的時候,雖然不會看到這個文件,但是實際上該文件會一直跟隨鏡像。
  • 鏡像層將會被緩存和復用(這也是從第二次開始構建鏡像時,速度會快的原因,優化鏡像構建速度的原理也是利用緩存原理來做)
  • 當 Dockerfile 的指令修改了,操作的文件變化了,或者構建鏡像時指定的變量不同了,對應的鏡像層緩存就會失效
  • docker build 的緩存機制,Docker 是怎么知道文件變化的呢?
  • Docker 采取的策略是:獲取 Dockerfile 下內容(包括文件的部分 inode 信息),計算出一個唯一的 hash 值,若 hash 值未發生變化,則可以認為文件內容沒有發生變化,可以使用緩存機制,反之亦然。
  • 某一層的鏡像緩存失效之后,它之后的鏡像層緩存都會失效
  • 鏡像的每一層只記錄文件變更,在容器啟動時,Docker 會將鏡像的各個層進行計算,最后生成一個文件系統當我知道這點時,我恍然大悟,我們使用的操作系統,比如安卓、iOS、Windows、macOS 等,其實就是一個文件系統,我們的軟件界面交互等,其實就是在讀寫文件,我們網頁寫個彈框,操作 dom,就是在讀寫本地文件或者是讀寫內存里的數據,個人的一些見解不知道對不對,本人非科班出身的前端 coder。

參考資料:https://www.cnblogs.com/handwr ... .html

ok,我們已經知道鏡像是由多層文件系統組成,想要優化它的大小,就需要去減少層數、每一層盡量只包含該層需要的東西,任何額外的東西應該在該層構建結束前清理掉,下面開始正文。

優化 Dockerfile

優化第一層 FROM node:14.17.3

方案一:使用 Node 的 Alpine 版本

這也是絕多數人知道的優化鏡像手段,Alpine 是一個很小的 Linux 發行版,只要選擇 Node 的 Alpine 版本,就會有很大改進,我們把這一句改成指令改成 FROM node:14.17.4-alpine(可以去 Dockerhub 查看 Node 有哪些版本標簽),build 后鏡像大小如下圖,瞬間從 1.06G 降到 238M,可以說是效果顯著。

如何優化 Node 項目的 Docker 鏡像

還可以使用其它的基礎小鏡像,比如 mhart/alpine-node,這個還能再小,改成 FROM mhart/alpine-node:14.17.3 再試試,可以看到又小了 5M?,雖然不多,但是秉著能壓榨一點是一點的“老板原則”,積少成多,極致壓榨。

如何優化 Node 項目的 Docker 鏡像

方案二:使用純凈 Alpine 鏡像手動裝 Node

既然 Alpine 是最小的 Linux,那我們試下用純凈的 Alpine 鏡像,自己再裝 Node 試試。

  1. FROM alpine:latest 
  2.  
  3. # 使用 apk 命令安裝 nodejs 和 yarn,如果使用 npm 啟動,就不需要裝 yarn 
  4. RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0 
  5.  
  6. # ... 后面的步驟不變 

build 后看下圖,只有 174M 了,又小了不少。

如何優化 Node 項目的 Docker 鏡像

結論就是不嫌麻煩追求極致就用方案二,從 1.06G 減少到 174M。

減少層數、不經常變動的層提到前面去

ENV 指令是可以一次性設置多個環境變量,能一次指令執行完,就不用兩次,多一個指令就多一層

EXPOSE 指令是暴露端口,其實也可以不用寫這個指令,在啟動容器的時候自己映射端口,如果寫了這個指令的話,因為端口不經常變,所以把這個指令提前,寫上這個指令有兩個好處:

  • 幫助鏡像使用者理解這個鏡像服務的守護端口,以方便配置映射
  • 在運行時使用隨機端口映射時,也就是 docker run -P 時,會自動隨機映射 EXPOSE 的端口

至于寫還是不寫,看個人吧,我個人一般不寫,因為我在項目啟動命令會指定項目端口,啟動容器的時候映射出來就好,這樣我就要維護一個地方,Dockerfile 也寫了的話,項目端口變了,這里也要修改,多了點維護成本,當然也有辦法讓兩邊端口變量取自配置文件,只要改配置文件即可。

下面是改寫后的 Dockerfile。

  1. FROM alpine:latest 
  2.  
  3. # 使用 apk 命令安裝 nodejs 和 yarn,如果使用 npm 啟動,就不需要裝 yarn 
  4. RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0 
  5.  
  6. # 暴露端口 
  7. EXPOSE 4300 
  8.  
  9. # 設置環境變量 
  10. ENV NODE_ENV=production \ 
  11. APP_PATH=/node/app 
  12.  
  13. # 設置工作目錄 
  14. WORKDIR $APP_PATH 
  15.  
  16. # 把當前目錄下的所有文件拷貝到鏡像的工作目錄下 .dockerignore 指定的文件不會拷貝 
  17. COPY . $APP_PATH 
  18.  
  19. # 安裝依賴 
  20. RUN yarn 
  21.  
  22. # 啟動命令 
  23. CMD yarn start 

這一步的優化,無論從鏡像大小還是構建鏡像速度都看不到明顯的差別,因為改動的層內容少(體現不出來),但是可以查看到鏡像的層是變少了的,可以自行試試查看鏡像的層試試。

減少鏡像層數是“好老板”的傳統優良習慣,不讓“員工”浪費資源。

package.json 提前提高編譯速度

從下圖可以看到每次我們 build 的時候最耗時的就是在執行 yarn 命令裝依賴的時候,大部分時候我們只是改代碼,依賴不變,這時候如果可以讓這一步緩存起來,依賴沒有變化的時候,就不需要重新裝依賴,就可以大大改進編譯速度。

如何優化 Node 項目的 Docker 鏡像

前面我們說了鏡像構建時,是一層層構建,前一層是后一層的基礎,既然是這樣的話,我們就把 package.json 文件單獨提前拷貝到鏡像,然后下一步裝依賴,執行命令裝依賴這層的前一層是拷貝 package.json 文件,因為安裝依賴命令不會變化,所以只要 package.json 文件沒變化,就不會重新執行 yarn 安裝依賴,它會復用之前安裝好的依賴,原理講清楚了,下面我們看效果。

改變后的 Dockerfile 文件:

  1. FROM alpine:latest 
  2.  
  3. # 使用 apk 命令安裝 nodejs 和 yarn,如果使用 npm 啟動,就不需要裝 yarn 
  4. RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0 
  5.  
  6. # 暴露端口 
  7. EXPOSE 4300 
  8.  
  9. # 設置環境變量 
  10. ENV NODE_ENV=production \ 
  11. APP_PATH=/node/app 
  12.  
  13. # 設置工作目錄 
  14. WORKDIR $APP_PATH 
  15.  
  16. # 拷貝 package.json 到工作跟目錄下 
  17. COPY package.json . 
  18.  
  19. # 安裝依賴 
  20. RUN yarn 
  21.  
  22. # 把當前目錄下的所有文件拷貝到鏡像的工作目錄下 .dockerignore 指定的文件不會拷貝 
  23. COPY . . 
  24.  
  25. # 啟動命令 
  26. CMD yarn start 

build 看下圖,編譯時間從 29.6s 到 1.3s,使用了緩存的層前面會有個 CACHED 字眼,仔細看下圖可以看到。

如何優化 Node 項目的 Docker 鏡像

充分利用 Docker 緩存特性是優化構建速度的利器。

使用多階段構建再次壓榨鏡像大小

多階段構建這里不多說了,不了解的可以先搜相關資料了解。

因為我們運行 Node 程序時只需要生產的依賴和最終 Node 可以運行的文件,就是說我們運行項目只需要 package.js 文件里 dependencies 里的依賴,devDependencies 依賴只是編譯階段用的,比如 eslint 等這些工具在項目運行時是用不到的,再比如我們項目是用 typescript 寫的,Node 是不能直接運行 ts 文件,ts 文件需要編譯成 js 文件,運行項目我們只需要編譯后的文件和 dependencies 里的依賴就可以運行,也就是說最終鏡像只需要我們需要的東西,任何其他東西都可以刪掉,下面我們使用多階段改寫 Dockerfile。

  1. # 構建基礎鏡像 
  2. FROM alpine:3.14 AS base 
  3.  
  4. # 設置環境變量 
  5. ENV NODE_ENV=production \ 
  6.     APP_PATH=/node/app 
  7.  
  8. # 設置工作目錄 
  9. WORKDIR $APP_PATH 
  10.  
  11. # 安裝 nodejs 和 yarn 
  12. RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0 
  13.  
  14. # 使用基礎鏡像裝依賴階段 
  15. FROM base AS install 
  16.  
  17. # 拷貝 package.json 到工作跟目錄下 
  18. COPY package.json ./ 
  19.  
  20. # 安裝依賴 
  21. RUN yarn 
  22.  
  23. # 最終階段,也就是輸出的鏡像是這個階段構建的,前面的階段都是為這個階段做鋪墊 
  24. FROM base 
  25.  
  26. # 拷貝 裝依賴階段 生成的 node_modules 文件夾到工作目錄下 
  27. COPY --from=install $APP_PATH/node_modules ./node_modules 
  28.  
  29. # 將當前目錄下的所有文件(除了.dockerignore排除的路徑),都拷貝進入鏡像的工作目錄下 
  30. COPY . . 
  31.  
  32. # 啟動 
  33. CMD yarn start 

細心的朋友會發現我這里有指定 Alpine 版本,而上面都是用的 latest 版本,因為就在剛剛發現有個坑需要注意下,就是我們選擇 Alpine 版本的時候,最好不要選擇 latest 版本,因為后面要裝的軟件版本可能會在 Alpine 的 latest 版本沒有對應軟件的版本號,就會安裝錯誤,我剛剛就翻車了,點擊查看 Alpine 版本下的包信息。

如何優化 Node 項目的 Docker 鏡像

build 后,我們看看鏡像大小,上次的是 174M 再次降到 73.4M,極致壓榨。鏡像:“放過我把,我真的沒有了”。

如何優化 Node 項目的 Docker 鏡像

講解:

我把這個構建分成了三個階段:

第一階段:構建基礎鏡像

安裝依賴、編譯、運行等等階段,就是所有階段共用的東西都在第一階段封到一個基礎鏡像里供其它階段使用,比如設置環境變量、設置工作目錄、安裝 nodejs、yarn 等等。

第二階段:裝依賴階段

在這個階段,裝依賴,如果項目需要編譯,可以在這個階段裝依賴編譯好。

這里在說下裝依賴的小細節,就是執行 yarn --production 加個 production 參數或者環境變量 NODE_ENV 為 production,yarn 將不會安裝 devDependencies 中列出的任何軟件包,點我查看官方文檔說明,因為我設置了環境變量所以就沒加這個參數

第三階段:最終使用鏡像

拷貝第二階段安裝的好的依賴文件夾,然后在拷貝代碼文件到工作目錄,執行啟動命令,第二階段裝依賴多出的一些垃圾我們不需要,我們就只拷貝我們要用的東西,大大減少鏡像的大小。

如果項目需要編譯,在拷貝編譯后的文件夾,不需要拷貝編譯前的代碼,有編譯后的代碼和依賴就可以跑起項目。

多階段構建,最后生成的鏡像只能是最后一個階段的結果,但是,能夠將前置階段中的文件拷貝到后邊的階段中,這就是多階段構建的最大意義。

最終優化成果:

  • 大小從 1.06G 到 73.4M
  • 構建速度從 29.6 秒到 1.3 秒(對比的是第二次構建的速度)

至此,壓榨鏡像手段就完了,如果各位老板還有壓榨手段可以分享分享。

鏡像內心獨白:“你禮貌嗎?還來”

GitHub 的 actions 構建鏡像問題

GitHub 提供的 actions,每次都是一個干凈的實例,什么意思,就是每次執行,都是干凈的機器,這會導致一個問題,會導致 Docker 沒法使用緩存,那有沒有解決辦法呢,我想到了三種解決辦法:

1、 Docker 官方提供的 action 緩存方案

我用的是 Github cache 方案。

2、自托管 actions 運行機器

相當于 GitLab 的 runner 一樣,自己提供運行器,自己提供的就不會每次都是干凈的機器,詳情看 actions 官方文檔。

3、先構建一個已經安裝好依賴包的鏡像,然后基于此鏡像再次構建,相當于多階段構建,把前兩個階段構建的鏡像產物推送到鏡像倉庫,再以這個鏡像為基礎去構建后續部分。借助鏡像倉庫存儲基礎鏡像從而達到緩存的效果。

  1. # 以這個鏡像為基礎去構建,這個鏡像是已經裝好項目依賴的鏡像并推送到鏡像倉庫里,這里從鏡像倉庫拉下來  
  2. FROM project-base-image:latest  
  3. COPY . .  
  4. CMD yarn start 

參考資料:https://evilmartians.com/chron ... ching

最后

項目倉庫地址:https://github.com/iamobj/wechat-bot

文章有錯誤的地方歡迎指正,避免誤人子弟。

原文地址:https://juejin.cn/post/6991689670027542564

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久伊人色| 91精品一区二区三区久久久久久 | 午夜成人在线视频 | 久久视频免费 | 久久精品1区 | 最近韩国日本免费观看mv免费版 | 九九99九九 | 在线a视频| 国产免费激情视频 | 国产精品成人一区二区三区夜夜夜 | 阿v视频在线观看 | 狠狠天天 | 污片网站| 午夜剧场在线免费观看 | 久草.com| 一级毛片免费视频 | 91av原创| 亚洲福利在线观看 | 日韩免费在线 | 一级片网 | 免看一级一片 | 九九九久久国产免费 | 成年免费视频黄网站在线观看 | 在线观看特色大片免费网站 | 超碰毛片 | 先锋影音av资源站 | 国产中文字幕在线观看 | 国产欧美日韩一区二区三区四区 | 国产一区二区视频在线观看 | av网站在线看 | 91av在 | 日夜夜精品视频 | 综合久久网 | 操久久| 日韩欧美国产精品 | 精品亚洲国产成av人片传媒 | 日韩成人精品 | 国产精品久久久久久久免费大片 | 狠狠操电影 | 亚洲视频 欧美视频 | 欧美精品成人一区二区三区四区 |