dockerfile多阶段构建的优缺点


一直以来,公司的CI/CD环境都是在Jenkins的工作节点中编译,再将编译打包好的目标程序直接使用dockerfile构建镜像。

以.NET程序来做例子,其dockerfile是这样的

FROM mcr.microsoft.com/dotnet/aspnet:3.1-focal
WORKDIR /app
COPY ./publish /app
CMD ["dotnet", "testapi.dll"]

Jenkins的shell脚本则直接执行

dotnet dotnet publish -o ./publish
docker build -t testapi .

 

以上做法是不符合docker的理念的,因为工作节点(docker的宿主机)还需要安装对应程序的sdk才可以进行程序的编译打包。

所以我决定对其进行一点改造,通过Dockerfile的多阶段构建,使程序的编译也依赖于docker镜像,这样工作节点就无需自己去安装SDK了,以后扩展多个工作节点也方便很多。

还是以.NET程序为例,改造后的dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:3.1-focal AS base

FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
WORKDIR /src
COPY ["testapi/testapi.csproj", "testapi/"]
COPY ["testapi.Infrastructure/testapi.Infrastructure.csproj", "testapi.Infrastructure/"]
COPY ["testapi.Core/testapi.Core.csproj", "testapi.Core/"]
COPY ["testapi.Model/testapi.Model.csproj", "testapi.Model/"]
COPY ["testapi.SocketServer/testapi.SocketServer.csproj", "testapi.SocketServer/"]
RUN dotnet restore "testapi/testapi.csproj"
COPY . .
WORKDIR "/src/testapi"

FROM build AS publish
RUN dotnet publish -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "testapi.dll"]

 

OK,简单的改造完成了,Jenkins执行脚本中省去pubilsh的步骤,直接

docker build -t testapi .

但是!但是!但是!但是!

执行下来结构却并不如意,因为这执行一趟下来,耗时4分30秒,而之前只需10多秒整个流程完成了。

查看日志发现,主要耗时在dotnet restore这一步中,总耗时3分多。而直接在工作节点宿主机中进行编译的话,因为之前还原的nuget包保存在硬盘中,所以不需要再次下载,所以我这次把宿主机中项目的文件全部删除,再次使用在没改造前的方式(在宿主机中编译)构建一次,这次耗时1分30秒多,可以发现,同样是执行dotnet restore,在dockerfile中执行会比宿主机中执行慢很多,要还原的nuget包越多就越慢。

当然,耗时这么多的执行过程,只限于第一次构建或者程序的.csproj有改动的情况,因为dockerfile分阶段构建,会留下缓存,体现在docker images会出现一个名称和tag皆为<none>的镜像,这个镜像就是dotnet编译过程中下产生的依赖包缓存了,所以这就出现第二个问题了,随着程序的改动,其他程序的编译,执行次数的增多,会有越来越多的<none>镜像出现(没错,每一次nuget包的变动都会有一个新的none镜像),虽然有命令可以批量删除,但是删除之后再次构建dockerfile就又会很慢,而且这些<none>镜像不好管理,size又普遍很大,占用磁盘空间。dotnet程序还好说,前端程序的module包都是1G2G的。。。

另外,在本地环境中,构建的镜像一般都不打版本号,每次tag都是latest,这也会导致<none>镜像的出现,所以公司有一个定时任务专门去清理这些<none>镜像。。

 dockerfile多阶段构建的优缺点

 

 

综上所述,在dockerfile中编译的缺点:

1、编译速度没有宿主机快

2、下载程序的依赖包比在宿主机中直接下载更加耗时

3、会产生none镜像,占用磁盘空间

 优点:

1、不需要在宿主机中安装各种SDK

2、有缓存(none镜像),且程序依赖没有改变的情况下,比在宿主机直接打包快

 

 

参考资料:

关于<none>空悬镜像

 

原创文章,作者:bd101bd101,如若转载,请注明出处:https://blog.ytso.com/267466.html

(0)
上一篇 2022年6月18日
下一篇 2022年6月18日

相关推荐

发表回复

登录后才能评论