.NET的Dockerfile文件编写要点——以WOL项目为例

news/2024/2/29 3:12:32

本文以 WOL 的.NET 项目为例,介绍了 Dockerfile 的基础知识和编写要点,旨在帮助读者更好地理解和掌握如何为 .NET 应用创建和优化 Dockerfile。

1. 背景

前面我们已经勾选了 Docker 容器化支持,项目已经生成了一个默认的 Dockerfile。但在实际项目中,我们需要根据项目的实际需求和环境来定制化 Dockerfile,以便更好地利用 Docker 的优势。本文将以 WOL (Wake On LAN) 项目为例,详细介绍如何编写一个针对 .NET 应用的 Dockerfile 文件,并分享一些实用的编写技巧。

2. 从默认模板入手

2.1 默认模板

以下是 .NET8 中 Web API 项目的默认模板,在这个默认模板中,我们可以看到一个典型的多阶段构建过程。

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base  
USER app  
WORKDIR /app  
EXPOSE 8080  
EXPOSE 8081  FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build  
ARG BUILD_CONFIGURATION=Release  
WORKDIR /src  
COPY ["WebApplication3/WebApplication3.csproj", "WebApplication3/"]  
RUN dotnet restore "./WebApplication3/./WebApplication3.csproj"  
COPY . .  
WORKDIR "/src/WebApplication3"  
RUN dotnet build "./WebApplication3.csproj" -c $BUILD_CONFIGURATION -o /app/build  FROM build AS publish  
ARG BUILD_CONFIGURATION=Release  
RUN dotnet publish "./WebApplication3.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false  FROM base AS final  
WORKDIR /app  
COPY --from=publish /app/publish .  
ENTRYPOINT ["dotnet", "WebApplication3.dll"]

2.2 模板介绍

根据默认模板,我们先来复习一下 Dockerfile 的基本结构:

  1. FROM:指定基础镜像,并可以使用 AS 为这个阶段设置别名,如 FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
  2. USER:设置运行时的用户,如 USER app
  3. WORKDIR:设置工作目录,如 WORKDIR /app
  4. EXPOSE:暴露容器需要监听的端口,如 EXPOSE 8080EXPOSE 8081
  5. COPY:复制文件或目录,如 COPY ["WebApplication3/WebApplication3.csproj", "WebApplication3/"]
  6. RUN:执行命令,如 RUN dotnet restore "./WebApplication3/./WebApplication3.csproj"
  7. ARG:定义构建参数,如 ARG BUILD_CONFIGURATION=Release
  8. ENTRYPOINT:指定容器启动时执行的命令,如 ENTRYPOINT ["dotnet", "WebApplication3.dll"]

在默认模板中,我们还可以看到一个典型的多阶段构建过程。多阶段构建可以减小最终生成的镜像大小,提高构建速度。在上述示例中,我们使用了四个阶段,分别命名为 base、build、publish 和 final,用于不同的构建和运行阶段。

3. WOL 项目的 Dockerfile

一般来说使用默认的 Dockerfile 就可以了,但是有时候我们需要根据项目的特定需求和环境对 Dockerfile 进行调整和优化。

3.1 额外的依赖

项目可能需要一些额外的系统依赖或者工具。可以通过 RUN 指令和包管理器(如 apt-get、yum 等)来安装这些依赖。有时我们可以在编程中就能发现并意识到,但是更多的时候需要我们在容器化后对项目做好测试工作,确保所有功能都能正常运行。

比如在 WOL 项目的工具类中有写这样一个检查设备是否在线的函数:

internal static bool Ping(string iP)
{// 检查IP是否在线Ping ping = new Ping();PingReply pingReply = ping.Send(iP,100);return pingReply.Status == IPStatus.Success;
}

写起来倒是很简单,也很省事。但是如果不知道其运行原理的话,就会在容器化后遇到问题。这个函数使用了 System.Net.NetworkInformation.Ping 类来检查目标 IP 地址是否在线,但是其依然是使用了系统的 Ping 工具来处理。Docker 的 Base 镜像都是最简版本,为了轻便,都是不包含 Ping 工具的。

为了解决这个问题,我们就需要将缺失的依赖安装恢复,Debian 的 Ping 工具包为 Iputils-ping,在 final 阶段通过 apt 安装即可。

3.2 更改安装源

在上一节中,我们讨论了安装额外依赖的必要性。为了加速镜像构建过程中的软件包安装,我们可以考虑修改安装源。通常,我们会在物理机上更改镜像源以加速软件包的安装。同样的方法也适用于容器镜像的构建过程。如果不更改安装源,一个镜像的构建可能会花费数小时,这对于开发者来说是难以忍受的。

在使用 mcr.microsoft.com/dotnet/aspnet:8.0 镜像时,底层基于 Debian 系统。为了加速软件包的安装,我们可以更改安装源。在这个例子中,我们将安装源更改为清华大学的镜像源。以下是如何在 Dockerfile 中进行更改的示例:

sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list.d/debian.sources && \
apt-get update

这段代码使用 sed 命令修改了 /etc/apt/sources.list.d/debian.sources 文件中的安装源,将其从 deb.debian.org 更改为了 mirrors.tuna.tsinghua.edu.cn。接下来,使用 apt-get update 命令更新软件包列表。

通过这样的设置,我们可以加速后续软件包的下载和安装过程,从而提高整体镜像构建速度。

3.3 清理垃圾

在执行 apt update 和安装软件包之后,我们需要注意清理系统中产生的缓存和临时文件。这些文件会增加镜像的大小,而在大多数情况下,它们在运行时并不需要。因此,我们可以在 Dockerfile 中添加相应的指令来清理这些垃圾文件,从而减小最终生成的镜像大小。

在使用 apt-get 安装软件包后,可以使用以下命令清理缓存:

apt-get clean
rm -rf /var/lib/apt/lists/*

这段代码首先使用 apt-get clean 命令清理软件包缓存,然后使用 rm -rf /var/lib/apt/lists/* 删除下载的软件包列表。这样一来,我们就可以在构建过程中有效地减小镜像大小。

3.4 权限问题

前面已节我们已经按照了系统的 ping 工具,这样我们就可以正常的使用 System.Net.NetworkInformation.Ping 类来检查目标 IP 地址是否在线。但是在 Linux 系统中,Ping 的实现依赖于 ICMP 协议,而在容器中执行 ICMP 请求通常需要特殊权限,直接容器化运行项目会发现下面的问题:

ping: socktype: SOCK_RAW                                                         
ping: socket: Operation not permitted                                            
ping: => missing cap_net_raw+p capability or setuid?

这是因为为了提高安全性,我们已经将应用的运行用户更改为了 app。为了解决这个问题,我们可以在 Dockerfile 中为更改 ping 命令的权限。

chmod u+s /bin/ping

3.5 编码问题

处理到这里,Dockerfile 的文件就基本解决完毕。但是在实际测试中我们会发现,API 接口中返回的中文会出现乱码的情况:

请添加图片描述

我们可以看到,由配置文件返回的中文信息并没有出现乱码,而通过代码直接返回的中文出现了乱码的情况。这里是因为默认的代码文件编码是 GB18030 ,我们只需要将其改为 UTF-8 ,然后重新制备镜像即可解决这种硬编码导致的乱码问题。

请添加图片描述

4. 要点总结

通过以上的问题重现和处理,我们最终的项目 Dockerfile 如下:

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["WakeOnLan/WakeOnLan.csproj", "WakeOnLan/"]
RUN dotnet restore "WakeOnLan/WakeOnLan.csproj"
COPY . .
WORKDIR "/src/WakeOnLan"
RUN dotnet build "WakeOnLan.csproj" -c $BUILD_CONFIGURATION -o /app/buildFROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "WakeOnLan.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=trueFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list.d/debian.sources \&& apt-get update \&& apt-get install -y --no-install-recommends iputils-ping \&& apt-get clean \&& rm -rf /var/lib/apt/lists/* \&& chmod u+s /bin/ping
WORKDIR /app
USER app
EXPOSE 8080
COPY --from=publish /app/publish .
ENTRYPOINT ["./WakeOnLan"]

最后总结在编写 Dockerfile 时需要注意的一些要点:

  1. 使用多阶段构建:多阶段构建可以减小最终生成的镜像大小,提高构建速度。在上述示例中,我们使用了三个阶段,分别用于编译、发布和运行应用程序。

  2. 使用官方镜像:尽量使用官方提供的基础镜像,以确保镜像的安全性和可靠性。

  3. 优化镜像层:尽量将不会经常变动的文件放在前面,以充分利用镜像层缓存,提高构建速度。

  4. 安装额外依赖:根据项目实际需求,安装额外的依赖和工具,确保所有功能正常运行。

  5. 更改安装源:更改镜像源以加速软件包的下载和安装过程,减少构建时间。

  6. 清理缓存和临时文件:清理缓存和临时文件,减小生成的镜像大小。

  7. 解决权限问题:确保容器化应用程序的安全性,遵循最小权限原则,避免使用 root 用户运行容器。设置运行时用户并调整文件和目录的权限。

  8. 充分测试:对容器化后的项目进行充分的测试工作,以确保所有功能都能正常运行。

通过关注这些要点,我们可以针对实际项目编写和调整 Dockerfile,以便更好地利用 Docker 的优势。同时,对容器化后的项目进行充分的测试工作也是至关重要的。


http://www.ppmy.cn/news/1243975.html

相关文章

Netty 模型理解

参考文章 1 参考文章 2 官网API文档 Reactor模型 Netty模型 Netty主要基于主从Reactor多线程模型进行了一定的修改,该模型包括以下几个组件: MainReactor(主Reactor):负责处理客户端的连接请求。它监听服务器上的端口…

【面经八股】搜广推方向:常见面试题(二)

【面经&八股】搜广推方向:常见面试题(二) 文章目录 【面经&八股】搜广推方向:常见面试题(二)1. FTRL 是什么?(Follow The Regularized Leader)2. 梯度下降方法3. 推荐系统中常见的Embedding方法有哪些?4. Embedding与推荐系统有哪些结合5. FM 和 FFM6. FNN7. 深…

【第二节:微信小程序 app.json配置】微信小程序入门,以思维导图的方式展开2

以思维导图的方式呈现出来,是不是会更加直观一些呢 如果看不清楚,私信给单发 : 第二节:微信小程序 app.json配置: 包括: window pages tabBar networkTimeout debug 如下图所示: 2、ap…

JackSon设置空值不序列化

JsonInclude(JsonInclude.Include.NON_EMPTY) private PageInfo page;

【实战教程】PHP与七牛云的完美对接

前言: 随着互联网的迅速发展,越来越多的网站和应用程序需要处理大量的图片、视频和其他文件。为了有效地存储和管理这些文件,并提供快速的内容分发服务,开发者们常常依赖于云存储和CDN服务提供商。 七牛云是一家领先的云存储和C…

glibc和gcc源码

glibc下载 $ git clone git://sourceware.org/git/glibc.gitgcc编译器,https://gcc.gnu.org/ git clone git://gcc.gnu.org/git/gcc.git

C语言:一个数如果恰好等于除它本身外的因子之和,这个数就称为完数。例如6=1+2+3。编程找出1000以内的所有完数。

分析: 在主函数 main 中,程序首先定义三个整型变量 m、s 和 i,并用于计算和判断完数。然后使用 printf 函数输出提示信息。 接下来,程序使用 for 循环结构,从 2 到 999 遍历所有的数。对于每个遍历到的数 m&#xff0c…

JavaScript中Object.prototype.toString.call()、instanceOf和Array.isArray()的区别

JavaScript是一种非常流行的编程语言,它具有许多强大的功能和特性。在JavaScript中,有一些方法和操作符可以帮助我们更好地处理数据类型和对象。本文将重点讨论Object.prototype.toString.call()、instanceOf和Array.isArray()这三个在JavaScript中常用的…

数据结构之时间复杂度与空间复杂度

1.算法效率 1.1 如何衡量一个算法的好坏&#xff1f; 比方说我们非常熟悉的斐波拉契数列&#xff1a; long long Fib(int N) {if(N < 3)return 1;return Fib(N-1) Fib(N-2); } 递归实现方式非常简洁&#xff0c;但一定好吗&#xff1f;如何衡量其好与坏&#xff1f; 1…

海外Leads Generation产业:中国出海群体的行业大机会

Leads Generation&#xff08;简称LeadsGen&#xff09;指的是集中精力吸引和开发潜在客户的营销策略。通过引导式的营销策略&#xff0c;企业分发内容吸引潜在客户&#xff0c;引导客户留下电话/邮件/姓名等信息。基于这些信息&#xff0c;企业可建立潜在客户数据库&#xff0…

规则引擎Drools使用,0基础入门规则引擎Drools(四)WorkBench控制台

文章目录 系列文章索引八、WorkBench简介与安装1、WorkBench简介2、安装 九、WorkBench使用方式1、创建空间2、创建项目3、创建数据对象4、创建DRL规则文件5、创建测试场景6、设置KieBase和KieSession7、编译、构建、部署8、在项目中使用部署的规则 系列文章索引 规则引擎Droo…

全面探讨HTTP协议从0.9到3.0版本的发展和特点

前言&#xff1a; 最近的几场面试都问到了http的相关知识点&#xff0c;博主在此结合书籍和网上资料做下总结。本篇文章讲收录到秋招专题&#xff0c;该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出&#xff0c;对大佬有帮…

IDEA2023版本创建Sping项目只能勾选17和21,却无法使用Java8?(已解决)

文章目录 前言分析解决方案一&#xff1a;替换创建项目的源方案二&#xff1a;升级JDK版本 参考文献 前言 起因 想创建一个springboot的项目&#xff0c;本地安装的是1.8&#xff0c;但是在使用Spring Initializr创建项目时&#xff0c;发现版本只有17和21。 在JDK为1.8的情况下…

初识前后端数据交互(新手篇)

一个软件项目的开发必然是离不开前端和后端的协作&#xff0c;对于刚入行的新手前端或者新手后端来说&#xff0c;很有必要了解一下对方是在做什么&#xff0c;以及提供给自己什么样的帮助&#xff0c;为什么需要对方共同协作才能完成整个软件项目的开发呢&#xff1f;希望这篇…

docker介绍、部署与常用命令

一、docker 介绍 1、容器&#xff08;Container&#xff09;&#xff1a; (1) 概念&#xff1a; 容器是一种用于运行和部署应用程序的技术。它将应用程序及其所有依赖项&#xff08;例如代码、运行时、系统工具、系统库等&#xff09;打包在一个独立的、可移植的运行环境中&…

kubernetes架构及核心组件简单介绍

目录 整体架构控制面kube-apiserver访问控制通知 kube-scheduler概述默认调度策略 kube-controller-manageretcd架构Raft协议日志复制 数据面kubeletkube-proxy 整体架构 集群架构图 控制面 控制面是kubernetes的核心组件&#xff0c;负责管理和控制集群的整体行为&#xf…

Java 设计模式之命令模式

命令模式 介绍 命令模式是一种行为类设计模式&#xff0c;核心是将每种请求或操作封装为一个独立的对象&#xff0c;从而可以集中管理这些请求或操作&#xff0c;比如将请求队列化依次执行、或者对操作进行记录和撤销。 命令模式通过将请求的发送者&#xff08;客户端&#x…

yolov5检测(前向)输入视频输出(不在图上画标签形式的原)图片的方法,及设置每隔几帧保存的方式(不每帧保存减少重复)

这些天我忽然有个需求&#xff0c;要更新迭代一个场景的检测模型&#xff0c;甲方爸爸提供的新数据集是监控视频形式的(因为拍视频确实更加的方便)&#xff0c;而我训练模型确实要标注好的图片形式。 根据这些条件的话&#xff0c;思路应该是要这样的&#xff1a;首先使用现有的…

新手如何对一个web网页进行一次渗透测试

新手如何对一个web网页进行一次渗透测试 文章目录 新手如何对一个web网页进行一次渗透测试什么是渗透测试?渗透测试和红蓝对抗的区别那么拿到一个网站后如何进行一次优雅的渗透测试呢 什么是渗透测试? 在获得web服务运营的公司书面授权的情况下&#xff0c;模拟攻击者的行为…

深入理解JMM以及并发三大特性(2)

书接上文 文章目录 (1)CPU高速缓存(2)缓冲一致性(3)总线仲裁机制(4)总线窥探(Bus Snooping) 前面介绍到实现可见性&#xff0c;底层常用的一种方案是使用内存屏障&#xff0c;而内存屏障在汇编层面又是使用lock前缀指令来实现的&#xff0c;所以这里来介绍一下lock前缀指令。 …
最新文章