mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +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