Create Global Backend Ingress
This commit is contained in:
parent
41eb4f1c70
commit
461ebf6d88
5 changed files with 298 additions and 4 deletions
|
@ -36,6 +36,8 @@ const (
|
|||
ruleTypeReplacePath = "ReplacePath"
|
||||
traefikDefaultRealm = "traefik"
|
||||
traefikDefaultIngressClass = "traefik"
|
||||
defaultBackendName = "global-default-backend"
|
||||
defaultFrontendName = "global-default-frontend"
|
||||
)
|
||||
|
||||
// IngressEndpoint holds the endpoint information for the Kubernetes provider
|
||||
|
@ -164,7 +166,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
|||
func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) {
|
||||
ingresses := k8sClient.GetIngresses()
|
||||
|
||||
templateObjects := types.Configuration{
|
||||
templateObjects := &types.Configuration{
|
||||
Backends: map[string]*types.Backend{},
|
||||
Frontends: map[string]*types.Frontend{},
|
||||
}
|
||||
|
@ -184,6 +186,14 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
|||
}
|
||||
templateObjects.TLS = append(templateObjects.TLS, tlsSection...)
|
||||
|
||||
if i.Spec.Backend != nil {
|
||||
err := p.addGlobalBackend(k8sClient, i, templateObjects)
|
||||
if err != nil {
|
||||
log.Errorf("Error creating global backend for ingress %s/%s: %v", i.Namespace, i.Name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var weightAllocator weightAllocator = &defaultWeightAllocator{}
|
||||
annotationPercentageWeights := getAnnotationName(i.Annotations, annotationKubernetesServiceWeights)
|
||||
if _, ok := i.Annotations[annotationPercentageWeights]; ok {
|
||||
|
@ -351,7 +361,7 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
|||
log.Errorf("Cannot update Ingress %s/%s due to error: %v", i.Namespace, i.Name, err)
|
||||
}
|
||||
}
|
||||
return &templateObjects, nil
|
||||
return templateObjects, nil
|
||||
}
|
||||
|
||||
func (p *Provider) updateIngressStatus(i *extensionsv1beta1.Ingress, k8sClient Client) error {
|
||||
|
@ -401,6 +411,100 @@ func (p *Provider) loadConfig(templateObjects types.Configuration) *types.Config
|
|||
return configuration
|
||||
}
|
||||
|
||||
func (p *Provider) addGlobalBackend(cl Client, i *extensionsv1beta1.Ingress, templateObjects *types.Configuration) error {
|
||||
// Ensure that we are not duplicating the frontend
|
||||
if _, exists := templateObjects.Frontends[defaultFrontendName]; exists {
|
||||
return errors.New("duplicate frontend: " + defaultFrontendName)
|
||||
}
|
||||
|
||||
// Ensure we are not duplicating the backend
|
||||
if _, exists := templateObjects.Backends[defaultBackendName]; exists {
|
||||
return errors.New("duplicate backend: " + defaultBackendName)
|
||||
}
|
||||
|
||||
templateObjects.Backends[defaultBackendName] = &types.Backend{
|
||||
Servers: make(map[string]types.Server),
|
||||
LoadBalancer: &types.LoadBalancer{
|
||||
Method: "wrr",
|
||||
},
|
||||
}
|
||||
|
||||
service, exists, err := cl.GetService(i.Namespace, i.Spec.Backend.ServiceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while retrieving service information from k8s API %s/%s: %v", i.Namespace, i.Spec.Backend.ServiceName, err)
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("service not found for %s/%s", i.Namespace, i.Spec.Backend.ServiceName)
|
||||
}
|
||||
|
||||
templateObjects.Backends[defaultBackendName].CircuitBreaker = getCircuitBreaker(service)
|
||||
templateObjects.Backends[defaultBackendName].LoadBalancer = getLoadBalancer(service)
|
||||
templateObjects.Backends[defaultBackendName].MaxConn = getMaxConn(service)
|
||||
templateObjects.Backends[defaultBackendName].Buffering = getBuffering(service)
|
||||
|
||||
endpoints, exists, err := cl.GetEndpoints(service.Namespace, service.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving endpoint information from k8s API %s/%s: %v", service.Namespace, service.Name, err)
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("endpoints not found for %s/%s", service.Namespace, service.Name)
|
||||
}
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return fmt.Errorf("endpoints not available for %s/%s", service.Namespace, service.Name)
|
||||
}
|
||||
|
||||
for _, subset := range endpoints.Subsets {
|
||||
endpointPort := endpointPortNumber(corev1.ServicePort{Protocol: "TCP", Port: int32(i.Spec.Backend.ServicePort.IntValue())}, subset.Ports)
|
||||
if endpointPort == 0 {
|
||||
// endpoint port does not match service.
|
||||
continue
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
for _, address := range subset.Addresses {
|
||||
if endpointPort == 443 || strings.HasPrefix(i.Spec.Backend.ServicePort.String(), "https") {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(address.IP, strconv.FormatInt(int64(endpointPort), 10)))
|
||||
name := url
|
||||
if address.TargetRef != nil && address.TargetRef.Name != "" {
|
||||
name = address.TargetRef.Name
|
||||
}
|
||||
|
||||
templateObjects.Backends[defaultBackendName].Servers[name] = types.Server{
|
||||
URL: url,
|
||||
Weight: label.DefaultWeight,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
|
||||
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert)
|
||||
priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0)
|
||||
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
|
||||
|
||||
templateObjects.Frontends[defaultFrontendName] = &types.Frontend{
|
||||
Backend: defaultBackendName,
|
||||
PassHostHeader: passHostHeader,
|
||||
PassTLSCert: passTLSCert,
|
||||
Routes: make(map[string]types.Route),
|
||||
Priority: priority,
|
||||
WhiteList: getWhiteList(i),
|
||||
Redirect: getFrontendRedirect(i),
|
||||
EntryPoints: entryPoints,
|
||||
Headers: getHeader(i),
|
||||
Errors: getErrorPages(i),
|
||||
RateLimit: getRateLimit(i),
|
||||
}
|
||||
|
||||
templateObjects.Frontends[defaultFrontendName].Routes["/"] = types.Route{
|
||||
Rule: "PathPrefix:/",
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRuleForPath(pa extensionsv1beta1.HTTPIngressPath, i *extensionsv1beta1.Ingress) (string, error) {
|
||||
if len(pa.Path) == 0 {
|
||||
return "", nil
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue