Service Fabric 多个服务实例及其配置覆盖

20
我们的服务织物应用程序包括一个无状态服务,通过 OwinCommunicationListener 公开 HTTP 端点。

此服务的 ServiceManifest.Xml 指定了服务端点 <Endpoint Name="ServiceEndpoint" Type="Input" Protocol="http" Port="8090" />

然后可以通过浏览器访问无状态服务在 http://localhost:8090/

我们要做的是通过 ApplicationManifest 在同一服务织物应用程序上实例化此服务的多个实例到不同的端点。

ServiceManifestImport 导入我们的服务包并允许在应用程序级别进行配置覆盖。但无法以这种方式覆盖 ServiceEndpoint,只能覆盖 Settings.xml 中的值。

<ServiceManifestImport>
  <ServiceManifestRef ServiceManifestName="FooServicePkg" ServiceManifestVersion="1.0.0" >
    <ConfigOverrides Name="Config">
      <Settings>
        <SectionName Name="MySettings">
        <Parameter Name="MySetting" Value="SomeValue">
      </Settings>
    </ConfigOverrides>
</ServiceManifestImport>

我们可以通过在DefaultServices下指定多个Service节点来创建服务的命名实例。

<DefaultServices>
  <Service Name="FooInstanceA">
    <StatelessService ServiceTypeName="FooType" InstanceCount="1" />
      <SingletonPartition />
    </StatelessService>
  </Service>
  <Service Name="FooInstanceB">
    <StatelessService ServiceTypeName="FooType" InstanceCount="1" />
      <SingletonPartition />
    </StatelessService>
  </Service>
</DefaultServices>

是否可以通过配置为每个服务实例指定配置覆盖?

我尝试使用它们的服务名称来确定端口,使服务实例侦听特定端口,因此FooInstanceA侦听8090端口,而FooInstanceB侦听8091。

显然,在部署期间,Service Fabric进行了一些魔法操作,因此当FooInstanceB侦听的端口与ServiceEndpoint配置上指定的端口不同时,该服务将无法访问。

第一个原因是未在端点上设置DACL,解决方法是运行以下命令:

netsh http add urlacl http://+:8091/ user=everyone listen=yes

这样可以让服务在Service Fabric Explorer中成功启动并显示为健康状态,但是当我们使用http://localhost:8091/访问时,FooInstanceB将响应HTTP 503错误。

我们如何使服务实例侦听不同的端口?

希望这很清楚,谢谢。


3
你是否解决了这个问题?如果是,你介意总结一下答案吗? - FlavorScape
我有一个类似的问题。我有一个服务类型,我想创建多个具有不同配置的实例。现在,我必须注册不同的服务类型,它们除了一个参数完全相同。我很惊讶SF没有选项来传递附加参数给服务实例,我希望这是一个常见的地方。 - Alex Pryiomka
4个回答

7

实现这个目标的方法不是很多。以下是一些想法:

  1. 创建多个应用程序实例,而不是在应用程序中创建多个相同类型的服务。这将允许您使用应用程序参数来配置特定服务的行为。
  2. 在服务类型中创建多个配置包。每个配置包都用于一个服务实例。确定哪个配置包分配给服务实例需要是动态的,也许基于服务实例的名称?当然,并不是一个很好的选择,因为它将服务定义与将创建的实例数量耦合在一起。
  3. 自定义配置实现。也许让您的服务公开一个端点,以便您可以在部署后对其进行配置。或者让服务调用某个其他管理服务,在激活时提供其配置。

对于问题#2,您如何读取服务实例的名称?它们似乎只包含一个长ID,这个ID对于实例来说似乎是随机的。如果实例崩溃/重新启动,则会分配一个新的ID。需要获取基于索引的ID,但目前似乎不可能。 - Blue
有没有办法使用两个不同的应用程序清单(ApplicationManifest)实现http和https? - Ghebrehiywet
1
我的用例是代码重用...因为我的许多服务都使用同一组大型库,每个服务仅包含其上的业务逻辑的唯一实现,我希望不必为每个服务复制整个库集...我想一种方法是“数据包”,但那是针对数据而不是代码。应该有一种像docker-compose一样处理这个问题的方式(图像:x...环境:...)。记得DRY原则吗?无论如何,我想我正在要求第二种情况的示例(链接)。谢谢! - FizxMike
我找到了配置包的示例...但我处于“访客应用程序”模式...实际上没有访问那些配置(据我所知)。那么...有没有办法在SERVICE(实例)标记内进行资源或环境覆盖? - FizxMike
想知道如果自定义配置不被本地支持,那么拥有相同类型的多个服务(不同名称)的意义是什么。 - johni

2
您也可以让Service Fabric自动分配端口,然后使用Service Fabric附带的反向代理。

0

我已经成功使用ApplicationParameter xml文件,并在VSTS部署期间选择正确的文件。例如,这是我用于部署到测试环境的Cloud.xml文件。诀窍在第二行的Name参数上。我使用了这份文档来指定端口:https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-how-to-specify-port-number-using-parameters

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="fabric:/DotNetCoreTest" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="Web1_InstanceCount" Value="2" />
    <Parameter Name="ServiceEndpoint_PortNumber" Value="8909" />
  </Parameters>
</Application>

这是用于Staging的XML文件:Staging.xml

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="fabric:/DotNetCoreStaging" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="Web1_InstanceCount" Value="2" />
    <Parameter Name="ServiceEndpoint_PortNumber" Value="8910" />
  </Parameters>
</Application>

使用Traefik反向代理,如此处所述,我可以使用主机名来访问我的服务。 在VSTS中,我使用令牌化器在部署期间替换ServiceManifest中的主机名和ApplicationManifest中的ApplicationTypeName。

这是我的ServiceManifest:

<ServiceTypes>
    <!-- This is the name of your ServiceType. 
         This name must match the string used in RegisterServiceType call in Program.cs. -->
    <StatelessServiceType ServiceTypeName="Web1Type">
      <Extensions>
        <Extension Name="Traefik">
          <Labels xmlns="http://schemas.microsoft.com/2015/03/fabact-no-schema">
            <Label Key="traefik.frontend.rule.hostname">Host: #{HostName}#</Label>
            <Label Key="traefik.expose">true</Label>
            <Label Key="traefik.frontend.passHostHeader">true</Label>
          </Labels>
        </Extension>
      </Extensions>
    </StatelessServiceType>
  </ServiceTypes>

0
我认为在SF集群前面加入URL重写服务是个非常好的想法。
这可以让你拥有多个终点,并且可以进行URL重写、防火墙/黑名单、HTTPS等操作。
另一种方法是将该服务打包为库或Nuget,并使用不同的服务清单创建所需的N个服务。

好的,所以我们在服务织中创建了2个命名服务。Service1和Service2。现在,我该如何通过“ServiceProxy.Create”来负载均衡发送到Service1/Service2的请求呢? - Blue
不要使用ServiceProxy.Create,否则您需要理解它的2个服务的逻辑。如果您正在使用http,则大多数url重写网关都可以实现此功能,例如ngix。有一些关于蓝绿部署的内容,请参考https://blogs.msdn.microsoft.com/cloud_solution_architect/2016/10/17/bluegreen-deployments-in-service-fabric/。 - user1496062
你可能想要看一下Traefik https://blogs.msdn.microsoft.com/azureservicefabric/2018/04/05/intelligent-routing-on-service-fabric-with-traefik/ - E. Staal

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