From 1c6c76162f7893a1802e49b14c1cfb9f17e6a57d Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Fri, 17 Jan 2020 10:11:12 -0600 Subject: [PATCH 1/6] Add link to zip file --- slides/markmaker.py | 11 +++++++++++ slides/shared/prereqs.md | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/slides/markmaker.py b/slides/markmaker.py index c0eb15b8..aad08012 100755 --- a/slides/markmaker.py +++ b/slides/markmaker.py @@ -89,6 +89,15 @@ def flatten(titles): def generatefromyaml(manifest, filename): manifest = yaml.safe_load(manifest) + if "zip" not in manifest: + if manifest["slides"].endswith('/'): + manifest["zip"] = manifest["slides"] + "slides.zip" + else: + manifest["zip"] = manifest["slides"] + "/slides.zip" + + if "html" not in manifest: + manifest["html"] = filename + ".html" + markdown, titles = processchapter(manifest["chapters"], filename) logging.debug("Found {} titles.".format(len(titles))) toc = gentoc(titles) @@ -117,6 +126,8 @@ def generatefromyaml(manifest, filename): html = html.replace("@@CHAT@@", manifest["chat"]) html = html.replace("@@GITREPO@@", manifest["gitrepo"]) html = html.replace("@@SLIDES@@", manifest["slides"]) + html = html.replace("@@ZIP@@", manifest["zip"]) + html = html.replace("@@HTML@@", manifest["html"]) html = html.replace("@@TITLE@@", manifest["title"].replace("\n", " ")) html = html.replace("@@SLIDENUMBERPREFIX@@", manifest.get("slidenumberprefix", "")) return html diff --git a/slides/shared/prereqs.md b/slides/shared/prereqs.md index 0c66c22c..533a80d4 100644 --- a/slides/shared/prereqs.md +++ b/slides/shared/prereqs.md @@ -72,6 +72,12 @@ Misattributed to Benjamin Franklin - Slides will remain online so you can review them later if needed +- You can download the slides using that URL: + + @@ZIP@@ + + (then open the file `@@HTML@@`) + --- class: in-person From cff9cbdfbb5e4351b9bb67eadd87830d8771152d Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Fri, 17 Jan 2020 12:01:20 -0600 Subject: [PATCH 2/6] Add slide about versioning and cadence --- slides/k8s/versions-k8s.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/slides/k8s/versions-k8s.md b/slides/k8s/versions-k8s.md index 8f28c203..9c856b68 100644 --- a/slides/k8s/versions-k8s.md +++ b/slides/k8s/versions-k8s.md @@ -1,7 +1,7 @@ ## Versions installed -- Kubernetes 1.15.3 -- Docker Engine 19.03.1 +- Kubernetes 1.17.1 +- Docker Engine 19.03.5 - Docker Compose 1.24.1 @@ -23,6 +23,10 @@ class: extra-details ## Kubernetes and Docker compatibility +- Kubernetes 1.17 validates Docker Engine version [up to 19.03](https://github.com/kubernetes/kubernetes/pull/84476) + + *however ...* + - Kubernetes 1.15 validates Docker Engine versions [up to 18.09](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.15.md#dependencies)
(the latest version when Kubernetes 1.14 was released) @@ -40,5 +44,25 @@ class: extra-details - "Validates" = continuous integration builds with very extensive (and expensive) testing - The Docker API is versioned, and offers strong backward-compatibility +
+ (if a client uses e.g. API v1.25, the Docker Engine will keep behaving the same way) - (If a client uses e.g. API v1.25, the Docker Engine will keep behaving the same way) +--- + +## Kubernetes versioning and cadence + +- Kubernetes versions are expressed using *semantic versioning* + + (a Kubernetes version is expressed as MAJOR.MINOR.PATCH) + +- There is a new *patch* release whenever needed + + (generally, there is about [2 to 4 weeks](https://github.com/kubernetes/sig-release/blob/master/release-engineering/role-handbooks/patch-release-team.md#release-timing) between patch releases, + except when a critical bug or vulnerability is found: + in that case, a patch release will follow as fast as possible) + +- There is a new *minor* release approximately every 3 months + +- At any given time, 3 *minor* releases are maintained + + (in other words, a given *minor* release is maintained about 9 months) From 1f826d79935e9f74e251080d5ea54048abf84010 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Fri, 17 Jan 2020 12:28:27 -0600 Subject: [PATCH 3/6] Add slide about version skew --- slides/k8s/versions-k8s.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/slides/k8s/versions-k8s.md b/slides/k8s/versions-k8s.md index 9c856b68..2daf88f8 100644 --- a/slides/k8s/versions-k8s.md +++ b/slides/k8s/versions-k8s.md @@ -66,3 +66,25 @@ class: extra-details - At any given time, 3 *minor* releases are maintained (in other words, a given *minor* release is maintained about 9 months) + +--- + +## Kubernetes version compatibility + +*Should my version of `kubectl` match exactly my cluster version?* + +- `kubectl` can be up to one minor version older or newer than the cluster + + (if cluster version is 1.15.X, `kubectl` can be 1.14.Y, 1.15.Y, or 1.16.Y) + +- Things *might* work with larger version differences + + (but they will probably fail randomly, so be careful) + +- This is an example of an error indicating version compability issues: + ``` + error: SchemaError(io.k8s.api.autoscaling.v2beta1.ExternalMetricStatus): + invalid object doesn't have additional properties + ``` + +- Check [the documentation](https://kubernetes.io/docs/setup/release/version-skew-policy/#kubectl) for the whole story about compatibility From 328a2edaaf18129f18c0a9c1252df2117fe7acf9 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Fri, 17 Jan 2020 14:17:18 -0600 Subject: [PATCH 4/6] Add slide about number of nodes in a cluster --- slides/k8s/concepts-k8s.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/slides/k8s/concepts-k8s.md b/slides/k8s/concepts-k8s.md index 994f7ce8..2d07da54 100644 --- a/slides/k8s/concepts-k8s.md +++ b/slides/k8s/concepts-k8s.md @@ -199,6 +199,30 @@ class: extra-details class: extra-details +## How many nodes should a cluster have? + +- There is no particular constraint + + (no need to have an odd number of nodes for quorum) + +- A cluster can have zero node + + (but then it won't be able to start any pods) + +- For testing and development, having a single node is fine + +- For production, make sure that you have extra capacity + + (so that your workload still fits if you lose a node or a group of nodes) + +- Kubernetes is tested with [up to 5000 nodes](https://kubernetes.io/docs/setup/best-practices/cluster-large/) + + (however, running a cluster of that size requires a lot of tuning) + +--- + +class: extra-details + ## Do we need to run Docker at all? No! From 3e9a93957859a8cdaa2ec82f18958cb038924c95 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Fri, 17 Jan 2020 17:07:43 -0600 Subject: [PATCH 5/6] Add traffic split / canary for Traefik --- k8s/canary.yaml | 21 ++++++ slides/k8s/ingress.md | 161 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 k8s/canary.yaml diff --git a/k8s/canary.yaml b/k8s/canary.yaml new file mode 100644 index 00000000..88045150 --- /dev/null +++ b/k8s/canary.yaml @@ -0,0 +1,21 @@ +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: whatever + annotations: + traefik.ingress.kubernetes.io/service-weights: | + whatever: 90% + whatever-new: 10% +spec: + rules: + - host: whatever.A.B.C.D.nip.io + http: + paths: + - path: / + backend: + serviceName: whatever + servicePort: 80 + - path: / + backend: + serviceName: whatever-new + servicePort: 80 diff --git a/slides/k8s/ingress.md b/slides/k8s/ingress.md index 7b12100a..31511f53 100644 --- a/slides/k8s/ingress.md +++ b/slides/k8s/ingress.md @@ -524,3 +524,164 @@ spec: - This should eventually stabilize (remember that ingresses are currently `apiVersion: networking.k8s.io/v1beta1`) + +--- + +## A special feature in action + +- We're going to see how to implement *canary releases* with Traefik + +- This feature is available on multiple ingress controllers + +- ... But it is configured very differently on each of them + +--- + +## Canary releases + +- A *canary release* (or canary launch or canary deployment) is a release that will process only a small fraction of the workload + +- Example 1: a canary release is deployed 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: a canary release is deployed for a web app + + - 1% of users see the canary release + - the remaining 99% are sent to the normal release + +- We're going to implement example 1 (per-request routing) + +--- + +## Canary releases with Traefik + +- 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 + +- Let's send requests to our 3 cheesy services! + +.exercise[ + +- Create the resource shown on the next slide + +] + +--- + +## The Ingress resource + +.small[ +```yaml +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: cheeseplate + annotations: + traefik.ingress.kubernetes.io/service-weights: | + cheddar: 50% + wensleydale: 25% + stilton: 25% +spec: + rules: + - host: cheeseplate.`A.B.C.D`.nip.io + http: + paths: + - path: / + backend: + serviceName: cheddar + servicePort: 80 + - path: / + backend: + serviceName: wensledale + servicePort: 80 + - path: / + backend: + serviceName: stilton + servicePort: 80 +``` +] + +--- + +## Testing the canary + +- Let's check the percentage of requests going to each service + +.exercise[ + +- Continuously send HTTP requests to the new ingress: + ```bash + while sleep 0.1; do + curl -s http://cheeseplate.A.B.C.D.nip.io/ + done + ``` + +] + +We should see a 50/25/25 request mix. + +--- + +class: extra-details + +## Load balancing fairness + +Note: if we use odd request ratios, the load balancing algorithm might appear to be broken on a small scale (when sending a small number of requests), but on a large scale (with many requests) it will be fair. + +For instance, with a 11%/89% ratio, we can see 79 requests going to the 89%-weighted service, and then requests alternating between the two services; then 79 requests again, etc. + +--- + +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). From da9921d68abb3ee9877ba3fb10206c9a5e490fd4 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sat, 18 Jan 2020 02:36:41 -0600 Subject: [PATCH 6/6] Update explanations for canary --- slides/k8s/ingress.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/slides/k8s/ingress.md b/slides/k8s/ingress.md index 31511f53..a51c453b 100644 --- a/slides/k8s/ingress.md +++ b/slides/k8s/ingress.md @@ -541,16 +541,35 @@ spec: - A *canary release* (or canary launch or canary deployment) is a release that will process only a small fraction of the workload -- Example 1: a canary release is deployed for a microservice +- 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: a canary release is deployed for a web app +- Example 2: canary for a web app - - 1% of users see the canary release + - 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 reamining 99% are shipped with the normal process + - We're going to implement example 1 (per-request routing) ---