diff --git a/controllers/nginx/configuration.md b/controllers/nginx/configuration.md index 776644b6f..c494d1aab 100644 --- a/controllers/nginx/configuration.md +++ b/controllers/nginx/configuration.md @@ -66,7 +66,7 @@ In addition to the built-in functions provided by the Go package the following f - empty: returns true if the specified parameter (string) is empty - contains: [strings.Contains](https://golang.org/pkg/strings/#Contains) - - hasPrefix: [strings.HasPrefix](https://golang.org/pkg/strings/#Contains) + - hasPrefix: [strings.HasPrefix](https://golang.org/pkg/strings/#HasPrefix) - hasSuffix: [strings.HasSuffix](https://golang.org/pkg/strings/#HasSuffix) - toUpper: [strings.ToUpper](https://golang.org/pkg/strings/#ToUpper) - toLower: [strings.ToLower](https://golang.org/pkg/strings/#ToLower) diff --git a/controllers/nginx/pkg/cmd/controller/nginx.go b/controllers/nginx/pkg/cmd/controller/nginx.go index 9e2bb64d2..24a9a7046 100644 --- a/controllers/nginx/pkg/cmd/controller/nginx.go +++ b/controllers/nginx/pkg/cmd/controller/nginx.go @@ -132,10 +132,10 @@ NGINX master process died (%v): %v // we wait until the workers are killed for { conn, err := net.DialTimeout("tcp", "127.0.0.1:80", 1*time.Second) - if err == nil { - conn.Close() + if err != nil { break } + conn.Close() time.Sleep(1 * time.Second) } // start a new nginx master process @@ -331,7 +331,7 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) ([]byte, er PassthroughBackends: ingressCfg.PassthroughBackends, Servers: ingressCfg.Servers, TCPBackends: ingressCfg.TCPEndpoints, - UDPBackends: ingressCfg.UPDEndpoints, + UDPBackends: ingressCfg.UDPEndpoints, HealthzURI: ngxHealthPath, CustomErrors: len(cfg.CustomHTTPErrors) > 0, Cfg: cfg, diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index ed17a8dbb..6b6626631 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -203,7 +203,8 @@ http { server_name {{ $server.Hostname }}; listen [::]:80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $index 0 }} ipv6only=off{{end}}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}}; {{/* Listen on 442 because port 443 is used in the stream section */}} - {{ if not (empty $server.SSLCertificate) }}listen 442 {{ if $cfg.UseProxyProtocol }}proxy_protocol{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }}; + {{/* This listen cannot contains proxy_protocol directive because port 443 is in charge of decoding the protocol */}} + {{ if not (empty $server.SSLCertificate) }}listen 442 {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }}; {{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}} # PEM sha: {{ $server.SSLPemChecksum }} ssl_certificate {{ $server.SSLCertificate }}; @@ -437,8 +438,7 @@ stream { {{ buildSSPassthroughUpstreams $backends .PassthroughBackends }} server { - listen [::]:443 ipv6only=off; - {{ if $cfg.UseProxyProtocol }}proxy_protocol on;{{ end }} + listen [::]:443 ipv6only=off{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}; proxy_pass $stream_upstream; ssl_preread on; } diff --git a/core/pkg/ingress/controller/controller.go b/core/pkg/ingress/controller/controller.go index e992efda8..5c979dcce 100644 --- a/core/pkg/ingress/controller/controller.go +++ b/core/pkg/ingress/controller/controller.go @@ -330,7 +330,7 @@ func (ic GenericController) GetDefaultBackend() defaults.Backend { return ic.cfg.Backend.BackendDefaults() } -// GetSecret searchs for a secret in the local secrets Store +// GetSecret searches for a secret in the local secrets Store func (ic GenericController) GetSecret(name string) (*api.Secret, error) { s, exists, err := ic.secrLister.Store.GetByKey(name) if err != nil { @@ -390,8 +390,8 @@ func (ic *GenericController) sync(key interface{}) error { data, err := ic.cfg.Backend.OnUpdate(ingress.Configuration{ Backends: upstreams, Servers: servers, - TCPEndpoints: ic.getTCPServices(), - UPDEndpoints: ic.getUDPServices(), + TCPEndpoints: ic.getStreamServices(ic.cfg.TCPConfigMapName, api.ProtocolTCP), + UDPEndpoints: ic.getStreamServices(ic.cfg.UDPConfigMapName, api.ProtocolUDP), PassthroughBackends: passUpstreams, }) if err != nil { @@ -411,54 +411,31 @@ func (ic *GenericController) sync(key interface{}) error { return nil } -func (ic *GenericController) getTCPServices() []*ingress.Location { - if ic.cfg.TCPConfigMapName == "" { - // no configmap for TCP services +func (ic *GenericController) getStreamServices(configmapName string, proto api.Protocol) []*ingress.Location { + if configmapName == "" { + // no configmap configured return []*ingress.Location{} } - ns, name, err := k8s.ParseNameNS(ic.cfg.TCPConfigMapName) + ns, name, err := k8s.ParseNameNS(configmapName) if err != nil { - glog.Warningf("%v", err) + glog.Errorf("unexpected error reading configmap %v: %v", name, err) return []*ingress.Location{} } - tcpMap, err := ic.getConfigMap(ns, name) + + configmap, err := ic.getConfigMap(ns, name) if err != nil { - glog.V(5).Infof("no configured tcp services found: %v", err) + glog.Errorf("unexpected error reading configmap %v: %v", name, err) return []*ingress.Location{} } - return ic.getStreamServices(tcpMap.Data, api.ProtocolTCP) -} - -func (ic *GenericController) getUDPServices() []*ingress.Location { - if ic.cfg.UDPConfigMapName == "" { - // no configmap for TCP services - return []*ingress.Location{} - } - - ns, name, err := k8s.ParseNameNS(ic.cfg.UDPConfigMapName) - if err != nil { - glog.Warningf("%v", err) - return []*ingress.Location{} - } - tcpMap, err := ic.getConfigMap(ns, name) - if err != nil { - glog.V(3).Infof("no configured tcp services found: %v", err) - return []*ingress.Location{} - } - - return ic.getStreamServices(tcpMap.Data, api.ProtocolUDP) -} - -func (ic *GenericController) getStreamServices(data map[string]string, proto api.Protocol) []*ingress.Location { var svcs []*ingress.Location // k -> port to expose // v -> /: - for k, v := range data { + for k, v := range configmap.Data { _, err := strconv.Atoi(k) if err != nil { - glog.Warningf("%v is not valid as a TCP port", k) + glog.Warningf("%v is not valid as a TCP/UDP port", k) continue } diff --git a/core/pkg/ingress/resolver/main.go b/core/pkg/ingress/resolver/main.go index 1e122e236..6017c8cb5 100644 --- a/core/pkg/ingress/resolver/main.go +++ b/core/pkg/ingress/resolver/main.go @@ -28,7 +28,7 @@ type DefaultBackend interface { GetDefaultBackend() defaults.Backend } -// Secret has a method that searchs for secrets contenating +// Secret has a method that searches for secrets contenating // the namespace and name using a the character / type Secret interface { GetSecret(string) (*api.Secret, error) diff --git a/core/pkg/ingress/types.go b/core/pkg/ingress/types.go index 4891995e7..49f849a57 100644 --- a/core/pkg/ingress/types.go +++ b/core/pkg/ingress/types.go @@ -113,9 +113,9 @@ type Configuration struct { // TCPEndpoints contain endpoints for tcp streams handled by this backend // +optional TCPEndpoints []*Location `json:"tcpEndpoints,omitempty"` - // UPDEndpoints contain endpoints for udp streams handled by this backend + // UDPEndpoints contain endpoints for udp streams handled by this backend // +optional - UPDEndpoints []*Location `json:"udpEndpoints,omitempty"` + UDPEndpoints []*Location `json:"udpEndpoints,omitempty"` // PassthroughBackend contains the backends used for SSL passthrough. // It contains information about the associated Server Name Indication (SNI). // +optional diff --git a/docs/catalog.md b/docs/catalog.md index 6c1ccd43f..2612790c7 100644 --- a/docs/catalog.md +++ b/docs/catalog.md @@ -3,5 +3,4 @@ This is a non-comprehensive list of existing ingress controllers. * [Dummy controller backend](/examples/custom-controller) - - +* [HAProxy Ingress controller](https://github.com/jcmoraisjr/haproxy-ingress) diff --git a/docs/dev/setup.md b/docs/dev/setup.md index b41810e1b..f61695293 100644 --- a/docs/dev/setup.md +++ b/docs/dev/setup.md @@ -81,6 +81,14 @@ You may want to consider [using the VM's docker daemon](https://github.com/kubernetes/minikube/blob/master/README.md#reusing-the-docker-daemon) when developing. +### CoreOS Kubernetes + +[CoreOS Kubernetes](https://github.com/coreos/coreos-kubernetes/) repository has `Vagrantfile` +scripts to easily create a new Kubernetes cluster on VirtualBox, VMware or AWS. + +Follow the CoreOS [doc](https://coreos.com/kubernetes/docs/latest/kubernetes-on-vagrant-single.html) +for detailed instructions. + ## Deploy the ingress controller You can deploy an ingress controller on the cluster setup in the previous step diff --git a/examples/deployment/haproxy/README.md b/examples/deployment/haproxy/README.md new file mode 100644 index 000000000..f33769362 --- /dev/null +++ b/examples/deployment/haproxy/README.md @@ -0,0 +1,151 @@ +# Deploying HAProxy Ingress Controller + +If you don't have a Kubernetes cluster, please refer to [setup](/docs/dev/setup.md) +for instructions on how to create a new one. + +## Prerequisites + +This ingress controller doesn't yet have support for +[ingress classes](/examples/PREREQUISITES.md#ingress-class). You MUST turn +down any existing ingress controllers before running HAProxy Ingress controller or +they will fight for Ingresses. This includes any cloudprovider controller. + +This document has also the following prerequisites: + +* Deploy a [web app](/examples/PREREQUISITES.md#test-http-service) for testing +* Create a [TLS secret](/examples/PREREQUISITES.md#tls-certificates) named `tls-secret` to be used as default TLS certificate + +The web app can be created as follow: + +```console +$ kubectl run http-svc \ + --image=gcr.io/google_containers/echoserver:1.3 \ + --port=8080 \ + --replicas=2 \ + --expose +``` + +Creating the TLS secret: + +```console +$ openssl req \ + -x509 -newkey rsa:2048 -nodes -days 365 \ + -keyout tls.key -out tls.crt -subj '/CN=localhost' +$ kubectl create secret tls tls-secret --cert=tls.crt --key=tls.key +$ rm -v tls.crt tls.key +``` + +## Default backend + +Deploy a default backend used to serve `404 Not Found` pages: + +```console +$ kubectl run ingress-default-backend \ + --image=gcr.io/google_containers/defaultbackend:1.0 \ + --port=8080 \ + --limits=cpu=10m,memory=20Mi \ + --expose +``` + +Check if the default backend is up and running: + +```console +$ kubectl get pod +NAME READY STATUS RESTARTS AGE +ingress-default-backend-1110790216-gqr61 1/1 Running 0 10s +``` + +## Controller + +Deploy HAProxy Ingress: + +```console +$ kubectl create -f haproxy-ingress.yaml +``` + +Check if the controller was successfully deployed: + +```console +$ kubectl get pod -w +NAME READY STATUS RESTARTS AGE +haproxy-ingress-2556761959-tv20k 1/1 Running 0 12s +ingress-default-backend-1110790216-gqr61 1/1 Running 0 3m +^C +``` + +Deploy the ingress resource of our already deployed web app: + +```console +$ kubectl create -f - <