mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 14:58:16 +08:00
kubernetes provider (#772)
* feat: Kubernetes ServiceDiscoveryProvider * 编写k8s测试例子 * feat:fix kube config * feat: remove port * feat : complete the k8s test * feat : add kubeserviceDiscovery test * feat : add kube provider unittest * feat :add kubetnetes docs how to use ocelot with kubetnetes docs * keep the configuration as simple as possible, no qos, no cache * fix: use http * add PollingKubeServiceDiscovery * feat : refactor logger * feat : add pollkube docs * feat:Remove unnecessary code * feat : code-block json
This commit is contained in:

committed by
Marcelo Castagna

parent
05ede70e62
commit
44dccf1fce
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);
|
||||
}
|
||||
}
|
||||
}
|
63
src/Ocelot.Provider.Kubernetes/KubeProvider.cs
Normal file
63
src/Ocelot.Provider.Kubernetes/KubeProvider.cs
Normal file
@ -0,0 +1,63 @@
|
||||
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 Kube : IServiceDiscoveryProvider
|
||||
{
|
||||
private KubeRegistryConfiguration kubeRegistryConfiguration;
|
||||
private IOcelotLogger logger;
|
||||
private IKubeApiClient kubeApi;
|
||||
|
||||
public Kube(KubeRegistryConfiguration kubeRegistryConfiguration, IOcelotLoggerFactory factory, IKubeApiClientFactory kubeClientFactory)
|
||||
{
|
||||
this.kubeRegistryConfiguration = kubeRegistryConfiguration;
|
||||
this.logger = factory.CreateLogger<Kube>();
|
||||
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));
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning($"namespace:{kubeRegistryConfiguration.KubeNamespace }service:{kubeRegistryConfiguration.KeyOfServiceInK8s} Unable to use ,it is invalid. Address must contain host only e.g. localhost and port must be greater than 0");
|
||||
}
|
||||
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; }
|
||||
}
|
||||
}
|
38
src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs
Normal file
38
src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs
Normal file
@ -0,0 +1,38 @@
|
||||
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>();
|
||||
return GetkubeProvider(provider, config, name, factory);
|
||||
};
|
||||
|
||||
private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetkubeProvider(IServiceProvider provider, Configuration.ServiceProviderConfiguration config, string name, IOcelotLoggerFactory factory)
|
||||
{
|
||||
var kubeClientFactory = provider.GetService<IKubeApiClientFactory>();
|
||||
var k8sRegistryConfiguration = new KubeRegistryConfiguration()
|
||||
{
|
||||
ApiEndPoint = new Uri($"https://{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 Kube(k8sRegistryConfiguration, factory, kubeClientFactory);
|
||||
if (config.Type?.ToLower() == "pollkube")
|
||||
{
|
||||
return new PollKube(config.PollingInterval, factory, k8sServiceDiscoveryProvider);
|
||||
}
|
||||
return k8sServiceDiscoveryProvider;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="KubeClient" Version="2.2.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
15
src/Ocelot.Provider.Kubernetes/OcelotBuilderExtensions.cs
Normal file
15
src/Ocelot.Provider.Kubernetes/OcelotBuilderExtensions.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.DependencyInjection;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
50
src/Ocelot.Provider.Kubernetes/PollKube.cs
Normal file
50
src/Ocelot.Provider.Kubernetes/PollKube.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Ocelot.Values;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ocelot.Provider.Kubernetes
|
||||
{
|
||||
public class PollKube : IServiceDiscoveryProvider
|
||||
{
|
||||
private readonly IOcelotLogger _logger;
|
||||
private readonly IServiceDiscoveryProvider _kubeServiceDiscoveryProvider;
|
||||
private readonly Timer _timer;
|
||||
private bool _polling;
|
||||
private List<Service> _services;
|
||||
|
||||
public PollKube(int pollingInterval, IOcelotLoggerFactory factory, IServiceDiscoveryProvider kubeServiceDiscoveryProvider)
|
||||
{
|
||||
_logger = factory.CreateLogger<PollKube>();
|
||||
_kubeServiceDiscoveryProvider = kubeServiceDiscoveryProvider;
|
||||
_services = new List<Service>();
|
||||
|
||||
_timer = new Timer(async x =>
|
||||
{
|
||||
if (_polling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_polling = true;
|
||||
await Poll();
|
||||
_polling = false;
|
||||
}, null, pollingInterval, pollingInterval);
|
||||
}
|
||||
|
||||
public Task<List<Service>> Get()
|
||||
{
|
||||
return Task.FromResult(_services);
|
||||
}
|
||||
|
||||
private async Task Poll()
|
||||
{
|
||||
_services = await _kubeServiceDiscoveryProvider.Get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ namespace Ocelot.Configuration.Builder
|
||||
private string _token;
|
||||
private string _configurationKey;
|
||||
private int _pollingInterval;
|
||||
private string _namespace;
|
||||
|
||||
public ServiceProviderConfigurationBuilder WithHost(string serviceDiscoveryProviderHost)
|
||||
{
|
||||
@ -45,9 +46,15 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServiceProviderConfigurationBuilder WithNamesapce(string @namesapce)
|
||||
{
|
||||
_namespace = @namesapce;
|
||||
return this;
|
||||
}
|
||||
|
||||
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
|
||||
: "consul";
|
||||
var pollingInterval = globalConfiguration?.ServiceDiscoveryProvider?.PollingInterval ?? 0;
|
||||
var k8snamesapce = globalConfiguration?.ServiceDiscoveryProvider?.Namespace ?? string.Empty;
|
||||
|
||||
return new ServiceProviderConfigurationBuilder()
|
||||
.WithHost(host)
|
||||
@ -21,6 +22,7 @@ namespace Ocelot.Configuration.Creator
|
||||
.WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
|
||||
.WithConfigurationKey(globalConfiguration?.ServiceDiscoveryProvider?.ConfigurationKey)
|
||||
.WithPollingInterval(pollingInterval)
|
||||
.WithNamesapce(k8snamesapce)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
|
@ -8,5 +8,6 @@ namespace Ocelot.Configuration.File
|
||||
public string Token { get; set; }
|
||||
public string ConfigurationKey { get; set; }
|
||||
public int PollingInterval { get; set; }
|
||||
public string Namespace { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
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;
|
||||
Host = host;
|
||||
@ -10,13 +10,21 @@
|
||||
Token = token;
|
||||
Type = type;
|
||||
PollingInterval = pollingInterval;
|
||||
Namesapce = @namespace;
|
||||
}
|
||||
|
||||
public string Host { get; }
|
||||
|
||||
public int Port { get; }
|
||||
|
||||
public string Type { get; }
|
||||
|
||||
public string Token { get; }
|
||||
|
||||
public string ConfigurationKey { get; }
|
||||
|
||||
public int PollingInterval { get; }
|
||||
|
||||
public string Namesapce { get; }
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user