diff --git a/k8s/coffee-1.yaml b/k8s/coffee-1.yaml
new file mode 100644
index 00000000..68e5522e
--- /dev/null
+++ b/k8s/coffee-1.yaml
@@ -0,0 +1,15 @@
+apiVersion: apiextensions.k8s.io/v1alpha1
+kind: CustomResourceDefinition
+metadata:
+ name: coffees.container.training
+spec:
+ group: container.training
+ version: v1alpha1
+ scope: Namespaced
+ names:
+ plural: coffees
+ singular: coffee
+ kind: Coffee
+ shortNames:
+ - cof
+
diff --git a/k8s/coffee-2.yaml b/k8s/coffee-2.yaml
new file mode 100644
index 00000000..cb415751
--- /dev/null
+++ b/k8s/coffee-2.yaml
@@ -0,0 +1,32 @@
+apiVersion: apiextensions.k8s.io/v1alpha1
+kind: CustomResourceDefinition
+metadata:
+ name: coffees.container.training
+spec:
+ group: container.training
+ version: v1alpha1
+ scope: Namespaced
+ names:
+ plural: coffees
+ singular: coffee
+ kind: Coffee
+ shortNames:
+ - cof
+ additionalPrinterColumns:
+ - JSONPath: .spec.taste
+ description: Subjective taste of that kind of coffee bean
+ name: Taste
+ type: string
+ - JSONPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ validation:
+ openAPIV3Schema:
+ properties:
+ spec:
+ required:
+ - taste
+ properties:
+ taste:
+ description: Subjective taste of that kind of coffee bean
+ type: string
diff --git a/k8s/coffees.yaml b/k8s/coffees.yaml
new file mode 100644
index 00000000..8adf4f35
--- /dev/null
+++ b/k8s/coffees.yaml
@@ -0,0 +1,29 @@
+---
+kind: Coffee
+apiVersion: container.training/v1alpha1
+metadata:
+ name: arabica
+spec:
+ taste: strong
+---
+kind: Coffee
+apiVersion: container.training/v1alpha1
+metadata:
+ name: robusta
+spec:
+ taste: stronger
+---
+kind: Coffee
+apiVersion: container.training/v1alpha1
+metadata:
+ name: liberica
+spec:
+ taste: smoky
+---
+kind: Coffee
+apiVersion: container.training/v1alpha1
+metadata:
+ name: excelsa
+spec:
+ taste: fruity
+
diff --git a/k8s/nginx-3-with-git.yaml b/k8s/nginx-3-with-git.yaml
index c0ed9c96..a3ee90b0 100644
--- a/k8s/nginx-3-with-git.yaml
+++ b/k8s/nginx-3-with-git.yaml
@@ -13,7 +13,7 @@ spec:
mountPath: /usr/share/nginx/html/
- name: git
image: alpine
- command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/octocat/Spoon-Knife /www" ]
+ command: [ "sh", "-c", "apk add git && git clone https://github.com/octocat/Spoon-Knife /www" ]
volumeMounts:
- name: www
mountPath: /www/
diff --git a/prepare-vms/setup-admin-clusters.sh b/prepare-vms/setup-admin-clusters.sh
index ffbee227..b50783d4 100755
--- a/prepare-vms/setup-admin-clusters.sh
+++ b/prepare-vms/setup-admin-clusters.sh
@@ -61,6 +61,6 @@ TAG=$PREFIX-$SETTINGS
--count $((3*$STUDENTS))
./workshopctl deploy $TAG
-./workshopctl kube $TAG 1.14.6
+./workshopctl kube $TAG 1.16.6
./workshopctl cards $TAG
diff --git a/slides/k8s/cluster-upgrade.md b/slides/k8s/cluster-upgrade.md
index 2051d78d..20a22a22 100644
--- a/slides/k8s/cluster-upgrade.md
+++ b/slides/k8s/cluster-upgrade.md
@@ -81,7 +81,7 @@
## What version are we running anyway?
-- When I say, "I'm running Kubernetes 1.11", is that the version of:
+- When I say, "I'm running Kubernetes 1.16", is that the version of:
- kubectl
@@ -139,6 +139,73 @@
---
+## Important questions
+
+- Should we upgrade the control plane before or after the kubelets?
+
+- Within the control plane, should we upgrade the API server first or last?
+
+- How often should we upgrade?
+
+- How long are versions maintained?
+
+- All the answers are in [the documentation about version skew policy](https://kubernetes.io/docs/setup/release/version-skew-policy/)!
+
+- Let's review the key elements together ...
+
+---
+
+## Kubernetes uses semantic versioning
+
+- Kubernetes versions look like MAJOR.MINOR.PATCH; e.g. in 1.17.2:
+
+ - MAJOR = 1
+ - MINOR = 17
+ - PATCH = 2
+
+- It's always possible to mix and match different PATCH releases
+
+ (e.g. 1.16.1 and 1.16.6 are compatible)
+
+- It is recommended to run the latest PATCH release
+
+ (but it's mandatory only when there is a security advisory)
+
+---
+
+## Version skew
+
+- API server must be more recent than its clients (kubelet and control plane)
+
+- ... Which means it must always be upgraded first
+
+- All components support a difference of one¹ MINOR version
+
+- This allows live upgrades (since we can mix e.g. 1.15 and 1.16)
+
+- It also means that going from 1.14 to 1.16 requires going through 1.15
+
+.footnote[¹Except kubelet, which can be up to two MINOR behind API server,
+and kubectl, which can be one MINOR ahead or behind API server.]
+
+---
+
+## Release cycle
+
+- There is a new PATCH relese whenever necessary
+
+ (every few weeks, or "ASAP" when there is a security vulnerability)
+
+- There is a new MINOR release every 3 months (approximately)
+
+- At any given time, three MINOR releases are maintained
+
+- ... Which means that MINOR releases are maintained approximately 9 months
+
+- We should expect to upgrade at least every 3 months (on average)
+
+---
+
## In practice
- We are going to update a few cluster components
@@ -151,47 +218,6 @@
---
-## Updating kubelet
-
-- These nodes have been installed using the official Kubernetes packages
-
-- We can therefore use `apt` or `apt-get`
-
-.exercise[
-
-- Log into node `test3`
-
-- View available versions for package `kubelet`:
- ```bash
- apt show kubelet -a | grep ^Version
- ```
-
-- Upgrade kubelet:
- ```bash
- sudo apt install kubelet=1.15.3-00
- ```
-
-]
-
----
-
-## Checking what we've done
-
-.exercise[
-
-- Log into node `test1`
-
-- Check node versions:
- ```bash
- kubectl get nodes -o wide
- ```
-
-- Create a deployment and scale it to make sure that the node still works
-
-]
-
----
-
## Updating the API server
- This cluster has been deployed with kubeadm
@@ -228,7 +254,7 @@
sudo vim /etc/kubernetes/manifests/kube-apiserver.yaml
```
-- Look for the `image:` line, and update it to e.g. `v1.15.0`
+- Look for the `image:` line, and update it to e.g. `v1.17.0`
]
@@ -249,9 +275,27 @@
---
+## Was that a good idea?
+
+--
+
+**No!**
+
+--
+
+- Remember the guideline we gave earlier:
+
+ *To update a component, use whatever was used to install it.*
+
+- This control plane was deployed with kubeadm
+
+- We should use kubeadm to upgrade it!
+
+---
+
## Updating the whole control plane
-- As an example, we'll use kubeadm to upgrade the entire control plane
+- Let's make it right, and use kubeadm to upgrade the entire control plane
(note: this is possible only because the cluster was installed with kubeadm)
@@ -264,11 +308,11 @@
]
-Note 1: kubeadm thinks that our cluster is running 1.15.0.
+Note 1: kubeadm thinks that our cluster is running 1.17.0.
It is confused by our manual upgrade of the API server!
-Note 2: kubeadm itself is still version 1.14.6.
-
It doesn't know how to upgrade do 1.15.X.
+Note 2: kubeadm itself is still version 1.16.6.
+
It doesn't know how to upgrade do 1.17.X.
---
@@ -290,8 +334,8 @@ Note 2: kubeadm itself is still version 1.14.6.
]
-Note: kubeadm still thinks that our cluster is running 1.15.0.
-
But at least it knows about version 1.15.X now.
+Note: kubeadm still thinks that our cluster is running 1.17.0.
+
But at least it knows about version 1.17.X now.
---
@@ -307,28 +351,89 @@ Note: kubeadm still thinks that our cluster is running 1.15.0.
- Perform the upgrade:
```bash
- sudo kubeadm upgrade apply v1.15.3
+ sudo kubeadm upgrade apply v1.17.2
```
]
---
-## Updating kubelets
+## Updating kubelet
-- After updating the control plane, we need to update each kubelet
+- These nodes have been installed using the official Kubernetes packages
-- This requires to run a special command on each node, to download the config
+- We can therefore use `apt` or `apt-get`
- (this config is generated by kubeadm)
+.exercise[
+
+- Log into node `test3`
+
+- View available versions for package `kubelet`:
+ ```bash
+ apt show kubelet -a | grep ^Version
+ ```
+
+- Upgrade kubelet:
+ ```bash
+ sudo apt install kubelet=1.17.2-00
+ ```
+
+]
+
+---
+
+## Checking what we've done
+
+.exercise[
+
+- Log into node `test1`
+
+- Check node versions:
+ ```bash
+ kubectl get nodes -o wide
+ ```
+
+- Create a deployment and scale it to make sure that the node still works
+
+]
+
+---
+
+## Was that a good idea?
+
+--
+
+**Almost!**
+
+--
+
+- Yes, kubelet was installed with distribution packages
+
+- However, kubeadm took care of configuring kubelet
+
+ (when doing `kubeadm join ...`)
+
+- We were supposed to run a special command *before* upgrading kubelet!
+
+- That command should be executed on each node
+
+- It will download the kubelet configuration generated by kubeadm
+
+---
+
+## Upgrading kubelet the right way
+
+- The command that we need to run was shown by kubeadm
+
+ (after upgrading the control plane)
.exercise[
- Download the configuration on each node, and upgrade kubelet:
```bash
for N in 1 2 3; do
- ssh test$N sudo kubeadm upgrade node config --kubelet-version v1.15.3
- ssh test$N sudo apt install kubelet=1.15.3-00
+ ssh test$N sudo kubeadm upgrade node config --kubelet-version v1.17.2
+ ssh test$N sudo apt install kubelet=1.17.2-00
done
```
]
@@ -337,7 +442,7 @@ Note: kubeadm still thinks that our cluster is running 1.15.0.
## Checking what we've done
-- All our nodes should now be updated to version 1.15.3
+- All our nodes should now be updated to version 1.17.2
.exercise[
@@ -354,12 +459,12 @@ class: extra-details
## Skipping versions
-- This example worked because we went from 1.14 to 1.15
+- This example worked because we went from 1.16 to 1.17
-- If you are upgrading from e.g. 1.13, you will generally have to go through 1.14 first
+- If you are upgrading from e.g. 1.14, you will have to go through 1.15 first
-- This means upgrading kubeadm to 1.14.X, then using it to upgrade the cluster
+- This means upgrading kubeadm to 1.15.X, then using it to upgrade the cluster
-- Then upgrading kubeadm to 1.15.X, etc.
+- Then upgrading kubeadm to 1.16.X, etc.
- **Make sure to read the release notes before upgrading!**
diff --git a/slides/k8s/concepts-k8s.md b/slides/k8s/concepts-k8s.md
index 2d07da54..59594145 100644
--- a/slides/k8s/concepts-k8s.md
+++ b/slides/k8s/concepts-k8s.md
@@ -10,6 +10,29 @@
---
+## What can we do with Kubernetes?
+
+- Let's imagine that we have a 3-tier e-commerce app:
+
+ - web frontend
+
+ - API backend
+
+ - database (that we will keep out of Kubernetes for now)
+
+- We have built images for our frontend and backend components
+
+ (e.g. with Dockerfiles and `docker build`)
+
+- We are running them successfully with a local environment
+
+ (e.g. with Docker Compose)
+
+- Let's see how we would deploy our app on Kubernetes!
+
+---
+
+
## Basic things we can ask Kubernetes to do
--
diff --git a/slides/k8s/daemonset.md b/slides/k8s/daemonset.md
index d6668748..cbba5028 100644
--- a/slides/k8s/daemonset.md
+++ b/slides/k8s/daemonset.md
@@ -52,7 +52,7 @@
-- Unfortunately, as of Kubernetes 1.15, the CLI cannot create daemon sets
+- Unfortunately, as of Kubernetes 1.17, the CLI cannot create daemon sets
--
@@ -427,7 +427,7 @@ class: extra-details
- We need to change the selector of the `rng` service!
-- Let's add another label to that selector (e.g. `enabled=yes`)
+- Let's add another label to that selector (e.g. `active=yes`)
---
@@ -445,11 +445,11 @@ class: extra-details
## The plan
-1. Add the label `enabled=yes` to all our `rng` pods
+1. Add the label `active=yes` to all our `rng` pods
-2. Update the selector for the `rng` service to also include `enabled=yes`
+2. Update the selector for the `rng` service to also include `active=yes`
-3. Toggle traffic to a pod by manually adding/removing the `enabled` label
+3. Toggle traffic to a pod by manually adding/removing the `active` label
4. Profit!
@@ -464,7 +464,7 @@ be any interruption.*
## Adding labels to pods
-- We want to add the label `enabled=yes` to all pods that have `app=rng`
+- We want to add the label `active=yes` to all pods that have `app=rng`
- We could edit each pod one by one with `kubectl edit` ...
@@ -474,9 +474,9 @@ be any interruption.*
.exercise[
-- Add `enabled=yes` to all pods that have `app=rng`:
+- Add `active=yes` to all pods that have `app=rng`:
```bash
- kubectl label pods -l app=rng enabled=yes
+ kubectl label pods -l app=rng active=yes
```
]
@@ -495,7 +495,7 @@ be any interruption.*
.exercise[
-- Update the service to add `enabled: yes` to its selector:
+- Update the service to add `active: yes` to its selector:
```bash
kubectl edit service rng
```
@@ -504,7 +504,7 @@ be any interruption.*
```wait Please edit the object below```
```keys /app: rng```
```key ^J```
-```keys noenabled: yes```
+```keys noactive: yes```
```key ^[``` ]
```keys :wq```
```key ^J```
@@ -530,7 +530,7 @@ be any interruption.*
- If we want the string `"42"` or the string `"yes"`, we have to quote them
-- So we have to use `enabled: "yes"`
+- So we have to use `active: "yes"`
.footnote[For a good laugh: if we had used "ja", "oui", "si" ... as the value, it would have worked!]
@@ -542,7 +542,7 @@ be any interruption.*
- Update the YAML manifest of the service
-- Add `enabled: "yes"` to its selector
+- Add `active: "yes"` to its selector