继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Docker镜像优化

暮色呼如
关注TA
已关注
手记 247
粉丝 86
获赞 309

前言

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


 

一、以往Dockerfile构建模式

(1)发布API项目

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

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

(2)创建镜像

在发布目录新建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 baseWORKDIR /appEXPOSE 80 

FROM microsoft/dotnet:2.1-sdk AS buildWORKDIR /srcCOPY ["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 publishRUN dotnet publish "API.csproj" -c Release -o /app 

FROM base AS finalWORKDIR /appCOPY --from=publish /app .ENTRYPOINT ["dotnet", "API.dll"]

复制代码

它分为四个阶段,分别是base、build、publish和final。

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.使用多阶段构建镜像。

原文出处:https://www.cnblogs.com/FireworksEasyCool/p/10221299.html  

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP