mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
feat: Kubernetes ServiceDiscoveryProvider
This commit is contained in:
parent
08c2ac1b05
commit
3525fda8ad
@ -56,6 +56,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Provider.Rafty", "sr
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Tracing.Butterfly", "src\Ocelot.Tracing.Butterfly\Ocelot.Tracing.Butterfly.csproj", "{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Tracing.Butterfly", "src\Ocelot.Tracing.Butterfly\Ocelot.Tracing.Butterfly.csproj", "{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ocelot.Provider.Kubernetes", "src\Ocelot.Provider.Kubernetes\Ocelot.Provider.Kubernetes.csproj", "{72C8E528-B4F5-45CE-8A06-CD3787364856}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -114,6 +116,10 @@ Global
|
|||||||
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{72C8E528-B4F5-45CE-8A06-CD3787364856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{72C8E528-B4F5-45CE-8A06-CD3787364856}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{72C8E528-B4F5-45CE-8A06-CD3787364856}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{72C8E528-B4F5-45CE-8A06-CD3787364856}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -132,6 +138,7 @@ Global
|
|||||||
{1F6E5DCF-8A2E-4E24-A25D-064362DE8D0E} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
|
{1F6E5DCF-8A2E-4E24-A25D-064362DE8D0E} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
|
||||||
{AC153C67-EF18-47E6-A230-F0D3CF5F0A98} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
|
{AC153C67-EF18-47E6-A230-F0D3CF5F0A98} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
|
||||||
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
|
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
|
||||||
|
{72C8E528-B4F5-45CE-8A06-CD3787364856} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48}
|
SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48}
|
||||||
|
12
src/Ocelot.Provider.Kubernetes/IKubeApiClientFactory.cs
Normal file
12
src/Ocelot.Provider.Kubernetes/IKubeApiClientFactory.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using KubeClient;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ocelot.Provider.Kubernetes
|
||||||
|
{
|
||||||
|
public interface IKubeApiClientFactory
|
||||||
|
{
|
||||||
|
IKubeApiClient Get(KubeRegistryConfiguration config);
|
||||||
|
}
|
||||||
|
}
|
22
src/Ocelot.Provider.Kubernetes/KubeApiClientFactory.cs
Normal file
22
src/Ocelot.Provider.Kubernetes/KubeApiClientFactory.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using KubeClient;
|
||||||
|
|
||||||
|
namespace Ocelot.Provider.Kubernetes
|
||||||
|
{
|
||||||
|
public class KubeApiClientFactory : IKubeApiClientFactory
|
||||||
|
{
|
||||||
|
public IKubeApiClient Get(KubeRegistryConfiguration config)
|
||||||
|
{
|
||||||
|
var option = new KubeClientOptions
|
||||||
|
{
|
||||||
|
ApiEndPoint = config.ApiEndPoint
|
||||||
|
};
|
||||||
|
if(!string.IsNullOrEmpty(config?.AccessToken))
|
||||||
|
{
|
||||||
|
option.AccessToken = config.AccessToken;
|
||||||
|
option.AuthStrategy = config.AuthStrategy;
|
||||||
|
option.AllowInsecure = config.AllowInsecure;
|
||||||
|
}
|
||||||
|
return KubeApiClient.Create(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
src/Ocelot.Provider.Kubernetes/KubeProvider.cs
Normal file
59
src/Ocelot.Provider.Kubernetes/KubeProvider.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using KubeClient;
|
||||||
|
using KubeClient.Models;
|
||||||
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.ServiceDiscovery.Providers;
|
||||||
|
using Ocelot.Values;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ocelot.Provider.Kubernetes
|
||||||
|
{
|
||||||
|
public class KubeProvider : IServiceDiscoveryProvider
|
||||||
|
{
|
||||||
|
private KubeRegistryConfiguration kubeRegistryConfiguration;
|
||||||
|
private IOcelotLoggerFactory factory;
|
||||||
|
private IKubeApiClient kubeApi;
|
||||||
|
private IKubeApiClientFactory kubeClientFactory;
|
||||||
|
|
||||||
|
public KubeProvider(KubeRegistryConfiguration kubeRegistryConfiguration, IOcelotLoggerFactory factory, IKubeApiClientFactory kubeClientFactory)
|
||||||
|
{
|
||||||
|
this.kubeRegistryConfiguration = kubeRegistryConfiguration;
|
||||||
|
this.factory = factory;
|
||||||
|
this.kubeApi = kubeClientFactory.Get(kubeRegistryConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Service>> Get()
|
||||||
|
{
|
||||||
|
var service = await kubeApi.ServicesV1().Get(kubeRegistryConfiguration.KeyOfServiceInK8s, kubeRegistryConfiguration.KubeNamespace);
|
||||||
|
var services = new List<Service>();
|
||||||
|
if (IsValid(service))
|
||||||
|
{
|
||||||
|
services.Add(BuildService(service));
|
||||||
|
}
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValid(ServiceV1 service)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(service.Spec.ClusterIP) || service.Spec.Ports.Count <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Service BuildService(ServiceV1 serviceEntry)
|
||||||
|
{
|
||||||
|
var servicePort = serviceEntry.Spec.Ports.FirstOrDefault();
|
||||||
|
return new Service(
|
||||||
|
serviceEntry.Metadata.Name,
|
||||||
|
new ServiceHostAndPort(serviceEntry.Spec.ClusterIP, servicePort.Port),
|
||||||
|
serviceEntry.Metadata.Uid,
|
||||||
|
string.Empty,
|
||||||
|
Enumerable.Empty<string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
src/Ocelot.Provider.Kubernetes/KubeRegistryConfiguration.cs
Normal file
22
src/Ocelot.Provider.Kubernetes/KubeRegistryConfiguration.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using KubeClient;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ocelot.Provider.Kubernetes
|
||||||
|
{
|
||||||
|
public class KubeRegistryConfiguration
|
||||||
|
{
|
||||||
|
public Uri ApiEndPoint { get; set; }
|
||||||
|
|
||||||
|
public string KubeNamespace { get; set; }
|
||||||
|
|
||||||
|
public string KeyOfServiceInK8s { get; set; }
|
||||||
|
|
||||||
|
public KubeAuthStrategy AuthStrategy { get; set; }
|
||||||
|
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
|
||||||
|
public bool AllowInsecure { get; set; }
|
||||||
|
}
|
||||||
|
}
|
31
src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs
Normal file
31
src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using KubeClient;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.ServiceDiscovery;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ocelot.Provider.Kubernetes
|
||||||
|
{
|
||||||
|
public static class KubernetesProviderFactory
|
||||||
|
{
|
||||||
|
public static ServiceDiscoveryFinderDelegate Get = (provider, config, name) =>
|
||||||
|
{
|
||||||
|
var factory = provider.GetService<IOcelotLoggerFactory>();
|
||||||
|
|
||||||
|
var kubeClientFactory = provider.GetService<IKubeApiClientFactory>();
|
||||||
|
|
||||||
|
var k8sRegistryConfiguration = new KubeRegistryConfiguration() {
|
||||||
|
ApiEndPoint = new Uri($"http://{config.Host}:{config.Port}"),
|
||||||
|
KeyOfServiceInK8s = name,
|
||||||
|
KubeNamespace = config.Namesapce,
|
||||||
|
AuthStrategy = KubeAuthStrategy.BearerToken,
|
||||||
|
AccessToken = config.Token,
|
||||||
|
AllowInsecure = true // Don't validate server certificate
|
||||||
|
};
|
||||||
|
|
||||||
|
var k8sServiceDiscoveryProvider = new KubeProvider(k8sRegistryConfiguration, factory, kubeClientFactory);
|
||||||
|
|
||||||
|
return k8sServiceDiscoveryProvider;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="KubeClient" Version="2.2.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
20
src/Ocelot.Provider.Kubernetes/OcelotBuilderExtensions.cs
Normal file
20
src/Ocelot.Provider.Kubernetes/OcelotBuilderExtensions.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using KubeClient;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Ocelot.DependencyInjection;
|
||||||
|
using Ocelot.ServiceDiscovery;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ocelot.Provider.Kubernetes
|
||||||
|
{
|
||||||
|
public static class OcelotBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IOcelotBuilder AddKubernetes(this IOcelotBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton(KubernetesProviderFactory.Get);
|
||||||
|
builder.Services.AddSingleton<IKubeApiClientFactory, KubeApiClientFactory>();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
private string _token;
|
private string _token;
|
||||||
private string _configurationKey;
|
private string _configurationKey;
|
||||||
private int _pollingInterval;
|
private int _pollingInterval;
|
||||||
|
private string _namespace;
|
||||||
|
|
||||||
public ServiceProviderConfigurationBuilder WithHost(string serviceDiscoveryProviderHost)
|
public ServiceProviderConfigurationBuilder WithHost(string serviceDiscoveryProviderHost)
|
||||||
{
|
{
|
||||||
@ -45,9 +46,15 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ServiceProviderConfigurationBuilder WithNamesapce(string @namesapce)
|
||||||
|
{
|
||||||
|
_namespace = @namesapce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ServiceProviderConfiguration Build()
|
public ServiceProviderConfiguration Build()
|
||||||
{
|
{
|
||||||
return new ServiceProviderConfiguration(_type, _serviceDiscoveryProviderHost, _serviceDiscoveryProviderPort, _token, _configurationKey, _pollingInterval);
|
return new ServiceProviderConfiguration(_type, _serviceDiscoveryProviderHost, _serviceDiscoveryProviderPort, _token, _configurationKey, _pollingInterval, _namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
? globalConfiguration?.ServiceDiscoveryProvider?.Type
|
? globalConfiguration?.ServiceDiscoveryProvider?.Type
|
||||||
: "consul";
|
: "consul";
|
||||||
var pollingInterval = globalConfiguration?.ServiceDiscoveryProvider?.PollingInterval ?? 0;
|
var pollingInterval = globalConfiguration?.ServiceDiscoveryProvider?.PollingInterval ?? 0;
|
||||||
|
var k8snamesapce = globalConfiguration?.ServiceDiscoveryProvider?.Namespace ?? string.Empty;
|
||||||
|
|
||||||
return new ServiceProviderConfigurationBuilder()
|
return new ServiceProviderConfigurationBuilder()
|
||||||
.WithHost(host)
|
.WithHost(host)
|
||||||
@ -21,6 +22,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
.WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
|
.WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
|
||||||
.WithConfigurationKey(globalConfiguration?.ServiceDiscoveryProvider?.ConfigurationKey)
|
.WithConfigurationKey(globalConfiguration?.ServiceDiscoveryProvider?.ConfigurationKey)
|
||||||
.WithPollingInterval(pollingInterval)
|
.WithPollingInterval(pollingInterval)
|
||||||
|
.WithNamesapce(k8snamesapce)
|
||||||
.Build();
|
.Build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,6 @@ namespace Ocelot.Configuration.File
|
|||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
public string ConfigurationKey { get; set; }
|
public string ConfigurationKey { get; set; }
|
||||||
public int PollingInterval { get; set; }
|
public int PollingInterval { get; set; }
|
||||||
|
public string Namespace { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class ServiceProviderConfiguration
|
public class ServiceProviderConfiguration
|
||||||
{
|
{
|
||||||
public ServiceProviderConfiguration(string type, string host, int port, string token, string configurationKey, int pollingInterval)
|
public ServiceProviderConfiguration(string type, string host, int port, string token, string configurationKey, int pollingInterval, string @namespace = "")
|
||||||
{
|
{
|
||||||
ConfigurationKey = configurationKey;
|
ConfigurationKey = configurationKey;
|
||||||
Host = host;
|
Host = host;
|
||||||
@ -10,13 +10,21 @@
|
|||||||
Token = token;
|
Token = token;
|
||||||
Type = type;
|
Type = type;
|
||||||
PollingInterval = pollingInterval;
|
PollingInterval = pollingInterval;
|
||||||
|
Namesapce = @namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Host { get; }
|
public string Host { get; }
|
||||||
|
|
||||||
public int Port { get; }
|
public int Port { get; }
|
||||||
|
|
||||||
public string Type { get; }
|
public string Type { get; }
|
||||||
|
|
||||||
public string Token { get; }
|
public string Token { get; }
|
||||||
|
|
||||||
public string ConfigurationKey { get; }
|
public string ConfigurationKey { get; }
|
||||||
|
|
||||||
public int PollingInterval { get; }
|
public int PollingInterval { get; }
|
||||||
|
|
||||||
|
public string Namesapce { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,8 @@
|
|||||||
Host = "localhost",
|
Host = "localhost",
|
||||||
Port = consulPort,
|
Port = consulPort,
|
||||||
Type = "PollConsul",
|
Type = "PollConsul",
|
||||||
PollingInterval = 0
|
PollingInterval = 0,
|
||||||
|
Namespace = string.Empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,8 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
Port = 1234,
|
Port = 1234,
|
||||||
Type = "ServiceFabric",
|
Type = "ServiceFabric",
|
||||||
Token = "testtoken",
|
Token = "testtoken",
|
||||||
ConfigurationKey = "woo"
|
ConfigurationKey = "woo",
|
||||||
|
Namespace ="default"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,6 +41,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.WithType("ServiceFabric")
|
.WithType("ServiceFabric")
|
||||||
.WithToken("testtoken")
|
.WithToken("testtoken")
|
||||||
.WithConfigurationKey("woo")
|
.WithConfigurationKey("woo")
|
||||||
|
.WithNamesapce("default")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenTheFollowingGlobalConfig(globalConfig))
|
this.Given(x => x.GivenTheFollowingGlobalConfig(globalConfig))
|
||||||
@ -64,6 +66,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
_result.Port.ShouldBe(expected.Port);
|
_result.Port.ShouldBe(expected.Port);
|
||||||
_result.Token.ShouldBe(expected.Token);
|
_result.Token.ShouldBe(expected.Token);
|
||||||
_result.Type.ShouldBe(expected.Type);
|
_result.Type.ShouldBe(expected.Type);
|
||||||
|
_result.Namesapce.ShouldBe(expected.Namesapce);
|
||||||
_result.ConfigurationKey.ShouldBe(expected.ConfigurationKey);
|
_result.ConfigurationKey.ShouldBe(expected.ConfigurationKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user