Split documentation
196
docs/examples/PREREQUISITES.md
Normal 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
|
|
@ -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
|
||||
68
docs/examples/affinity/cookie/README.md
Normal 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.
|
||||
|
||||
18
docs/examples/affinity/cookie/ingress.yaml
Normal 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: /
|
||||
126
docs/examples/auth/basic/README.md
Normal 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-
|
||||
```
|
||||
0
docs/examples/auth/client-certs/README.md
Normal file
26
docs/examples/auth/client-certs/nginx-tls-auth.yaml
Normal 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
|
||||
|
||||
149
docs/examples/auth/external-auth/README.md
Normal 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
|
||||
```
|
||||
15
docs/examples/auth/external-auth/ingress.yaml
Normal 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: /
|
||||
12
docs/examples/customization/configuration-snippets/README.md
Normal 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`
|
||||
|
|
@ -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: /
|
||||
24
docs/examples/customization/custom-configuration/README.md
Normal 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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
80
docs/examples/customization/custom-errors/README.md
Normal 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
|
||||
```
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
76
docs/examples/customization/custom-headers/README.md
Normal 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`
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
47
docs/examples/customization/custom-upstream-check/README.md
Normal 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;
|
||||
|
||||
}
|
||||
....
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 59 KiB |
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
|
||||

|
||||
|
|
@ -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
|
||||
|
After Width: | Height: | Size: 969 KiB |
|
After Width: | Height: | Size: 451 KiB |
|
After Width: | Height: | Size: 244 KiB |
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: v1
|
||||
data:
|
||||
enable-vts-status: "true"
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: nginx-vts-metrics-conf
|
||||
namespace: kube-system
|
||||
23
docs/examples/customization/external-auth-headers/Makefile
Normal 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
|
||||
|
||||
138
docs/examples/customization/external-auth-headers/README.md
Normal 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
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
FROM alpine:3.5
|
||||
MAINTAINER Roman Safronov <electroma@gmail.com>
|
||||
COPY authsvc /
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/authsvc"]
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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: /
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
FROM alpine:3.5
|
||||
MAINTAINER Roman Safronov <electroma@gmail.com>
|
||||
COPY echosvc /
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/echosvc"]
|
||||
|
|
@ -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)
|
||||
}
|
||||
79
docs/examples/customization/ssl-dh-param/README.md
Normal 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`
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
apiVersion: v1
|
||||
data:
|
||||
dhparam.pem: "...base64 encoded data..."
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: lb-dhparam
|
||||
namespace: kube-system
|
||||
75
docs/examples/external-auth/README.md
Normal 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
|
||||
|
||||

|
||||
|
||||
- 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`
|
||||
|
||||

|
||||
|
||||
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`
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
38
docs/examples/external-auth/dashboard-ingress.yaml
Normal 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__
|
||||
BIN
docs/examples/external-auth/images/dashboard.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
docs/examples/external-auth/images/github-auth.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/examples/external-auth/images/oauth-login.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
docs/examples/external-auth/images/register-oauth-app-2.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
docs/examples/external-auth/images/register-oauth-app.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
56
docs/examples/external-auth/oauth2-proxy.yaml
Normal 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
|
||||
33
docs/examples/http-svc.yaml
Normal 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
|
||||
94
docs/examples/multi-tls/README.md
Normal 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
|
||||
```
|
||||
120
docs/examples/multi-tls/multi-tls.yaml
Normal 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: /
|
||||
128
docs/examples/rewrite/README.md
Normal 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
|
||||
```
|
||||
117
docs/examples/static-ip/README.md
Normal 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`.
|
||||
|
||||
52
docs/examples/static-ip/nginx-ingress-controller.yaml
Normal 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
|
||||
17
docs/examples/static-ip/nginx-ingress.yaml
Normal 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
|
||||
23
docs/examples/static-ip/static-ip-svc.yaml
Normal 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
|
||||
|
||||
71
docs/examples/tls-termination/README.md
Normal 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:
|
||||
|
||||
```
|
||||
17
docs/examples/tls-termination/ingress.yaml
Normal 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
|
||||