在 docker 中运行 c# worker 服务有意义吗?

Posted

技术标签:

【中文标题】在 docker 中运行 c# worker 服务有意义吗?【英文标题】:Does it make sense to run a c# worker service in docker? 【发布时间】:2020-11-09 18:06:46 【问题描述】:

我正在 docker 中开发一个多容器应用程序。其中一项服务是 C# 中一个长时间运行的控制台应用程序,它基本上对数据库进行一些轮询并将数据发送到 e 服务器。我只是通过添加以下语句来保持服务运行:

while(true);

现在我正在考虑将此服务更改为 .NET Core 辅助服务(甚至是 Windows 服务,因为我只在 Windows 主机上使用 Windows 容器)。我已经阅读了一些关于工作人员服务优点的文章,但是当涉及到容器化应用程序时,它们似乎都已经过时了,因为我的容器无论如何都作为一种“后台服务”运行(而且我每个容器/图像只使用一个服务)。所以我的问题是:

与在 docker 中运行控制台应用程序相比,在 docker 中运行核心工作者服务有什么好处或缺点?

更新:对于“工作服务”,我指的是 .NET Core 3.x 中可用的新工作服务模板:https://www.stevejgordon.co.uk/what-are-dotnet-worker-services

【问题讨论】:

你所说的“工人服务”到底是什么意思? @Dai .NET Core 3+ 提供的新工作服务模板stevejgordon.co.uk/what-are-dotnet-worker-services 您最终在哪里部署您的应用程序? kubernetes(本地或 AKS 或其他)?这是恕我直言讨论的一部分。 我目前正在本地部署,但考虑在未来部署到 azure 【参考方案1】:

简而言之,您的快乐路径代码的功能可能“大致相同”。

但是:

使用“通用主机”的好处是您可以从 Microsoft 为您创建的可重用组件中获益……而不是自己动手。

这意味着(恕我直言)更好的代码,因为您无需亲自处理长时间运行进程的许多常见问题。

基本上,与滚动自己的实现相比,您“免费”获得了大量管道代码。

3.0/3.1 之前的很多功能都与 asp.net 命名空间相结合。 3.0/3.1 更新有很多“把它放到一个用于 asp.net 和 .net(非 asp.net)的公共位置”以供使用。又名,将它与 asp.net 分开。

设置:(专用方法“AddHostedService”)

services.AddHostedService<MyWorkerThatImplementsIHostedService>();

因此,当未来的开发人员查看上面的代码时,他们确切地知道发生了什么。 (与找出自定义滚动实现相比)

或者在更大的代码示例中:

public class Program

    public static void Main(string[] args)
    
        CreateHostBuilder(args).Build().Run();
    

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices(services =>
            
                services.AddHostedService<MyWorkerThatImplementsIHostedService>();
            );

上面的代码~~看起来~~ asp.net'ish,其实是.net(非asp.net)的代码。 也就是,您的一致性得到了提高。

关机:

您会获得所有内置的“关闭”选项。这些都是“优雅的”关闭选项……不幸的是,“快乐路径”开发人员通常不会考虑这些选项。如果有任何理由跳入这个迷你图书馆......有某种优雅的退出就是它。硬退出可能会使您的处理过程处于未知的难以排除故障的状态。

CNLT-C

Programmatically (see https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.ihostapplicationlifetime.stopapplication?view=dotnet-plat-ext-3.1 )

Kubernetes Shutdown

微软甚至想出了“我可以将最终关机延迟一些”

见:How to apply HostOptions.ShutdownTimeout when configuring .NET Core Generic Host?

这是一个不错的链接,显示了一些选项(Timer vs Queue vs Monitor)

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio

您还可以将代码部署为:

容器

Windows 服务

** Linux Daemon(见https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.systemd.systemdhelpers.issystemdservice?view=dotnet-plat-ext-3.1)(这对于传统的dotnet框架开发者来说通常是一个新概念)

Azure 应用服务

哦,是的,Microsoft 甚至为您考虑了“健康检查”。

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-5.0#separate-readiness-and-liveness-probes-1

瓶装线,用这个代替定制的卷材。是经过深思熟虑的。

::::::::::::::::::::Previous Comments::::::::::::::::::::::::: ::::::::(下)

.......

C# 中的长时间运行控制台应用程序

短版:

借助现代代码部署策略,不仅仅是技术决策,还有财务决策。

加长版:

我最近进行过这个讨论,因为一些代码库已被指定用于“转换为 dotnet 核心”和“我们如何转换旧的 Windows 服务?”。

以下是我的想法:

哲学上。

您必须考虑“我在哪里部署以及成本是多少?”,而不仅仅是技术问题。你提到码头工人。但是你如何部署它? Kubernetes? (天蓝色的 AKS,其他?)这是一条重要的信息。

恕我直言:有了“云”,甚至是内部部署的 Kubernetes……你不想要“Windows 服务”的心态,这种心态只会运行、运行、运行,不断增加成本。除非你必须拥有这个。

你想启动一个进程,让它运行,然后尽快关闭它。

现在,如果您需要它每小时运行一次,那很好。

现在,如果您需要“即时”或“尽快处理”(例如查看队列中的消息),那么您可能会付出代价并拥有始终运行的东西,因为处理这些消息是比您为运行服务支付的价格更重要。

所以从技术上讲,我喜欢这个想法

https://www.stevejgordon.co.uk/what-are-dotnet-worker-services

什么是工人服务?不需要用户的应用程序 相互作用。使用主机维护控制台的生命周期 应用程序,直到主机发出关闭信号。转动一个 控制台应用程序转换为长期运行的服务。包括功能 ASP.NET Core 常见的依赖注入、日志记录和 配置。执行定期和长时间运行的工作负载。

但在财务上,我必须用在 Azure 上(甚至在本地)上运行的成本来应对。

处理消息队列消息意味着 --> “是的,必须一直运行”。所以我付出了让它一直运行的代价。

如果我知道我的客户在半夜发布了他们的导入文件,一次,那么我不想付出总是运行的代价。我想要一个在早上触发一次的控制台应用程序。进来,出去。尽快处理并离开。 Kubernetes 有调度机制。

使用 Azure,不仅仅是技术决策,还有财务决策。

未提及:如果您的代码计划每小时运行一次,但随后开始运行时间超过一小时,您就会遇到不同的问题。 Quartz.Net 是处理这些重叠问题的一种方法。

请记住,我必须对这个关于成本的论点非常坚定。大多数开发人员只是想将 windows-services 转换为 dotnet-core 并完成它。但这不是长期的想法,因为越来越多的代码迁移到云端,并且云运营的成本开始发挥作用。

PS

另外,请确保将所有代码向下移动到业务层中............并让这些方法中的任何一种

Console.App(只是普通的)

.NET Core 工作者服务

Quartz.Net 调度作业

让上面的项目成为“调用你的业务逻辑层的薄顶层”,然后你就不会把自己画到角落里。你做的顶层越薄越好。基本上,我的控制台应用程序是

void Main(string args)

  //wire up IoC
  //pull out the business logic layer object from the Ioc
  //call a single method on the business logic layer

还有一些 appsettings.json 文件是 Program.cs 所在的。什么都没有或很少。尽快将所有内容下推到业务逻辑层。

【讨论】:

感谢您的回答,但这项服务的要求很明确,它必须一直运行。我的问题仅与本地 docker 容器有关,以及我从将程序作为 .net core worker 服务在其中运行而不是使用“常规”控制台应用程序中获得的技术优势。如果我去 azure,无论如何我都会使用 azure 函数。 不要吹毛求疵,但在此评论之前您没有提到“天蓝色函数”。我的问题和您的评论(在您的问题下),您只提到了天蓝色。而“一直运行”,它可能意味着“它当前被编码为一直运行”与“未来的实现必须一直运行”。微妙,但不同。但是,当您收到第一份 Azure 账单时,请随时发布后续信息,并且您的客户部门会问“为什么这便士不像承诺的那样”。 #只是说好运。 我已经用其他一些想法更新了我的答案。希望这些更适合您。 这个答案也增加了解释,尤其是“如果你不能通过它的 ID 确定对象的存在,你必须执行查找查询:”。 @ 987654326@ :::我通过说“不要一次查找一个,使用相当于 SQL“WHERE IN”查询的 EF 以基于集合的方式查找所有这些来扩展这个答案。 【参考方案2】:

如果您总是要在容器中运行,请使用控制台应用程序。我认为作为服务运行并没有固有的好处,因为在 Kubernetes 等适当的编排下,容器应该被认为是短暂的。此外,如果您保持简单,即控制台,您将 .NET Core 3.1.x 应用程序作为 Linux 或 Windows 容器运行时的摩擦会更小。

另外,我将在您的控制台中使用以下行来确保它与为容器分配的 CPU 配合得很好:

while(true)

    Thread.Sleep(1 * 1000);

【讨论】:

以上是关于在 docker 中运行 c# worker 服务有意义吗?的主要内容,如果未能解决你的问题,请参考以下文章

是否有人将 django celery worker 实现为 docker 容器,它仅在分配任务时运行

Docker-compose:在npm安装成功解决方案后,卷中没有node_modules

Windows Worker 服务文件夹权限 (C#)

十docker swarm

Docker swarm 不会在集群中分发容器

在同一个容器中运行 celery worker + beat