diff --git a/slides/k8s/ingress-canary.md b/slides/k8s/ingress-canary.md
new file mode 100644
index 00000000..6905cf38
--- /dev/null
+++ b/slides/k8s/ingress-canary.md
@@ -0,0 +1,148 @@
+## Ingress and canary releases
+
+- Let's see how to implement *canary releases*
+
+- The example here will use Traefik v1
+
+ (which is obsolete)
+
+- It won't work on your Kubernetes cluster!
+
+ (unless you're running an oooooold version of Kubernetes)
+
+ (and an equally oooooooold version of Traefik)
+
+- We've left it here just as an example!
+
+---
+
+## Canary releases
+
+- A *canary release* (or canary launch or canary deployment) is a release that will process only a small fraction of the workload
+
+- After deploying the canary, we compare its metrics to the normal release
+
+- If the metrics look good, the canary will progressively receive more traffic
+
+ (until it gets 100% and becomes the new normal release)
+
+- If the metrics aren't good, the canary is automatically removed
+
+- When we deploy a bad release, only a tiny fraction of traffic is affected
+
+---
+
+## Various ways to implement canary
+
+- Example 1: canary for a microservice
+
+ - 1% of all requests (sampled randomly) are sent to the canary
+ - the remaining 99% are sent to the normal release
+
+- Example 2: canary for a web app
+
+ - 1% of users are sent to the canary web site
+ - the remaining 99% are sent to the normal release
+
+- Example 3: canary for shipping physical goods
+
+ - 1% of orders are shipped with the canary process
+ - the remaining 99% are shipped with the normal process
+
+- We're going to implement example 1 (per-request routing)
+
+---
+
+## Canary releases with Traefik v1
+
+- We need to deploy the canary and expose it with a separate service
+
+- Then, in the Ingress resource, we need:
+
+ - multiple `paths` entries (one for each service, canary and normal)
+
+ - an extra annotation indicating the weight of each service
+
+- If we want, we can send requests to more than 2 services
+
+---
+
+## The Ingress resource
+
+.small[
+```yaml
+apiVersion: networking.k8s.io/v1beta1
+kind: Ingress
+metadata:
+ name: rgb
+ annotations:
+ traefik.ingress.kubernetes.io/service-weights: |
+ red: 50%
+ green: 25%
+ blue: 25%
+spec:
+ rules:
+ - host: rgb.`A.B.C.D`.nip.io
+ http:
+ paths:
+ - path: /
+ backend:
+ serviceName: red
+ servicePort: 80
+ - path: /
+ backend:
+ serviceName: green
+ servicePort: 80
+ - path: /
+ backend:
+ serviceName: blue
+ servicePort: 80
+```
+]
+
+---
+
+class: extra-details
+
+## Other ingress controllers
+
+*Just to illustrate how different things are ...*
+
+- With the NGINX ingress controller:
+
+ - define two ingress ressources
+
+ (specifying rules with the same host+path)
+
+ - add `nginx.ingress.kubernetes.io/canary` annotations on each
+
+
+- With Linkerd2:
+
+ - define two services
+
+ - define an extra service for the weighted aggregate of the two
+
+ - define a TrafficSplit (this is a CRD introduced by the SMI spec)
+
+---
+
+class: extra-details
+
+## We need more than that
+
+What we saw is just one of the multiple building blocks that we need to achieve a canary release.
+
+We also need:
+
+- metrics (latency, performance ...) for our releases
+
+- automation to alter canary weights
+
+ (increase canary weight if metrics look good; decrease otherwise)
+
+- a mechanism to manage the lifecycle of the canary releases
+
+ (create them, promote them, delete them ...)
+
+For inspiration, check [flagger by Weave](https://github.com/weaveworks/flagger).
diff --git a/slides/k8s/ingress.md b/slides/k8s/ingress.md
index 81bc3459..8e24f83b 100644
--- a/slides/k8s/ingress.md
+++ b/slides/k8s/ingress.md
@@ -1,34 +1,36 @@
# Exposing HTTP services with Ingress resources
-- HTTP services are typically exposed on port 80
+- Service = layer 4 (TCP, UDP, SCTP)
- (and 443 for HTTPS)
+ - works with every TCP/UDP/SCTP protocol
-- `NodePort` services are great, but they are *not* on port 80
+ - doesn't "see" or interpret HTTP
- (by default, they use port range 30000-32767)
+- Ingress = layer 7 (HTTP)
-- How can we get *many* HTTP services on port 80? 🤔
+ - only for HTTP
+
+ - can route requests depending on URI or host header
+
+ - can handle TLS
---
-## Various ways to expose something on port 80
+## Why should we use Ingress resources?
-- Service with `type: LoadBalancer`
+A few use-cases:
- *costs a little bit of money; not always available*
+- URI routing (e.g. for single page apps)
-- Service with one (or multiple) `ExternalIP`
+ `/api` → service `api:5000`
- *requires public nodes; limited by number of nodes*
+ everything else → service `static:80`
-- Service with `hostPort` or `hostNetwork`
+- Cost optimization
- *same limitations as `ExternalIP`; even harder to manage*
+ (because individual `LoadBalancer` services typically cost money)
-- Ingress resources
-
- *addresses all these limitations, yay!*
+- Automatic handling of TLS certificates
---
@@ -181,20 +183,70 @@ class: extra-details
---
-## Deploying pods listening on port 80
+## Accepting connections on port 80 (and 443)
-- We want our ingress load balancer to be available on port 80
+- Web site users don't want to specify port numbers
-- The best way to do that would be with a `LoadBalancer` service
+ (e.g. "connect to https://blahblah.whatever:31550")
- ... but it requires support from the underlying infrastructure
+- Our ingress controller needs to actually be exposed on port 80
-- Instead, we are going to use the `hostNetwork` mode on the Traefik pods
+ (and 443 if we want to handle HTTPS)
-- Let's see what this `hostNetwork` mode is about ...
+- Let's see how we can achieve that!
---
+## Various ways to expose something on port 80
+
+- Service with `type: LoadBalancer`
+
+ *costs a little bit of money; not always available*
+
+- 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)
+
+- 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*
@@ -211,6 +263,8 @@ class: extra-details
---
+class: extra-details
+
## With `hostNetwork: true`
- No network namespace gets created
@@ -229,26 +283,6 @@ class: extra-details
---
-class: extra-details
-
-## Other techniques to expose port 80
-
-- We could use pods specifying `hostPort: 80`
-
- ... but with most CNI plugins, this [doesn't work or requires additional setup](https://github.com/kubernetes/kubernetes/issues/23920)
-
-- We could use a `NodePort` service
-
- ... but that requires [changing the `--service-node-port-range` flag in the API server](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/)
-
-- We could create a service with an external IP
-
- ... this would work, but would require a few extra steps
-
- (figuring out the IP address and adding it to the service)
-
----
-
## Running Traefik
- The [Traefik documentation][traefikdoc] recommends to use a Helm chart
@@ -270,6 +304,8 @@ class: extra-details
---
+class: extra-details
+
## Taints and tolerations
- A *taint* is an attribute added to a node
@@ -496,10 +532,6 @@ This is normal: we haven't provided any ingress rule yet.
## Creating ingress resources
-- Before Kubernetes 1.19, we must use YAML manifests
-
- (see example on next slide)
-
- Since Kubernetes 1.19, we can use `kubectl create ingress`
```bash
@@ -534,7 +566,21 @@ This is normal: we haven't provided any ingress rule yet.
---
-## Ingress resources in YAML
+## Before Kubernetes 1.19
+
+- Before Kubernetes 1.19:
+
+ - `kubectl create ingress` wasn't available
+
+ - `apiVersion: networking.k8s.io/v1` wasn't supported
+
+- It was necessary to use YAML, and `apiVersion: networking.k8s.io/v1beta1`
+
+ (see example on next slide)
+
+---
+
+## YAML for old ingress resources
Here is a minimal host-based ingress resource:
@@ -555,23 +601,15 @@ spec:
```
-(It is in `k8s/ingress.yaml`.)
-
---
-class: extra-details
-
-## Ingress API version
-
-- The YAML on the previous slide uses `apiVersion: networking.k8s.io/v1beta1`
+## YAML for new ingress resources
- Starting with Kubernetes 1.19, `networking.k8s.io/v1` is available
-- However, with Kubernetes 1.19 (and later), we can use `kubectl create ingress`
+- And we can use `kubectl create ingress` 🎉
-- We chose to keep an "old" (deprecated!) YAML example for folks still using older versions of Kubernetes
-
-- If we want to see "modern" YAML, we can use `-o yaml --dry-run=client`:
+- We can see "modern" YAML with `-o yaml --dry-run=client`:
```bash
kubectl create ingress red -o yaml --dry-run=client \
@@ -641,157 +679,6 @@ class: extra-details
- It is still in alpha stage
----
-
-## Vendor-specific example
-
-- Let's see how to implement *canary releases*
-
-- The example here will use Traefik v1
-
- (which is obsolete)
-
-- It won't work on your Kubernetes cluster!
-
- (unless you're running an oooooold version of Kubernetes)
-
- (and an equally oooooooold version of Traefik)
-
-- We've left it here just as an example!
-
----
-
-## Canary releases
-
-- A *canary release* (or canary launch or canary deployment) is a release that will process only a small fraction of the workload
-
-- After deploying the canary, we compare its metrics to the normal release
-
-- If the metrics look good, the canary will progressively receive more traffic
-
- (until it gets 100% and becomes the new normal release)
-
-- If the metrics aren't good, the canary is automatically removed
-
-- When we deploy a bad release, only a tiny fraction of traffic is affected
-
----
-
-## Various ways to implement canary
-
-- Example 1: canary for a microservice
-
- - 1% of all requests (sampled randomly) are sent to the canary
- - the remaining 99% are sent to the normal release
-
-- Example 2: canary for a web app
-
- - 1% of users are sent to the canary web site
- - the remaining 99% are sent to the normal release
-
-- Example 3: canary for shipping physical goods
-
- - 1% of orders are shipped with the canary process
- - the remaining 99% are shipped with the normal process
-
-- We're going to implement example 1 (per-request routing)
-
----
-
-## Canary releases with Traefik v1
-
-- We need to deploy the canary and expose it with a separate service
-
-- Then, in the Ingress resource, we need:
-
- - multiple `paths` entries (one for each service, canary and normal)
-
- - an extra annotation indicating the weight of each service
-
-- If we want, we can send requests to more than 2 services
-
----
-
-## The Ingress resource
-
-.small[
-```yaml
-apiVersion: networking.k8s.io/v1beta1
-kind: Ingress
-metadata:
- name: rgb
- annotations:
- traefik.ingress.kubernetes.io/service-weights: |
- red: 50%
- green: 25%
- blue: 25%
-spec:
- rules:
- - host: rgb.`A.B.C.D`.nip.io
- http:
- paths:
- - path: /
- backend:
- serviceName: red
- servicePort: 80
- - path: /
- backend:
- serviceName: green
- servicePort: 80
- - path: /
- backend:
- serviceName: blue
- servicePort: 80
-```
-]
-
----
-
-class: extra-details
-
-## Other ingress controllers
-
-*Just to illustrate how different things are ...*
-
-- With the NGINX ingress controller:
-
- - define two ingress ressources
-
- (specifying rules with the same host+path)
-
- - add `nginx.ingress.kubernetes.io/canary` annotations on each
-
-
-- With Linkerd2:
-
- - define two services
-
- - define an extra service for the weighted aggregate of the two
-
- - define a TrafficSplit (this is a CRD introduced by the SMI spec)
-
----
-
-class: extra-details
-
-## We need more than that
-
-What we saw is just one of the multiple building blocks that we need to achieve a canary release.
-
-We also need:
-
-- metrics (latency, performance ...) for our releases
-
-- automation to alter canary weights
-
- (increase canary weight if metrics look good; decrease otherwise)
-
-- a mechanism to manage the lifecycle of the canary releases
-
- (create them, promote them, delete them ...)
-
-For inspiration, check [flagger by Weave](https://github.com/weaveworks/flagger).
-
???
:EN:- The Ingress resource
diff --git a/slides/kube-adv.yml b/slides/kube-adv.yml
index 6f765a04..1aae34d1 100644
--- a/slides/kube-adv.yml
+++ b/slides/kube-adv.yml
@@ -62,6 +62,7 @@ content:
- #6
- k8s/ingress-tls.md
- k8s/ingress-advanced.md
+ #- k8s/ingress-canary.md
- k8s/cert-manager.md
- k8s/cainjector.md
- k8s/eck.md
diff --git a/slides/kube-selfpaced.yml b/slides/kube-selfpaced.yml
index 86b0ca6c..c102f69e 100644
--- a/slides/kube-selfpaced.yml
+++ b/slides/kube-selfpaced.yml
@@ -82,6 +82,7 @@ content:
-
- k8s/ingress.md
- k8s/ingress-advanced.md
+ #- k8s/ingress-canary.md
- k8s/ingress-tls.md
- k8s/cert-manager.md
- k8s/cainjector.md
diff --git a/slides/kube-twodays.yml b/slides/kube-twodays.yml
index b8eb46ab..d6c0906f 100644
--- a/slides/kube-twodays.yml
+++ b/slides/kube-twodays.yml
@@ -80,6 +80,7 @@ content:
- k8s/namespaces.md
- k8s/ingress.md
#- k8s/ingress-advanced.md
+ #- k8s/ingress-canary.md
#- k8s/ingress-tls.md
- k8s/kustomize.md
- k8s/helm-intro.md