From e963d095abd08ead164e6da325737f5c7270c57d Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Thu, 10 Nov 2016 18:46:41 -0300 Subject: [PATCH] Remove nginx-alpha, examples and simplify read files --- controllers/README.md | 128 --------------- controllers/nginx-alpha/Dockerfile | 18 --- controllers/nginx-alpha/Makefile | 17 -- controllers/nginx-alpha/README.md | 116 -------------- controllers/nginx-alpha/controller.go | 95 ----------- controllers/nginx-alpha/default.conf | 4 - controllers/nginx-alpha/rc.yaml | 22 --- controllers/nginx/examples/README.md | 8 - controllers/nginx/examples/auth/README.md | 126 --------------- .../examples/custom-configuration/README.md | 57 ------- .../rc-custom-configuration.yaml | 52 ------ .../nginx/examples/custom-errors/README.md | 80 ---------- .../custom-errors/custom-default-backend.yaml | 31 ---- .../custom-errors/rc-custom-errors.yaml | 51 ------ .../nginx/examples/custom-template/README.md | 9 -- .../custom-template/custom-template.yaml | 62 -------- .../examples/custom-upstream-check/README.md | 45 ------ .../custom-upstream-check/custom-upstream.png | Bin 60592 -> 0 bytes .../nginx/examples/daemonset/README.md | 8 - .../examples/daemonset/as-daemonset.yaml | 45 ------ .../nginx/examples/default-backend.yaml | 36 ----- controllers/nginx/examples/default/README.md | 76 --------- .../nginx/examples/default/rc-default.yaml | 51 ------ .../nginx/examples/external-auth/README.md | 148 ------------------ .../nginx/examples/external-auth/ingress.yaml | 15 -- controllers/nginx/examples/full/rc-full.yaml | 62 -------- controllers/nginx/examples/ingress.yaml | 25 --- .../nginx/examples/multi-tls/README.md | 94 ----------- .../nginx/examples/multi-tls/multi-tls.yaml | 102 ------------ .../nginx/examples/proxy-protocol/README.md | 34 ---- .../proxy-protocol/nginx-configmap.yaml | 6 - .../examples/proxy-protocol/nginx-rc.yaml | 50 ------ .../examples/proxy-protocol/nginx-svc.yaml | 19 --- controllers/nginx/examples/rewrite/README.md | 67 -------- .../sysctl/change-proc-values-rc.yaml | 128 --------------- controllers/nginx/examples/tcp/README.md | 74 --------- controllers/nginx/examples/tcp/rc-tcp.yaml | 56 ------- .../examples/tcp/tcp-configmap-example.yaml | 6 - controllers/nginx/examples/tls/README.md | 90 ----------- controllers/nginx/examples/tls/dhparam.sh | 35 ----- controllers/nginx/examples/tls/rc-ssl.yaml | 51 ------ controllers/nginx/examples/udp/README.md | 13 -- controllers/nginx/examples/udp/rc-udp.yaml | 54 ------- .../examples/udp/udp-configmap-example.yaml | 6 - .../nginx/examples/whitelist/README.md | 123 --------------- 45 files changed, 2395 deletions(-) delete mode 100644 controllers/nginx-alpha/Dockerfile delete mode 100644 controllers/nginx-alpha/Makefile delete mode 100644 controllers/nginx-alpha/README.md delete mode 100644 controllers/nginx-alpha/controller.go delete mode 100644 controllers/nginx-alpha/default.conf delete mode 100644 controllers/nginx-alpha/rc.yaml delete mode 100644 controllers/nginx/examples/README.md delete mode 100644 controllers/nginx/examples/auth/README.md delete mode 100644 controllers/nginx/examples/custom-configuration/README.md delete mode 100644 controllers/nginx/examples/custom-configuration/rc-custom-configuration.yaml delete mode 100644 controllers/nginx/examples/custom-errors/README.md delete mode 100644 controllers/nginx/examples/custom-errors/custom-default-backend.yaml delete mode 100644 controllers/nginx/examples/custom-errors/rc-custom-errors.yaml delete mode 100644 controllers/nginx/examples/custom-template/README.md delete mode 100644 controllers/nginx/examples/custom-template/custom-template.yaml delete mode 100644 controllers/nginx/examples/custom-upstream-check/README.md delete mode 100644 controllers/nginx/examples/custom-upstream-check/custom-upstream.png delete mode 100644 controllers/nginx/examples/daemonset/README.md delete mode 100644 controllers/nginx/examples/daemonset/as-daemonset.yaml delete mode 100644 controllers/nginx/examples/default-backend.yaml delete mode 100644 controllers/nginx/examples/default/README.md delete mode 100644 controllers/nginx/examples/default/rc-default.yaml delete mode 100644 controllers/nginx/examples/external-auth/README.md delete mode 100644 controllers/nginx/examples/external-auth/ingress.yaml delete mode 100644 controllers/nginx/examples/full/rc-full.yaml delete mode 100644 controllers/nginx/examples/ingress.yaml delete mode 100644 controllers/nginx/examples/multi-tls/README.md delete mode 100644 controllers/nginx/examples/multi-tls/multi-tls.yaml delete mode 100644 controllers/nginx/examples/proxy-protocol/README.md delete mode 100644 controllers/nginx/examples/proxy-protocol/nginx-configmap.yaml delete mode 100644 controllers/nginx/examples/proxy-protocol/nginx-rc.yaml delete mode 100644 controllers/nginx/examples/proxy-protocol/nginx-svc.yaml delete mode 100644 controllers/nginx/examples/rewrite/README.md delete mode 100644 controllers/nginx/examples/sysctl/change-proc-values-rc.yaml delete mode 100644 controllers/nginx/examples/tcp/README.md delete mode 100644 controllers/nginx/examples/tcp/rc-tcp.yaml delete mode 100644 controllers/nginx/examples/tcp/tcp-configmap-example.yaml delete mode 100644 controllers/nginx/examples/tls/README.md delete mode 100755 controllers/nginx/examples/tls/dhparam.sh delete mode 100644 controllers/nginx/examples/tls/rc-ssl.yaml delete mode 100644 controllers/nginx/examples/udp/README.md delete mode 100644 controllers/nginx/examples/udp/rc-udp.yaml delete mode 100644 controllers/nginx/examples/udp/udp-configmap-example.yaml delete mode 100644 controllers/nginx/examples/whitelist/README.md diff --git a/controllers/README.md b/controllers/README.md index 9b0d4fd0a..6df8a3abf 100644 --- a/controllers/README.md +++ b/controllers/README.md @@ -9,131 +9,3 @@ Configuring a webserver or loadbalancer is harder than it should be. Most webser ## What is an Ingress Controller? An Ingress Controller is a daemon, deployed as a Kubernetes Pod, that watches the ApiServer's `/ingresses` endpoint for updates to the [Ingress resource](https://github.com/kubernetes/kubernetes/blob/master/docs/user-guide/ingress.md). Its job is to satisfy requests for ingress. - -## Writing an Ingress Controller - -Writing an Ingress controller is simple. By way of example, the [nginx controller] (nginx-alpha) does the following: -* Poll until apiserver reports a new Ingress -* Write the nginx config file based on a [go text/template](https://golang.org/pkg/text/template/) -* Reload nginx - -Pay attention to how it denormalizes the Kubernetes Ingress object into an nginx config: -```go -const ( - nginxConf = ` -events { - worker_connections 1024; -} -http { -{{range $ing := .Items}} -{{range $rule := $ing.Spec.Rules}} - server { - listen 80; - server_name {{$rule.Host}}; -{{ range $path := $rule.HTTP.Paths }} - location {{$path.Path}} { - proxy_set_header Host $host; - proxy_pass http://{{$path.Backend.ServiceName}}.{{$ing.Namespace}}.svc.cluster.local:{{$path.Backend.ServicePort}}; - }{{end}} - }{{end}}{{end}} -}` -) -``` - -You can take a similar approach to denormalize the Ingress to a [haproxy config](https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/template.cfg) or use it to configure a cloud loadbalancer such as a [GCE L7](https://github.com/kubernetes/contrib/blob/master/ingress/controllers/gce/README.md). - -And here is the Ingress controller's control loop: - -```go -for { - rateLimiter.Accept() - ingresses, err := ingClient.List(labels.Everything(), fields.Everything()) - if err != nil || reflect.DeepEqual(ingresses.Items, known.Items) { - continue - } - if w, err := os.Create("/etc/nginx/nginx.conf"); err != nil { - log.Fatalf("Failed to open %v: %v", nginxConf, err) - } else if err := tmpl.Execute(w, ingresses); err != nil { - log.Fatalf("Failed to write template %v", err) - } - shellOut("nginx -s reload") -} -``` - -All this is doing is: -* List Ingresses, optionally you can watch for changes (see [GCE Ingress controller](https://github.com/kubernetes/contrib/blob/master/ingress/controllers/gce/controller/controller.go) for an example) -* Executes the template and writes results to `/etc/nginx/nginx.conf` -* Reloads nginx - -You can deploy this controller to a Kubernetes cluster by [creating an RC](nginx-alpha/rc.yaml). After doing so, if you were to create an Ingress such as: -```yaml -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: test -spec: - rules: - - host: foo.bar.com - http: - paths: - - path: /foo - backend: - serviceName: fooSvc - servicePort: 80 - - host: bar.baz.com - http: - paths: - - path: /bar - backend: - serviceName: barSvc - servicePort: 80 -``` - -Where `fooSvc` and `barSvc` are 2 services running in your Kubernetes cluster. The controller would satisfy the Ingress by writing a configuration file to /etc/nginx/nginx.conf: -```nginx -events { - worker_connections 1024; -} -http { - server { - listen 80; - server_name foo.bar.com; - - location /foo { - proxy_pass http://fooSvc; - } - } - server { - listen 80; - server_name bar.baz.com; - - location /bar { - proxy_pass http://barSvc; - } - } -} -``` - -And you can reach the `/foo` and `/bar` endpoints on the publicIP of the VM the nginx-ingress pod landed on. -``` -$ kubectl get pods -o wide -NAME READY STATUS RESTARTS AGE NODE -nginx-ingress-tk7dl 1/1 Running 0 3m e2e-test-beeps-minion-15p3 - -$ kubectl get nodes e2e-test-beeps-minion-15p3 -o yaml | grep -i externalip -B 1 - - address: 104.197.203.179 - type: ExternalIP - -$ curl --resolve foo.bar.com:80:104.197.203.179 foo.bar.com/foo -``` - -## Future work - -This section can also bear the title "why anyone would want to write an Ingress controller instead of directly configuring Services". There is more to Ingress than webserver configuration. *Real* HA usually involves the configuration of gateways and packet forwarding devices, which most cloud providers allow you to do through an API. See the GCE Loadbalancer Controller, which is deployed as a [cluster addon](https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/cluster-loadbalancing/glbc) in GCE and GKE clusters for more advanced Ingress configuration examples. Post 1.2 the Ingress resource will support at least the following: -* More TLS options (SNI, re-encrypt etc) -* L4 and L7 loadbalancing (it currently only supports HTTP rules) -* Ingress Rules that are not limited to a simple path regex (eg: redirect rules, session persistence) - -And is expected to be the way one configures "frontends" that handle user traffic for a Kubernetes cluster. - - diff --git a/controllers/nginx-alpha/Dockerfile b/controllers/nginx-alpha/Dockerfile deleted file mode 100644 index 57d46009e..000000000 --- a/controllers/nginx-alpha/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2015 The Kubernetes Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -FROM gcr.io/google_containers/nginx -COPY controller / -COPY default.conf /etc/nginx/nginx.conf -CMD ["/controller"] diff --git a/controllers/nginx-alpha/Makefile b/controllers/nginx-alpha/Makefile deleted file mode 100644 index b43eb454a..000000000 --- a/controllers/nginx-alpha/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -all: push - -# 0.0 shouldn't clobber any release builds -TAG = 0.0 -PREFIX = gcr.io/google_containers/nginx-ingress - -controller: controller.go - CGO_ENABLED=0 GOOS=linux godep go build -a -installsuffix cgo -ldflags '-w' -o controller ./controller.go - -container: controller - docker build -t $(PREFIX):$(TAG) . - -push: container - gcloud docker push $(PREFIX):$(TAG) - -clean: - rm -f controller diff --git a/controllers/nginx-alpha/README.md b/controllers/nginx-alpha/README.md deleted file mode 100644 index 3c829e9c2..000000000 --- a/controllers/nginx-alpha/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# Nginx Ingress Controller - -This is a simple nginx Ingress controller. Expect it to grow up. See [Ingress controller documentation](../README.md) for details on how it works. - -## Deploying the controller - -Deploying the controller is as easy as creating the RC in this directory. Having done so you can test it with the following echoheaders application: - -```yaml -# 3 Services for the 3 endpoints of the Ingress -apiVersion: v1 -kind: Service -metadata: - name: echoheaders-x - labels: - app: echoheaders -spec: - type: NodePort - ports: - - port: 80 - nodePort: 30301 - targetPort: 8080 - protocol: TCP - name: http - selector: - app: echoheaders ---- -apiVersion: v1 -kind: Service -metadata: - name: echoheaders-default - labels: - app: echoheaders -spec: - type: NodePort - ports: - - port: 80 - nodePort: 30302 - targetPort: 8080 - protocol: TCP - name: http - selector: - app: echoheaders ---- -apiVersion: v1 -kind: Service -metadata: - name: echoheaders-y - labels: - app: echoheaders -spec: - type: NodePort - ports: - - port: 80 - nodePort: 30284 - targetPort: 8080 - protocol: TCP - name: http - selector: - app: echoheaders ---- -# A single RC matching all Services -apiVersion: v1 -kind: ReplicationController -metadata: - name: echoheaders -spec: - replicas: 1 - template: - metadata: - labels: - app: echoheaders - spec: - containers: - - name: echoheaders - image: gcr.io/google_containers/echoserver:1.0 - ports: - - containerPort: 8080 ---- -# An Ingress with 2 hosts and 3 endpoints -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: echomap -spec: - rules: - - host: foo.bar.com - http: - paths: - - path: /foo - backend: - serviceName: echoheaders-x - servicePort: 80 - - host: bar.baz.com - http: - paths: - - path: /bar - backend: - serviceName: echoheaders-y - servicePort: 80 - - path: /foo - backend: - serviceName: echoheaders-x - servicePort: 80 -``` -You should be able to access the Services on the public IP of the node the nginx pod lands on. - -## Wishlist - -* SSL/TLS -* Production ready options -* Dynamic adding backends -* Varied loadbalancing algorithms - -... this list goes on. If you feel you know nginx better than I do, please contribute. - diff --git a/controllers/nginx-alpha/controller.go b/controllers/nginx-alpha/controller.go deleted file mode 100644 index 10ba92bad..000000000 --- a/controllers/nginx-alpha/controller.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "log" - "os" - "os/exec" - "reflect" - "text/template" - - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - client "k8s.io/kubernetes/pkg/client/unversioned" - "k8s.io/kubernetes/pkg/util/flowcontrol" -) - -const ( - nginxConf = ` -events { - worker_connections 1024; -} -http { - # http://nginx.org/en/docs/http/ngx_http_core_module.html - types_hash_max_size 2048; - server_names_hash_max_size 512; - server_names_hash_bucket_size 64; - -{{range $ing := .Items}} -{{range $rule := $ing.Spec.Rules}} - server { - listen 80; - server_name {{$rule.Host}}; -{{ range $path := $rule.HTTP.Paths }} - location {{$path.Path}} { - proxy_set_header Host $host; - proxy_pass http://{{$path.Backend.ServiceName}}.{{$ing.Namespace}}.svc.cluster.local:{{$path.Backend.ServicePort}}; - }{{end}} - }{{end}}{{end}} -}` -) - -func shellOut(cmd string) { - out, err := exec.Command("sh", "-c", cmd).CombinedOutput() - if err != nil { - log.Fatalf("Failed to execute %v: %v, err: %v", cmd, string(out), err) - } -} - -func main() { - var ingClient client.IngressInterface - if kubeClient, err := client.NewInCluster(); err != nil { - log.Fatalf("Failed to create client: %v.", err) - } else { - ingClient = kubeClient.Extensions().Ingress(api.NamespaceAll) - } - tmpl, _ := template.New("nginx").Parse(nginxConf) - rateLimiter := flowcontrol.NewTokenBucketRateLimiter(0.1, 1) - known := &extensions.IngressList{} - - // Controller loop - shellOut("nginx") - for { - rateLimiter.Accept() - ingresses, err := ingClient.List(api.ListOptions{}) - if err != nil { - log.Printf("Error retrieving ingresses: %v", err) - continue - } - if reflect.DeepEqual(ingresses.Items, known.Items) { - continue - } - known = ingresses - if w, err := os.Create("/etc/nginx/nginx.conf"); err != nil { - log.Fatalf("Failed to open %v: %v", nginxConf, err) - } else if err := tmpl.Execute(w, ingresses); err != nil { - log.Fatalf("Failed to write template %v", err) - } - shellOut("nginx -s reload") - } -} diff --git a/controllers/nginx-alpha/default.conf b/controllers/nginx-alpha/default.conf deleted file mode 100644 index 159715bdf..000000000 --- a/controllers/nginx-alpha/default.conf +++ /dev/null @@ -1,4 +0,0 @@ -# A very simple nginx configuration file that forces nginx to start as a daemon. -events {} -http {} -daemon on; diff --git a/controllers/nginx-alpha/rc.yaml b/controllers/nginx-alpha/rc.yaml deleted file mode 100644 index ab8f83aca..000000000 --- a/controllers/nginx-alpha/rc.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress - labels: - app: nginx-ingress -spec: - replicas: 1 - selector: - app: nginx-ingress - template: - metadata: - labels: - app: nginx-ingress - spec: - containers: - - image: gcr.io/google_containers/nginx-ingress:0.1 - imagePullPolicy: Always - name: nginx - ports: - - containerPort: 80 - hostPort: 80 diff --git a/controllers/nginx/examples/README.md b/controllers/nginx/examples/README.md deleted file mode 100644 index 9ca7f024c..000000000 --- a/controllers/nginx/examples/README.md +++ /dev/null @@ -1,8 +0,0 @@ - -All the examples references the services `echoheaders-x` and `echoheaders-y` - -``` -kubectl run echoheaders --image=gcr.io/google_containers/echoserver:1.4 --replicas=1 --port=8080 -kubectl expose deployment echoheaders --port=80 --target-port=8080 --name=echoheaders-x -kubectl expose deployment echoheaders --port=80 --target-port=8080 --name=echoheaders-x -``` diff --git a/controllers/nginx/examples/auth/README.md b/controllers/nginx/examples/auth/README.md deleted file mode 100644 index c7dd50168..000000000 --- a/controllers/nginx/examples/auth/README.md +++ /dev/null @@ -1,126 +0,0 @@ - -This example shows how to add authentication in a Ingress rule using a secret that contains a file generated with `htpasswd`. - - -``` -$ htpasswd -c auth foo -New password: -New password: -Re-type new password: -Adding password for user foo -``` - -``` -$ kubectl create secret generic basic-auth --from-file=auth -secret "basic-auth" created -``` - -``` -$ kubectl get secret basic-auth -o yaml -apiVersion: v1 -data: - auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK -kind: Secret -metadata: - name: basic-auth - namespace: default -type: Opaque -``` - -``` -echo " -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-with-auth - annotations: - # type of authentication - ingress.kubernetes.io/auth-type: basic - # name of the secret that contains the user/password definitions - ingress.kubernetes.io/auth-secret: basic-auth - # message to display with an appropiate context why the authentication is required - ingress.kubernetes.io/auth-realm: "Authentication Required - foo" -spec: - rules: - - host: foo.bar.com - http: - paths: - - path: / - backend: - serviceName: echoheaders - servicePort: 80 -" | kubectl create -f - -``` - -``` -$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com' -* Trying 10.2.29.4... -* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0) -> GET / HTTP/1.1 -> Host: foo.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 401 Unauthorized -< Server: nginx/1.10.0 -< Date: Wed, 11 May 2016 05:27:23 GMT -< Content-Type: text/html -< Content-Length: 195 -< Connection: keep-alive -< WWW-Authenticate: Basic realm="Authentication Required - foo" -< - -401 Authorization Required - -

401 Authorization Required

-
nginx/1.10.0
- - -* Connection #0 to host 10.2.29.4 left intact -``` - -``` -$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com' -u 'foo:bar' -* Trying 10.2.29.4... -* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0) -* Server auth using Basic with user 'foo' -> GET / HTTP/1.1 -> Host: foo.bar.com -> Authorization: Basic Zm9vOmJhcg== -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 200 OK -< Server: nginx/1.10.0 -< Date: Wed, 11 May 2016 06:05:26 GMT -< Content-Type: text/plain -< Transfer-Encoding: chunked -< Connection: keep-alive -< Vary: Accept-Encoding -< -CLIENT VALUES: -client_address=10.2.29.4 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://foo.bar.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.11 - lua: 10001 - -HEADERS RECEIVED: -accept=*/* -authorization=Basic Zm9vOmJhcg== -connection=close -host=foo.bar.com -user-agent=curl/7.43.0 -x-forwarded-for=10.2.29.1 -x-forwarded-host=foo.bar.com -x-forwarded-port=80 -x-forwarded-proto=http -x-real-ip=10.2.29.1 -BODY: -* Connection #0 to host 10.2.29.4 left intact --no body in request- -``` diff --git a/controllers/nginx/examples/custom-configuration/README.md b/controllers/nginx/examples/custom-configuration/README.md deleted file mode 100644 index d052df4df..000000000 --- a/controllers/nginx/examples/custom-configuration/README.md +++ /dev/null @@ -1,57 +0,0 @@ -The next command shows the defaults: -``` -$ ./nginx-third-party-lb --dump-nginx—configuration -Example of ConfigMap to customize NGINX configuration: -data: - body-size: 1m - error-log-level: info - gzip-types: application/atom+xml application/javascript application/json application/rss+xml - application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json - application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon - text/css text/plain text/x-component - hts-include-subdomains: "true" - hts-max-age: "15724800" - keep-alive: "75" - max-worker-connections: "16384" - proxy-connect-timeout: "30" - proxy-read-timeout: "30" - proxy-real-ip-cidr: 0.0.0.0/0 - proxy-send-timeout: "30" - server-name-hash-bucket-size: "64" - server-name-hash-max-size: "512" - ssl-buffer-size: 4k - ssl-ciphers: ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA - ssl-protocols: TLSv1 TLSv1.1 TLSv1.2 - ssl-session-cache: "true" - ssl-session-cache-size: 10m - ssl-session-tickets: "true" - ssl-session-timeout: 10m - use-gzip: "true" - use-hts: "true" - worker-processes: "8" -metadata: - name: custom-name - namespace: a-valid-namespace -``` - -For instance, if we want to change the timeouts we need to create a ConfigMap: -``` -$ cat nginx-load-balancer-conf.yaml -apiVersion: v1 -data: - proxy-connect-timeout: "10" - proxy-read-timeout: "120" - proxy-send-imeout: "120" -kind: ConfigMap -metadata: - name: nginx-load-balancer-conf - -``` - -``` -$ kubectl create -f nginx-load-balancer-conf.yaml -``` - -Please check the example `rc-custom-configuration.yaml` - -If the Configmap it is updated, NGINX will be reloaded with the new configuration diff --git a/controllers/nginx/examples/custom-configuration/rc-custom-configuration.yaml b/controllers/nginx/examples/custom-configuration/rc-custom-configuration.yaml deleted file mode 100644 index 7d3713093..000000000 --- a/controllers/nginx/examples/custom-configuration/rc-custom-configuration.yaml +++ /dev/null @@ -1,52 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - - --nginx-configmap=$(POD_NAMESPACE)/nginx-load-balancer-conf diff --git a/controllers/nginx/examples/custom-errors/README.md b/controllers/nginx/examples/custom-errors/README.md deleted file mode 100644 index e9faf1fc8..000000000 --- a/controllers/nginx/examples/custom-errors/README.md +++ /dev/null @@ -1,80 +0,0 @@ - -This example shows how is possible to use a custom backend to render custom error pages. The code of this example is located here [nginx-debug-server](https://github.com/aledbf/contrib/tree/nginx-debug-server) - - -The idea is to use the headers `X-Code` and `X-Format` that NGINX pass to the backend in case of an error to find out the best existent representation of the response to be returned. i.e. if the request contains an `Accept` header of type `json` the error should be in that format and not in `html` (the default in NGINX). - -First create the custom backend to use in the Ingress controller - -```$ kubectl create -f custom-default-backend.yaml -service "nginx-errors" created -replicationcontroller "nginx-errors" created -``` - -```$ kubectl get svc -NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE -echoheaders 10.3.0.7 nodes 80/TCP 23d -kubernetes 10.3.0.1 443/TCP 34d -nginx-errors 10.3.0.102 80/TCP 11s -``` - -```$ kubectl get rc -CONTROLLER REPLICAS AGE -echoheaders 1 19d -nginx-errors 1 19s -``` - -Next create the Ingress controller executing -``` -$ kubectl create -f rc-custom-errors.yaml -``` - -Now to check if this is working we use curl: - -``` -$ curl -v http://172.17.4.99/ -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET / HTTP/1.1 -> Host: 172.17.4.99 -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 404 Not Found -< Server: nginx/1.10.0 -< Date: Wed, 04 May 2016 02:53:45 GMT -< Content-Type: text/html -< Transfer-Encoding: chunked -< Connection: keep-alive -< Vary: Accept-Encoding -< -The page you're looking for could not be found. - -* Connection #0 to host 172.17.4.99 left intact -``` - -Specifying json as expected format: - -``` -$ curl -v http://172.17.4.99/ -H 'Accept: application/json' -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET / HTTP/1.1 -> Host: 172.17.4.99 -> User-Agent: curl/7.43.0 -> Accept: application/json -> -< HTTP/1.1 404 Not Found -< Server: nginx/1.10.0 -< Date: Wed, 04 May 2016 02:54:00 GMT -< Content-Type: text/html -< Transfer-Encoding: chunked -< Connection: keep-alive -< Vary: Accept-Encoding -< -{ "message": "The page you're looking for could not be found" } - -* Connection #0 to host 172.17.4.99 left intact -``` - -By default the Ingress controller provides support for `html`, `json` and `XML`. diff --git a/controllers/nginx/examples/custom-errors/custom-default-backend.yaml b/controllers/nginx/examples/custom-errors/custom-default-backend.yaml deleted file mode 100644 index fce7c0bcb..000000000 --- a/controllers/nginx/examples/custom-errors/custom-default-backend.yaml +++ /dev/null @@ -1,31 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: nginx-errors - labels: - app: nginx-errors -spec: - ports: - - port: 80 - targetPort: 80 - protocol: TCP - name: http - selector: - app: nginx-errors ---- -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-errors -spec: - replicas: 1 - template: - metadata: - labels: - app: nginx-errors - spec: - containers: - - name: nginx-errors - image: aledbf/nginx-error-server:0.1 - ports: - - containerPort: 80 \ No newline at end of file diff --git a/controllers/nginx/examples/custom-errors/rc-custom-errors.yaml b/controllers/nginx/examples/custom-errors/rc-custom-errors.yaml deleted file mode 100644 index bd85754e3..000000000 --- a/controllers/nginx/examples/custom-errors/rc-custom-errors.yaml +++ /dev/null @@ -1,51 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/nginx-errors diff --git a/controllers/nginx/examples/custom-template/README.md b/controllers/nginx/examples/custom-template/README.md deleted file mode 100644 index 6d6375d0b..000000000 --- a/controllers/nginx/examples/custom-template/README.md +++ /dev/null @@ -1,9 +0,0 @@ - -This example shows how is possible to use a custom template - -First create a configmap with a template inside running: -``` -kubectl create configmap nginx-template --from-file=nginx.tmpl=../../nginx.tmpl -``` - -Next create the rc `kubectl create -f custom-template.yaml` diff --git a/controllers/nginx/examples/custom-template/custom-template.yaml b/controllers/nginx/examples/custom-template/custom-template.yaml deleted file mode 100644 index 5434a8c8a..000000000 --- a/controllers/nginx/examples/custom-template/custom-template.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - volumeMounts: - - mountPath: /etc/nginx/template - name: nginx-template-volume - readOnly: true - volumes: - - name: nginx-template-volume - configMap: - name: nginx-template - items: - - key: nginx.tmpl - path: nginx.tmpl diff --git a/controllers/nginx/examples/custom-upstream-check/README.md b/controllers/nginx/examples/custom-upstream-check/README.md deleted file mode 100644 index 612c93922..000000000 --- a/controllers/nginx/examples/custom-upstream-check/README.md +++ /dev/null @@ -1,45 +0,0 @@ -This example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule. - -``` -echo " -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: echoheaders - annotations: - ingress.kubernetes.io/upstream-fail-timeout: "30" -spec: - rules: - - host: foo.bar.com - http: - paths: - - path: / - backend: - serviceName: echoheaders - servicePort: 80 -" | kubectl create -f - -``` - -Check the annotation is present in the Ingress rule: -``` -kubectl get ingress echoheaders -o yaml -``` - -Check the NGINX configuration is updated using kubectl or the status page: - -``` -$ kubectl exec nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf -``` - -``` -.... - upstream default-echoheaders-x-80 { - least_conn; - server 10.2.92.2:8080 max_fails=5 fail_timeout=30; - - } -.... -``` - - -![nginx-module-vts](contrib/ingress/controllers/nginx/examples/custom-upstream-check/custom-upstream.png "screenshot with custom configuration") diff --git a/controllers/nginx/examples/custom-upstream-check/custom-upstream.png b/controllers/nginx/examples/custom-upstream-check/custom-upstream.png deleted file mode 100644 index 30417894bfae8f02b1f10e71a535c19cd51f5573..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60592 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%0Di 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 diff --git a/controllers/nginx/examples/daemonset/README.md b/controllers/nginx/examples/daemonset/README.md deleted file mode 100644 index 42eb73b52..000000000 --- a/controllers/nginx/examples/daemonset/README.md +++ /dev/null @@ -1,8 +0,0 @@ - -In some cases could be required to run the Ingress controller in all the nodes in cluster. -Using [DaemonSet](https://github.com/kubernetes/kubernetes/blob/master/docs/design/daemon.md) it is possible to do this. -The file `as-daemonset.yaml` contains an example - -``` -kubectl create -f as-daemonset.yaml -``` \ No newline at end of file diff --git a/controllers/nginx/examples/daemonset/as-daemonset.yaml b/controllers/nginx/examples/daemonset/as-daemonset.yaml deleted file mode 100644 index 5b68a4045..000000000 --- a/controllers/nginx/examples/daemonset/as-daemonset.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: DaemonSet -metadata: - name: nginx-ingress-lb -spec: - template: - metadata: - labels: - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend diff --git a/controllers/nginx/examples/default-backend.yaml b/controllers/nginx/examples/default-backend.yaml deleted file mode 100644 index 77b4f6742..000000000 --- a/controllers/nginx/examples/default-backend.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: default-http-backend -spec: - replicas: 1 - selector: - app: default-http-backend - template: - metadata: - labels: - app: default-http-backend - spec: - terminationGracePeriodSeconds: 60 - containers: - - name: default-http-backend - # Any image is permissable as long as: - # 1. It serves a 404 page at / - # 2. It serves 200 on a /healthz endpoint - image: gcr.io/google_containers/defaultbackend:1.0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - scheme: HTTP - initialDelaySeconds: 30 - timeoutSeconds: 5 - ports: - - containerPort: 8080 - resources: - limits: - cpu: 10m - memory: 20Mi - requests: - cpu: 10m - memory: 20Mi diff --git a/controllers/nginx/examples/default/README.md b/controllers/nginx/examples/default/README.md deleted file mode 100644 index 2051a818b..000000000 --- a/controllers/nginx/examples/default/README.md +++ /dev/null @@ -1,76 +0,0 @@ - -Create the Ingress controller -``` -kubectl create -f rc-default.yaml -``` - -To test if evertyhing is working correctly: - -`curl -v http://:80/foo -H 'Host: foo.bar.com'` - -You should see an output similar to -``` -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET /foo HTTP/1.1 -> Host: foo.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 200 OK -< Server: nginx/1.9.8 -< Date: Tue, 15 Dec 2015 13:45:13 GMT -< Content-Type: text/plain -< Transfer-Encoding: chunked -< Connection: keep-alive -< Vary: Accept-Encoding -< -CLIENT VALUES: -client_address=10.2.84.43 -command=GET -real path=/foo -query=nil -request_version=1.1 -request_uri=http://foo.bar.com:8080/foo - -SERVER VALUES: -server_version=nginx: 1.9.7 - lua: 9019 - -HEADERS RECEIVED: -accept=*/* -connection=close -host=foo.bar.com -user-agent=curl/7.43.0 -x-forwarded-for=172.17.4.1 -x-forwarded-host=foo.bar.com -x-forwarded-server=foo.bar.com -x-real-ip=172.17.4.1 -BODY: -* Connection #0 to host 172.17.4.99 left intact -``` - -If we try to get a non exising route like `/foobar` we should see -``` -$ curl -v 172.17.4.99/foobar -H 'Host: foo.bar.com' -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET /foobar HTTP/1.1 -> Host: foo.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 404 Not Found -< Server: nginx/1.9.8 -< Date: Tue, 15 Dec 2015 13:48:18 GMT -< Content-Type: text/html -< Transfer-Encoding: chunked -< Connection: keep-alive -< Vary: Accept-Encoding -< -default backend - 404 -* Connection #0 to host 172.17.4.99 left intact -``` - -(this test checked that the default backend is properly working) - -*Replacing the default backend with a custom one we can change the default error pages provided by nginx* diff --git a/controllers/nginx/examples/default/rc-default.yaml b/controllers/nginx/examples/default/rc-default.yaml deleted file mode 100644 index 7577c8b7b..000000000 --- a/controllers/nginx/examples/default/rc-default.yaml +++ /dev/null @@ -1,51 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend diff --git a/controllers/nginx/examples/external-auth/README.md b/controllers/nginx/examples/external-auth/README.md deleted file mode 100644 index db522c1d2..000000000 --- a/controllers/nginx/examples/external-auth/README.md +++ /dev/null @@ -1,148 +0,0 @@ -# External authentication - -### Example 1: - -Use an external service (Basic Auth) located in `https://httpbin.org` - -``` -$ kubectl create -f ingress.yaml -ingress "external-auth" created -$ kubectl get ing external-auth -NAME HOSTS ADDRESS PORTS AGE -external-auth external-auth-01.sample.com 172.17.4.99 80 13s -$ kubectl get ing external-auth -o yaml -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - annotations: - ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd - creationTimestamp: 2016-10-03T13:50:35Z - generation: 1 - name: external-auth - namespace: default - resourceVersion: "2068378" - selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth - uid: 5c388f1d-8970-11e6-9004-080027d2dc94 -spec: - rules: - - host: external-auth-01.sample.com - http: - paths: - - backend: - serviceName: echoheaders - servicePort: 80 - path: / -status: - loadBalancer: - ingress: - - ip: 172.17.4.99 -$ -``` - -Test 1: no username/password (expect code 401) -``` -$ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -* Rebuilt URL to: http://172.17.4.99/ -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET / HTTP/1.1 -> Host: external-auth-01.sample.com -> User-Agent: curl/7.50.1 -> Accept: */* -> -< HTTP/1.1 401 Unauthorized -< Server: nginx/1.11.3 -< Date: Mon, 03 Oct 2016 14:52:08 GMT -< Content-Type: text/html -< Content-Length: 195 -< Connection: keep-alive -< WWW-Authenticate: Basic realm="Fake Realm" -< - -401 Authorization Required - -

401 Authorization Required

-
nginx/1.11.3
- - -* Connection #0 to host 172.17.4.99 left intact -``` - -Test 2: valid username/password (expect code 200) -``` -$ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:passwd' -* Rebuilt URL to: http://172.17.4.99/ -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -* Server auth using Basic with user 'user' -> GET / HTTP/1.1 -> Host: external-auth-01.sample.com -> Authorization: Basic dXNlcjpwYXNzd2Q= -> User-Agent: curl/7.50.1 -> Accept: */* -> -< HTTP/1.1 200 OK -< Server: nginx/1.11.3 -< Date: Mon, 03 Oct 2016 14:52:50 GMT -< Content-Type: text/plain -< Transfer-Encoding: chunked -< Connection: keep-alive -< -CLIENT VALUES: -client_address=10.2.60.2 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://external-auth-01.sample.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.11 - lua: 10001 - -HEADERS RECEIVED: -accept=*/* -authorization=Basic dXNlcjpwYXNzd2Q= -connection=close -host=external-auth-01.sample.com -user-agent=curl/7.50.1 -x-forwarded-for=10.2.60.1 -x-forwarded-host=external-auth-01.sample.com -x-forwarded-port=80 -x-forwarded-proto=http -x-real-ip=10.2.60.1 -BODY: -* Connection #0 to host 172.17.4.99 left intact --no body in request- -``` - -Test 3: invalid username/password (expect code 401) -``` -curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user' -* Rebuilt URL to: http://172.17.4.99/ -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -* Server auth using Basic with user 'user' -> GET / HTTP/1.1 -> Host: external-auth-01.sample.com -> Authorization: Basic dXNlcjp1c2Vy -> User-Agent: curl/7.50.1 -> Accept: */* -> -< HTTP/1.1 401 Unauthorized -< Server: nginx/1.11.3 -< Date: Mon, 03 Oct 2016 14:53:04 GMT -< Content-Type: text/html -< Content-Length: 195 -< Connection: keep-alive -* Authentication problem. Ignoring this. -< WWW-Authenticate: Basic realm="Fake Realm" -< - -401 Authorization Required - -

401 Authorization Required

-
nginx/1.11.3
- - -* Connection #0 to host 172.17.4.99 left intact -``` diff --git a/controllers/nginx/examples/external-auth/ingress.yaml b/controllers/nginx/examples/external-auth/ingress.yaml deleted file mode 100644 index 1cf779ce2..000000000 --- a/controllers/nginx/examples/external-auth/ingress.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - annotations: - ingress.kubernetes.io/auth-url: "https://httpbin.org/basic-auth/user/passwd" - name: external-auth -spec: - rules: - - host: external-auth-01.sample.com - http: - paths: - - backend: - serviceName: echoheaders - servicePort: 80 - path: / \ No newline at end of file diff --git a/controllers/nginx/examples/full/rc-full.yaml b/controllers/nginx/examples/full/rc-full.yaml deleted file mode 100644 index 847297b43..000000000 --- a/controllers/nginx/examples/full/rc-full.yaml +++ /dev/null @@ -1,62 +0,0 @@ - -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - volumes: - - name: dhparam-example - secret: - secretName: dhparam-example - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - - containerPort: 8080 - hostPort: 9000 - volumeMounts: - - mountPath: /etc/nginx-ssl/dhparam - name: dhparam-example - args: - - /nginx-ingress-controller - - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-configmap-example - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend diff --git a/controllers/nginx/examples/ingress.yaml b/controllers/nginx/examples/ingress.yaml deleted file mode 100644 index c5d300a6d..000000000 --- a/controllers/nginx/examples/ingress.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# An Ingress with 2 hosts and 3 endpoints -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: echomap -spec: - rules: - - host: foo.bar.com - http: - paths: - - path: /foo - backend: - serviceName: echoheaders-x - servicePort: 80 - - host: bar.baz.com - http: - paths: - - path: /bar - backend: - serviceName: echoheaders-y - servicePort: 80 - - path: /foo - backend: - serviceName: echoheaders-x - servicePort: 80 diff --git a/controllers/nginx/examples/multi-tls/README.md b/controllers/nginx/examples/multi-tls/README.md deleted file mode 100644 index 12f4b76e9..000000000 --- a/controllers/nginx/examples/multi-tls/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# Multi TLS certificate termination - -This examples uses 2 different certificates to terminate SSL for 2 hostnames. - -1. Deploy the controller by creating the rc in the parent dir -2. Create tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml -3. Create multi-tls.yaml - -This should generate a segment like: -```console -$ kubectl exec -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf | grep "foo.bar.com" -B 7 -A 35 - server { - listen 80; - listen 443 ssl http2; - ssl_certificate /etc/nginx-ssl/default-foobar.pem; - ssl_certificate_key /etc/nginx-ssl/default-foobar.pem; - - - server_name foo.bar.com; - - - if ($scheme = http) { - return 301 https://$host$request_uri; - } - - - - location / { - proxy_set_header Host $host; - - # Pass Real IP - proxy_set_header X-Real-IP $remote_addr; - - # Allow websocket connections - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; - - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Proto $pass_access_scheme; - - proxy_connect_timeout 5s; - proxy_send_timeout 60s; - proxy_read_timeout 60s; - - proxy_redirect off; - proxy_buffering off; - - proxy_http_version 1.1; - - proxy_pass http://default-echoheaders-80; - } -``` - -And you should be able to reach your nginx service or echoheaders service using a hostname switch: -```console -$ kubectl get ing -NAME RULE BACKEND ADDRESS AGE -foo-tls - 104.154.30.67 13m - foo.bar.com - / echoheaders:80 - bar.baz.com - / nginx:80 - -$ curl https://104.154.30.67 -H 'Host:foo.bar.com' -k -CLIENT VALUES: -client_address=10.245.0.6 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://foo.bar.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.11 - lua: 10001 - -HEADERS RECEIVED: -accept=*/* -connection=close -host=foo.bar.com -user-agent=curl/7.35.0 -x-forwarded-for=10.245.0.1 -x-forwarded-host=foo.bar.com -x-forwarded-proto=https - -$ curl https://104.154.30.67 -H 'Host:bar.baz.com' -k - - - -Welcome to nginx on Debian! - -$ curl 104.154.30.67 -default backend - 404 -``` diff --git a/controllers/nginx/examples/multi-tls/multi-tls.yaml b/controllers/nginx/examples/multi-tls/multi-tls.yaml deleted file mode 100644 index c23f3a193..000000000 --- a/controllers/nginx/examples/multi-tls/multi-tls.yaml +++ /dev/null @@ -1,102 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: nginx - labels: - app: nginx -spec: - ports: - - port: 80 - targetPort: 80 - protocol: TCP - name: http - selector: - app: nginx ---- -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx -spec: - replicas: 1 - template: - metadata: - labels: - app: nginx - spec: - containers: - - name: nginx - image: gcr.io/google_containers/nginx - ports: - - containerPort: 80 ---- -apiVersion: v1 -kind: Service -metadata: - name: echoheaders - labels: - app: echoheaders -spec: - ports: - - port: 80 - targetPort: 8080 - protocol: TCP - name: http - selector: - app: echoheaders ---- -apiVersion: v1 -kind: ReplicationController -metadata: - name: echoheaders -spec: - replicas: 1 - template: - metadata: - labels: - app: echoheaders - spec: - containers: - - name: echoheaders - image: gcr.io/google_containers/echoserver:1.4 - ports: - - containerPort: 8080 ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: foo-tls - namespace: default -spec: - tls: - - hosts: - - foo.bar.com - # This secret must exist beforehand - # The cert must also contain the subj-name foo.bar.com - # You can create it via: - # make keys secret SECRET=/tmp/foobar.json HOST=foo.bar.com NAME=foobar - # https://github.com/kubernetes/contrib/tree/master/ingress/controllers/gce/https_example - secretName: foobar - - hosts: - - bar.baz.com - # This secret must exist beforehand - # The cert must also contain the subj-name bar.baz.com - # You can create it via: - # make keys secret SECRET=/tmp/barbaz.json HOST=bar.baz.com NAME=barbaz - # https://github.com/kubernetes/contrib/tree/master/ingress/controllers/gce/https_example - secretName: barbaz - rules: - - host: foo.bar.com - http: - paths: - - backend: - serviceName: echoheaders - servicePort: 80 - path: / - - host: bar.baz.com - http: - paths: - - backend: - serviceName: nginx - servicePort: 80 - path: / diff --git a/controllers/nginx/examples/proxy-protocol/README.md b/controllers/nginx/examples/proxy-protocol/README.md deleted file mode 100644 index 929b82fb1..000000000 --- a/controllers/nginx/examples/proxy-protocol/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Nginx ingress controller using Proxy Protocol - -For using the Proxy Protocol in a load balancing solution, both the load balancer and its backend need to enable Proxy Protocol. - -To enable it for NGINX you have to setup a [configmap](nginx-configmap.yaml) option. - -## HAProxy - -This HAProxy snippet would forward HTTP(S) traffic to a two worker kubernetes cluster, with NGINX running on the node ports, like defined in this example's [service](nginx-svc.yaml). - - -``` -listen kube-nginx-http - bind :::80 v6only - bind 0.0.0.0:80 - mode tcp - option tcplog - balance leastconn - server node1 :32080 check-send-proxy inter 10s send-proxy - server node2 :32080 check-send-proxy inter 10s send-proxy - -listen kube-nginx-https - bind :::443 v6only - bind 0.0.0.0:443 - mode tcp - option tcplog - balance leastconn - server node1 :32443 check-send-proxy inter 10s send-proxy - server node2 :32443 check-send-proxy inter 10s send-proxy -``` - -## ELBs in AWS - -See this [documentation](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/enable-proxy-protocol.html) how to enable Proxy Protocol in ELBs diff --git a/controllers/nginx/examples/proxy-protocol/nginx-configmap.yaml b/controllers/nginx/examples/proxy-protocol/nginx-configmap.yaml deleted file mode 100644 index 3f049e370..000000000 --- a/controllers/nginx/examples/proxy-protocol/nginx-configmap.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -metadata: - name: nginx-ingress-controller -data: - use-proxy-protocol: "true" -kind: ConfigMap diff --git a/controllers/nginx/examples/proxy-protocol/nginx-rc.yaml b/controllers/nginx/examples/proxy-protocol/nginx-rc.yaml deleted file mode 100644 index 16e8500c9..000000000 --- a/controllers/nginx/examples/proxy-protocol/nginx-rc.yaml +++ /dev/null @@ -1,50 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - - containerPort: 443 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - - --nginx-configmap=$(POD_NAMESPACE)/nginx-ingress-controller diff --git a/controllers/nginx/examples/proxy-protocol/nginx-svc.yaml b/controllers/nginx/examples/proxy-protocol/nginx-svc.yaml deleted file mode 100644 index 0ef41fc43..000000000 --- a/controllers/nginx/examples/proxy-protocol/nginx-svc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: nginx-ingress-controller -spec: - type: NodePort - ports: - - port: 80 - targetPort: 80 - nodePort: 32080 - protocol: TCP - name: http - - port: 443 - targetPort: 443 - nodePort: 32443 - protocol: TCP - name: https - selector: - k8s-app: nginx-ingress-lb diff --git a/controllers/nginx/examples/rewrite/README.md b/controllers/nginx/examples/rewrite/README.md deleted file mode 100644 index 507b4315a..000000000 --- a/controllers/nginx/examples/rewrite/README.md +++ /dev/null @@ -1,67 +0,0 @@ - -Create an Ingress rule with a rewrite annotation: -``` -$ echo " -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - annotations: - ingress.kubernetes.io/rewrite-target: / - name: rewrite - namespace: default -spec: - rules: - - host: rewrite.bar.com - http: - paths: - - backend: - serviceName: echoheaders - servicePort: 80 - path: /something -" | kubectl create -f - -``` - -Check the rewrite is working - -``` -$ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com' -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET /something HTTP/1.1 -> Host: rewrite.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 200 OK -< Server: nginx/1.11.0 -< Date: Tue, 31 May 2016 16:07:31 GMT -< Content-Type: text/plain -< Transfer-Encoding: chunked -< Connection: keep-alive -< -CLIENT VALUES: -client_address=10.2.56.9 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://rewrite.bar.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.11 - lua: 10001 - -HEADERS RECEIVED: -accept=*/* -connection=close -host=rewrite.bar.com -user-agent=curl/7.43.0 -x-forwarded-for=10.2.56.1 -x-forwarded-host=rewrite.bar.com -x-forwarded-port=80 -x-forwarded-proto=http -x-real-ip=10.2.56.1 -BODY: -* Connection #0 to host 172.17.4.99 left intact --no body in request- -``` - diff --git a/controllers/nginx/examples/sysctl/change-proc-values-rc.yaml b/controllers/nginx/examples/sysctl/change-proc-values-rc.yaml deleted file mode 100644 index d84d58fb7..000000000 --- a/controllers/nginx/examples/sysctl/change-proc-values-rc.yaml +++ /dev/null @@ -1,128 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: default-http-backend - labels: - k8s-app: default-http-backend -spec: - ports: - - port: 80 - targetPort: 8080 - protocol: TCP - name: http - selector: - k8s-app: default-http-backend ---- -apiVersion: v1 -kind: ReplicationController -metadata: - name: default-http-backend -spec: - replicas: 1 - selector: - k8s-app: default-http-backend - template: - metadata: - labels: - k8s-app: default-http-backend - spec: - terminationGracePeriodSeconds: 60 - containers: - - name: default-http-backend - # Any image is permissable as long as: - # 1. It serves a 404 page at / - # 2. It serves 200 on a /healthz endpoint - image: gcr.io/google_containers/defaultbackend:1.0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - scheme: HTTP - initialDelaySeconds: 30 - timeoutSeconds: 5 - ports: - - containerPort: 8080 - resources: - limits: - cpu: 10m - memory: 20Mi - requests: - cpu: 10m - memory: 20Mi ---- -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: alpine:3.4 - name: sysctl-buddy - # using kubectl exec you can check which other parameters is possible to change - # IPC Namespace: kernel.msgmax, kernel.msgmnb, kernel.msgmni, kernel.sem, kernel.shmall, - # kernel.shmmax, kernel.shmmni, kernel.shm_rmid_forced and Sysctls - # beginning with fs.mqueue.* - # Network Namespace: Sysctls beginning with net.* - # - # kubectl -c sysctl-buddy -- sysctl -A | grep net - command: - - /bin/sh - - -c - - | - while true; do - sysctl -w net.core.somaxconn=32768 - sysctl -w net.ipv4.ip_local_port_range='1024 65535' - sleep 10 - done - imagePullPolicy: IfNotPresent - securityContext: - privileged: true - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - # we expose 8080 to access nginx stats in url /nginx-status - # this is optional - - containerPort: 8080 - hostPort: 8080 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend diff --git a/controllers/nginx/examples/tcp/README.md b/controllers/nginx/examples/tcp/README.md deleted file mode 100644 index a42c88d24..000000000 --- a/controllers/nginx/examples/tcp/README.md +++ /dev/null @@ -1,74 +0,0 @@ - -To configure which services and ports will be exposed -``` -kubectl create -f tcp-configmap-example.yaml -``` - -The file `tcp-configmap-example.yaml` uses a ConfigMap where the key is the external port to use and the value is -`:` -It is possible to use a number or the name of the port. - -``` -kubectl create -f rc-tcp.yaml -``` - -Now we can test the new service: -``` -$ (sleep 1; echo "GET / HTTP/1.1"; echo "Host: 172.17.4.99:9000"; echo;echo;sleep 2) | telnet 172.17.4.99 9000 - -Trying 172.17.4.99... -Connected to 172.17.4.99. -Escape character is '^]'. -HTTP/1.1 200 OK -Server: nginx/1.9.7 -Date: Tue, 15 Dec 2015 14:46:28 GMT -Content-Type: text/plain -Transfer-Encoding: chunked -Connection: keep-alive - -f -CLIENT VALUES: - -1a -client_address=10.2.84.45 - -c -command=GET - -c -real path=/ - -a -query=nil - -14 -request_version=1.1 - -25 -request_uri=http://172.17.4.99:8080/ - -1 - - -f -SERVER VALUES: - -28 -server_version=nginx: 1.9.7 - lua: 9019 - -1 - - -12 -HEADERS RECEIVED: - -16 -host=172.17.4.99:9000 - -6 -BODY: - -14 --no body in request- -0 -``` diff --git a/controllers/nginx/examples/tcp/rc-tcp.yaml b/controllers/nginx/examples/tcp/rc-tcp.yaml deleted file mode 100644 index 010ca87de..000000000 --- a/controllers/nginx/examples/tcp/rc-tcp.yaml +++ /dev/null @@ -1,56 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - # service echoheaders as TCP service default/echoheaders:9000 - # 9000 indicates the port used to expose the service - - containerPort: 9000 - hostPort: 9000 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-configmap-example diff --git a/controllers/nginx/examples/tcp/tcp-configmap-example.yaml b/controllers/nginx/examples/tcp/tcp-configmap-example.yaml deleted file mode 100644 index b3be42694..000000000 --- a/controllers/nginx/examples/tcp/tcp-configmap-example.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: tcp-configmap-example -data: - 9000: "default/example-go:8080" diff --git a/controllers/nginx/examples/tls/README.md b/controllers/nginx/examples/tls/README.md deleted file mode 100644 index 39ea28406..000000000 --- a/controllers/nginx/examples/tls/README.md +++ /dev/null @@ -1,90 +0,0 @@ -This is an example to use a TLS Ingress rule to use SSL in NGINX - -# TLS certificate termination - -This examples uses 2 different certificates to terminate SSL for 2 hostnames. - -1. Deploy the controller by creating the rc in the parent dir -2. Create tls secret for foo.bar.com -3. Create rc-ssl.yaml - -*Next create a SSL certificate for `foo.bar.com` host:* - -``` -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=foo.bar.com" -``` - -*Now store the SSL certificate in a secret:* - -``` -echo " -apiVersion: v1 -kind: Secret -metadata: - name: foo-secret -data: - tls.crt: `base64 /tmp/tls.crt` - tls.key: `base64 /tmp/tls.key` -" | kubectl create -f - -``` - -*Finally create a tls Ingress rule:* - -``` -echo " -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: foo - namespace: default -spec: - tls: - - hosts: - - foo.bar.com - secretName: foo-secret - rules: - - host: foo.bar.com - http: - paths: - - backend: - serviceName: echoheaders-x - servicePort: 80 - path: / -" | kubectl create -f - -``` - -You should be able to reach your nginx service or echoheaders service using a hostname: -``` -$ kubectl get ing -NAME RULE BACKEND ADDRESS -foo - 10.4.0.3 - foo.bar.com - / echoheaders-x:80 -``` - -``` -$ curl https://10.4.0.3 -H 'Host:foo.bar.com' -k -old-mbp:contrib aledbf$ curl https://10.4.0.3 -H 'Host:foo.bar.com' -k -CLIENT VALUES: -client_address=10.2.48.4 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://foo.bar.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.7 - lua: 9019 - -HEADERS RECEIVED: -accept=*/* -connection=close -host=foo.bar.com -user-agent=curl/7.43.0 -x-forwarded-for=10.2.48.1 -x-forwarded-host=foo.bar.com -x-forwarded-proto=https -x-real-ip=10.2.48.1 -BODY: --no body in request- -``` diff --git a/controllers/nginx/examples/tls/dhparam.sh b/controllers/nginx/examples/tls/dhparam.sh deleted file mode 100755 index 5852e5afe..000000000 --- a/controllers/nginx/examples/tls/dhparam.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2015 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -# https://www.openssl.org/docs/manmaster/apps/dhparam.html -# this command generates a key used to get "Perfect Forward Secrecy" in nginx -# https://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam -openssl dhparam -out dhparam.pem 4096 - -cat < dhparam-example.yaml -{ - "kind": "Secret", - "apiVersion": "v1", - "metadata": { - "name": "dhparam-example" - }, - "data": { - "dhparam.pem": "$(cat ./dhparam.pem | base64)" - } -} - -EOF diff --git a/controllers/nginx/examples/tls/rc-ssl.yaml b/controllers/nginx/examples/tls/rc-ssl.yaml deleted file mode 100644 index 7577c8b7b..000000000 --- a/controllers/nginx/examples/tls/rc-ssl.yaml +++ /dev/null @@ -1,51 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend diff --git a/controllers/nginx/examples/udp/README.md b/controllers/nginx/examples/udp/README.md deleted file mode 100644 index 454873706..000000000 --- a/controllers/nginx/examples/udp/README.md +++ /dev/null @@ -1,13 +0,0 @@ - -To configure which services and ports will be exposed -``` -kubectl create -f udp-configmap-example.yaml -``` - -The file `udp-configmap-example.yaml` uses a ConfigMap where the key is the external port to use and the value is -`:` -It is possible to use a number or the name of the port. - -``` -kubectl create -f rc-udp.yaml -``` diff --git a/controllers/nginx/examples/udp/rc-udp.yaml b/controllers/nginx/examples/udp/rc-udp.yaml deleted file mode 100644 index 9fbddced0..000000000 --- a/controllers/nginx/examples/udp/rc-udp.yaml +++ /dev/null @@ -1,54 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: nginx-ingress-controller - labels: - k8s-app: nginx-ingress-lb -spec: - replicas: 1 - selector: - k8s-app: nginx-ingress-lb - template: - metadata: - labels: - k8s-app: nginx-ingress-lb - name: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3 - name: nginx-ingress-lb - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 1 - # use downward API - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - hostPort: 80 - - containerPort: 443 - hostPort: 443 - - containerPort: 53 - hostPort: 53 - args: - - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - - --udp-services-configmap=$(POD_NAMESPACE)/udp-configmap-example diff --git a/controllers/nginx/examples/udp/udp-configmap-example.yaml b/controllers/nginx/examples/udp/udp-configmap-example.yaml deleted file mode 100644 index bf368cb49..000000000 --- a/controllers/nginx/examples/udp/udp-configmap-example.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: udp-configmap-example -data: - 53: "kube-system/kube-dns:53" diff --git a/controllers/nginx/examples/whitelist/README.md b/controllers/nginx/examples/whitelist/README.md deleted file mode 100644 index 0de5cf3a6..000000000 --- a/controllers/nginx/examples/whitelist/README.md +++ /dev/null @@ -1,123 +0,0 @@ - -This example shows how is possible to restrict access - -``` -echo " -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: whitelist - annotations: - ingress.kubernetes.io/whitelist-source-range: "1.1.1.1/24" -spec: - rules: - - host: foo.bar.com - http: - paths: - - path: / - backend: - serviceName: echoheaders - servicePort: 80 -" | kubectl create -f - -``` - -Check the annotation is present in the Ingress rule: -``` -$ kubectl get ingress whitelist -o yaml -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - annotations: - ingress.kubernetes.io/whitelist-source-range: 1.1.1.1/24 - creationTimestamp: 2016-06-09T21:39:06Z - generation: 2 - name: whitelist - namespace: default - resourceVersion: "419363" - selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/whitelist - uid: 97b74737-2e8a-11e6-90db-080027d2dc94 -spec: - rules: - - host: whitelist.bar.com - http: - paths: - - backend: - serviceName: echoheaders - servicePort: 80 - path: / -status: - loadBalancer: - ingress: - - ip: 172.17.4.99 -``` - -Finally test is not possible to access the URL - -``` -$ curl -v http://172.17.4.99/ -H 'Host: whitelist.bar.com' -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET / HTTP/1.1 -> Host: whitelist.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 403 Forbidden -< Server: nginx/1.11.1 -< Date: Thu, 09 Jun 2016 21:56:17 GMT -< Content-Type: text/html -< Content-Length: 169 -< Connection: keep-alive -< - -403 Forbidden - -

403 Forbidden

-
nginx/1.11.1
- - -* Connection #0 to host 172.17.4.99 left intact -``` - -Removing the annotation removes the restriction - -``` -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET / HTTP/1.1 -> Host: whitelist.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 200 OK -< Server: nginx/1.11.1 -< Date: Thu, 09 Jun 2016 21:57:44 GMT -< Content-Type: text/plain -< Transfer-Encoding: chunked -< Connection: keep-alive -< -CLIENT VALUES: -client_address=10.2.89.7 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://whitelist.bar.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.11 - lua: 10001 - -HEADERS RECEIVED: -accept=*/* -connection=close -host=whitelist.bar.com -user-agent=curl/7.43.0 -x-forwarded-for=10.2.89.1 -x-forwarded-host=whitelist.bar.com -x-forwarded-port=80 -x-forwarded-proto=http -x-real-ip=10.2.89.1 -BODY: -* Connection #0 to host 172.17.4.99 left intact -``` -