云应用程序一般都须要使用前端网关,为用户、设备或其余应用程序提供同一个入口点。 在 Service Fabric 中,网关能够是任意无状态服务(如 ASP.NET Core 应用程序) 。html
本文介绍了如何将Ocelot用做 Service Fabric 应用程序的网关。Ocelot直接与 Service Fabric 集成,以即可以使用一组丰富的路由规则向后端 Service Fabric 服务发布 API。前端
架构git
常见 Service Fabric 体系结构使用单页 Web 应用程序,向公开 HTTP API 的后端服务发出 HTTP 调用请求。github
随着应用程序愈来愈复杂,必须向大量后端服务发布API的网关亦是如此。Ocelot旨在经过路由规则、访问控制、速率限制、监视、事件日志记录和响应缓存来处理复杂 API,最大限度地减小用户须要执行的操做。 Ocelot支持 Service Fabric 服务发现、分区解析和副本选择,从而智能地将请求直接路由到 Service Fabric 中的后端服务,用户无需编写本身的无状态 API 网关。web
应用程序方案shell
Service Fabric 中的服务能够是无状态服务,也能够是有状态服务,可采用如下三种方案之一进行分区:单独分区、Int64 范围分区和已命名分区。 必须肯定特定服务实例的具体分区,才能解析服务终结点。解析服务终结点时,必须指定服务实例名称(例如,fabric:/myapp/myservice)以及服务的具体分区,但单独分区状况除外。后端
Ocelot可与无状态服务、有状态服务和任何分区方案的任意组合配合使用。api
https://ocelot.readthedocs.io/en/latest/features/servicefabric.html缓存
若是您正在使用无状态/Guest服务,则ocelot将可以经过命名服务进行代理而无需其余任何操做。可是,若是您正在使用有状态服务/ actor服务,则必须使用客户端请求发送PartitionKind和PartitionKey查询字符串值。安全
如下示例展现如何设置一个ReRoute以便在在Service Fabric中工做。 最重要的是ServiceName,它由Service Fabric应用程序名称和特定服务名称组成的。 咱们还须要将UseServiceDiscovery设置为true,并在GlobalConfiguration中设置ServiceDiscoveryProvider。 这里的例子显示了一个典型的配置。 它假定Service Fabric在本地主机上运行,而且命名服务位于19081端口上。
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/values",
"UpstreamPathTemplate": "/servicea/api/values",
"UpstreamHttpMethod": [ "Get"],
"DownstreamScheme": "http",
"ServiceName": "NanoFabric_ServiceFabric/ServiceA",
"UseServiceDiscovery": true,
"AuthenticationOptions": {
"AuthenticationProviderKey": "apikey",
"AllowedScopes": []
},
"AddHeadersToRequest": {
"claims_City": "Claims[City] > value > |",
"claims_State": "Claims[State] > value > |"
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/{route}",
"UpstreamPathTemplate": "/serviceoauth/{route}",
"UpstreamHttpMethod": [ "Get", "Options", "Post" ],
"DownstreamScheme": "http",
"ServiceName": "NanoFabric_ServiceFabric/ServiceOAuth",
"UseServiceDiscovery": true
}
],
"GlobalConfiguration": {
"RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration",
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 19081,
"Type": "ServiceFabric"
}
}
}
原理就是借助 Service Fabric 中内置的反向代理,Service Fabric 群集中运行的微服务能够发现包含 http 终结点的其余服务,并与之通讯。
微服务通讯模型
Service Fabric 中的微服务在群集中的部分节点上运行,能够出于各类缘由在这些节点之间迁移。 所以,微服务的终结点可能会动态变化。 若要发现群集中的其余服务并与之通讯,微服务必须完成如下步骤:
l 经过命名服务解析服务位置。
l 链接到服务。
l 在实现服务解析以及在发生链接故障时应用的重试策略的循环中,包装上述步骤
使用反向代理通讯
反向代理是在每一个节点上运行的服务,用于表明客户端服务处理终结点解析、自动重试及其余链接故障。 能够将反向代理配置为,一边处理客户端服务的请求,一边应用各类策略。 借助反向代理,客户端服务可使用任意客户端 HTTP 通讯库,无需服务中有特殊的解析和重试逻辑。
反向代理在本地节点上公开一个或多个终结点,以供客户端服务用来向其余服务发送请求。
反向代理使用特定的统一资源标识符 (URI) 格式来识别传入请求应该转发到的服务分区:
http(s)://<Cluster FQDN | internal IP>:Port/<ServiceInstanceName>/<Suffix path>?PartitionKey=<key>&PartitionKind=<partitionkind>&ListenerName=<listenerName>&TargetReplicaSelector=<targetReplicaSelector>&Timeout=<timeout_in_seconds>
l http(s): 能够将反向代理配置为接受 HTTP 或 HTTPS 流量。 对于 HTTPS 转发,在设置反向代理侦听 HTTPS 后,请参阅使用反向代理链接到安全服务。
l 群集的彻底限定域名 (FQDN) | 内部 IP: 对于外部客户端,能够配置反向代理,以即可以经过群集域(例如 mycluster.eastus.cloudapp.azure.com)访问反向代理。 默认状况下,反向代理在每一个节点上运行。 对于内部流量,可在本地主机或任意内部节点 IP(例如 10.0.0.1)上访问反向代理。
l Port:为反向代理指定的端口,例如 19081。
l ServiceInstanceName: 在不使用“fabric:/”方案的状况下尝试访问的已部署服务实例的彻底限定名称。 例如,若要访问 fabric:/myapp/myservice/ 服务,可使用 myapp/myservice。
l 服务实例名称要区分大小写。 若 URL 中的服务实例名称大小写不一样,则会致使请求失败,并显示 404(未找到)。
l 后缀路径: 要链接到的服务的实际 URL 路径,例如 myapi/values/add/3。
l PartitionKey: 对于分区服务,这是针对要访问的分区计算出的分区键。 请注意,这不是分区 ID GUID。 对于使用单独分区方案的服务,此参数不是必需的。
l PartitionKind: 服务分区方案。 该方案能够是“Int64Range”或“Named”。 对于使用单独分区方案的服务,此参数不是必需的。
l ListenerName 服务中的终结点采用如下形式:{"Endpoints":{"Listener1":"Endpoint1","Listener2":"Endpoint2" ...}}。 当服务公开了多个终结点时,此参数标识应将客户端请求转发到的终结点。 若是服务只有一个侦听器,则能够省略此项。
l TargetReplicaSelector 这指定应当如何选择目标副本或实例。
l 当目标服务为有状态服务时,TargetReplicaSelector 能够是下列其中一项:“PrimaryReplica”、“RandomSecondaryReplica”或“RandomReplica”。 若是未指定此参数,默认值为“PrimaryReplica”。
l 当目标服务为无状态服务时,反向代理将选择服务分区的一个随机实例来将实例转发到其中。
l Timeout: 此参数指定反向代理针对服务建立的 HTTP 请求(表明客户端请求)的超时。 默认值为 60 秒。 这是一个可选参数
Ocelot充当微服务和外部客户端之间的网络边界,能够进行网络地址转换并将外部请求转发到内部的 IP:端口终结点。 要容许外部客户端直接访问微服务的终结点,必须先将Ocelot配置为将流量转发到群集中服务使用的每一个端口。 另外,大多数微服务(尤为是有状态微服务)并不驻留在群集的全部节点上。 这些微服务在故障转移时可在节点之间移动。 在这种状况下,负载均衡器没法有效肯定要将流量转发到的副本的目标节点位置。
能够在Ocelot中直接配置反向代理的端口,而无需配置单个服务的端口。 这种配置可以让群集外部的客户端使用反向代理访问群集内部的服务,无需通过额外的配置。
经过Ocelot可从群集外部访问群集中公开 HTTP 终结点的全部微服务。 这意味着微服务设计为内部的可能会被肯定的恶意用户发现。这潜在地提供可被利用的严重漏洞;例如:
恶意用户能够经过反复调用没有足够强化的攻击面的内部服务来发起拒绝服务攻击。
恶意用户可能会将格式错误的数据包传送到内部服务,从而致使意外行为。
设计为内部的服务可能会返回不该公开给群集外部的服务的私有或敏感信息,从而将此敏感信息泄露给恶意用户。在网关上开启身份认证、流控等措施来解决安全问题。
反向代理是一种可选的 Azure Service Fabric 服务,有助于在 Service Fabric 群集中运行的微服务发现包含 http 终结点的其余服务,并与之通讯,在建立新的 Service Fabric 群集时,Azure 门户提供了一个启用反向代理的选项。 没法经过门户升级现有群集来使用反向代理。
咱们的示例项目代码放在 https://github.com/geffzhang/NanoFabric-ServiceFabric ,解决方案中包含了一个后端服务ServiceA,是个无状态的服务,一个Ocelot 网关和一个Identity Server 4的认证服务,在网关上集成了IdentityServer4 的认证服务 ,由网关负责认证,认证完成将Claims 转换为HttpHeader 中转发到下游服务。
服务实例A是一个无状态的服务
咱们将其配置为运行2个实例。在Application Parameters中,我将* _InstanceCount参数值设置为2:
让Service Fabric选择端口,咱们将从端点中删除该Port
属性:
当开发机器上的没法实如今同一端口上运行多个实例,若是填写了Port 属性,_InstanceCount只能保持为1. 让端口保持动态,咱们能够在本地实现服务的伸缩。
部署本身的网关这听起来像是须要作不少工做,实际上很是简单。咱们须要与反向代理相同的行为,只须要更多的控制。在咱们这个开源的开发的世界,这个问题已经解决了,咱们有开源的API网关Ocelot http://threemammals.com/ocelot ,并且作得很是好,能够完美的和Service Fabric 一块儿工做。
咱们将添加一个新的空aspnet core无状态服务
让咱们配置咱们的端点。您须要知道咱们的网关在哪里,因此咱们给它一个特定的端口。在ServiceManifest中,设置端点的端口:
<Endpoint Protocol="http" Name="ServiceEndpoint" Type="Input" Port="8492" />
网关是系统的入口点,必须保持可用状态。咱们在每一个节点上部署它。修改ApplicationParameters中添加的参数NanoFabricGateway_InstanceCount。确保生产部署的值为-1。
<Parameter Name="NanoFabricGateway_InstanceCount" Value="-1"/>
请注意,若是部署到本地群集,则没法在同一端口上运行多个服务实例。对于本地开发群集,要么将其保留为1,要么让端口为动态。
代码实现上并无什么特殊的地方。
固然,没有人想经过端口访问您的网站8492。接下来,咱们须要设置负载均衡器以指向咱们新部署的网关。在部署在azure上的新集群(能够参考这篇文章使用Powershell https://noelbundick.com/posts/service-fabric-cluster-quickstart/ ),现有AppPortLBRule1端口80。编辑它,并将后端端口更改成指向网关端口:8492在个人状况下。同时请注意,Load Balancer定义了一个Health Probe。若是健康检测未成功,则负载均衡器将假定后端服务池不健康,而且不会重定向您的请求。
参考文章:
https://docs.microsoft.com/zh-cn/azure/service-fabric/service-fabric-api-management-overview
https://ocelot.readthedocs.io/en/latest/features/servicefabric.html