具有配置覆盖的 Service Fabric 多个服务实例
Service Fabric Multiple service instances with config override
我们的服务结构应用程序包括一个无状态服务,该服务通过 OwinCommunicationListener
.
公开一个 HTTP 端点
此服务的 ServiceManifest.Xml 指定服务端点 <Endpoint Name="ServiceEndpoint" Type="Input" Protocol="http" Port="8090" />
然后可以在 http://localhost:8090/
上通过浏览器访问无状态服务
我们要做的是通过 ApplicationManifest 在同一 Service Fabric 应用程序的不同端点上实例化该服务的多个实例。
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 错误
如何让服务实例监听不同的端口?
我希望你明白了,谢谢。
实现此目的的好选择不多。以下是一些想法:
- 创建多个应用程序实例,而不是在一个应用程序中创建多个相同类型的服务。这将允许您使用应用程序参数来配置特定服务的行为。
- 在您的服务类型中创建多个配置包。每个配置包都将用于其中一个服务实例。确定服务实例分配给哪个配置包需要是动态的,可能基于服务实例的名称?当然,这不是一个很好的选择,因为它将服务定义与将要创建的实例数量结合在一起。
- 自定义配置实现。也许让您的服务公开一个端点,允许您配置它 post-deployment。或者让服务调用在激活时提供其配置的其他管理服务。
您也可以让 Service Fabric 自动分配端口,然后使用 Service Fabric 自带的反向代理。
我认为在 SF 集群前有一个 url 重写服务是个好主意。
这可以为您提供多个端点并进行 url 重写、防火墙/黑名单、https 等。
其他方法是将服务打包为 lib 或 Nuget 并使用不同的服务清单创建您需要的 N 个服务。
我已经设法使用 ApplicationParameter xml 文件做到了这一点,并在 VSTS 中部署期间选择了正确的文件。
例如,这是我用于部署到我的测试环境的 Cloud.xml。诀窍是第二行的 Name 参数。我已经使用此文档指定了端口:https://docs.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>
这是用于暂存的 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 反向代理 here 我可以使用主机名来访问我的服务。
在 VSTS 中,我使用标记器在部署期间替换 ServiceManifest 中的主机名并替换 ApplicationManifest 中的 ApplicationTypeName。
这是我的服务清单:
<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>
我们的服务结构应用程序包括一个无状态服务,该服务通过 OwinCommunicationListener
.
此服务的 ServiceManifest.Xml 指定服务端点 <Endpoint Name="ServiceEndpoint" Type="Input" Protocol="http" Port="8090" />
然后可以在 http://localhost:8090/
上通过浏览器访问无状态服务我们要做的是通过 ApplicationManifest 在同一 Service Fabric 应用程序的不同端点上实例化该服务的多个实例。
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 错误如何让服务实例监听不同的端口?
我希望你明白了,谢谢。
实现此目的的好选择不多。以下是一些想法:
- 创建多个应用程序实例,而不是在一个应用程序中创建多个相同类型的服务。这将允许您使用应用程序参数来配置特定服务的行为。
- 在您的服务类型中创建多个配置包。每个配置包都将用于其中一个服务实例。确定服务实例分配给哪个配置包需要是动态的,可能基于服务实例的名称?当然,这不是一个很好的选择,因为它将服务定义与将要创建的实例数量结合在一起。
- 自定义配置实现。也许让您的服务公开一个端点,允许您配置它 post-deployment。或者让服务调用在激活时提供其配置的其他管理服务。
您也可以让 Service Fabric 自动分配端口,然后使用 Service Fabric 自带的反向代理。
我认为在 SF 集群前有一个 url 重写服务是个好主意。
这可以为您提供多个端点并进行 url 重写、防火墙/黑名单、https 等。
其他方法是将服务打包为 lib 或 Nuget 并使用不同的服务清单创建您需要的 N 个服务。
我已经设法使用 ApplicationParameter xml 文件做到了这一点,并在 VSTS 中部署期间选择了正确的文件。 例如,这是我用于部署到我的测试环境的 Cloud.xml。诀窍是第二行的 Name 参数。我已经使用此文档指定了端口:https://docs.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>
这是用于暂存的 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 反向代理 here 我可以使用主机名来访问我的服务。 在 VSTS 中,我使用标记器在部署期间替换 ServiceManifest 中的主机名并替换 ApplicationManifest 中的 ApplicationTypeName。
这是我的服务清单:
<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>