Merge pull request #344 from aledbf/tcp-udp
Refactoring of TCP and UDP services
This commit is contained in:
commit
f509d5b44f
7 changed files with 71 additions and 116 deletions
|
@ -299,8 +299,8 @@ type TemplateConfig struct {
|
||||||
Backends []*ingress.Backend
|
Backends []*ingress.Backend
|
||||||
PassthroughBackends []*ingress.SSLPassthroughBackend
|
PassthroughBackends []*ingress.SSLPassthroughBackend
|
||||||
Servers []*ingress.Server
|
Servers []*ingress.Server
|
||||||
TCPBackends []*ingress.Location
|
TCPBackends []ingress.L4Service
|
||||||
UDPBackends []*ingress.Location
|
UDPBackends []ingress.L4Service
|
||||||
HealthzURI string
|
HealthzURI string
|
||||||
CustomErrors bool
|
CustomErrors bool
|
||||||
Cfg Configuration
|
Cfg Configuration
|
||||||
|
|
|
@ -134,7 +134,6 @@ var (
|
||||||
"buildSSLPassthroughUpstreams": buildSSLPassthroughUpstreams,
|
"buildSSLPassthroughUpstreams": buildSSLPassthroughUpstreams,
|
||||||
"buildResolvers": buildResolvers,
|
"buildResolvers": buildResolvers,
|
||||||
"isLocationAllowed": isLocationAllowed,
|
"isLocationAllowed": isLocationAllowed,
|
||||||
"buildStreamUpstreams": buildStreamUpstreams,
|
|
||||||
|
|
||||||
"contains": strings.Contains,
|
"contains": strings.Contains,
|
||||||
"hasPrefix": strings.HasPrefix,
|
"hasPrefix": strings.HasPrefix,
|
||||||
|
@ -193,34 +192,6 @@ func buildSSLPassthroughUpstreams(b interface{}, sslb interface{}) string {
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildStreamUpstreams(proto string, b interface{}, s interface{}) string {
|
|
||||||
backends := b.([]*ingress.Backend)
|
|
||||||
streams := s.([]*ingress.Location)
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 10))
|
|
||||||
// multiple services can use the same upstream.
|
|
||||||
// avoid duplications using a map[name]=true
|
|
||||||
u := make(map[string]bool)
|
|
||||||
for _, stream := range streams {
|
|
||||||
if u[stream.Backend] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
u[stream.Backend] = true
|
|
||||||
fmt.Fprintf(buf, "upstream %v-%v {\n", proto, stream.Backend)
|
|
||||||
// TODO: find a better way to avoid empty stream upstreams
|
|
||||||
fmt.Fprintf(buf, "\t\tserver 127.0.0.1:8181 down;\n")
|
|
||||||
for _, backend := range backends {
|
|
||||||
if backend.Name == stream.Backend {
|
|
||||||
for _, server := range backend.Endpoints {
|
|
||||||
fmt.Fprintf(buf, "\t\tserver %v:%v;\n", server.Address, server.Port)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprint(buf, "\t}\n\n")
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildLocation produces the location string, if the ingress has redirects
|
// buildLocation produces the location string, if the ingress has redirects
|
||||||
// (specified through the ingress.kubernetes.io/rewrite-to annotation)
|
// (specified through the ingress.kubernetes.io/rewrite-to annotation)
|
||||||
func buildLocation(input interface{}) string {
|
func buildLocation(input interface{}) string {
|
||||||
|
|
|
@ -326,8 +326,8 @@ http {
|
||||||
|
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
proxy_cookie_domain {{ $location.Proxy.CookiePath }};
|
proxy_cookie_domain {{ $location.Proxy.CookieDomain }};
|
||||||
proxy_cookie_path {{ $location.Proxy.CookieDomain }};
|
proxy_cookie_path {{ $location.Proxy.CookiePath }};
|
||||||
|
|
||||||
{{/* rewrite only works if the content is not compressed */}}
|
{{/* rewrite only works if the content is not compressed */}}
|
||||||
{{ if $location.Redirect.AddBaseURL }}
|
{{ if $location.Redirect.AddBaseURL }}
|
||||||
|
@ -460,25 +460,33 @@ stream {
|
||||||
ssl_preread on;
|
ssl_preread on;
|
||||||
}
|
}
|
||||||
|
|
||||||
{{ buildStreamUpstreams "tcp" $backends .TCPBackends }}
|
|
||||||
|
|
||||||
{{ buildStreamUpstreams "udp" $backends .UDPBackends }}
|
|
||||||
|
|
||||||
# TCP services
|
# TCP services
|
||||||
{{ range $i, $tcpServer := .TCPBackends }}
|
{{ range $i, $tcpServer := .TCPBackends }}
|
||||||
server {
|
upstream {{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }} {
|
||||||
listen {{ $tcpServer.Path }};
|
{{ range $j, $endpoint := $tcpServer.Endpoints }}
|
||||||
proxy_pass tcp-{{ $tcpServer.Backend }};
|
server {{ $endpoint.Address }}:{{ $endpoint.Port }};
|
||||||
}
|
{{ end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen {{ $tcpServer.Port }};
|
||||||
|
proxy_pass {{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }};
|
||||||
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
# UDP services
|
# UDP services
|
||||||
{{ range $i, $udpServer := .UDPBackends }}
|
{{ range $i, $udpServer := .UDPBackends }}
|
||||||
server {
|
upstream {{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }} {
|
||||||
listen {{ $udpServer.Path }} udp;
|
{{ range $j, $endpoint := $udpServer.Endpoints }}
|
||||||
proxy_responses 1;
|
server {{ $endpoint.Address }}:{{ $endpoint.Port }};
|
||||||
proxy_pass udp-{{ $udpServer.Backend }};
|
{{ end }}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen {{ $udpServer.Port }};
|
||||||
|
proxy_responses 1;
|
||||||
|
proxy_pass {{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }};
|
||||||
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57134,57 +57134,7 @@
|
||||||
}]
|
}]
|
||||||
}],
|
}],
|
||||||
"sslDHParam": "",
|
"sslDHParam": "",
|
||||||
"tcpBackends": [{
|
"tcpBackends": [],
|
||||||
"path": "2222",
|
|
||||||
"isDefBackend": false,
|
|
||||||
"backend": "default-echoheaders-2222",
|
|
||||||
"basicDigestAuth": {
|
|
||||||
"type": "",
|
|
||||||
"realm": "",
|
|
||||||
"file": "",
|
|
||||||
"secured": false
|
|
||||||
},
|
|
||||||
"externalAuth": {
|
|
||||||
"url": "",
|
|
||||||
"method": "",
|
|
||||||
"sendBody": false
|
|
||||||
},
|
|
||||||
"rateLimit": {
|
|
||||||
"connections": {
|
|
||||||
"name": "",
|
|
||||||
"limit": 0,
|
|
||||||
"burst": 0,
|
|
||||||
"sharedSize": 0
|
|
||||||
},
|
|
||||||
"rps": {
|
|
||||||
"name": "",
|
|
||||||
"limit": 0,
|
|
||||||
"burst": 0,
|
|
||||||
"sharedSize": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"redirect": {
|
|
||||||
"target": "",
|
|
||||||
"addBaseUrl": false,
|
|
||||||
"sslRedirect": false
|
|
||||||
},
|
|
||||||
"whitelist": {
|
|
||||||
"cidr": null
|
|
||||||
},
|
|
||||||
"proxy": {
|
|
||||||
"conectTimeout": 0,
|
|
||||||
"sendTimeout": 0,
|
|
||||||
"readTimeout": 0,
|
|
||||||
"bufferSize": ""
|
|
||||||
},
|
|
||||||
"certificateAuth": {
|
|
||||||
"secret": "",
|
|
||||||
"certFilename": "",
|
|
||||||
"keyFilename": "",
|
|
||||||
"caFilename": "",
|
|
||||||
"pemSha": ""
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"udpBackends": [],
|
"udpBackends": [],
|
||||||
"backends": [{
|
"backends": [{
|
||||||
"name": "default-echoheaders-80",
|
"name": "default-echoheaders-80",
|
||||||
|
|
|
@ -40,8 +40,8 @@ type Configuration struct {
|
||||||
SendTimeout int `json:"sendTimeout"`
|
SendTimeout int `json:"sendTimeout"`
|
||||||
ReadTimeout int `json:"readTimeout"`
|
ReadTimeout int `json:"readTimeout"`
|
||||||
BufferSize string `json:"bufferSize"`
|
BufferSize string `json:"bufferSize"`
|
||||||
CookieDomain string `json:"proxyCookieDomain"`
|
CookieDomain string `json:"cookieDomain"`
|
||||||
CookiePath string `json:"proxyCookiePath"`
|
CookiePath string `json:"cookiePath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type proxy struct {
|
type proxy struct {
|
||||||
|
@ -83,8 +83,8 @@ func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cd, err := parser.GetStringAnnotation(cookieDomain, ing)
|
cd, err := parser.GetStringAnnotation(cookieDomain, ing)
|
||||||
if err != nil || cp == "" {
|
if err != nil || cd == "" {
|
||||||
cp = defBackend.ProxyCookieDomain
|
cd = defBackend.ProxyCookieDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
bs, err := parser.GetStringAnnotation(bodySize, ing)
|
bs, err := parser.GetStringAnnotation(bodySize, ing)
|
||||||
|
@ -92,6 +92,5 @@ func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
bs = defBackend.ProxyBodySize
|
bs = defBackend.ProxyBodySize
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Configuration{bs, ct, st, rt, bufs,
|
return &Configuration{bs, ct, st, rt, bufs, cd, cp}, nil
|
||||||
cd, cp}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,30 +426,30 @@ func (ic *GenericController) sync(key interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *GenericController) getStreamServices(configmapName string, proto api.Protocol) []*ingress.Location {
|
func (ic *GenericController) getStreamServices(configmapName string, proto api.Protocol) []ingress.L4Service {
|
||||||
glog.V(3).Infof("obtaining information about stream services of type %v located in configmap %v", proto, configmapName)
|
glog.V(3).Infof("obtaining information about stream services of type %v located in configmap %v", proto, configmapName)
|
||||||
if configmapName == "" {
|
if configmapName == "" {
|
||||||
// no configmap configured
|
// no configmap configured
|
||||||
return []*ingress.Location{}
|
return []ingress.L4Service{}
|
||||||
}
|
}
|
||||||
|
|
||||||
ns, name, err := k8s.ParseNameNS(configmapName)
|
ns, name, err := k8s.ParseNameNS(configmapName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("unexpected error reading configmap %v: %v", name, err)
|
glog.Errorf("unexpected error reading configmap %v: %v", name, err)
|
||||||
return []*ingress.Location{}
|
return []ingress.L4Service{}
|
||||||
}
|
}
|
||||||
|
|
||||||
configmap, err := ic.getConfigMap(ns, name)
|
configmap, err := ic.getConfigMap(ns, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("unexpected error reading configmap %v: %v", name, err)
|
glog.Errorf("unexpected error reading configmap %v: %v", name, err)
|
||||||
return []*ingress.Location{}
|
return []ingress.L4Service{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var svcs []*ingress.Location
|
var svcs []ingress.L4Service
|
||||||
// k -> port to expose
|
// k -> port to expose
|
||||||
// v -> <namespace>/<service name>:<port from service to be used>
|
// v -> <namespace>/<service name>:<port from service to be used>
|
||||||
for k, v := range configmap.Data {
|
for k, v := range configmap.Data {
|
||||||
_, err := strconv.Atoi(k)
|
externalPort, err := strconv.Atoi(k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("%v is not valid as a TCP/UDP port", k)
|
glog.Warningf("%v is not valid as a TCP/UDP port", k)
|
||||||
continue
|
continue
|
||||||
|
@ -517,9 +517,15 @@ func (ic *GenericController) getStreamServices(configmapName string, proto api.P
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
svcs = append(svcs, &ingress.Location{
|
svcs = append(svcs, ingress.L4Service{
|
||||||
Path: k,
|
Port: externalPort,
|
||||||
Backend: fmt.Sprintf("%v-%v-%v", svcNs, svcName, svcPort),
|
Backend: ingress.L4Backend{
|
||||||
|
Name: svcName,
|
||||||
|
Namespace: svcNs,
|
||||||
|
Port: intstr.FromString(svcPort),
|
||||||
|
Protocol: proto,
|
||||||
|
},
|
||||||
|
Endpoints: endps,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,6 +823,8 @@ func (ic *GenericController) createServers(data []interface{},
|
||||||
SendTimeout: bdef.ProxySendTimeout,
|
SendTimeout: bdef.ProxySendTimeout,
|
||||||
ReadTimeout: bdef.ProxyReadTimeout,
|
ReadTimeout: bdef.ProxyReadTimeout,
|
||||||
BufferSize: bdef.ProxyBufferSize,
|
BufferSize: bdef.ProxyBufferSize,
|
||||||
|
CookieDomain: bdef.ProxyCookieDomain,
|
||||||
|
CookiePath: bdef.ProxyCookiePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This adds the Default Certificate to Default Backend and also for vhosts missing the secret
|
// This adds the Default Certificate to Default Backend and also for vhosts missing the secret
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/client/cache"
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
"k8s.io/kubernetes/pkg/healthz"
|
"k8s.io/kubernetes/pkg/healthz"
|
||||||
|
"k8s.io/kubernetes/pkg/util/intstr"
|
||||||
|
|
||||||
cache_store "k8s.io/ingress/core/pkg/cache"
|
cache_store "k8s.io/ingress/core/pkg/cache"
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/auth"
|
"k8s.io/ingress/core/pkg/ingress/annotations/auth"
|
||||||
|
@ -132,10 +133,10 @@ type Configuration struct {
|
||||||
Servers []*Server `json:"servers"`
|
Servers []*Server `json:"servers"`
|
||||||
// TCPEndpoints contain endpoints for tcp streams handled by this backend
|
// TCPEndpoints contain endpoints for tcp streams handled by this backend
|
||||||
// +optional
|
// +optional
|
||||||
TCPEndpoints []*Location `json:"tcpEndpoints,omitempty"`
|
TCPEndpoints []L4Service `json:"tcpEndpoints,omitempty"`
|
||||||
// UDPEndpoints contain endpoints for udp streams handled by this backend
|
// UDPEndpoints contain endpoints for udp streams handled by this backend
|
||||||
// +optional
|
// +optional
|
||||||
UDPEndpoints []*Location `json:"udpEndpoints,omitempty"`
|
UDPEndpoints []L4Service `json:"udpEndpoints,omitempty"`
|
||||||
// PassthroughBackend contains the backends used for SSL passthrough.
|
// PassthroughBackend contains the backends used for SSL passthrough.
|
||||||
// It contains information about the associated Server Name Indication (SNI).
|
// It contains information about the associated Server Name Indication (SNI).
|
||||||
// +optional
|
// +optional
|
||||||
|
@ -292,3 +293,21 @@ type SSLPassthroughBackend struct {
|
||||||
// Hostname returns the FQDN of the server
|
// Hostname returns the FQDN of the server
|
||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// L4Service describes a L4 Ingress service.
|
||||||
|
type L4Service struct {
|
||||||
|
// Port external port to expose
|
||||||
|
Port int `json:"port"`
|
||||||
|
// Backend of the service
|
||||||
|
Backend L4Backend `json:"backend"`
|
||||||
|
// Endpoints active endpoints of the service
|
||||||
|
Endpoints []Endpoint `json:"endpoins"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4Backend describes the kubernetes service behind L4 Ingress service
|
||||||
|
type L4Backend struct {
|
||||||
|
Port intstr.IntOrString `json:"port"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
Protocol api.Protocol `json:"protocol"`
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue