feat: Kubernetes ServiceDiscoveryProvider

This commit is contained in:
geffzhang
2019-01-13 19:23:12 +08:00
parent 08c2ac1b05
commit 3525fda8ad
14 changed files with 215 additions and 5 deletions

View 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);
}
}

View 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);
}
}
}

View 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>());
}
}
}

View 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; }
}
}

View 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;
};
}
}

View File

@ -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>

View 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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}