Dockerfile優(yōu)化
本文的起因是在做的一個(gè)項(xiàng)目打包時(shí)間實(shí)在太慢了扎拣,所謂代碼5分鐘,打包半小時(shí)瓶盛,又正好在看docker的一些東西惯疙,所以打算優(yōu)化一下這個(gè)dockerfile
文前
- dive工具,可以用來分析鏡像的大小荚斯,傳送門:https://github.com/wagoodman/dive
- dockerfile最佳實(shí)踐文章埠居,傳送門:https://zhuanlan.zhihu.com/p/26904830
一.首先來看下這個(gè)dockerfile
- 首先將一個(gè)
image1
鏡像(這里隨意寫的查牌,舉例而已)作為compile
鏡像 - 指定了
/code
目錄 - 拷貝了本地的
package.json
,yarn.lock
,npmrc
文件到/code
目錄中,用于安裝NPM
模塊 - 運(yùn)行了
yarn install --production
滥壕,并且將node_module
拷貝到臨時(shí)目錄 - 再運(yùn)行
yarn
- 在拷貝所有文件到
/code
目錄中 - 運(yùn)行
npm run build
來打包項(xiàng)目 - 到這里先提出兩個(gè)問題
- 問題1:為什么要運(yùn)行了
yarn install --production
以后再運(yùn)行yarn
僧免,這不是重復(fù)了,多此一舉嗎 - 問題2:為什么要拷貝了
package.json
到/code
目錄下捏浊,然后再拷貝一遍全部文件呢懂衩,這不是也重復(fù)了嗎
- 問題1:為什么要運(yùn)行了
- 然后將
image2
鏡像作為release
鏡像 - 將本地的文件拷貝到當(dāng)前鏡像中
- 指定
/code
目錄 - 從上一層鏡像臨時(shí)目錄中中拷貝
node_module
- 從上一層鏡像中
client
,config
文件夾 - 運(yùn)行
yarn start
- 解決問題
- 問題1:當(dāng)時(shí)沒想通,后來突然想通了金踪,運(yùn)行了
yarn install --production
是安裝了生產(chǎn)要用的NPM
包浊洞,然后拷貝到臨時(shí)目錄里,后面從臨時(shí)目錄里拷貝胡岔,拷貝出來的是生產(chǎn)時(shí)要用的包法希,不是全部的包,減少了包的體積 - 問題2:為什么要先拷貝
package.json
靶瘸,是因?yàn)槲覀儜?yīng)該把變化最少的部分放在Dockerfile的前面苫亦,這樣可以充分利用鏡像緩存,詳見https://zhuanlan.zhihu.com/p/26904830中的11.合理調(diào)整COPY與RUN的順序
- 問題1:當(dāng)時(shí)沒想通,后來突然想通了金踪,運(yùn)行了
二.這個(gè)dockerfile打包出來的鏡像的大小,可以看到有725M怨咪,中間鏡像有2.11G屋剑,真的對得起代碼5分鐘,打包半小時(shí)
三.dive工具分析這個(gè)鏡像诗眨,(dive 鏡像id)唉匾,詳見https://github.com/wagoodman/dive, 可以看到總共725M匠楚,可以優(yōu)化的有421M
四.優(yōu)化后的dockerfile
我為什么這么優(yōu)化
我沒有先拷貝
package.json
等文件并安裝了NPM
包以后再拷貝其他文件巍膘,因?yàn)楸酒恼轮械?https://zhuanlan.zhihu.com/p/26904830 的合理調(diào)整COPY與RUN的順序中寫到的是首先將package.json
拷貝進(jìn)來,然后安裝包芋簿,再將剩余其他文件拷貝進(jìn)指定的目錄峡懈,而我這個(gè)項(xiàng)目,package.json
以外的文件都要用到与斤,第一次拷貝package.json
等文件以后肪康,第二次拷貝最方便的方法是COPY . /code
,要拷貝其他文件幽告,而排除package.json
文件的做法反而繁瑣-
基于上面那一點(diǎn)的操作的考慮以后梅鹦,在
compile
鏡像中- 指定
/code
目錄, - 將本地文件拷貝到
/code
目錄下冗锁, - 用
yarn build
代替npm run build
齐唆,然后將yarn
和yarn build
命令合并
- 指定
-
在
release
鏡像中- 去掉
code . /code
,因?yàn)楹秃竺娴?code>copy --from=compile那些命令重復(fù)了 - 去掉
code . /code
以后冻河,鏡像是跑不起來的箍邮,因?yàn)樯倭艘恍┪募?code>package.json和next.config.js
茉帅,運(yùn)行yarn start
的時(shí)候要package.json
文件,而yarn start
命令是NEXT_ENV=prod PORT=3000 next start client
锭弊,要next的配置文件
- 去掉
-
我是怎么知道少了這些文件的
-
docker run --name test -p 4040:3000 5be399174a72
首先先跑起這個(gè)鏡像 -
docker ps -a
找出容器 -
docker exec -it c57cb2999203 /bin/sh
進(jìn)入到容器中查看堪澎,可以看到/code
目錄中有這些文件,對比起先可以跑起來的容器里面的文件和跑不起來的容器的報(bào)錯(cuò)味滞,排查出少了哪些文件樱蛤,需要哪些文件
-
-
根據(jù)問題1的解答,我為什么不用
yarn install --production
了剑鞍,因?yàn)橹挥眠@些包昨凡,yarn start
命令是跑不起來的,而且從下面的dive工具顯示蚁署,可以優(yōu)化的已經(jīng)只有358K了便脊,也就沒有必要運(yùn)行這個(gè)命令再拷貝到臨時(shí)目錄了,畢竟后面也還要運(yùn)行yarn
五.可以看到現(xiàn)在鏡像只有489M的光戈,中間鏡像compile
也變少了哪痰,只有1.71G
六.再用dive工具查看這個(gè)鏡像,發(fā)現(xiàn)總共489M久妆,可以優(yōu)化的只有358K了
七. 優(yōu)化升級.dockerignore
- 因?yàn)槲覀儠脃arn重新晌杰,所以沒有必要將本地的
node_module
包傳到docker服務(wù)器上 - 可以看到,設(shè)置
.dockerignore
以后镇饺,傳到docker服務(wù)器上的大小從343M減到了29M
八.為什么這個(gè)dockerfile跑不起來
- 因?yàn)楦鶕?jù)dive工具分析出了是
node_module
乎莉,所以這個(gè)dockerfile在最初的dockerfile上加了一句RUN /bin/rm -fr node_modules
- 前面說到了,
yarn start
的時(shí)候要用到node_module
奸笤,所以在前面刪了node_module
會跑不起來