• Docker镜像优化


    前言

           上篇博文说到使用Visual Studio Tools for Docker帮助我们生成Dockerfile,现在我们讨论下生成的Dockerfile的优劣。


    一、以往Dockerfile构建模式

           (1)发布API项目

           新建Web API项目,项目名称为API

           在项目所在目录输入指令:dotnet publish --runtime ubuntu.16.04-x64

           (2)创建镜像

           在发布目录publish文件下新建Dockerfile文件,黏贴以下代码

    # 声明使用的基础镜像
    
    FROM microsoft/dotnet:2.1-sdk
    
    # 设置工作目录
    
    WORKDIR /app
    
    # 将本地应用拷贝到 容器/app 目录下
    
    COPY ./ ./
    
    # 设置导出端口
    
    EXPOSE 80
    
    # 指定应用入口点 API.dll代表的是主程序文件
    
    ENTRYPOINT ["dotnet", "API.dll"]

            在Dockerfile所在的目录下输入指令生成镜像:docker build -t api .

           不要忘记后面有一个点 .

           

           生成api:latest镜像成功

           参考博客操作步骤:https://www.cnblogs.com/bluesummer/p/8087326.html

           (3)分析镜像

           我们来查看镜像信息,输入:docker images

           

           发现api:latest镜像的大小为1.83GB,大得有点夸张。

           现在我们来分析这个Dockerfile:

           FROM microsoft/dotnet:2.1-sdk

           FROM:指定所创建的基础镜像,如果本地不存在,则默认去Docker Hub下载指定镜像。任何Dockerfile中的第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像,可以使用多个FROM指令。

           文中Dockerfile基于microsoft/dotnet:2.1-sdk镜像,而图中可看到,microsoft/dotnet:2.1-sdk镜像大小已经达到1.73GB了,所以最后生成的api:latest镜像大小为1.83GB也不足为怪。

           那问题来了,我们应该采用哪个镜像作为基础镜像,来创建我们自己的镜像呢?

           查阅了微软官网文档说明:

           microsoft/dotnet:<version>-sdk包含带有.NET Core 和命令行工具 (CLI) 的.NET Core SDK。此镜像将映射到开发方案,可使用此镜像进行本地开发、调试和单元测试。

           microsoft/dotnet:<version>-runtime包含.NET Core(runtime和库),并且针对在生产环境中运行.NET Core 应用进行了优化。

           我们修改Dockerfile的FROM指令为

           FROM microsoft/dotnet:2.1-aspnetcore-runtime

           其他指令保持不变,新建一个api:1.0.0的镜像。

           

           可以看到,镜像大小瞬间小了很多。但是我们还不满足,因为原本microsoft/dotnet:2.1-aspnetcore-runtime镜像才253MB,而我们的镜像是353MB。

           WORKDIR /app

           WORKDIR:为后续RUN、CMD和ENTRYPOINT指令设置工作目录。可以使用多个WORKDIR,后续命令如果参数是相对路径,则会基于之前命令指定路径。例如:

           WORKDIR /app

           WORKDIR publish

           WORKDIR api

           最终路径为:/app/publish/api

           这个指令在这里看上去应该优化不了。

           COPY ./ ./

           COPY:格式为COPY <src> <dest>。复制本地主机的<src>(为Dockerfile所在的目录的相对路径)下的内容到容器中的<dest>下。目标路径不存在,则自动创建。

           ./ ./ 就是将本地Dockerfile所在的目录的文件和文件夹都复制到镜像中的/app目录下。

           注意区分以下两条指令:

           COPY test relativeDir/   # adds "test" to `WORKDIR`/relativeDir/

           COPY test /absoluteDir/  # adds "test" to /absoluteDir/

           想了下,这里应该是不合理的,把全部文件都复制过去,这肯定会造成镜像变大。

           又想了下,这个已经是我们发布过的文件,那还能怎么办。问题先放这里,等会再解决。

           EXPOSE 80

           EXPOSE:声明镜像内服务所监听的端口。

           ENTRYPOINT ["dotnet", "API.dll"]

           ENTRYPOINT:指定镜像的默认入口命令,该入口命令会在启动容器是作为跟命令执行,所有传入值作为该命令的参数。支持两种格式:

           ENTRYPOINT [“executable”,”param1”,”param2”] (exec调用执行)

           ENTRYPOINT command param1 param2 (shell中执行)

           每个Dockerfile里若出现多个ENTRYPOINT,只有放后面的那个ENTRYPOINT有效。

           Dockerfile参考:https://docs.docker.com/engine/reference/builder/#usage  里面有各个指令的详细介绍。


    二、multi-stage builds(多阶段构建)

           在多阶段构建的过程中,我们在Dockerfile使用多个FROM指令,每个FROM指令使用不同的基础镜像构成了不同阶段。你可以选择从上一个阶段的产物(artifacts)复制到下一个阶段,从而确保不会把不需要的东西带到下一阶段。这种方法可以有效减小Docker镜像的大小。

           默认情况下,这些阶段没有被命名,可以通过它们的整数引用它们,第一个FROM指令从0开始。然而,我们也可以以as <NAME>的方式命名每个阶段。

           参考官网:https://docs.docker.com/develop/develop-images/multistage-build/

           以下我们用Visual Studio Tools for Docker生成的Dockerfile进行介绍。 

    FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
    
    WORKDIR /app
    
    EXPOSE 80
    
     
    
    FROM microsoft/dotnet:2.1-sdk AS build
    
    WORKDIR /src
    
    COPY ["API/API.csproj", "API/"]
    
    RUN dotnet restore "API/API.csproj"
    
    COPY . .
    
    WORKDIR "/src/API"
    
    RUN dotnet build "API.csproj" -c Release -o /app
    
     
    
    FROM build AS publish
    
    RUN dotnet publish "API.csproj" -c Release -o /app
    
     
    
    FROM base AS final
    
    WORKDIR /app
    
    COPY --from=publish /app .
    
    ENTRYPOINT ["dotnet", "API.dll"]

           它分为四个阶段,分别是basebuildpublishfinal

           base阶段:上面已经分析了这里不再详述。

           build阶段:

           FROM microsoft/dotnet:2.1-sdk AS build以microsoft/dotnet:2.1-sdk为基础镜像

           WORKDIR /src工作目录为/src

           COPY ["API/API.csproj", "API/"]把Dockerfile所在目录的API/API.csproj文件复制到容器的/src/API/中

           RUN dotnet restore "API/API.csproj"在当前镜像的基础上执行dotnet restore "API/API.csproj",把API项目的依赖项和工具还原,并输出结果。

           dotnet restore这条命令是使用 NuGet 还原依赖项以及在 project 文件中指定项目特殊的工具执行对依赖项和工具的还原。

           COPY . .

           WORKDIR "/src/API"切换工作目录到/src/API,可以用WORKDIR API替代,但明显第一种方法更直观。

           RUN dotnet build "API.csproj" -c Release -o /app执行dotnet build "API.csproj" -c Release -o /app,以Release模式生成API项目及其所有依赖项并把生成的二进制文件输出到/app目录。

            publish阶段:

           FROM build AS publish以上一阶段build为基础镜像

           RUN dotnet publish "API.csproj" -c Release -o /app执行dotnet publish "API.csproj" -c Release -o /app,以Release模式把API应用程序及其依赖项打包到/app目录以部署到托管系统。

            final阶段:

           FROM base AS final以上阶段base为基础镜像

           WORKDIR /app以/app为工作目录

           COPY --from=publish /app .把publish阶段生成的/app目录下的文件和文件夹复制到/app目录。

           这样做的原因是,上阶段的产物是不会带到下一阶段。

           现在可以解释为什么使用Visual Studio Tools for Docker不用发布也能生成可运行的镜像了,它实时 (JIT) 编译,提高启动性能。而且它只获取了程序运行所需要的文件放到镜像中。

           我们生成一个最新的镜像

           

            发现它和microsoft/dotnet:2.1-aspnetcore-runtime镜像一样大,这下满足了,毕竟我们没写什么代码到项目中。


    三、优化Docker镜像的方向

           1.精简镜像用途,尽量让每个镜像的用途都比较集中、单一,避免构造大而复杂,功能多的镜像。

           2.选用合适的基础镜像。

           3.在Dockerfile中写上注释,方便维护和他人使用。

           4.正确使用版本号,如1.0.1。

           5.使用多阶段构建镜像。

  • 相关阅读:
    汇编学习--第十天
    linux(03)基础系统优化
    linux(02)基础shell命令
    lf 前后端分离 (6) 支付
    lf 前后端分离 (5) 优惠券
    lf 前后端分离 (4) 价格策略
    lf 前后端分离 (3) 中间建跨域
    lf 前后端分离 (2) 课程数据获取,Serializer的返回
    lf 前后端分离 (1) auth,token认证
    支付宝接口调用总结(1)
  • 原文地址:https://www.cnblogs.com/FireworksEasyCool/p/10221299.html
Copyright © 2020-2023  润新知