序言
准備寫這一個系列也挺久了,但一直未動手,一方面自身積累不足,另一方面也不知從何處下手。直到最近稍微得空一些,另一方面也有一些新的體驗。
在此純粹作為自己個人的一個回顧記錄吧。正所謂好記性不如爛筆頭么。
總覽
目前規划的整個微服務體系分為三層。
最外面一層就是Ocelot,負責路由轉發,統一認證、限流熔斷等。
然后第二層是各個應用服務,也可以說是聚合服務,webapi形式對外提供接口能力,支撐PC、H5、APP等。
最后面一層就是基於領域驅動划分的各個小的服務,grpc形式互相調用。
但是目前來說其實只做到第一層、第二層。有項目工期很緊的原因,但最主要還是業務場景不夠熟悉。這一次才體會到拋開業務場景,談微服務的話,有點兒耍流氓。
尤其在做微服務拆分的時候相當痛苦,沒有領域專家參與,拆分過程相當痛苦,后來只能做更多的妥協。后續再專門開一篇講一講,回歸正題了。
准備工作
我使用的是Ocelot最新版本,園子里也有關於Ocelot集成K8s的分享,但是最新的Ocelot版本,在集成k8s的過程中,還是存在一些問題的。
下面簡單講述一下具體的操作步驟了。
(1)根據Oclelot版本,引入對應的K8s Provider。我這里因為用的是最新版本的Ocelot,所以直接選用最新版的K8s Provider。

(2)在StartUp類的ConfigureService方法中添加以下代碼:
services.AddOcelot()
.AddPolly()
.AddKubernetes();
(3)配置文件中,配置k8s支持。在最新版中,已經不需要配置Host、Port、Token信息。只需配置好k8s服務對應的命名空間即可。
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/values",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/values",
"ServiceName": "testapiservice",
"UpstreamHttpMethod": [ "Get" ]
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Namespace": "dev",
"Type": "kube"
}
}
(4)ocelot中通過k8s服務名轉發,具體的實現機制就是通過KubeClient這個K8s的C#語言客戶端。具體信息在張隊的博客中已經有介紹。因為我們的ocelot網關最終也是運行在pod中的,
在pod中通過api訪問集群服務,是需要經過k8s內部認證的。我們可以通過給serviceaccount進行授權,來解決認證問題。關於k8s中的serviceaccount概念就不多展開了。
在k8s集群節點中執行以下命令:
kubectl create clusterrolebinding permissive-binding –clusterrole=cluster-admin –user=admin –user=kubelet –group=system:serviceaccounts
至此,本來可以開開心心的部署服務,愉快的進行路由轉發了。嗯,等會兒,Unable to find service discovery provider for type: kube。嗯哼,這是個什么鬼,心態爆炸有木有!!!
解決辦法
一開始,我以為是配置問題,然后又覺着是k8s的問題。一通嘗試無果,后來,通過在ocelot的issues中尋找到解決方案。原來這是ocelot最新版本的bug,通過以下擴展代碼可修復。
官方也注意到這個問題,應該也會在后續的版本更新中修復掉。
public static class OcelotBuilderExtensions
{
private static readonly ServiceDiscoveryFinderDelegate FixedKubernetesProviderFactoryGet = (provider, config, reroute) =>
{
var serviceDiscoveryProvider = KubernetesProviderFactory.Get(provider, config, reroute);
if (serviceDiscoveryProvider is KubernetesServiceDiscoveryProvider)
{
serviceDiscoveryProvider = new Kube(serviceDiscoveryProvider);
}
else if (serviceDiscoveryProvider is PollKubernetes)
{
serviceDiscoveryProvider = new PollKube(serviceDiscoveryProvider);
}
return serviceDiscoveryProvider;
};
public static IOcelotBuilder AddKubernetesFixed(this IOcelotBuilder builder, bool usePodServiceAccount = true)
{
builder.Services.AddSingleton(FixedKubernetesProviderFactoryGet);
builder.Services.AddKubeClient(usePodServiceAccount);
return builder;
}
private class Kube : IServiceDiscoveryProvider
{
private readonly IServiceDiscoveryProvider serviceDiscoveryProvider;
public Kube(IServiceDiscoveryProvider serviceDiscoveryProvider)
{
this.serviceDiscoveryProvider = serviceDiscoveryProvider;
}
public Task<List<Service>> Get()
{
return this.serviceDiscoveryProvider.Get();
}
}
private class PollKube : IServiceDiscoveryProvider
{
private readonly IServiceDiscoveryProvider serviceDiscoveryProvider;
public PollKube(IServiceDiscoveryProvider serviceDiscoveryProvider)
{
this.serviceDiscoveryProvider = serviceDiscoveryProvider;
}
public Task<List<Service>> Get()
{
return this.serviceDiscoveryProvider.Get();
}
}
}
添加此擴展代碼后,在我們上述步驟中的:AddKubernetes() 需替換成AddKubernetesFixed()
至此,終於可以在k8s中愉快的使用ocelot了。
尾聲
ocelot第一階段的工作可以說是完成了。但在整個體系中,網關還需集成認證。認證我使用的是ids4,在請求到達網關時,直接在網關層進行認證,認證通過后再轉發到下游服務。
所以第二階段是需配置ocelot集成ids4.
然后因為我的所有服務都是通過apollo來進行配置的,而且打包成鏡像后,在通過修改json文件來修改配置也實在繁瑣。
所以第三階段就是ocelot使用apollo來進行配置管理。
