Dockerfile優(yōu)化
本文的起因是在做的一個項目打包時間實在太慢了,所謂代碼5分鐘,打包半小時,又正好在看docker的一些東西,所以打算優(yōu)化一下這個dockerfile
文前
- dive工具,可以用來分析鏡像的大小,傳送門:https://github.com/wagoodman/dive
- dockerfile最佳實踐文章,傳送門:https://zhuanlan.zhihu.com/p/26904830
一.首先來看下這個dockerfile

- 首先將一個
image1鏡像(這里隨意寫的,舉例而已)作為compile鏡像 - 指定了
/code目錄 - 拷貝了本地的
package.json,yarn.lock,npmrc文件到/code目錄中,用于安裝NPM模塊 - 運行了
yarn install --production,并且將node_module拷貝到臨時目錄 - 再運行
yarn - 在拷貝所有文件到
/code目錄中 - 運行
npm run build來打包項目 - 到這里先提出兩個問題
- 問題1:為什么要運行了
yarn install --production以后再運行yarn,這不是重復了,多此一舉嗎 - 問題2:為什么要拷貝了
package.json到/code目錄下,然后再拷貝一遍全部文件呢,這不是也重復了嗎
- 問題1:為什么要運行了
- 然后將
image2鏡像作為release鏡像 - 將本地的文件拷貝到當前鏡像中
- 指定
/code目錄 - 從上一層鏡像臨時目錄中中拷貝
node_module - 從上一層鏡像中
client,config文件夾 - 運行
yarn start - 解決問題
- 問題1:當時沒想通,后來突然想通了,運行了
yarn install --production是安裝了生產要用的NPM包,然后拷貝到臨時目錄里,后面從臨時目錄里拷貝,拷貝出來的是生產時要用的包,不是全部的包,減少了包的體積 - 問題2:為什么要先拷貝
package.json,是因為我們應該把變化最少的部分放在Dockerfile的前面,這樣可以充分利用鏡像緩存,詳見https://zhuanlan.zhihu.com/p/26904830中的11.合理調整COPY與RUN的順序
- 問題1:當時沒想通,后來突然想通了,運行了
二.這個dockerfile打包出來的鏡像的大小,可以看到有725M,中間鏡像有2.11G,真的對得起代碼5分鐘,打包半小時

三.dive工具分析這個鏡像,(dive 鏡像id),詳見https://github.com/wagoodman/dive, 可以看到總共725M,可以優(yōu)化的有421M

四.優(yōu)化后的dockerfile

我為什么這么優(yōu)化
我沒有先拷貝
package.json等文件并安裝了NPM包以后再拷貝其他文件,因為本篇文章中的 https://zhuanlan.zhihu.com/p/26904830 的合理調整COPY與RUN的順序中寫到的是首先將package.json拷貝進來,然后安裝包,再將剩余其他文件拷貝進指定的目錄,而我這個項目,package.json以外的文件都要用到,第一次拷貝package.json等文件以后,第二次拷貝最方便的方法是COPY . /code,要拷貝其他文件,而排除package.json文件的做法反而繁瑣-
基于上面那一點的操作的考慮以后,在
compile鏡像中- 指定
/code目錄, - 將本地文件拷貝到
/code目錄下, - 用
yarn build代替npm run build,然后將yarn和yarn build命令合并
- 指定
-
在
release鏡像中- 去掉
code . /code,因為和后面的copy --from=compile那些命令重復了 - 去掉
code . /code以后,鏡像是跑不起來的,因為少了一些文件,package.json和next.config.js,運行yarn start的時候要package.json文件,而yarn start命令是NEXT_ENV=prod PORT=3000 next start client,要next的配置文件
- 去掉
-
我是怎么知道少了這些文件的
-
docker run --name test -p 4040:3000 5be399174a72首先先跑起這個鏡像 -
docker ps -a找出容器 -
docker exec -it c57cb2999203 /bin/sh進入到容器中查看,可以看到/code目錄中有這些文件,對比起先可以跑起來的容器里面的文件和跑不起來的容器的報錯,排查出少了哪些文件,需要哪些文件
-
-
根據問題1的解答,我為什么不用
yarn install --production了,因為只用這些包,yarn start命令是跑不起來的,而且從下面的dive工具顯示,可以優(yōu)化的已經只有358K了,也就沒有必要運行這個命令再拷貝到臨時目錄了,畢竟后面也還要運行yarnexec.png
五.可以看到現在鏡像只有489M的,中間鏡像compile也變少了,只有1.71G

六.再用dive工具查看這個鏡像,發(fā)現總共489M,可以優(yōu)化的只有358K了

七. 優(yōu)化升級.dockerignore
- 因為我們會用yarn重新,所以沒有必要將本地的
node_module包傳到docker服務器上 - 可以看到,設置
.dockerignore以后,傳到docker服務器上的大小從343M減到了29M


八.為什么這個dockerfile跑不起來
- 因為根據dive工具分析出了是
node_module,所以這個dockerfile在最初的dockerfile上加了一句RUN /bin/rm -fr node_modules - 前面說到了,
yarn start的時候要用到node_module,所以在前面刪了node_module會跑不起來

