一直以来,公司的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中编译的缺点:
1、编译速度没有宿主机快
2、下载程序的依赖包比在宿主机中直接下载更加耗时
3、会产生none镜像,占用磁盘空间
优点:
1、不需要在宿主机中安装各种SDK
2、有缓存(none镜像),且程序依赖没有改变的情况下,比在宿主机直接打包快
参考资料:
关于<none>空悬镜像