Update ingress chapter and manifest

This commit is contained in:
Jérôme Petazzoni
2023-05-13 12:06:47 +02:00
parent e29bfe7921
commit 9cd812de75
2 changed files with 225 additions and 192 deletions

View File

@@ -1,36 +1,44 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: traefik
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: kube-system
name: traefik
namespace: traefik
---
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: traefik-ingress-controller
namespace: kube-system
name: traefik
namespace: traefik
labels:
k8s-app: traefik-ingress-lb
app: traefik
spec:
selector:
matchLabels:
k8s-app: traefik-ingress-lb
app: traefik
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
app: traefik
name: traefik
spec:
tolerations:
- effect: NoSchedule
operator: Exists
hostNetwork: true
serviceAccountName: traefik-ingress-controller
# If, for some reason, our CNI plugin doesn't support hostPort,
# we can enable hostNetwork instead. That should work everywhere
# but it doesn't provide the same isolation.
#hostNetwork: true
serviceAccountName: traefik
terminationGracePeriodSeconds: 60
containers:
- image: traefik:v2.5
name: traefik-ingress-lb
- image: traefik:v2.10
name: traefik
ports:
- name: http
containerPort: 80
@@ -61,7 +69,7 @@ spec:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-ingress-controller
name: traefik
rules:
- apiGroups:
- ""
@@ -73,14 +81,6 @@ rules:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
@@ -94,15 +94,15 @@ rules:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-ingress-controller
name: traefik
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
name: traefik
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
name: traefik
namespace: traefik
---
kind: IngressClass
apiVersion: networking.k8s.io/v1

View File

@@ -28,7 +28,7 @@ A few use-cases:
- Cost optimization
(because individual `LoadBalancer` services typically cost money)
(using `LoadBalancer` services for everything would be expensive)
- Automatic handling of TLS certificates
@@ -109,7 +109,7 @@ A few use-cases:
- Step 1: deploy an *ingress controller*
(one-time setup)
(one-time setup; typically done by cluster admin)
- Step 2: create *Ingress resources*
@@ -117,7 +117,7 @@ A few use-cases:
- the controller watches ingress resources and sets up a LB
- Step 3: set up DNS
- Step 3: set up DNS (optional)
- associate DNS entries with the load balancer address
@@ -175,15 +175,50 @@ class: extra-details
- maybe motivated by the fact that Traefik releases are named after cheeses
- For DNS, we will use [nip.io](http://nip.io/)
- We will create ingress resources for various HTTP services
- For DNS, we can use [nip.io](http://nip.io/)
- `*.1.2.3.4.nip.io` resolves to `1.2.3.4`
- We will create ingress resources for various HTTP services
---
## Classic ingress controller setup
- Ingress controller runs with a Deployment
(with at least 2 replicas for redundancy)
- It is exposed with a `LoadBalancer` Service
- Typical for cloud-based clusters
- Also common when running or on-premises with [MetalLB] or [kube-vip]
[MetalLB]: https://metallb.org/
[kube-vip]: https://kube-vip.io/
---
## Accepting connections on port 80 (and 443)
## Alternate ingress controller setup
- Ingress controller runs with a DaemonSet
(on bigger clusters, this can be coupled with a `nodeSelector`)
- It is exposed with `externalIPs`, `hostPort`, or `hostNetwork`
- Typical for on-premises clusters
(where at least a set of nodes have a stable IP and high availability)
---
class: extra-details
## Why not a `NodePort` Service?
- Node ports are typically in the 30000-32767 range
- Web site users don't want to specify port numbers
@@ -193,94 +228,40 @@ class: extra-details
(and 443 if we want to handle HTTPS)
- Let's see how we can achieve that!
---
class: extra-details
## Local clusters
- When running a local cluster, some extra steps might be necessary
- When using Docker-based clusters on Linux:
*connect directly to the node's IP address (172.X.Y.Z)*
- When using Docker-based clusters with Docker Desktop:
*set up port mapping (then connect to localhost:XYZ)*
- Generic scenario:
*run `kubectl port-forward 8888:80` to the ingress controller*
<br/>
*(and then connect to `http://localhost:8888`)*
---
## Various ways to expose something on port 80
## Trying it out with Traefik
- Service with `type: LoadBalancer`
- We are going to run Traefik with a DaemonSet
*costs a little bit of money; not always available*
(there will be one instance of Traefik on every node of the cluster)
- Service with one (or multiple) `ExternalIP`
*requires public nodes; limited by number of nodes*
- Service with `hostPort` or `hostNetwork`
*same limitations as `ExternalIP`; even harder to manage*
---
## Deploying pods listening on port 80
- We are going to run Traefik in Pods with `hostNetwork: true`
(so that our load balancer can use the "real" port 80 of our nodes)
- Traefik Pods will be created by a DaemonSet
(so that we get one instance of Traefik on every node of the cluster)
- The Pods will use `hostPort: 80`
- This means that we will be able to connect to any node of the cluster on port 80
.warning[This is not typical of a production setup!]
---
## Doing it in production
- When running "on cloud", the easiest option is a `LoadBalancer` service
- When running "on prem", it depends:
- [MetalLB] is a good option if a pool of public IP addresses is available
- otherwise, using `externalIPs` on a few nodes (2-3 for redundancy)
- Many variations/optimizations are possible depending on our exact scenario!
[MetalLB]: https://metallb.org/
---
class: extra-details
## Without `hostNetwork`
- Normally, each pod gets its own *network namespace*
(sometimes called sandbox or network sandbox)
- An IP address is assigned to the pod
- This IP address is routed/connected to the cluster network
- All containers of that pod are sharing that network namespace
(and therefore using the same IP address)
---
class: extra-details
## With `hostNetwork: true`
- No network namespace gets created
- The pod is using the network namespace of the host
- It "sees" (and can use) the interfaces (and IP addresses) of the host
- The pod can receive outside traffic directly, on any port
- Downside: with most network plugins, network policies won't work for that pod
- most network policies work at the IP address level
- filtering that pod = filtering traffic from the node
---
## Running Traefik
@@ -293,7 +274,7 @@ class: extra-details
- use a Daemon Set so that each node can accept connections
- enable `hostNetwork`
- enable `hostPort: 80`
- add a *toleration* so that Traefik also runs on all nodes
@@ -426,11 +407,13 @@ This one is a special case that means "ignore all taints and run anyway."
## Running Traefik on our cluster
- We provide a YAML file (`k8s/traefik.yaml`) which is essentially the sum of:
- We provide a YAML file (@@LINK[k8s/traefik.yaml]) which contains:
- [Traefik's Daemon Set resources](https://github.com/containous/traefik/blob/v1.7/examples/k8s/traefik-ds.yaml) (patched with `hostNetwork` and tolerations)
- a `traefik` Namespace
- [Traefik's RBAC rules](https://github.com/containous/traefik/blob/v1.7/examples/k8s/traefik-rbac.yaml) allowing it to watch necessary API objects
- a `traefik` DaemonSet in that Namespace
- RBAC rules allowing Traefik to watch the necessary API objects
.lab[
@@ -462,20 +445,6 @@ This is normal: we haven't provided any ingress rule yet.
---
## Setting up DNS
- To make our lives easier, we will use [nip.io](http://nip.io)
- Check out `http://red.A.B.C.D.nip.io`
(replacing A.B.C.D with the IP address of `node1`)
- We should get the same `404 page not found` error
(meaning that our DNS is "set up properly", so to speak!)
---
## Traefik web UI
- Traefik provides a web dashboard
@@ -492,7 +461,7 @@ This is normal: we haven't provided any ingress rule yet.
---
## Setting up host-based routing ingress rules
## Setting up routing ingress rules
- We are going to use the `jpetazzo/color` image
@@ -504,7 +473,7 @@ This is normal: we haven't provided any ingress rule yet.
- Then we will create 3 ingress rules (one for each service)
- We will route `<color>.A.B.C.D.nip.io` to the corresponding deployment
- We will route requests to `/red`, `/green`, `/blue`
---
@@ -534,100 +503,164 @@ This is normal: we haven't provided any ingress rule yet.
- Since Kubernetes 1.19, we can use `kubectl create ingress`
(if you're running an older version of Kubernetes, **you must upgrade**)
.lab[
- Create the three ingress resources:
```bash
kubectl create ingress red \
--rule=red.`A.B.C.D`.nip.io/*=red:80
kubectl create ingress red --rule=/red=red:80
kubectl create ingress green --rule=/green=green:80
kubectl create ingress blue --rule=/blue=blue:80
```
- We can specify multiple rules per resource
]
---
## Testing
- We should now be able to access `localhost/red`, `localhost/green`, etc.
.lab[
- Check that these routes work correctly:
```bash
curl http://localhost/red
curl http://localhost/green
curl http://localhost/blue
```
]
---
## Accessing other URIs
- What happens if we try to access e.g. `/blue/hello`?
.lab[
- Retrieve the `ClusterIP` of Service `blue`:
```bash
BLUE=$(kubectl get svc blue -o jsonpath={.spec.clusterIP})
```
- Check that the `blue` app serves `/hello`:
```bash
curl $BLUE/hello
```
- See what happens if we try to access it through the Ingress:
```bash
curl http://localhost/blue/hello
```
]
---
## Exact or prefix matches
- By default, ingress rules are *exact* matches
(the request is routed only if the URI is exactly `/blue`)
- We can also ask a *prefix* match by adding a `*` to the rule
.lab[
- Create a prefix match rule for the `blue` service:
```bash
kubectl create ingress bluestar --rule=/blue*:blue:80
```
- Check that it works:
```bash
curl http://localhost/blue/hello
```
]
---
## Multiple rules per Ingress resource
- It is also possible to have multiple rules in a single resource
.lab[
- Create an Ingress resource with multiple rules:
```bash
kubectl create ingress rgb \
--rule=red.`A.B.C.D`.nip.io/*=red:80 \
--rule=green.`A.B.C.D`.nip.io/*=green:80 \
--rule=blue.`A.B.C.D`.nip.io/*=blue:80
--rule=/red*=red:80 \
--rule=/green*=green:80 \
--rule=/blue*=blue:80
```
---
- Check that everything still works after deleting individual rules
## Pay attention to the `*`!
- The `*` is important:
```
--rule=red.A.B.C.D.nip.io/`*`=red:80
```
- It means "all URIs below that path"
- Without the `*`, it means "only that exact path"
(if we omit it, requests for e.g. `red.A.B.C.D.nip.io/hello` will 404)
]
---
## Before Kubernetes 1.19
## Using domain-based routing
- Before Kubernetes 1.19:
- In the previous examples, we didn't use domain names
- `kubectl create ingress` wasn't available
(we routed solely based on the URI of the request)
- `apiVersion: networking.k8s.io/v1` wasn't supported
- We are now going to show how to use domain-based routing
- It was necessary to use YAML, and `apiVersion: networking.k8s.io/v1beta1`
- We are going to assume that we have a domain name
(see example on next slide)
(for instance: `cloudnative.tld`)
- That domain name should be set up so that a few subdomains point to the ingress
(for instance, `blue.cloudnative.tld`, `green.cloudnative.tld`...)
- For simplicity or flexibility, we can also use a wildcard record
---
## YAML for old ingress resources
## Setting up DNS
Here is a minimal host-based ingress resource:
- To make our lives easier, we will use [nip.io](http://nip.io)
```yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: red
spec:
rules:
- host: red.`A.B.C.D`.nip.io
http:
paths:
- path: /
backend:
serviceName: red
servicePort: 80
- Check out `http://red.A.B.C.D.nip.io`
```
(replacing A.B.C.D with the IP address of `node1`)
- We should get the same `404 page not found` error
(meaning that our DNS is "set up properly", so to speak!)
---
## YAML for new ingress resources
## Setting up name-based Ingress
- Starting with Kubernetes 1.19, `networking.k8s.io/v1` is available
- And we can use `kubectl create ingress` 🎉
- We can see "modern" YAML with `-o yaml --dry-run=client`:
.lab[
- Set the `$IPADDR` variable to our ingress controller address:
```bash
kubectl create ingress red -o yaml --dry-run=client \
--rule=red.`A.B.C.D`.nip.io/*=red:80
IPADDR=`A.B.C.D`
```
---
- Create our Ingress resource:
```bash
kubectl create ingress rgb-with-domain \
--rule=red.$IPADDR.nip.io/*=red:80 \
--rule=green.$IPADDR.nip.io/*=green:80 \
--rule=blue.$IPADDR.nip.io/*=blue:80
```
## Creating ingress resources
- Test it out:
```bash
curl http://red.$IPADDR.nip.io/hello
```
- Create the ingress resources with `kubectl create ingress`
(or use the YAML manifests if using Kubernetes 1.18 or older)
- Make sure to update the hostnames!
- Check that you can connect to the exposed web apps
]
---
@@ -677,7 +710,7 @@ class: extra-details
GatewayClass, Gateway, HTTPRoute, TCPRoute...
- It is still in alpha stage
- It is now in beta (since v0.5.0, released in 2022)
???