Dockerfile优化
本文的起因是在做的一个项目打包时间实在太慢了,所谓代码5分钟,打包半小时,又正好在看docker的一些东西,所以打算优化一下这个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,可以优化的有421M
四.优化后的dockerfile
我为什么这么优化
我没有先拷贝
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工具显示,可以优化的已经只有358K了,也就没有必要运行这个命令再拷贝到临时目录了,毕竟后面也还要运行yarn
五.可以看到现在镜像只有489M的,中间镜像compile
也变少了,只有1.71G
六.再用dive工具查看这个镜像,发现总共489M,可以优化的只有358K了
七. 优化升级.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
会跑不起来