TurboRepo Docker镜像优化指南:轻松打造轻量级镜像
本篇文章主要讲解在TurboRepo项目中,如何让Docker打包的镜像变得更小,然后分步逐行解释Dockerfile,帮助大家制定自己的Dockerfile。
背景
TurboRepo中打包Docker之所以复杂的原因大致有两点:
1.pnpm-lock.yaml文件只有一个:在根目录下,因为其管理着整个项目的依赖,而不是在每个项目的根目录下。 如果我们直接从根目录打包,或者复制lock文件到项目文件中打包,Docker镜像中就会包含所有的依赖,这样镜像会变得很大。
2.项目之间的依赖:TurboRepo中的项目之间是可以相互依赖的,这样就会导致项目之间的依赖会被打包到镜像中。
比如下面的项目结构:
在这个项目中,main-server依赖了share和pub-auth,但是因为在大仓中,我们直接运行pnpm install
,所有的依赖都会被安装到node_modules中,这样就会导致镜像变得很大。
比如我在我没优化之前,我的项目镜像大概有1.5G(前端的依赖太多了),优化之后,镜像大小只有200M。
解决方案
解决方案大致有三个:
1.使用turbo prune
turbo prune主要解决了项目之间的依赖问题,它会将项目之间的依赖删除,只保留项目自己的依赖。
比如在上面的结构中,我们可以运行turbo prune main-server --docker
,这样就会删除没有用到的依赖,只保留main-server自己的依赖放在out
文件夹中。
在out
目录在,其结构的规则如下:
- 根目录保留了一份pnpm-lock.yaml文件用于安装build时的依赖
- full目录下存放了main-server和其依赖项目的源码
- json目录下存放了main-server和其依赖项目的package.json文件
结构变成这样:
这样我们就可以在Dockerfile中使用这些文件来构建项目。
2.使用pnpm install —prod (pnpm prune)
在上面的动作中,我们已经删除了项目之间的依赖,但是还有一个问题,就是我们的项目中可能会有很多开发依赖,这些依赖在生产环境中是不需要的,所以我们需要删除这些依赖。
在文档中对pnpm prune
的描述如下:
Remove the packages specified in devDependencies.
这个命令会删除devDependencies
中的依赖 ( ⚠️ 注意,不要将运行时依赖放在devDependencies
中,否则会影响项目的运行)。
不过这个命令在TurboRepo中并不适用,因为我们的项目中可能会有很多子项目,这些子项目的依赖可能会被删除,导致项目无法运行。
但是我们可以复制项目中的package.json
到根目录,然后删除node_modules
,然后运行pnpm install --prod
,这样就可以删除开发依赖。
3.使用多阶段构建
多阶段构建是Dockerfile中的一个特性,可以让我们在一个Dockerfile中构建多个镜像,然后将最终的镜像复制到最终的镜像中。
这个Dockerfile主要分为四个阶段:
- 第一个阶段是在alpine镜像中安装pnpm和turbo
- 第二个阶段是在base镜像中,运行
turbo prune
,删除项目之间的依赖 - 第三个阶段是在builder镜像中,运行
pnpm install --prod
,删除开发依赖,然后运行turbo build
,构建项目 - 第四个阶段是在runner镜像中,运行项目
这里就不再赘述了,其目的是为了不将构建环境的依赖放到最终的镜像中,从而减小镜像的大小。 具体可以参考Docker多阶段构建。
最终的Dockerfile
这里的ARG PROJECT=main-server
是为了方便在构建时指定项目,比如docker build --build-arg PROJECT=main-server .
© 2024 ABFree Co. All rights reserved.