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

28

所有的服务织物 示例 都展示了单一解决方案服务织物示例。这似乎与微服务的理念相悖,微服务需要在服务之间实现完全的依赖隔离。尽管您可以手动遵循此模式,但更常见的做法是通过使每个服务成为其自己的存储库和解决方案/项目来强制执行它。

如何使用多个解决方案(位于多个 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) 作为一名开发者,我希望检查和构建所有当前的应用程序/服务版本。我想启动管理所有清单的 Service Fabric 项目,并将其部署到我的本地开发群集中。我想强制执行解决方案之间相同的服务接口。我不明白如何做到这一点,因为应用程序是服务外部的。

2) 作为 DevOps 团队,我希望自动拉取应用程序,构建并将其部署到 Azure。

我们如何通过单独的解决方案来"强制执行"隔离,同时使它们易于合并并部署到群集中,同时还要容易创建针对 DEV、QA 和 PROD 环境分别配置的管道。

哪些工作流程/流程/项目结构可以实现这一点?这真的可能吗?


1
一年过去了,你的情况如何?我们正在考虑做类似的事情——但我找不到如何做的例子。你有什么建议吗? - RPM1984
你能告诉我你是如何处理这个问题的吗? - Alex Gordon
2个回答

17
是的,这是可能的 - 我以前做过类似的事情。以下是我立刻想到的想法...
在每个Service Fabric解决方案中都有一个“公共”项目,其中包含您希望从该应用程序中的服务公开的接口。此项目的输出可以打包为nuget包并推送到私有存储库。你可以称之为“interfaces(接口)”项目,但如果您想将其中一些接口视为内部接口,则不必公开所有接口;这些接口可以在单独的未公开项目中定义。
其他想要引用另一个应用程序公开的服务的解决方案只需下载相关的nuget包即可获取对服务接口的引用。
现在这并非没有问题:
- 消费应用程序仍然需要知道服务的地址,以便为它们构建代理。你可以将它们作为常量公开定义在nuget包的某个地方,或者如果你要走完整的DI路线并且不介意在任何地方将自己耦合到DI容器中(或想尝试将其抽象掉),你可以从nuget包中公开一个模块,该模块可以将服务接口注册为代表依赖应用程序进行服务代理创建的lambda。 - 你更容易遭受合同违约的风险。您需要非常小心地更新方法签名,因为现在由您负责应用程序/服务部署的细粒度和协调。 - 您可以过于详细 - 如您所述,Service Fabric工具指导您将多个服务放入一个解决方案中。即使采用上述方法,我仍然会尝试在一定程度上逻辑地对我的服务进行分组,即不要选择应用程序与服务之间的一对一映射 - 那肯定会比它值得的更痛苦。
希望这有所帮助。
编辑:
注册DI模块中的服务接口示例(Autofac样式)...
这将是您从公共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();
}

当然,如果您没有将服务进行分区,那么这种方法才有效...


2
这很棒。我希望MSDN / Azure添加更多的SF示例,超越他们的会议演示材料。 - FlavorScape
1
你提到了一个“可以将服务接口注册为执行服务代理创建的Lambda函数”的包。你知道这个样板代码是什么样的,或者能指导我正确的方向吗?我的研究结果都是我已经点击过的链接 =)谢谢! - FlavorScape
1
已编辑并包含简单示例。 - Mike Goatly
非常感谢您提供这个很棒的示例和答案。@MikeGoatly,我想知道我们如何在微服务中对BLL进行版本控制?服务A需要调用服务B的v1版本,但服务B已经升级到v2版本。请注意,没有任何合同变更,唯一的变化是服务B的BLL。在这种情况下,我们应该如何进行版本控制呢? - Alex Gordon
@l--''''''---------'''''''''''' 这个答案中应该有足够的材料来提取您场景的答案。结合服务织物版本控制机制,使用依赖注入(DI),可能添加一些服务参数来引导 DI 解析。 - Peter Bons
我无法从中提取出一个解决方案,而且在我看来,这似乎是一个非常脆弱/难以维护的解决方案,你不同意吗? - Alex Gordon

1
你也可以使用更松散耦合的协议,例如基于HTTP的使用XML\WSDL或JSON\Swagger并自动生成或手动创建的HTTP客户端代理。
管理NuGet库、nuspec等的成本很高。

你如何对BLL进行版本控制? - Alex Gordon
BLL 如果你指的是数据实体,那就是另一个问题了,这取决于你的数据存储方式。 - user1496062

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接