Split documentation

This commit is contained in:
Manuel de Brito Fontes 2017-10-13 10:55:03 -03:00
parent a18daabc51
commit a9168f276e
144 changed files with 1780 additions and 3789 deletions

View file

@ -0,0 +1,196 @@
# Prerequisites
Many of the examples in this directory have common prerequisites.
## TLS certificates
Unless otherwise mentioned, the TLS secret used in examples is a 2048 bit RSA
key/cert pair with an arbitrarily chosen hostname, created as follows
```console
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
Generating a 2048 bit RSA private key
................+++
................+++
writing new private key to 'tls.key'
-----
$ kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret "tls-secret" created
```
## CA Authentication
You can act as your very own CA, or use an existing one. As an exercise / learning, we're going to generate our
own CA, and also generate a client certificate.
These instructions are based on CoreOS OpenSSL [instructions](https://coreos.com/kubernetes/docs/latest/openssl.html)
### Generating a CA
First of all, you've to generate a CA. This is going to be the one who will sign your client certificates.
In real production world, you may face CAs with intermediate certificates, as the following:
```console
$ openssl s_client -connect www.google.com:443
[...]
---
Certificate chain
0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com
i:/C=US/O=Google Inc/CN=Google Internet Authority G2
1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
```
To generate our CA Certificate, we've to run the following commands:
```console
$ openssl genrsa -out ca.key 2048
$ openssl req -x509 -new -nodes -key ca.key -days 10000 -out ca.crt -subj "/CN=example-ca"
```
This will generate two files: A private key (ca.key) and a public key (ca.crt). This CA is valid for 10000 days.
The ca.crt can be used later in the step of creation of CA authentication secret.
### Generating the client certificate
The following steps generate a client certificate signed by the CA generated above. This client can be
used to authenticate in a tls-auth configured ingress.
First, we need to generate an 'openssl.cnf' file that will be used while signing the keys:
```console
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
```
Then, a user generates his very own private key (that he needs to keep secret)
and a CSR (Certificate Signing Request) that will be sent to the CA to sign and generate a certificate.
```console
$ openssl genrsa -out client1.key 2048
$ openssl req -new -key client1.key -out client1.csr -subj "/CN=client1" -config openssl.cnf
```
As the CA receives the generated 'client1.csr' file, it signs it and generates a client.crt certificate:
```console
$ openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days 365 -extensions v3_req -extfile openssl.cnf
```
Then, you'll have 3 files: the client.key (user's private key), client.crt (user's public key) and client.csr (disposable CSR).
### Creating the CA Authentication secret
If you're using the CA Authentication feature, you need to generate a secret containing
all the authorized CAs. You must download them from your CA site in PEM format (like the following):
```
-----BEGIN CERTIFICATE-----
[....]
-----END CERTIFICATE-----
```
You can have as many certificates as you want. If they're in the binary DER format,
you can convert them as the following:
```console
$ openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem
```
Then, you've to concatenate them all in only one file, named 'ca.crt' as the following:
```console
$ cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt
```
The final step is to create a secret with the content of this file. This secret is going to be used in
the TLS Auth directive:
```console
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt=<ca.crt>
```
Note: You can also generate the CA Authentication Secret along with the TLS Secret by using:
```console
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt=<ca.crt> --from-file=tls.crt=<tls.crt> --from-file=tls.key=<tls.key>
```
## Test HTTP Service
All examples that require a test HTTP Service use the standard http-svc pod,
which you can deploy as follows
```console
$ kubectl create -f http-svc.yaml
service "http-svc" created
replicationcontroller "http-svc" created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
http-svc-p1t3t 1/1 Running 0 1d
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-svc 10.0.122.116 <pending> 80:30301/TCP 1d
```
You can test that the HTTP Service works by exposing it temporarily
```console
$ kubectl patch svc http-svc -p '{"spec":{"type": "LoadBalancer"}}'
"http-svc" patched
$ kubectl get svc http-svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-svc 10.0.122.116 <pending> 80:30301/TCP 1d
$ kubectl describe svc http-svc
Name: http-svc
Namespace: default
Labels: app=http-svc
Selector: app=http-svc
Type: LoadBalancer
IP: 10.0.122.116
LoadBalancer Ingress: 108.59.87.136
Port: http 80/TCP
NodePort: http 30301/TCP
Endpoints: 10.180.1.6:8080
Session Affinity: None
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {service-controller } Normal Type ClusterIP -> LoadBalancer
1m 1m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer
16s 16s 1 {service-controller } Normal CreatedLoadBalancer Created load balancer
$ curl 108.59.87.126
CLIENT VALUES:
client_address=10.240.0.3
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://108.59.87.136:8080/
SERVER VALUES:
server_version=nginx: 1.9.11 - lua: 10001
HEADERS RECEIVED:
accept=*/*
host=108.59.87.136
user-agent=curl/7.46.0
BODY:
-no body in request-
$ kubectl patch svc http-svc -p '{"spec":{"type": "NodePort"}}'
"http-svc" patched
```

94
docs/examples/README.md Normal file
View file

@ -0,0 +1,94 @@
# Ingress examples
This directory contains a catalog of examples on how to run, configure and
scale Ingress. Please review the [prerequisites](PREREQUISITES.md) before
trying them.
## Basic cross platform
Name | Description | Complexity Level
-----| ----------- | ----------------
Deployment | basic deployment of controllers | Beginner
TLS termination | terminate TLS at the ingress controller | Beginner
Name based virtual hosting | `Host` header routing | Beginner
Path routing | URL regex routing | Beginner
Health checking | configure/optimize health checks | Intermediate
Pipeline | pipeline cloud and nginx | Advanced
## AWS
Name | Description | Complexity Level
-----| ----------- | ----------------
AWS | basic deployment | Intermediate
## TLS
Name | Description | Complexity Level
-----| ----------- | ----------------
LetsEncrypt | acquire certs via ACME protocol | Intermediate
Intermediate certs | terminate TLS with intermediate certs | Advanced
Client certs | client cert authentication | Advanced
Re-encrypty | terminate, apply routing rules, re-encrypt | Advanced
## Scaling
Name | Description | Complexity Level
-----| ----------- | ----------------
Daemonset | run multiple controllers in a daemonset | Intermediate
Deployment | run multiple controllers as a deployment | Intermediate
Static-ip | a single ingress gets a single static ip | Intermediate
Geo-routing | route to geographically closest endpoint | Advanced
## Algorithms
Name | Description | Complexity Level
-----| ----------- | ----------------
Session stickyness | route requests consistently to the same endpoint | Advanced
Least connections | route requests based on least connections | Advanced
Weights | route requests to backends based on weights | Advanced
## Routing
Name | Description | Complexity Level
-----| ----------- | ----------------
Redirects | send a 301 re-direct | Intermediate
URL-rewriting | re-write path | Intermediate
SNI + HTTP | HTTP routing based on SNI hostname | Advanced
SNI + TCP | TLS routing based on SNI hostname | Advanced
## Auth
Name | Description | Complexity Level
-----| ----------- | ----------------
Basic auth | password protect your website | nginx | Intermediate
[External auth plugin](external-auth/README.md) | defer to an external auth service | Intermediate
## Protocols
Name | Description | Complexity Level
-----| ----------- | ----------------
TCP | TCP loadbalancing | Intermediate
UDP | UDP loadbalancing | Intermediate
Websockets | websockets loadbalancing | Intermediate
HTTP/2 | HTTP/2 loadbalancing | Intermediate
Proxy protocol | leverage the proxy protocol for source IP | Advanced
## Custom controllers
Name | Description | Complexity Level
-----| ----------- | ----------------
Dummy | A simple dummy controller that logs updates | Advanced
## Customization
Name | Description | Complexity Level
-----| ----------- | ----------------
custom-headers | set custom headers before send traffic to backends | Advanced
configuration-snippets | customize nginx location configuration using annotations | Advanced
## RBAC
Name | Description | Complexity Level
-----| ----------- | ----------------
rbac | Configuring Role Base Access Control | intermediate

View file

@ -0,0 +1,68 @@
# Sticky Session
This example demonstrates how to achieve session affinity using cookies
## Deployment
Session stickyness is achieved through 3 annotations on the Ingress, as shown in the [example](sticky-ingress.yaml).
|Name|Description|Values|
| --- | --- | --- |
|ingress.kubernetes.io/affinity|Sets the affinity type|string (in NGINX only ``cookie`` is possible|
|ingress.kubernetes.io/session-cookie-name|Name of the cookie that will be used|string (default to route)|
|ingress.kubernetes.io/session-cookie-hash|Type of hash that will be used in cookie value|sha1/md5/index|
You can create the ingress to test this
```console
kubectl create -f ingress.yaml
```
## Validation
You can confirm that the Ingress works.
```console
$ kubectl describe ing nginx-test
Name: nginx-test
Namespace: default
Address:
Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)
Rules:
Host Path Backends
---- ---- --------
stickyingress.example.com
/ nginx-service:80 (<none>)
Annotations:
affinity: cookie
session-cookie-hash: sha1
session-cookie-name: route
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test
$ curl -I http://stickyingress.example.com
HTTP/1.1 200 OK
Server: nginx/1.11.9
Date: Fri, 10 Feb 2017 14:11:12 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Set-Cookie: route=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly
Last-Modified: Tue, 24 Jan 2017 14:02:19 GMT
ETag: "58875e6b-264"
Accept-Ranges: bytes
```
In the example above, you can see a line containing the 'Set-Cookie: route' setting the right defined stickness cookie.
This cookie is created by NGINX containing the hash of the used upstream in that request.
If the user changes this cookie, NGINX creates a new one and redirect the user to another upstream.
If the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded.
When the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid.
When you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used.
This means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.

View file

@ -0,0 +1,18 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test
annotations:
ingress.kubernetes.io/affinity: "cookie"
ingress.kubernetes.io/session-cookie-name: "route"
ingress.kubernetes.io/session-cookie-hash: "sha1"
spec:
rules:
- host: stickyingress.example.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /

View file

@ -0,0 +1,126 @@
# Basic Authentication
This example shows how to add authentication in a Ingress rule using a secret that contains a file generated with `htpasswd`.
```console
$ htpasswd -c auth foo
New password: <bar>
New password:
Re-type new password:
Adding password for user foo
```
```console
$ kubectl create secret generic basic-auth --from-file=auth
secret "basic-auth" created
```
```console
$ kubectl get secret basic-auth -o yaml
apiVersion: v1
data:
auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK
kind: Secret
metadata:
name: basic-auth
namespace: default
type: Opaque
```
```console
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: http-svc
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"
<
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.10.0</center>
</body>
</html>
* 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-
```

View file

@ -0,0 +1,26 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
# Create this with kubectl create secret generic caingress --from-file=ca.crt --namespace=default
ingress.kubernetes.io/auth-tls-secret: "default/caingress"
ingress.kubernetes.io/auth-tls-verify-depth: "3"
ingress.kubernetes.io/auth-tls-verify-client: "on"
auth-tls-error-page: "http://www.mysite.com/error-cert.html"
kubernetes.io/ingress.class: "nginx"
name: nginx-test
namespace: default
spec:
rules:
- host: ingress.test.com
http:
paths:
- backend:
serviceName: http-svc:80
servicePort: 80
path: /
tls:
- hosts:
- ingress.test.com
secretName: tls-secret

View file

@ -0,0 +1,149 @@
# 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: http-svc
servicePort: 80
path: /
status:
loadBalancer:
ingress:
- ip: 172.17.4.99
$
```
Test 1: no username/password (expect code 401)
```console
$ 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"
<
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.11.3</center>
</body>
</html>
* 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"
<
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.11.3</center>
</body>
</html>
* Connection #0 to host 172.17.4.99 left intact
```

View file

@ -0,0 +1,15 @@
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: http-svc
servicePort: 80
path: /

View file

@ -0,0 +1,12 @@
## Ingress
The Ingress in this example adds a custom header to Nginx configuration that only applies to that specific Ingress. If you want to add headers that apply globally to all Ingresses, please have a look at [this example](/examples/customization/custom-headers/nginx).
```console
$ kubectl apply -f ingress.yaml
```
## Test
Check if the contents of the annotation are present in the nginx.conf file using:
`kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf`

View file

@ -0,0 +1,18 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-configuration-snippet
annotations:
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Request-Id: $request_id";
spec:
rules:
- host: custom.configuration.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /

View file

@ -0,0 +1,24 @@
Using a [ConfigMap](https://kubernetes.io/docs/user-guide/configmap/) is possible to customize the NGINX configuration
For example, 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-timeout: "120"
kind: ConfigMap
metadata:
name: nginx-load-balancer-conf
```
```
$ kubectl create -f nginx-load-balancer-conf.yaml
```
Please check the example `nginx-custom-configuration.yaml`
If the Configmap it is updated, NGINX will be reloaded with the new configuration.

View file

@ -0,0 +1,56 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
labels:
k8s-app: nginx-ingress-controller
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: nginx-ingress-controller
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
# hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration
# however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host
# that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used
# like with kubeadm
# hostNetwork: true
terminationGracePeriodSeconds: 60
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.15
name: nginx-ingress-controller
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 1
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-custom-configuration

View file

@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-custom-configuration
labels:
k8s-app: nginx-ingress-controller
namespace: kube-system
data:
proxy-connect-timeout: "10"
proxy-read-timeout: "120"
proxy-send-timeout: "120"

View file

@ -0,0 +1,80 @@
This example shows how is possible to use a custom backend to render custom error pages. The code of this example is located here [custom-error-pages](https://github.com/kubernetes/ingress/tree/master/examples/customization/custom-errors/nginx)
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 <none> 443/TCP 34d
nginx-errors 10.3.0.102 <none> 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
<
<span>The page you're looking for could not be found.</span>
* 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
```

View file

@ -0,0 +1,31 @@
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

View file

@ -0,0 +1,51 @@
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.9.0-beta.15
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

View file

@ -0,0 +1,76 @@
# Deploying the Nginx Ingress controller
This example aims to demonstrate the deployment of an nginx ingress controller and
use a ConfigMap to configure a custom list of headers to be passed to the upstream
server
## Default Backend
The default backend is a Service capable of handling all url paths and hosts the
nginx controller doesn't understand. This most basic implementation just returns
a 404 page:
```console
$ kubectl apply -f default-backend.yaml
deployment "default-http-backend" created
service "default-http-backend" created
$ kubectl -n kube-system get po
NAME READY STATUS RESTARTS AGE
default-http-backend-2657704409-qgwdd 1/1 Running 0 28s
```
## Custom configuration
```console
$ cat nginx-load-balancer-conf.yaml
apiVersion: v1
data:
proxy-set-headers: "default/custom-headers"
kind: ConfigMap
metadata:
name: nginx-load-balancer-conf
```
```console
$ kubectl create -f nginx-load-balancer-conf.yaml
```
## Custom headers
```console
$ cat custom-headers.yaml
apiVersion: v1
data:
X-Different-Name: "true"
X-Request-Start: t=${msec}
X-Using-Nginx-Controller: "true"
kind: ConfigMap
metadata:
name: proxy-headers
namespace: default
```
```console
$ kubectl create -f custom-headers.yaml
```
## Controller
You can deploy the controller as follows:
```console
$ kubectl apply -f nginx-ingress-controller.yaml
deployment "nginx-ingress-controller" created
$ kubectl -n kube-system get po
NAME READY STATUS RESTARTS AGE
default-http-backend-2657704409-qgwdd 1/1 Running 0 2m
nginx-ingress-controller-873061567-4n3k2 1/1 Running 0 42s
```
## Test
Check the contents of the configmap is present in the nginx.conf file using:
`kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf`

View file

@ -0,0 +1,9 @@
apiVersion: v1
data:
X-Different-Name: "true"
X-Request-Start: t=${msec}
X-Using-Nginx-Controller: "true"
kind: ConfigMap
metadata:
name: custom-headers
namespace: kube-system

View file

@ -0,0 +1,51 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: default-http-backend
labels:
k8s-app: default-http-backend
namespace: kube-system
spec:
replicas: 1
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: Service
metadata:
name: default-http-backend
namespace: kube-system
labels:
k8s-app: default-http-backend
spec:
ports:
- port: 80
targetPort: 8080
selector:
k8s-app: default-http-backend

View file

@ -0,0 +1,53 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
labels:
k8s-app: nginx-ingress-controller
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: nginx-ingress-controller
spec:
# hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration
# however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host
# that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used
# like with kubeadm
# hostNetwork: true
terminationGracePeriodSeconds: 60
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.15
name: nginx-ingress-controller
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 1
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-load-balancer-conf

View file

@ -0,0 +1,7 @@
apiVersion: v1
data:
proxy-set-headers: "kube-system/custom-headers"
kind: ConfigMap
metadata:
name: nginx-load-balancer-conf
namespace: kube-system

View file

@ -0,0 +1,47 @@
# Custom Upstream server checks
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: http-svc
annotations:
ingress.kubernetes.io/upstream-fail-timeout: "30"
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /
backend:
serviceName: http-svc
servicePort: 80
" | kubectl create -f -
```
Check the annotation is present in the Ingress rule:
```
kubectl get ingress http-svc -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-http-svc-x-80 {
least_conn;
server 10.2.92.2:8080 max_fails=5 fail_timeout=30;
}
....
```
![nginx-module-vts](custom-upstream.png "screenshot with custom configuration")

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -0,0 +1,128 @@
# Deploying the Nginx Ingress controller
This example aims to demonstrate the deployment of an nginx ingress controller and use a ConfigMap to enable [nginx vts module](https://github.com/vozlt/nginx-module-vts
) to export metrics in prometheus format.
# vts-metrics
Vts-metrics export NGINX metrics. To deploy all the files simply run `kubectl apply -f nginx`. A deployment and service will be
created which already has a `prometheus.io/scrape: 'true'` annotation and if you added
the recommended Prometheus service-endpoint scraping [configuration](https://raw.githubusercontent.com/prometheus/prometheus/master/documentation/examples/prometheus-kubernetes.yml),
Prometheus will scrape it automatically and you start using the generated metrics right away.
## Default Backend
The default backend is a Service capable of handling all url paths and hosts the
nginx controller doesn't understand. This most basic implementation just returns
a 404 page:
```console
$ kubectl apply -f default-backend.yaml
deployment "default-http-backend" created
service "default-http-backend" created
$ kubectl -n kube-system get po
NAME READY STATUS RESTARTS AGE
default-http-backend-2657704409-qgwdd 1/1 Running 0 28s
```
## Custom configuration
```console
$ cat nginx-vts-metrics-conf.yaml
apiVersion: v1
data:
enable-vts-status: "true"
kind: ConfigMap
metadata:
name: nginx-vts-metrics-conf
namespace: kube-system
```
```console
$ kubectl create -f nginx-vts-metrics-conf.yaml
```
## Controller
You can deploy the controller as follows:
```console
$ kubectl apply -f nginx-ingress-controller.yaml
deployment "nginx-ingress-controller" created
$ kubectl -n kube-system get po
NAME READY STATUS RESTARTS AGE
default-http-backend-2657704409-qgwdd 1/1 Running 0 2m
nginx-ingress-controller-873061567-4n3k2 1/1 Running 0 42s
```
## Result
Check whether the ingress controller successfully generated the NGINX vts status:
```console
$ kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf|grep vhost_traffic_status_display
vhost_traffic_status_display;
vhost_traffic_status_display_format html;
```
### NGINX vts dashboard
The vts dashboard provides real time metrics.
![vts dashboard](imgs/vts-dashboard.png)
Because the vts port it's not yet exposed, you should forward the controller port to see it.
```console
$ kubectl port-forward $(kubectl get pods --selector=k8s-app=nginx-ingress-controller -n kube-system --output=jsonpath={.items..metadata.name}) -n kube-system 18080
```
Now open the url [http://localhost:18080/nginx_status](http://localhost:18080/nginx_status) in your browser.
### Prometheus metrics output
NGINX Ingress controller already has a parser to convert vts metrics to Prometheus format. It exports prometheus metrics to the address `:10254/metrics`.
```console
$ kubectl exec -ti -n kube-system $(kubectl get pods --selector=k8s-app=nginx-ingress-controller -n kube-system --output=jsonpath={.items..metadata.name}) curl localhost:10254/metrics
ingress_controller_ssl_expire_time_seconds{host="foo.bar.com"} -6.21355968e+10
# HELP ingress_controller_success Cumulative number of Ingress controller reload operations
# TYPE ingress_controller_success counter
ingress_controller_success{count="reloads"} 3
# HELP nginx_bytes_total Nginx bytes count
# TYPE nginx_bytes_total counter
nginx_bytes_total{direction="in",ingress_class="nginx",namespace="",server_zone="*"} 3708
nginx_bytes_total{direction="in",ingress_class="nginx",namespace="",server_zone="_"} 3708
nginx_bytes_total{direction="out",ingress_class="nginx",namespace="",server_zone="*"} 5256
nginx_bytes_total{direction="out",ingress_class="nginx",namespace="",server_zone="_"} 5256
```
### Customize metrics
The default [vts vhost key](https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_filter_by_set_key) is `$geoip_country_code country::*` that expose metrics groupped by server and country code. The example below show how to have metrics grouped by server and server path.
![vts dashboard](imgs/vts-dashboard-filter-key-path.png)
## NGINX custom configuration ( http level )
```
apiVersion: v1
kind: ConfigMap
data:
enable-vts-status: "true"
vts-default-filter-key: "$server_name"
...
```
## Customize ingress
```
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/vts-filter-key: $uri $server_name
name: ingress
```
## Result
![prometheus filter key path](imgs/prometheus-filter-key-path.png)

View file

@ -0,0 +1,51 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: default-http-backend
labels:
k8s-app: default-http-backend
namespace: kube-system
spec:
replicas: 1
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: Service
metadata:
name: default-http-backend
namespace: kube-system
labels:
k8s-app: default-http-backend
spec:
ports:
- port: 80
targetPort: 8080
selector:
k8s-app: default-http-backend

Binary file not shown.

After

Width:  |  Height:  |  Size: 969 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View file

@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress-controller-service
namespace: kube-system
labels:
k8s-app: nginx-ingress-controller-service
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
ports:
- name: http-metrics
port: 8080
targetPort: 10254
protocol: TCP
selector:
k8s-app: nginx-ingress-controller

View file

@ -0,0 +1,56 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
labels:
k8s-app: nginx-ingress-controller
namespace: kube-system
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: nginx-ingress-controller
spec:
# hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration
# however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host
# that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used
# like with kubeadm
# hostNetwork: true
terminationGracePeriodSeconds: 60
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.15
name: nginx-ingress-controller
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 1
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-vts-metrics-conf

View file

@ -0,0 +1,7 @@
apiVersion: v1
data:
enable-vts-status: "true"
kind: ConfigMap
metadata:
name: nginx-vts-metrics-conf
namespace: kube-system

View file

@ -0,0 +1,23 @@
all: push
TAG=0.1
PREFIX?=electroma/ingress-demo-
ARCH?=amd64
GOLANG_VERSION=1.8
TEMP_DIR:=$(shell mktemp -d)
build: clean
CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o authsvc/authsvc authsvc/authsvc.go
CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o echosvc/echosvc echosvc/echosvc.go
container: build
docker build --pull -t $(PREFIX)authsvc-$(ARCH):$(TAG) authsvc
docker build --pull -t $(PREFIX)echosvc-$(ARCH):$(TAG) echosvc
push: container
docker push $(PREFIX)authsvc-$(ARCH):$(TAG)
docker push $(PREFIX)echosvc-$(ARCH):$(TAG)
clean:
rm -f authsvc/authsvc echosvc/echosvc

View file

@ -0,0 +1,138 @@
# External authentication, authentication service response headers propagation
This example demonstrates propagation of selected authentication service response headers
to backend service.
Sample configuration includes:
* Sample authentication service producing several response headers
* Authentication logic is based on HTTP header: requests with header `User` containing string `internal` are considered authenticated
* After successful authentication service generates response headers `UserID` and `UserRole`
* Sample echo service displaying header information
* Two ingress objects pointing to echo service
* Public, which allows access from unauthenticated users
* Private, which allows access from authenticated users only
You can deploy the controller as
follows:
```console
$ kubectl create -f deploy/
deployment "demo-auth-service" created
service "demo-auth-service" created
ingress "demo-auth-service" created
deployment "default-http-backend" created
service "default-http-backend" created
deployment "demo-echo-service" created
service "demo-echo-service" created
ingress "public-demo-echo-service" created
ingress "secure-demo-echo-service" created
deployment "nginx-ingress-controller" created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
NAME READY STATUS RESTARTS AGE
default-http-backend-2657704409-vv0hm 1/1 Running 0 29s
demo-auth-service-2769076528-7g9mh 1/1 Running 0 30s
demo-echo-service-3636052215-3vw8c 1/1 Running 0 29s
kubectl get ing
NAME HOSTS ADDRESS PORTS AGE
public-demo-echo-service public-demo-echo-service.kube.local 80 1m
secure-demo-echo-service secure-demo-echo-service.kube.local 80 1m
```
Test 1: public service with no auth header
```
$ curl -H 'Host: public-demo-echo-service.kube.local' -v 192.168.99.100
* Rebuilt URL to: 192.168.99.100/
* Trying 192.168.99.100...
* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
> GET / HTTP/1.1
> Host: public-demo-echo-service.kube.local
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.11.10
< Date: Mon, 13 Mar 2017 20:19:21 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 20
< Connection: keep-alive
<
* Connection #0 to host 192.168.99.100 left intact
UserID: , UserRole:
```
Test 2: secure service with no auth header
```
$ curl -H 'Host: secure-demo-echo-service.kube.local' -v 192.168.99.100
* Rebuilt URL to: 192.168.99.100/
* Trying 192.168.99.100...
* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
> GET / HTTP/1.1
> Host: secure-demo-echo-service.kube.local
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Server: nginx/1.11.10
< Date: Mon, 13 Mar 2017 20:18:48 GMT
< Content-Type: text/html
< Content-Length: 170
< Connection: keep-alive
<
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.11.10</center>
</body>
</html>
* Connection #0 to host 192.168.99.100 left intact
```
Test 3: public service with valid auth header
```
$ curl -H 'Host: public-demo-echo-service.kube.local' -H 'User:internal' -v 192.168.99.100
* Rebuilt URL to: 192.168.99.100/
* Trying 192.168.99.100...
* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
> GET / HTTP/1.1
> Host: public-demo-echo-service.kube.local
> User-Agent: curl/7.43.0
> Accept: */*
> User:internal
>
< HTTP/1.1 200 OK
< Server: nginx/1.11.10
< Date: Mon, 13 Mar 2017 20:19:59 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 44
< Connection: keep-alive
<
* Connection #0 to host 192.168.99.100 left intact
UserID: 1443635317331776148, UserRole: admin
```
Test 4: public service with valid auth header
```
$ curl -H 'Host: secure-demo-echo-service.kube.local' -H 'User:internal' -v 192.168.99.100
* Rebuilt URL to: 192.168.99.100/
* Trying 192.168.99.100...
* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
> GET / HTTP/1.1
> Host: secure-demo-echo-service.kube.local
> User-Agent: curl/7.43.0
> Accept: */*
> User:internal
>
< HTTP/1.1 200 OK
< Server: nginx/1.11.10
< Date: Mon, 13 Mar 2017 20:17:23 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 43
< Connection: keep-alive
<
* Connection #0 to host 192.168.99.100 left intact
UserID: 605394647632969758, UserRole: admin
```

View file

@ -0,0 +1,5 @@
FROM alpine:3.5
MAINTAINER Roman Safronov <electroma@gmail.com>
COPY authsvc /
EXPOSE 8080
ENTRYPOINT ["/authsvc"]

View file

@ -0,0 +1,33 @@
package main
import (
"fmt"
"math/rand"
"net/http"
"strconv"
"strings"
)
// Sample authentication service returning several HTTP headers in response
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if strings.ContainsAny(r.Header.Get("User"), "internal") {
w.Header().Add("UserID", strconv.Itoa(rand.Int()))
w.Header().Add("UserRole", "admin")
w.Header().Add("Other", "not used")
fmt.Fprint(w, "ok")
} else {
rc := http.StatusForbidden
if c := r.URL.Query().Get("code"); len(c) > 0 {
c, _ := strconv.Atoi(c)
if c > 0 && c < 600 {
rc = c
}
}
w.WriteHeader(rc)
fmt.Fprint(w, "unauthorized")
}
})
http.ListenAndServe(":8080", nil)
}

View file

@ -0,0 +1,41 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: demo-auth-service
labels:
k8s-app: demo-auth-service
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: demo-auth-service
spec:
terminationGracePeriodSeconds: 60
containers:
- name: auth-service
image: electroma/ingress-demo-authsvc-amd64:0.1
ports:
- containerPort: 8080
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
---
apiVersion: v1
kind: Service
metadata:
name: demo-auth-service
labels:
k8s-app: demo-auth-service
namespace: default
spec:
ports:
- port: 80
targetPort: 8080
selector:
k8s-app: demo-auth-service

View file

@ -0,0 +1,48 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: default-http-backend
labels:
k8s-app: default-http-backend
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: default-http-backend
spec:
terminationGracePeriodSeconds: 60
containers:
- name: default-http-backend
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: Service
metadata:
name: default-http-backend
namespace: default
labels:
k8s-app: default-http-backend
spec:
ports:
- port: 80
targetPort: 8080
selector:
k8s-app: default-http-backend

View file

@ -0,0 +1,77 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: demo-echo-service
labels:
k8s-app: demo-echo-service
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: demo-echo-service
spec:
terminationGracePeriodSeconds: 60
containers:
- name: echo-service
image: electroma/ingress-demo-echosvc-amd64:0.1
ports:
- containerPort: 8080
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
---
apiVersion: v1
kind: Service
metadata:
name: demo-echo-service
labels:
k8s-app: demo-echo-service
namespace: default
spec:
ports:
- port: 80
targetPort: 8080
selector:
k8s-app: demo-echo-service
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: public-demo-echo-service
annotations:
ingress.kubernetes.io/auth-url: http://demo-auth-service.default.svc.cluster.local?code=200
ingress.kubernetes.io/auth-response-headers: UserID, UserRole
namespace: default
spec:
rules:
- host: public-demo-echo-service.kube.local
http:
paths:
- backend:
serviceName: demo-echo-service
servicePort: 80
path: /
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: secure-demo-echo-service
annotations:
ingress.kubernetes.io/auth-url: http://demo-auth-service.default.svc.cluster.local
ingress.kubernetes.io/auth-response-headers: UserID, UserRole
namespace: default
spec:
rules:
- host: secure-demo-echo-service.kube.local
http:
paths:
- backend:
serviceName: demo-echo-service
servicePort: 80
path: /

View file

@ -0,0 +1,33 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
labels:
k8s-app: nginx-ingress-controller
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: nginx-ingress-controller
spec:
terminationGracePeriodSeconds: 60
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2
name: nginx-ingress-controller
ports:
- containerPort: 80
hostPort: 80
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend

View file

@ -0,0 +1,5 @@
FROM alpine:3.5
MAINTAINER Roman Safronov <electroma@gmail.com>
COPY echosvc /
EXPOSE 8080
ENTRYPOINT ["/echosvc"]

View file

@ -0,0 +1,16 @@
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "UserID: %s, UserRole: %s", r.Header.Get("UserID"), r.Header.Get("UserRole"))
}
// Sample "echo" service displaying UserID and UserRole HTTP request headers
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}

View file

@ -0,0 +1,79 @@
# Deploying the Nginx Ingress controller
This example aims to demonstrate the deployment of an nginx ingress controller and
use a ConfigMap to configure custom Diffie-Hellman parameters file to help with
"Perfect Forward Secrecy".
## Default Backend
The default backend is a Service capable of handling all url paths and hosts the
nginx controller doesn't understand. This most basic implementation just returns
a 404 page:
```console
$ kubectl apply -f default-backend.yaml
deployment "default-http-backend" created
service "default-http-backend" created
$ kubectl -n kube-system get po
NAME READY STATUS RESTARTS AGE
default-http-backend-2657704409-qgwdd 1/1 Running 0 28s
```
## Custom configuration
```console
$ cat nginx-load-balancer-conf.yaml
apiVersion: v1
data:
ssl-dh-param: "kube-system/lb-dhparam"
kind: ConfigMap
metadata:
name: nginx-load-balancer-conf
```
```console
$ kubectl create -f nginx-load-balancer-conf.yaml
```
## Custom DH parameters secret
```console
$> openssl dhparam 1024 2> /dev/null | base64
LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...
```
```console
$ cat ssl-dh-param.yaml
apiVersion: v1
data:
dhparam.pem: "LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ..."
kind: Secret
type: Opaque
metadata:
name: lb-dhparam
namespace: kube-system
```
```console
$ kubectl create -f ssl-dh-param.yaml
```
## Controller
You can deploy the controller as follows:
```console
$ kubectl apply -f nginx-ingress-controller.yaml
deployment "nginx-ingress-controller" created
$ kubectl -n kube-system get po
NAME READY STATUS RESTARTS AGE
default-http-backend-2657704409-qgwdd 1/1 Running 0 2m
nginx-ingress-controller-873061567-4n3k2 1/1 Running 0 42s
```
## Test
Check the contents of the configmap is present in the nginx.conf file using:
`kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf`

View file

@ -0,0 +1,51 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: default-http-backend
labels:
k8s-app: default-http-backend
namespace: kube-system
spec:
replicas: 1
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: Service
metadata:
name: default-http-backend
namespace: kube-system
labels:
k8s-app: default-http-backend
spec:
ports:
- port: 80
targetPort: 8080
selector:
k8s-app: default-http-backend

View file

@ -0,0 +1,53 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
labels:
k8s-app: nginx-ingress-controller
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: nginx-ingress-controller
spec:
# hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration
# however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host
# that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used
# like with kubeadm
# hostNetwork: true
terminationGracePeriodSeconds: 60
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.15
name: nginx-ingress-controller
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 1
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-load-balancer-conf

View file

@ -0,0 +1,7 @@
apiVersion: v1
data:
ssl-dh-param: "kube-system/lb-dhparam"
kind: ConfigMap
metadata:
name: nginx-load-balancer-conf
namespace: kube-system

View file

@ -0,0 +1,8 @@
apiVersion: v1
data:
dhparam.pem: "...base64 encoded data..."
kind: Secret
type: Opaque
metadata:
name: lb-dhparam
namespace: kube-system

View file

@ -0,0 +1,75 @@
# External Authentication
### Overview
The `auth-url` and `auth-signin` annotations allow you to use an external
authentication provider to protect your Ingress resources.
(Note, this annotation requires `nginx-ingress-controller v0.9.0` or greater.)
### Key Detail
This functionality is enabled by deploying multiple Ingress objects for a single host.
One Ingress object has no special annotations and handles authentication.
Other Ingress objects can then be annotated in such a way that require the user to
authenticate against the first Ingress's endpoint, and can redirect `401`s to the
same endpoint.
Sample:
```yaml
...
metadata:
name: application
annotations:
"ingress.kubernetes.io/auth-url": "https://$host/oauth2/auth"
"ingress.kubernetes.io/auth-signin": "https://$host/oauth2/sign_in"
...
```
### Example: OAuth2 Proxy + Kubernetes-Dashboard
This example will show you how to deploy [`oauth2_proxy`](https://github.com/bitly/oauth2_proxy)
into a Kubernetes cluster and use it to protect the Kubernetes Dashboard using github as oAuth2 provider
#### Prepare
1. Install the kubernetes dashboard
```console
kubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/kubernetes-dashboard/v1.5.0.yaml
```
2. Create a custom Github OAuth application https://github.com/settings/applications/new
![Register OAuth2 Application](images/register-oauth-app.png)
- Homepage URL is the FQDN in the Ingress rule, like `https://foo.bar.com`
- Authorization callback URL is the same as the base FQDN plus `/oauth2`, like `https://foo.bar.com/oauth2`
![Register OAuth2 Application](images/register-oauth-app-2.png)
3. Configure oauth2_proxy values in the file oauth2-proxy.yaml with the values:
- OAUTH2_PROXY_CLIENT_ID with the github `<Client ID>`
- OAUTH2_PROXY_CLIENT_SECRET with the github `<Client Secret>`
- OAUTH2_PROXY_COOKIE_SECRET with value of `python -c 'import os,base64; print base64.b64encode(os.urandom(16))'`
4. Customize the contents of the file dashboard-ingress.yaml:
Replace `__INGRESS_HOST__` with a valid FQDN and `__INGRESS_SECRET__` with a Secret with a valid SSL certificate.
5. Deploy the oauth2 proxy and the ingress rules running:
```console
$ kubectl create -f oauth2-proxy.yaml,dashboard-ingress.yaml
```
Test the oauth integration accessing the configured URL, like `https://foo.bar.com`
![Register OAuth2 Application](images/github-auth.png)
![Github authentication](images/oauth-login.png)
![Kubernetes dashboard](images/dashboard.png)

View file

@ -0,0 +1,38 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/auth-signin: https://$host/oauth2/start
ingress.kubernetes.io/auth-url: https://$host/oauth2/auth
name: external-auth-oauth2
namespace: kube-system
spec:
rules:
- host: __INGRESS_HOST__
http:
paths:
- backend:
serviceName: kubernetes-dashboard
servicePort: 80
path: /
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: oauth2-proxy
namespace: kube-system
spec:
rules:
- host: __INGRESS_HOST__
http:
paths:
- backend:
serviceName: oauth2-proxy
servicePort: 4180
path: /oauth2
tls:
- hosts:
- __INGRESS_HOST__
secretName: __INGRESS_SECRET__

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View file

@ -0,0 +1,56 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
k8s-app: oauth2-proxy
name: oauth2-proxy
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
k8s-app: oauth2-proxy
template:
metadata:
labels:
k8s-app: oauth2-proxy
spec:
containers:
- args:
- --provider=github
- --email-domain=*
- --upstream=file:///dev/null
- --http-address=0.0.0.0:4180
# Register a new application
# https://github.com/settings/applications/new
env:
- name: OAUTH2_PROXY_CLIENT_ID
value: <Client ID>
- name: OAUTH2_PROXY_CLIENT_SECRET
value: <Client Secret>
# python -c 'import os,base64; print base64.b64encode(os.urandom(16))'
- name: OAUTH2_PROXY_COOKIE_SECRET
value: SECRET
image: docker.io/colemickens/oauth2_proxy:latest
imagePullPolicy: Always
name: oauth2-proxy
ports:
- containerPort: 4180
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: oauth2-proxy
name: oauth2-proxy
spec:
ports:
- name: http
port: 4180
protocol: TCP
targetPort: 4180
selector:
k8s-app: oauth2-proxy

View file

@ -0,0 +1,33 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: http-svc
spec:
replicas: 1
template:
metadata:
labels:
app: http-svc
spec:
containers:
- name: http-svc
image: gcr.io/google_containers/echoserver:1.8
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: http-svc
labels:
app: http-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: http-svc

View file

@ -0,0 +1,94 @@
# Multi TLS certificate termination
This example 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-http-svc-80;
}
```
And you should be able to reach your nginx service or http-svc service using a hostname switch:
```console
$ kubectl get ing
NAME RULE BACKEND ADDRESS AGE
foo-tls - 104.154.30.67 13m
foo.bar.com
/ http-svc: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
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on Debian!</title>
$ curl 104.154.30.67
default backend - 404
```

View file

@ -0,0 +1,120 @@
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: http-svc
labels:
app: http-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: http-svc
---
apiVersion: v1
kind: ReplicationController
metadata:
name: http-svc
spec:
replicas: 1
template:
metadata:
labels:
app: http-svc
spec:
containers:
- name: http-svc
image: gcr.io/google_containers/echoserver:1.8
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
---
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/ingress/tree/master/controllers/gce/examples/https
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/ingress/tree/master/controllers/gce/examples/https
secretName: barbaz
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
- host: bar.baz.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
path: /

View file

@ -0,0 +1,128 @@
# Rewrite
This example demonstrates how to use the Rewrite annotations
## Prerequisites
You will need to make sure you Ingress targets exactly one Ingress
controller by specifying the [ingress.class annotation](/examples/PREREQUISITES.md#ingress-class),
and that you have an ingress controller [running](/examples/deployment) in your cluster.
## Deployment
Rewriting can be controlled using the following annotations:
|Name|Description|Values|
| --- | --- | --- |
|ingress.kubernetes.io/rewrite-target|Target URI where the traffic must be redirected|string|
|ingress.kubernetes.io/add-base-url|indicates if is required to add a base tag in the head of the responses from the upstream servers|bool|
|ingress.kubernetes.io/base-url-scheme|Override for the scheme passed to the base tag|string|
|ingress.kubernetes.io/ssl-redirect|Indicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate)|bool|
|ingress.kubernetes.io/force-ssl-redirect|Forces the redirection to HTTPS even if the Ingress is not TLS Enabled|bool|
|ingress.kubernetes.io/app-root|Defines the Application Root that the Controller must redirect if it's not in '/' context|string|
## Validation
### Rewrite Target
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: http-svc
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-
```
### App Root
Create an Ingress rule with a app-root annotation:
```
$ echo "
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/app-root: /app1
name: approot
namespace: default
spec:
rules:
- host: approot.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
" | kubectl create -f -
```
Check the rewrite is working
```
$ curl -I -k http://approot.bar.com/
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.11.10
Date: Mon, 13 Mar 2017 14:57:15 GMT
Content-Type: text/html
Content-Length: 162
Location: http://stickyingress.example.com/app1
Connection: keep-alive
```

View file

@ -0,0 +1,117 @@
# Static IPs
This example demonstrates how to assign a static-ip to an Ingress on through the Nginx controller.
## Prerequisites
You need a [TLS cert](/examples/PREREQUISITES.md#tls-certificates) and a [test HTTP service](/examples/PREREQUISITES.md#test-http-service) for this example.
You will also need to make sure you Ingress targets exactly one Ingress
controller by specifying the [ingress.class annotation](/examples/PREREQUISITES.md#ingress-class),
and that you have an ingress controller [running](/examples/deployment) in your cluster.
## Acquiring an IP
Since instances of the nginx controller actually run on nodes in your cluster,
by default nginx Ingresses will only get static IPs if your cloudprovider
supports static IP assignments to nodes. On GKE/GCE for example, even though
nodes get static IPs, the IPs are not retained across upgrade.
To acquire a static IP for the nginx ingress controller, simply put it
behind a Service of `Type=LoadBalancer`.
First, create a loadbalancer Service and wait for it to acquire an IP
```console
$ kubectl create -f static-ip-svc.yaml
service "nginx-ingress-lb" created
$ kubectl get svc nginx-ingress-lb
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-lb 10.0.138.113 104.154.109.191 80:31457/TCP,443:32240/TCP 15m
```
then, update the ingress controller so it adopts the static IP of the Service
by passing the `--publish-service` flag (the example yaml used in the next step
already has it set to "nginx-ingress-lb").
```console
$ kubectl create -f nginx-ingress-controller.yaml
deployment "nginx-ingress-controller" created
```
## Assigning the IP to an Ingress
From here on every Ingress created with the `ingress.class` annotation set to
`nginx` will get the IP allocated in the previous step
```console
$ kubectl create -f nginx-ingress.yaml
ingress "nginx-ingress" created
$ kubectl get ing nginx-ingress
NAME HOSTS ADDRESS PORTS AGE
nginx-ingress * 104.154.109.191 80, 443 13m
$ curl 104.154.109.191 -kL
CLIENT VALUES:
client_address=10.180.1.25
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://104.154.109.191:8080/
...
```
## Retaining the IP
You can test retention by deleting the Ingress
```console
$ kubectl delete ing nginx-ingress
ingress "nginx-ingress" deleted
$ kubectl create -f nginx-ingress.yaml
ingress "nginx-ingress" created
$ kubectl get ing nginx-ingress
NAME HOSTS ADDRESS PORTS AGE
nginx-ingress * 104.154.109.191 80, 443 13m
```
Note that unlike the GCE Ingress, the same loadbalancer IP is shared amongst all
Ingresses, because all requests are proxied through the same set of nginx
controllers.
## Promote ephemeral to static IP
To promote the allocated IP to static, you can update the Service manifest
```console
$ kubectl patch svc nginx-ingress-lb -p '{"spec": {"loadBalancerIP": "104.154.109.191"}}'
"nginx-ingress-lb" patched
```
and promote the IP to static (promotion works differently for cloudproviders,
provided example is for GKE/GCE)
`
```console
$ gcloud compute addresses create nginx-ingress-lb --addresses 104.154.109.191 --region us-central1
Created [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb].
---
address: 104.154.109.191
creationTimestamp: '2017-01-31T16:34:50.089-08:00'
description: ''
id: '5208037144487826373'
kind: compute#address
name: nginx-ingress-lb
region: us-central1
selfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb
status: IN_USE
users:
- us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000
```
Now even if the Service is deleted, the IP will persist, so you can recreate the
Service with `spec.loadBalancerIP` set to `104.154.109.191`.

View file

@ -0,0 +1,52 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
labels:
k8s-app: nginx-ingress-controller
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: nginx-ingress-controller
spec:
# hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration
# however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host
# that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used
# like with kubeadm
# hostNetwork: true
terminationGracePeriodSeconds: 60
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.15
name: nginx-ingress-controller
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 1
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --publish-service=$(POD_NAMESPACE)/nginx-ingress-lb

View file

@ -0,0 +1,17 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
# This assumes tls-secret exists.
- secretName: tls-secret
rules:
- http:
paths:
- backend:
# This assumes http-svc exists and routes to healthy endpoints.
serviceName: http-svc
servicePort: 80

View file

@ -0,0 +1,23 @@
# This is the backend service
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress-lb
annotations:
service.beta.kubernetes.io/external-traffic: OnlyLocal
labels:
app: nginx-ingress-lb
spec:
type: LoadBalancer
loadBalancerIP: 104.154.109.191
ports:
- port: 80
name: http
targetPort: 80
- port: 443
name: https
targetPort: 443
selector:
# Selects nginx-ingress-controller pods
k8s-app: nginx-ingress-controller

View file

@ -0,0 +1,71 @@
# TLS termination
This example demonstrates how to terminate TLS through the nginx Ingress controller.
## Prerequisites
You need a [TLS cert](../PREREQUISITES.md#tls-certificates) and a [test HTTP service](../PREREQUISITES.md#test-http-service) for this example.
## Deployment
The following command instructs the controller to terminate traffic using the provided
TLS cert, and forward un-encrypted HTTP traffic to the test HTTP service.
```console
kubectl apply -f ingress.yaml
```
## Validation
You can confirm that the Ingress works.
```console
$ kubectl describe ing nginx-test
Name: nginx-test
Namespace: default
Address: 104.198.183.6
Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)
TLS:
tls-secret terminates
Rules:
Host Path Backends
---- ---- --------
*
http-svc:80 (<none>)
Annotations:
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test
7s 7s 1 {nginx-ingress-controller } Normal UPDATE default/nginx-test
7s 7s 1 {nginx-ingress-controller } Normal CREATE ip: 104.198.183.6
7s 7s 1 {nginx-ingress-controller } Warning MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming /
$ curl 104.198.183.6 -L
curl: (60) SSL certificate problem: self signed certificate
More details here: http://curl.haxx.se/docs/sslcerts.html
$ curl 104.198.183.6 -Lk
CLIENT VALUES:
client_address=10.240.0.4
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://35.186.221.137:8080/
SERVER VALUES:
server_version=nginx: 1.9.11 - lua: 10001
HEADERS RECEIVED:
accept=*/*
connection=Keep-Alive
host=35.186.221.137
user-agent=curl/7.46.0
via=1.1 google
x-cloud-trace-context=f708ea7e369d4514fc90d51d7e27e91d/13322322294276298106
x-forwarded-for=104.132.0.80, 35.186.221.137
x-forwarded-proto=https
BODY:
```

View file

@ -0,0 +1,17 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
# This assumes tls-secret exists.
- secretName: tls-secret
rules:
- http:
paths:
- backend:
# This assumes http-svc exists and routes to healthy endpoints.
serviceName: http-svc
servicePort: 80