Files
flagger/pkg/router/factory.go
Samuel Lang ca14a08f9c Skipper Router Implementation
Router implementation for zalan.do/Skipper Ingress -
An HTTP router and reverse proxy for service composition, including use cases like Kubernetes Ingress

https://github.com/zalando/skipper/

* The concept is to define routes with specific weights via the skipper specific annotation predicate of "zalando.org/backend-weights".
* A new "canary ingress" is created that has higher "weight" thus receiving all traffic, which distributes progressively
* After the canary process is finished, this ingress is disabled via the "False()" annotation predicate to route traffic again back to the apex Ingress.
There are certain Skipper principles which are taken into account:

```
Skipper Principles:
* if only one backend has a weight, only one backend will get 100% traffic
* if two of three or more backends have a weight, only those two should get traffic.
* if two backends don't have any weight, it's undefined and right now they get equal amount of traffic.
* weights can be int or float, but always treated as a ratio.

Implementation:
* apex Ingress is immutable
* new canary Ingress contains two paths for primary and canary service
* canary Ingress manages weights on primary & canary service, hence no traffic to apex service
```
2020-08-17 08:23:38 +02:00

141 lines
4.4 KiB
Go

package router
import (
"strings"
"go.uber.org/zap"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1"
clientset "github.com/weaveworks/flagger/pkg/client/clientset/versioned"
)
type Factory struct {
kubeConfig *restclient.Config
kubeClient kubernetes.Interface
meshClient clientset.Interface
flaggerClient clientset.Interface
ingressAnnotationsPrefix string
ingressClass string
logger *zap.SugaredLogger
}
func NewFactory(kubeConfig *restclient.Config, kubeClient kubernetes.Interface,
flaggerClient clientset.Interface,
ingressAnnotationsPrefix string,
ingressClass string,
logger *zap.SugaredLogger,
meshClient clientset.Interface) *Factory {
return &Factory{
kubeConfig: kubeConfig,
meshClient: meshClient,
kubeClient: kubeClient,
flaggerClient: flaggerClient,
ingressAnnotationsPrefix: ingressAnnotationsPrefix,
ingressClass: ingressClass,
logger: logger,
}
}
// KubernetesRouter returns a KubernetesRouter interface implementation
func (factory *Factory) KubernetesRouter(kind string, labelSelector string, ports map[string]int32) KubernetesRouter {
switch kind {
case "Service":
return &KubernetesNoopRouter{}
default: // Daemonset or Deployment
return &KubernetesDefaultRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
labelSelector: labelSelector,
ports: ports,
}
}
}
// MeshRouter returns a service mesh router
func (factory *Factory) MeshRouter(provider string, labelSelector string) Interface {
switch {
case strings.HasPrefix(provider, flaggerv1.AppMeshProvider+":v1beta2"):
return &AppMeshv1beta2Router{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
appmeshClient: factory.meshClient,
labelSelector: labelSelector,
}
case provider == flaggerv1.AppMeshProvider:
return &AppMeshRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
appmeshClient: factory.meshClient,
}
case provider == flaggerv1.LinkerdProvider:
return &SmiRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
smiClient: factory.meshClient,
targetMesh: flaggerv1.LinkerdProvider,
}
case provider == flaggerv1.IstioProvider:
return &IstioRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
istioClient: factory.meshClient,
}
case strings.HasPrefix(provider, flaggerv1.SMIProvider):
mesh := strings.TrimPrefix(provider, flaggerv1.SMIProvider+":")
return &SmiRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
smiClient: factory.meshClient,
targetMesh: mesh,
}
case provider == flaggerv1.ContourProvider:
return &ContourRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
contourClient: factory.meshClient,
ingressClass: factory.ingressClass,
}
case strings.HasPrefix(provider, flaggerv1.GlooProvider):
upstreamDiscoveryNs := flaggerv1.GlooProvider + "-system"
if strings.HasPrefix(provider, flaggerv1.GlooProvider+":") {
upstreamDiscoveryNs = strings.TrimPrefix(provider, flaggerv1.GlooProvider+":")
}
return &GlooRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
glooClient: factory.meshClient,
upstreamDiscoveryNs: upstreamDiscoveryNs,
}
case provider == flaggerv1.NGINXProvider:
return &IngressRouter{
logger: factory.logger,
kubeClient: factory.kubeClient,
annotationsPrefix: factory.ingressAnnotationsPrefix,
}
case provider == flaggerv1.SkipperProvider:
return &SkipperRouter{
logger: factory.logger,
kubeClient: factory.kubeClient,
}
case provider == flaggerv1.KubernetesProvider:
return &NopRouter{}
default:
return &IstioRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
istioClient: factory.meshClient,
}
}
}