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