如何对 Service Fabric 应用程序进行版本控制和分离?

How to version and separate Service Fabric applications?

所有服务结构 examples 描述单一解决方案服务结构示例。这似乎 微服务的理念背道而驰,在微服务理念中,您希望在服务之间实现完全的依赖隔离。虽然您可以手动遵循此模式,但更常见的做法是通过使每个服务成为自己的存储库和 solution/project.

来强制执行此模式。

您如何使用多个解决方案(在多个 Git 存储库中)管理和部署服务结构服务并执行服务合同 (ServiceInferfaces)?

例如

Service Fabric Solution
      App1 - Customers
         - Service1 [Carts] From Other Solution
         - Service2 [LocationInfo]From Other Solution
         - Service3 [REST WebAPI for Admin] From Other Solution
      App2 - Products
         - Service4 [Status]From Other Solution
         - Service5 [Firmware]From Other Solution
         - Service6 [Event Stream] From Other Solution

External Solution
   - Service1
External Solution
   - Service2
External Solution
   - Service3

External Solution
   - Service4
External Solution
   - Service5
External Solution
   - Service6

1) 作为一名开发人员,我想检查并构建 apps/services 的所有当前版本。我想启动管理所有清单的 Service Fabric 项目,并将其部署到我的本地开发集群。我想在解决方案之间实施相同的服务接口。我不明白你是怎么做到的,因为应用程序在服务之外。

2) 作为 DevOps 团队,我想自动拉取应用程序、构建它们并部署到 Azure。

我们如何 "enforce" 通过单独的解决方案进行隔离,但又可以轻松地将它们组合在一起并部署到集群中,同时还可以轻松地使管道部署为 DEV、QA 独特配置的每个集群和 PROD 环境。

启用此功能的 workflow/process/project 结构是什么?有可能吗?

是的,这是可能的 - 我之前已经按照这些思路做了一些事情。这些是 spring 立即想到的想法...

在每个 Service Fabric 解决方案中都有一个 "public" 项目,其中仅包含您希望从该应用程序中的服务公开的接口。该项目的输出可以打包为 nuget 包并推送到私有存储库。我猜你可以称它为 "interfaces" 项目,但如果你想考虑应用程序内部的某些接口,则不必公开所有接口;这些可以在一个单独的、未公开的项目中定义。

想要引用另一个应用程序公开的服务的其他解决方案只需要下拉相关的 nuget 包以获取对服务接口的引用。

现在这并非没有问题:

  • 消费应用程序仍然需要知道服务的地址才能为它们构建代理。您可以将它们公开为在 nuget 包中某处定义的常量,或者如果您沿着完整的 DI 路线走并且不介意将自己耦合到任何地方的 DI 容器(或者想尝试将其抽象掉),您可以公开nuget 包中的一个模块,可以将服务接口注册为 lambda,代表相关应用程序创建服务代理。
  • 更容易违约。您需要非常小心地更新方法签名,因为 现在负责 application/service 部署的粒度和协调。
  • 您可以过于细化 - 正如您提到的,Service Fabric 工具会引导您在一个解决方案中拥有多项服务。即使使用上述方法,我仍然会尝试在某种程度上从逻辑上对我的服务进行分组,即不要在应用程序和服务之间进行一对一的映射 - 这肯定会比它的价值更痛苦。

希望对您有所帮助。

编辑:

在DI模块中注册服务接口的例子,(Autofac风格)...

这将是您从 public nuget 包公开的 DI 模块:

using System;
using Autofac;
using Microsoft.ServiceFabric.Services.Remoting.Client;

public class MyAppModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register(component => ServiceProxy.Create<IMyService>(new Uri("fabric:/App/MyService"))).As<IMyService>();
        // Other services...
    }
}

并且在您的消费应用程序的 Program.cs 中,您将包含如下内容:

public static void Main()
{
    try
    {
        var container = ConfigureServiceContainer();

        ServiceRuntime.RegisterServiceAsync(
            "MyConsumingServiceType",
            context => container.Resolve<MyConsumingService>(new TypedParameter(typeof(StatefulServiceContext), context))).GetAwaiter().GetResult();
        ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(MyConsumingService).Name);

        Thread.Sleep(Timeout.Infinite);
    }
    catch (Exception e)
    {
        ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
        throw;
    }
}

private static IContainer ConfigureServiceContainer()
{
    var containerBuilder = new ContainerBuilder();

    // Other registrations...

    containerBuilder.RegisterModule<MyAppModule>();

    return containerBuilder.Build();
}

当然,这种方法只有在您不对服务进行分区时才有效...

您还可以使用耦合度较低的协议,例如使用 xml\wsdl 或 json\swagger 的基于 http 的协议以及自动生成或手动创建的 httpclient 代理。

管理 nugget 库、nuspec 等的成本很高。