From 2ce50007d20e6d00cd458f6e598ddb366ded445b Mon Sep 17 00:00:00 2001 From: Bret Fisher Date: Mon, 16 Mar 2020 17:57:41 -0400 Subject: [PATCH 01/41] update k8s dashboard versions --- k8s/insecure-dashboard.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/k8s/insecure-dashboard.yaml b/k8s/insecure-dashboard.yaml index ebf49362..f1ed0ee1 100644 --- a/k8s/insecure-dashboard.yaml +++ b/k8s/insecure-dashboard.yaml @@ -187,7 +187,7 @@ spec: spec: containers: - name: kubernetes-dashboard - image: kubernetesui/dashboard:v2.0.0-rc2 + image: kubernetesui/dashboard:v2.0.0-rc6 imagePullPolicy: Always ports: - containerPort: 8443 @@ -272,7 +272,7 @@ spec: spec: containers: - name: dashboard-metrics-scraper - image: kubernetesui/metrics-scraper:v1.0.2 + image: kubernetesui/metrics-scraper:v1.0.3 ports: - containerPort: 8000 protocol: TCP From 9f049951ab7fd22214e55609ae036c8af0136cf1 Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Mon, 27 Apr 2020 20:46:06 +0200 Subject: [PATCH 02/41] Remove experimental status on kubeadm HA --- slides/k8s/setup-k8s.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/slides/k8s/setup-k8s.md b/slides/k8s/setup-k8s.md index 91740afa..b0fe878e 100644 --- a/slides/k8s/setup-k8s.md +++ b/slides/k8s/setup-k8s.md @@ -32,11 +32,7 @@ - Doesn't set up the overlay network -- Doesn't set up multi-master (no high availability) - --- - - (At least ... not yet! Though it's [experimental in 1.12](https://kubernetes.io/docs/setup/independent/high-availability/).) +- [Some extra steps](https://kubernetes.io/docs/setup/independent/high-availability/) to support HA control plane -- From f4f2d83fa46935ff838f928b1f214489d68cb85e Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Mon, 27 Apr 2020 20:55:23 +0200 Subject: [PATCH 03/41] separate managed options from deployment --- slides/k8s/setup-k8s.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/slides/k8s/setup-k8s.md b/slides/k8s/setup-k8s.md index 91740afa..44447cdf 100644 --- a/slides/k8s/setup-k8s.md +++ b/slides/k8s/setup-k8s.md @@ -44,18 +44,19 @@ --- +## Managed options + +- On Azure: [AKS](https://azure.microsoft.com/services/kubernetes-service/) + +- On Google Cloud: [GKE](https://cloud.google.com/kubernetes-engine/) + +- On AWS: [EKS](https://aws.amazon.com/eks/), + [eksctl](https://eksctl.io/) + +--- + ## Other deployment options -- [AKS](https://azure.microsoft.com/services/kubernetes-service/): - managed Kubernetes on Azure - -- [GKE](https://cloud.google.com/kubernetes-engine/): - managed Kubernetes on Google Cloud - -- [EKS](https://aws.amazon.com/eks/), - [eksctl](https://eksctl.io/): - managed Kubernetes on AWS - - [kops](https://github.com/kubernetes/kops): customizable deployments on AWS, Digital Ocean, GCE (beta), vSphere (alpha) From 2ba35e1f8d5814e383d336d66cffb6d36723faf9 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Tue, 28 Apr 2020 14:20:22 -0500 Subject: [PATCH 04/41] typo --- slides/k8s/healthchecks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slides/k8s/healthchecks.md b/slides/k8s/healthchecks.md index ad31ab77..e0031783 100644 --- a/slides/k8s/healthchecks.md +++ b/slides/k8s/healthchecks.md @@ -286,4 +286,4 @@ If the Redis process becomes unresponsive, it will be killed. ??? :EN:- Using healthchecks to improve availability -:FR:- Utiliser des *healthchecks* pour amémliorer la disponibilité +:FR:- Utiliser des *healthchecks* pour améliorer la disponibilité From 0c8b20f6b6dc38167747370c1234ddcbbe8a1ef4 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Tue, 28 Apr 2020 14:21:31 -0500 Subject: [PATCH 05/41] typo --- slides/k8s/volumes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slides/k8s/volumes.md b/slides/k8s/volumes.md index 0e644bad..2870877b 100644 --- a/slides/k8s/volumes.md +++ b/slides/k8s/volumes.md @@ -474,4 +474,4 @@ spec: :EN:- When and how to use Init Containers :FR:- Partager des données grâce aux volumes -:FR:- Quand et comment utilise un *Init Container* +:FR:- Quand et comment utiliser un *Init Container* From 6f806ed20026661e53aed13016218d102d5c2936 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Tue, 28 Apr 2020 14:23:52 -0500 Subject: [PATCH 06/41] typo --- slides/k8s/helm-intro.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/slides/k8s/helm-intro.md b/slides/k8s/helm-intro.md index 6e200148..e98cd8a9 100644 --- a/slides/k8s/helm-intro.md +++ b/slides/k8s/helm-intro.md @@ -427,6 +427,3 @@ All unspecified values will take the default values defined in the chart. :FR:- Fonctionnement général de Helm :FR:- Installer des composants via Helm :FR:- Helm 2, Helm 3, et le *Helm Hub* - - -:FR:- Comment From b0bff595cf002be223ba9cf283f4a040023a46ec Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Wed, 29 Apr 2020 22:31:49 +0200 Subject: [PATCH 07/41] psp: update generator helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kubectl run → kubectl create deployment kubectl run --restart=Never → kubectl run --- slides/k8s/podsecuritypolicy.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/slides/k8s/podsecuritypolicy.md b/slides/k8s/podsecuritypolicy.md index 8e0e9a0c..b15a6d3b 100644 --- a/slides/k8s/podsecuritypolicy.md +++ b/slides/k8s/podsecuritypolicy.md @@ -280,14 +280,14 @@ - Try to create a Pod directly: ```bash - kubectl run testpsp1 --image=nginx --restart=Never + kubectl run testpsp1 --image=nginx ``` - Try to create a Deployment: ```bash - kubectl run testpsp2 --image=nginx + kubectl create deployment testpsp2 --image=nginx ``` - Look at existing resources: @@ -345,12 +345,12 @@ We can get hints at what's happening by looking at the ReplicaSet and Events. - Check that we can now create a Pod directly: ```bash - kubectl run testpsp3 --image=nginx --restart=Never + kubectl run testpsp3 --image=nginx ``` - Create a Deployment as well: ```bash - kubectl run testpsp4 --image=nginx + kubectl create deployment testpsp4 --image=nginx ``` - Confirm that the Deployment is *not* creating any Pods: From a6c7d699865597bfc8dcaeafd9543864deee97f9 Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Wed, 29 Apr 2020 22:37:49 +0200 Subject: [PATCH 08/41] volume: add missing pod nginx-with-init creating --- slides/k8s/volumes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/slides/k8s/volumes.md b/slides/k8s/volumes.md index 2870877b..a5a9c730 100644 --- a/slides/k8s/volumes.md +++ b/slides/k8s/volumes.md @@ -417,6 +417,11 @@ spec: .exercise[ +- Create the pod: + ```bash + kubectl create -f ~/container.training/k8s/nginx-4-with-init.yaml + ``` + - Repeat the same operation as earlier (try to send HTTP requests as soon as the pod comes up) From 1de539bff83544d45535b68e08e051a0c5a9a51d Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Wed, 29 Apr 2020 22:26:19 +0200 Subject: [PATCH 09/41] healthcheck: fix rng manifest filename --- slides/k8s/healthchecks-more.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slides/k8s/healthchecks-more.md b/slides/k8s/healthchecks-more.md index 8e6b51b2..16ea8cf1 100644 --- a/slides/k8s/healthchecks-more.md +++ b/slides/k8s/healthchecks-more.md @@ -154,9 +154,9 @@ It will use the default success threshold (1 successful attempt = alive). .exercise[ -- Edit `rng-daemonset.yaml` and add the liveness probe +- Edit `rng-deployment.yaml` and add the liveness probe ```bash - vim rng-daemonset.yaml + vim rng-deployment.yaml ``` - Load the YAML for all the resources of DockerCoins: From 7402c8e6a86c3fc373a77042be304c739f9110f0 Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Wed, 29 Apr 2020 22:46:33 +0200 Subject: [PATCH 10/41] psp: update psp apiVersion to policy/v1beta1 --- k8s/psp-restricted.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/psp-restricted.yaml b/k8s/psp-restricted.yaml index a73e7049..962685d0 100644 --- a/k8s/psp-restricted.yaml +++ b/k8s/psp-restricted.yaml @@ -1,5 +1,5 @@ --- -apiVersion: extensions/v1beta1 +apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: annotations: From d3c931e602aab2e5f637a8f459e345964f5f4ca2 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 30 Apr 2020 15:42:41 -0500 Subject: [PATCH 11/41] Add separate instructions for Zoom webinar --- slides/intro-fullday.yml | 3 +- slides/intro-selfpaced.yml | 3 +- slides/intro-twodays.yml | 3 +- slides/kadm-fullday.yml | 3 +- slides/kadm-twodays.yml | 3 +- slides/kube-fullday.yml | 3 +- slides/kube-halfday.yml | 3 +- slides/kube-selfpaced.yml | 3 +- slides/kube-twodays.yml | 3 +- ...room-zoom.md => chat-room-zoom-meeting.md} | 0 slides/shared/chat-room-zoom-webinar.md | 37 +++++++++++++++++++ slides/swarm-fullday.yml | 3 +- slides/swarm-halfday.yml | 3 +- slides/swarm-selfpaced.yml | 3 +- 14 files changed, 61 insertions(+), 12 deletions(-) rename slides/shared/{chat-room-zoom.md => chat-room-zoom-meeting.md} (100%) create mode 100644 slides/shared/chat-room-zoom-webinar.md diff --git a/slides/intro-fullday.yml b/slides/intro-fullday.yml index ba8b8cba..7662786d 100644 --- a/slides/intro-fullday.yml +++ b/slides/intro-fullday.yml @@ -20,7 +20,8 @@ content: - containers/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - #- containers/Docker_Overview.md diff --git a/slides/intro-selfpaced.yml b/slides/intro-selfpaced.yml index 12316bf9..96c2b837 100644 --- a/slides/intro-selfpaced.yml +++ b/slides/intro-selfpaced.yml @@ -20,7 +20,8 @@ content: - containers/intro.md - shared/about-slides.md #- shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - containers/Docker_Overview.md - containers/Docker_History.md diff --git a/slides/intro-twodays.yml b/slides/intro-twodays.yml index ecebcdb1..e0a15e33 100644 --- a/slides/intro-twodays.yml +++ b/slides/intro-twodays.yml @@ -20,7 +20,8 @@ content: - containers/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - # DAY 1 - containers/Docker_Overview.md diff --git a/slides/kadm-fullday.yml b/slides/kadm-fullday.yml index d6fd87db..4e99906c 100644 --- a/slides/kadm-fullday.yml +++ b/slides/kadm-fullday.yml @@ -22,7 +22,8 @@ content: - k8s/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - k8s/prereqs-admin.md diff --git a/slides/kadm-twodays.yml b/slides/kadm-twodays.yml index 053c6f43..699a8eb3 100644 --- a/slides/kadm-twodays.yml +++ b/slides/kadm-twodays.yml @@ -22,7 +22,8 @@ content: - k8s/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md # DAY 1 - - k8s/prereqs-admin.md diff --git a/slides/kube-fullday.yml b/slides/kube-fullday.yml index 4315f930..a4eb6917 100644 --- a/slides/kube-fullday.yml +++ b/slides/kube-fullday.yml @@ -21,7 +21,8 @@ content: - k8s/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - shared/prereqs.md diff --git a/slides/kube-halfday.yml b/slides/kube-halfday.yml index f498ea00..0752d87b 100644 --- a/slides/kube-halfday.yml +++ b/slides/kube-halfday.yml @@ -23,7 +23,8 @@ content: - k8s/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - shared/prereqs.md #- shared/webssh.md diff --git a/slides/kube-selfpaced.yml b/slides/kube-selfpaced.yml index faabfd3d..9eec5b79 100644 --- a/slides/kube-selfpaced.yml +++ b/slides/kube-selfpaced.yml @@ -21,7 +21,8 @@ content: - k8s/intro.md - shared/about-slides.md #- shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - shared/prereqs.md diff --git a/slides/kube-twodays.yml b/slides/kube-twodays.yml index d4c461e7..a3e9a824 100644 --- a/slides/kube-twodays.yml +++ b/slides/kube-twodays.yml @@ -21,7 +21,8 @@ content: - k8s/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - shared/prereqs.md diff --git a/slides/shared/chat-room-zoom.md b/slides/shared/chat-room-zoom-meeting.md similarity index 100% rename from slides/shared/chat-room-zoom.md rename to slides/shared/chat-room-zoom-meeting.md diff --git a/slides/shared/chat-room-zoom-webinar.md b/slides/shared/chat-room-zoom-webinar.md new file mode 100644 index 00000000..7ce2c950 --- /dev/null +++ b/slides/shared/chat-room-zoom-webinar.md @@ -0,0 +1,37 @@ +## Use the chat! + +- We have set up a chat room on @@CHAT@@ + + (clicking the link above will take you to the chat room) + +- Don't hesitate to use it to ask questions, or get help, or share feedback + +- We will *not* use the Zoom chat room for Q&A + + (we've tried it in past training sessions, and participants preferred @@CHAT@@) + +- Feel free to ask questions at any time + +- Sometimes we will wait a bit to answer ... + + ... but don't worry, we'll make sure to address all your questions! + +--- + +## Use non-verbal communication cues + +- ... wait, what?!? + +-- + +- In the chat room, you are welcome (even encouraged!) to use emojis! + +- Some of our favorites: + + .emoji[🤔✔️👍🏻👍🏼👍🏽👍🏾👍🏿⚠️🛑] + +- During the session, we'll often ask audience participation questions + +- Feel free to answer in the chat room, any way you like! + + (short message, emoji reaction ...) diff --git a/slides/swarm-fullday.yml b/slides/swarm-fullday.yml index 5d9646eb..76800ca6 100644 --- a/slides/swarm-fullday.yml +++ b/slides/swarm-fullday.yml @@ -25,7 +25,8 @@ content: - swarm/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - shared/prereqs.md - shared/connecting.md diff --git a/slides/swarm-halfday.yml b/slides/swarm-halfday.yml index 87953485..a1c1a086 100644 --- a/slides/swarm-halfday.yml +++ b/slides/swarm-halfday.yml @@ -25,7 +25,8 @@ content: - swarm/intro.md - shared/about-slides.md - shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - shared/prereqs.md - shared/connecting.md diff --git a/slides/swarm-selfpaced.yml b/slides/swarm-selfpaced.yml index fc415531..43ad7b44 100644 --- a/slides/swarm-selfpaced.yml +++ b/slides/swarm-selfpaced.yml @@ -20,7 +20,8 @@ content: - swarm/intro.md - shared/about-slides.md #- shared/chat-room-im.md -#- shared/chat-room-zoom.md +#- shared/chat-room-zoom-meeting.md +#- shared/chat-room-zoom-webinar.md - shared/toc.md - - shared/prereqs.md - shared/connecting.md From 7302d3533fde2cbff201d4e1e0cb1d5d72241f3b Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 30 Apr 2020 15:45:12 -0500 Subject: [PATCH 12/41] Use built-in dockercoins manifest instead of separate kubercoins repo --- slides/k8s/kubercoins.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/slides/k8s/kubercoins.md b/slides/k8s/kubercoins.md index ea0ef31f..4cbcc57e 100644 --- a/slides/k8s/kubercoins.md +++ b/slides/k8s/kubercoins.md @@ -31,23 +31,17 @@ --- -## Cloning some repos +## Cloning the repository -- We will need two repositories: +- We will need to clone the training repository - - the first one has the "DockerCoins" demo app +- It has the DockerCoins demo app ... - - the second one has these slides, some scripts, more manifests ... +- ... as well as these slides, some scripts, more manifests .exercise[ -- Clone the kubercoins repository on `node1`: - ```bash - git clone https://github.com/jpetazzo/kubercoins - ``` - - -- Clone the container.training repository as well: +- Clone the repository on `node1`: ```bash git clone https://@@GITREPO@@ ``` @@ -62,9 +56,9 @@ Without further ado, let's start this application! .exercise[ -- Apply all the manifests from the kubercoins repository: +- Apply the manifest for dockercoins: ```bash - kubectl apply -f kubercoins/ + kubectl apply -f ~/container.training/k8s/dockercoins.yaml ``` ] @@ -247,4 +241,3 @@ graph will appear. :EN:- Deploying a sample app with YAML manifests :FR:- Lancer une application de démo avec du YAML - From 0b10d3d40df68f7356d18d0d6090d4c91136d957 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 30 Apr 2020 15:50:24 -0500 Subject: [PATCH 13/41] Add a bunch of other managed offerings --- slides/k8s/setup-k8s.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/slides/k8s/setup-k8s.md b/slides/k8s/setup-k8s.md index a0ec4401..55b8748b 100644 --- a/slides/k8s/setup-k8s.md +++ b/slides/k8s/setup-k8s.md @@ -42,12 +42,22 @@ ## Managed options +- On AWS: [EKS](https://aws.amazon.com/eks/), + [eksctl](https://eksctl.io/) + - On Azure: [AKS](https://azure.microsoft.com/services/kubernetes-service/) +- On DigitalOcean: [DOK](https://www.digitalocean.com/products/kubernetes/) + - On Google Cloud: [GKE](https://cloud.google.com/kubernetes-engine/) -- On AWS: [EKS](https://aws.amazon.com/eks/), - [eksctl](https://eksctl.io/) +- On Linode: [LKE](https://www.linode.com/products/kubernetes/) + +- On OVHcloud: [Managed Kubernetes Service](https://www.ovhcloud.com/en/public-cloud/kubernetes/) + +- On Scaleway: [Kapsule](https://www.scaleway.com/en/kubernetes-kapsule/) + +- and much more! --- From 690a1eb75c4250ba007a14eed9cf362c2bd695aa Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Fri, 1 May 2020 15:37:57 -0500 Subject: [PATCH 14/41] Move Ardan Live --- slides/index.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slides/index.yaml b/slides/index.yaml index f73be801..9d68f82e 100644 --- a/slides/index.yaml +++ b/slides/index.yaml @@ -1,4 +1,4 @@ -- date: [2020-06-16, 2020-06-18] +- date: [2020-06-09, 2020-06-11] country: www city: streaming event: Ardan Live From 0d6c364a959bc9075c6cc77c24ffbebc551c075b Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sun, 3 May 2020 13:40:01 +0200 Subject: [PATCH 15/41] Add MacPorts instructions for stern --- slides/k8s/logs-cli.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/slides/k8s/logs-cli.md b/slides/k8s/logs-cli.md index 288d929a..93485ab2 100644 --- a/slides/k8s/logs-cli.md +++ b/slides/k8s/logs-cli.md @@ -45,7 +45,7 @@ Exactly what we need! --- -## Installing Stern +## Checking if Stern is installed - Run `stern` (without arguments) to check if it's installed: @@ -57,7 +57,17 @@ Exactly what we need! stern pod-query [flags] ``` -- If it is not installed, the easiest method is to download a [binary release](https://github.com/wercker/stern/releases) +- If it's missing, let's see how to install it + +--- + +## Installing Stern + +- Stern is written in Go, and Go programs are usually shipped as a single binary + +- We just need to download that binary and put it in our `PATH`! + +- Binary releases are available [here](https://github.com/wercker/stern/releases) on GitHub - The following commands will install Stern on a Linux Intel 64 bit machine: ```bash @@ -66,7 +76,7 @@ Exactly what we need! sudo chmod +x /usr/local/bin/stern ``` -- On OS X, just `brew install stern` +- On macOS, we can also `brew install stern` or `port install stern` From af0762a0a20e4ffbb085b6201189e5731e260a2b Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sun, 3 May 2020 15:49:37 +0200 Subject: [PATCH 16/41] Remove ':' from file names Colons are not allowed in file names on Windows. Let's use something else instead. (Initially reported by @DenisBalan. This closes #549.) --- ...users:jean.doe.yaml => user=jean.doe.yaml} | 8 ++-- slides/k8s/csr-api.md | 48 +++++++++++++++---- 2 files changed, 42 insertions(+), 14 deletions(-) rename k8s/{users:jean.doe.yaml => user=jean.doe.yaml} (85%) diff --git a/k8s/users:jean.doe.yaml b/k8s/user=jean.doe.yaml similarity index 85% rename from k8s/users:jean.doe.yaml rename to k8s/user=jean.doe.yaml index ef96d39e..4789038d 100644 --- a/k8s/users:jean.doe.yaml +++ b/k8s/user=jean.doe.yaml @@ -8,24 +8,24 @@ metadata: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: users:jean.doe + name: user=jean.doe rules: - apiGroups: [ certificates.k8s.io ] resources: [ certificatesigningrequests ] verbs: [ create ] - apiGroups: [ certificates.k8s.io ] - resourceNames: [ users:jean.doe ] + resourceNames: [ user=jean.doe ] resources: [ certificatesigningrequests ] verbs: [ get, create, delete, watch ] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: users:jean.doe + name: user=jean.doe roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: users:jean.doe + name: user=jean.doe subjects: - kind: ServiceAccount name: jean.doe diff --git a/slides/k8s/csr-api.md b/slides/k8s/csr-api.md index 47c83cac..fabf5c5f 100644 --- a/slides/k8s/csr-api.md +++ b/slides/k8s/csr-api.md @@ -132,11 +132,33 @@ For a user named `jean.doe`, we will have: - ServiceAccount `jean.doe` in Namespace `users` -- CertificateSigningRequest `users:jean.doe` +- CertificateSigningRequest `user=jean.doe` -- ClusterRole `users:jean.doe` giving read/write access to that CSR +- ClusterRole `user=jean.doe` giving read/write access to that CSR -- ClusterRoleBinding `users:jean.doe` binding ClusterRole and ServiceAccount +- ClusterRoleBinding `user=jean.doe` binding ClusterRole and ServiceAccount + +--- + +class: extra-details + +## About resource name constraints + +- Most Kubernetes identifiers and names are fairly restricted + +- They generally are DNS-1123 *labels* or *subdomains* (from [RFC 1123](https://tools.ietf.org/html/rfc1123)) + +- A label is lowercase letters, numbers, dashes; can't start or finish with a dash + +- A subdomain is one or multiple labels separated by dots + +- Some resources have more relaxed constraints, and can be "path segment names" + + (uppercase are allowed, as well as some characters like `#:?!,_`) + +- This includes RBAC objects (like Roles, RoleBindings...) and CSRs + +- See the [Identifiers and Names](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/identifiers.md) design document and the [Object Names and IDs](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#path-segment-names) documentation page for more details --- @@ -153,7 +175,7 @@ For a user named `jean.doe`, we will have: - Create the ServiceAccount, ClusterRole, ClusterRoleBinding for `jean.doe`: ```bash - kubectl apply -f ~/container.training/k8s/users:jean.doe.yaml + kubectl apply -f ~/container.training/k8s/user=jean.doe.yaml ``` ] @@ -195,7 +217,13 @@ For a user named `jean.doe`, we will have: - Add a new context using that identity: ```bash - kubectl config set-context jean.doe --user=token:jean.doe --cluster=kubernetes + kubectl config set-context jean.doe --user=token:jean.doe --cluster=`kubernetes` + ``` + (Make sure to adapt the cluster name if yours is different!) + +- Use that context: + ```bash + kubectl config use-context jean.doe ``` ] @@ -216,7 +244,7 @@ For a user named `jean.doe`, we will have: - Try to access "our" CertificateSigningRequest: ```bash - kubectl get csr users:jean.doe + kubectl get csr user=jean.doe ``` (This should tell us "NotFound") @@ -273,7 +301,7 @@ The command above generates: apiVersion: certificates.k8s.io/v1beta1 kind: CertificateSigningRequest metadata: - name: users:jean.doe + name: user=jean.doe spec: request: $(base64 -w0 < csr.pem) usages: @@ -324,12 +352,12 @@ The command above generates: - Inspect the CSR: ```bash - kubectl describe csr users:jean.doe + kubectl describe csr user=jean.doe ``` - Approve it: ```bash - kubectl certificate approve users:jean.doe + kubectl certificate approve user=jean.doe ``` ] @@ -347,7 +375,7 @@ The command above generates: - Retrieve the updated CSR object and extract the certificate: ```bash - kubectl get csr users:jean.doe \ + kubectl get csr user=jean.doe \ -o jsonpath={.status.certificate} \ | base64 -d > cert.pem ``` From efdcf4905d2ea9ee560ba995754542432bca46c0 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sun, 3 May 2020 16:01:19 +0200 Subject: [PATCH 17/41] Bump up Kubernetes dashboard to 2.0.0 --- k8s/insecure-dashboard.yaml | 15 +- k8s/kubernetes-dashboard.yaml | 313 +++++++++++++++++++++++++--------- 2 files changed, 239 insertions(+), 89 deletions(-) diff --git a/k8s/insecure-dashboard.yaml b/k8s/insecure-dashboard.yaml index f1ed0ee1..373ec001 100644 --- a/k8s/insecure-dashboard.yaml +++ b/k8s/insecure-dashboard.yaml @@ -1,3 +1,10 @@ +# This file is based on the following manifest: +# https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml +# It adds the "skip login" flag, as well as an insecure hack to defeat SSL. +# As its name implies, it is INSECURE and you should not use it in production, +# or on clusters that contain any kind of important or sensitive data, or on +# clusters that have a life span of more than a few hours. + # Copyright 2017 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -187,7 +194,7 @@ spec: spec: containers: - name: kubernetes-dashboard - image: kubernetesui/dashboard:v2.0.0-rc6 + image: kubernetesui/dashboard:v2.0.0 imagePullPolicy: Always ports: - containerPort: 8443 @@ -226,7 +233,7 @@ spec: emptyDir: {} serviceAccountName: kubernetes-dashboard nodeSelector: - "beta.kubernetes.io/os": linux + "kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master @@ -272,7 +279,7 @@ spec: spec: containers: - name: dashboard-metrics-scraper - image: kubernetesui/metrics-scraper:v1.0.3 + image: kubernetesui/metrics-scraper:v1.0.4 ports: - containerPort: 8000 protocol: TCP @@ -293,7 +300,7 @@ spec: runAsGroup: 2001 serviceAccountName: kubernetes-dashboard nodeSelector: - "beta.kubernetes.io/os": linux + "kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master diff --git a/k8s/kubernetes-dashboard.yaml b/k8s/kubernetes-dashboard.yaml index ee6977bf..b2e5802b 100644 --- a/k8s/kubernetes-dashboard.yaml +++ b/k8s/kubernetes-dashboard.yaml @@ -1,3 +1,6 @@ +# This is a copy of the following file: +# https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml + # Copyright 2017 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,19 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -# ------------------- Dashboard Secret ------------------- # - apiVersion: v1 -kind: Secret +kind: Namespace metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-certs - namespace: kube-system -type: Opaque + name: kubernetes-dashboard --- -# ------------------- Dashboard Service Account ------------------- # apiVersion: v1 kind: ServiceAccount @@ -32,62 +28,147 @@ metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard - namespace: kube-system + namespace: kubernetes-dashboard + +--- + +kind: Service +apiVersion: v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard +spec: + ports: + - port: 443 + targetPort: 8443 + selector: + k8s-app: kubernetes-dashboard + +--- + +apiVersion: v1 +kind: Secret +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-certs + namespace: kubernetes-dashboard +type: Opaque + +--- + +apiVersion: v1 +kind: Secret +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-csrf + namespace: kubernetes-dashboard +type: Opaque +data: + csrf: "" + +--- + +apiVersion: v1 +kind: Secret +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-key-holder + namespace: kubernetes-dashboard +type: Opaque + +--- + +kind: ConfigMap +apiVersion: v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-settings + namespace: kubernetes-dashboard --- -# ------------------- Dashboard Role & Role Binding ------------------- # kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: kubernetes-dashboard-minimal - namespace: kube-system + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard rules: - # Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret. -- apiGroups: [""] - resources: ["secrets"] - verbs: ["create"] - # Allow Dashboard to create 'kubernetes-dashboard-settings' config map. -- apiGroups: [""] - resources: ["configmaps"] - verbs: ["create"] # Allow Dashboard to get, update and delete Dashboard exclusive secrets. -- apiGroups: [""] - resources: ["secrets"] - resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"] - verbs: ["get", "update", "delete"] - # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. -- apiGroups: [""] - resources: ["configmaps"] - resourceNames: ["kubernetes-dashboard-settings"] - verbs: ["get", "update"] - # Allow Dashboard to get metrics from heapster. -- apiGroups: [""] - resources: ["services"] - resourceNames: ["heapster"] - verbs: ["proxy"] -- apiGroups: [""] - resources: ["services/proxy"] - resourceNames: ["heapster", "http:heapster:", "https:heapster:"] - verbs: ["get"] + - apiGroups: [""] + resources: ["secrets"] + resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"] + verbs: ["get", "update", "delete"] + # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. + - apiGroups: [""] + resources: ["configmaps"] + resourceNames: ["kubernetes-dashboard-settings"] + verbs: ["get", "update"] + # Allow Dashboard to get metrics. + - apiGroups: [""] + resources: ["services"] + resourceNames: ["heapster", "dashboard-metrics-scraper"] + verbs: ["proxy"] + - apiGroups: [""] + resources: ["services/proxy"] + resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"] + verbs: ["get"] --- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard +rules: + # Allow Metrics Scraper to get metrics from the Metrics server + - apiGroups: ["metrics.k8s.io"] + resources: ["pods", "nodes"] + verbs: ["get", "list", "watch"] + +--- + apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: kubernetes-dashboard-minimal - namespace: kube-system + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: kubernetes-dashboard-minimal -subjects: -- kind: ServiceAccount name: kubernetes-dashboard - namespace: kube-system +subjects: + - kind: ServiceAccount + name: kubernetes-dashboard + namespace: kubernetes-dashboard + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kubernetes-dashboard +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kubernetes-dashboard +subjects: + - kind: ServiceAccount + name: kubernetes-dashboard + namespace: kubernetes-dashboard --- -# ------------------- Dashboard Deployment ------------------- # kind: Deployment apiVersion: apps/v1 @@ -95,7 +176,7 @@ metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard - namespace: kube-system + namespace: kubernetes-dashboard spec: replicas: 1 revisionHistoryLimit: 10 @@ -108,55 +189,117 @@ spec: k8s-app: kubernetes-dashboard spec: containers: - - name: kubernetes-dashboard - image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1 - ports: - - containerPort: 8443 - protocol: TCP - args: - - --auto-generate-certificates - # Uncomment the following line to manually specify Kubernetes API server Host - # If not specified, Dashboard will attempt to auto discover the API server and connect - # to it. Uncomment only if the default does not work. - # - --apiserver-host=http://my-address:port - volumeMounts: - - name: kubernetes-dashboard-certs - mountPath: /certs - # Create on-disk volume to store exec logs - - mountPath: /tmp - name: tmp-volume - livenessProbe: - httpGet: - scheme: HTTPS - path: / - port: 8443 - initialDelaySeconds: 30 - timeoutSeconds: 30 + - name: kubernetes-dashboard + image: kubernetesui/dashboard:v2.0.0 + imagePullPolicy: Always + ports: + - containerPort: 8443 + protocol: TCP + args: + - --auto-generate-certificates + - --namespace=kubernetes-dashboard + # Uncomment the following line to manually specify Kubernetes API server Host + # If not specified, Dashboard will attempt to auto discover the API server and connect + # to it. Uncomment only if the default does not work. + # - --apiserver-host=http://my-address:port + volumeMounts: + - name: kubernetes-dashboard-certs + mountPath: /certs + # Create on-disk volume to store exec logs + - mountPath: /tmp + name: tmp-volume + livenessProbe: + httpGet: + scheme: HTTPS + path: / + port: 8443 + initialDelaySeconds: 30 + timeoutSeconds: 30 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsUser: 1001 + runAsGroup: 2001 volumes: - - name: kubernetes-dashboard-certs - secret: - secretName: kubernetes-dashboard-certs - - name: tmp-volume - emptyDir: {} + - name: kubernetes-dashboard-certs + secret: + secretName: kubernetes-dashboard-certs + - name: tmp-volume + emptyDir: {} serviceAccountName: kubernetes-dashboard + nodeSelector: + "kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule + - key: node-role.kubernetes.io/master + effect: NoSchedule --- -# ------------------- Dashboard Service ------------------- # kind: Service apiVersion: v1 metadata: labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kube-system + k8s-app: dashboard-metrics-scraper + name: dashboard-metrics-scraper + namespace: kubernetes-dashboard spec: ports: - - port: 443 - targetPort: 8443 + - port: 8000 + targetPort: 8000 selector: - k8s-app: kubernetes-dashboard + k8s-app: dashboard-metrics-scraper + +--- + +kind: Deployment +apiVersion: apps/v1 +metadata: + labels: + k8s-app: dashboard-metrics-scraper + name: dashboard-metrics-scraper + namespace: kubernetes-dashboard +spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + k8s-app: dashboard-metrics-scraper + template: + metadata: + labels: + k8s-app: dashboard-metrics-scraper + annotations: + seccomp.security.alpha.kubernetes.io/pod: 'runtime/default' + spec: + containers: + - name: dashboard-metrics-scraper + image: kubernetesui/metrics-scraper:v1.0.4 + ports: + - containerPort: 8000 + protocol: TCP + livenessProbe: + httpGet: + scheme: HTTP + path: / + port: 8000 + initialDelaySeconds: 30 + timeoutSeconds: 30 + volumeMounts: + - mountPath: /tmp + name: tmp-volume + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsUser: 1001 + runAsGroup: 2001 + serviceAccountName: kubernetes-dashboard + nodeSelector: + "kubernetes.io/os": linux + # Comment the following tolerations if Dashboard must not be deployed on master + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule + volumes: + - name: tmp-volume + emptyDir: {} From 40b2b8e62ea09f3175aa94bf6c3aec291ad02806 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sun, 3 May 2020 16:53:21 +0200 Subject: [PATCH 18/41] Fix deployment name in labels/selector intro (Fixes #552) --- slides/k8s/labels-annotations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slides/k8s/labels-annotations.md b/slides/k8s/labels-annotations.md index 790841ba..a295c289 100644 --- a/slides/k8s/labels-annotations.md +++ b/slides/k8s/labels-annotations.md @@ -26,12 +26,12 @@ - Create a Deployment: ```bash - kubectl create deployment web --image=nginx + kubectl create deployment clock --image=jpetazzo/clock ``` - Look at its annotations and labels: ```bash - kubectl describe deployment web + kubectl describe deployment clock ``` ] From ce4e2ffe46a35051e2517551e1ce3589a767ce3f Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sun, 3 May 2020 17:01:59 +0200 Subject: [PATCH 19/41] Add sleep command in init container example It can be tricky to illustrate what's going on here, since installing git and cloning the repo can be so fast. So we're sleeping a few seconds to help with this demo and make it easier to show the race condition. --- k8s/nginx-4-with-init.yaml | 2 +- slides/k8s/volumes.md | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/k8s/nginx-4-with-init.yaml b/k8s/nginx-4-with-init.yaml index d41ecd7a..c3023070 100644 --- a/k8s/nginx-4-with-init.yaml +++ b/k8s/nginx-4-with-init.yaml @@ -14,7 +14,7 @@ spec: initContainers: - 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 && sleep 5 && git clone https://github.com/octocat/Spoon-Knife /www" ] volumeMounts: - name: www mountPath: /www/ diff --git a/slides/k8s/volumes.md b/slides/k8s/volumes.md index a5a9c730..8e408c2f 100644 --- a/slides/k8s/volumes.md +++ b/slides/k8s/volumes.md @@ -404,7 +404,7 @@ spec: initContainers: - 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/ @@ -422,9 +422,7 @@ spec: kubectl create -f ~/container.training/k8s/nginx-4-with-init.yaml ``` -- Repeat the same operation as earlier - - (try to send HTTP requests as soon as the pod comes up) +- Try to send HTTP requests as soon as the pod comes up @@ -345,7 +345,7 @@ We can get hints at what's happening by looking at the ReplicaSet and Events. - Check that we can now create a Pod directly: ```bash - kubectl run testpsp3 --image=nginx + kubectl run testpsp3 --image=nginx --restart=Never ``` - Create a Deployment as well: From c31c81a286a8cb087187574f3335241a6a558ee2 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 4 May 2020 00:54:34 +0200 Subject: [PATCH 21/41] Allow overriding YAML desc through env vars --- slides/markmaker.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/slides/markmaker.py b/slides/markmaker.py index 5e2b20ca..00ea6be2 100755 --- a/slides/markmaker.py +++ b/slides/markmaker.py @@ -89,6 +89,11 @@ def flatten(titles): def generatefromyaml(manifest, filename): manifest = yaml.safe_load(manifest) + for k in manifest: + override = os.environ.get("OVERRIDE_"+k) + if override: + manifest[k] = override + if "zip" not in manifest: if manifest["slides"].endswith('/'): manifest["zip"] = manifest["slides"] + "slides.zip" From 8d98431ba032394dd66f6e57f26173057b9c8868 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 4 May 2020 02:09:00 +0200 Subject: [PATCH 22/41] Add Helm graduation status --- slides/k8s/helm-intro.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/slides/k8s/helm-intro.md b/slides/k8s/helm-intro.md index e98cd8a9..2db93989 100644 --- a/slides/k8s/helm-intro.md +++ b/slides/k8s/helm-intro.md @@ -18,6 +18,25 @@ --- +## CNCF graduation status + +- On April 30th 2020, Helm was the 10th project to *graduate* within the CNCF + + .emoji[🎉] + + (alongside Containerd, Prometheus, and Kubernetes itself) + +- This is an acknowledgement by the CNCF for projects that + + *demonstrate thriving adoption, an open governance process, +
+ and a strong commitment to community, sustainability, and inclusivity.* + +- See [CNCF announcement](https://www.cncf.io/announcement/2020/04/30/cloud-native-computing-foundation-announces-helm-graduation/) + and [Helm announcement](https://helm.sh/blog/celebrating-helms-cncf-graduation/) + +--- + ## Helm concepts - `helm` is a CLI tool From 1bbfba0531980cde0a9e6f9a08d38001046af07f Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 4 May 2020 02:18:05 +0200 Subject: [PATCH 23/41] Add definition of idempotent --- slides/k8s/helm-create-better-chart.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/slides/k8s/helm-create-better-chart.md b/slides/k8s/helm-create-better-chart.md index a96d46dc..992f7fd2 100644 --- a/slides/k8s/helm-create-better-chart.md +++ b/slides/k8s/helm-create-better-chart.md @@ -121,7 +121,7 @@ This creates a basic chart in the directory `helmcoins`. helm install COMPONENT-NAME CHART-DIRECTORY ``` -- We can also use the following command, which is idempotent: +- We can also use the following command, which is *idempotent*: ```bash helm upgrade COMPONENT-NAME CHART-DIRECTORY --install ``` @@ -139,6 +139,28 @@ This creates a basic chart in the directory `helmcoins`. --- +class: extra-details + +## "Idempotent" + +- Idempotent = that can be applied multiple times without changing the result + + (the word is commonly used in maths and computer science) + +- In this context, this means: + + - if the action (installing the chart) wasn't done, do it + + - if the action was already done, don't do anything + +- Ideally, when such an action fails, it can be retried safely + + (as opposed to, e.g., installing a new release each time we run it) + +- Other example: `kubectl -f some-file.yaml` + +--- + ## Checking what we've done - Let's see if DockerCoins is working! From 5a24df3fd44f9649a8581d19cd2080f24027cace Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 4 May 2020 16:25:35 +0200 Subject: [PATCH 24/41] Add details on Kustomize --- slides/k8s/kustomize.md | 212 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 193 insertions(+), 19 deletions(-) diff --git a/slides/k8s/kustomize.md b/slides/k8s/kustomize.md index 84fa9d19..db3dd89d 100644 --- a/slides/k8s/kustomize.md +++ b/slides/k8s/kustomize.md @@ -8,45 +8,164 @@ - They are left untouched by Kustomize -- Kustomize lets us define *overlays* that extend or change the resource files +- Kustomize lets us define *kustomizations* + +- A *kustomization* is conceptually similar to a *layer* + +- Technically, a *kustomization* is a file named `kustomization.yaml` + + (or a directory containing that files + additional files) --- -## Differences with Helm +## What's in a kustomization -- Helm charts use placeholders `{{ like.this }}` +- A kustomization can do any combination of the following: -- Kustomize "bases" are standard Kubernetes YAML + - include other kustomizations -- It is possible to use an existing set of YAML as a Kustomize base + - include Kubernetes resources defined in YAML files -- As a result, writing a Helm chart is more work ... + - patch Kubernetes resources (change values) -- ... But Helm charts are also more powerful; e.g. they can: + - add labels or annotations to all resources - - use flags to conditionally include resources or blocks + - specify ConfigMaps and Secrets from literal values or local files - - check if a given Kubernetes API group is supported - - - [and much more](https://helm.sh/docs/chart_template_guide/) +(... And a few more advanced features that we won't cover today!) --- -## Kustomize concepts +## A simple kustomization -- Kustomize needs a `kustomization.yaml` file +This features a Deployment, Service, and Ingress (in separate files), +and a couple of patches (to change the number of replicas and the hostname +used in the Ingress). -- That file can be a *base* or a *variant* +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +patchesStrategicMerge: +- scale-deployment.yaml +- ingress-hostname.yaml +resources: +- deployment.yaml +- service.yaml +- ingress.yaml +``` -- If it's a *base*: +On the next slide, let's see a more complex example ... - - it lists YAML resource files to use +--- -- If it's a *variant* (or *overlay*): +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +commonLabels: + add-this-to-all-my-resources: please +patchesStrategicMerge: +- prod-scaling.yaml +- prod-healthchecks.yaml +bases: +- api/ +- frontend/ +- db/ +- github.com/example/app?ref=tag-or-branch +resources: +- ingress.yaml +- permissions.yaml +configMapGenerator: +- name: appconfig + files: + - global.conf + - local.conf=prod.conf +``` - - it refers to (at least) one *base* +--- - - and some *patches* +## Glossary + +- A *base* is a kustomization that is referred to by other kustomizations + +- An *overlay* is a kustomization that refers to other kustomizations + +- A kustomization can be both a base and an overlay at the same time + + (a kustomization can refer to another, which can refer to a third) + +- A *patch* describes how to alter an existing resource + + (e.g. to change the image in a Deployment; or scaling parameters; etc.) + +- A *variant* is the final outcome of applying bases + overlays + +(See the [kustomize glossary](https://github.com/kubernetes-sigs/kustomize/blob/master/docs/glossary.md) for more definitions!) + +--- + +## What Kustomize *cannot* do + +- By design, there are a number of things that Kustomize won't do + +- For instance: + + - using command-line arguments or environment variables to generate a variant + + - overlays can only *add* resources, not *remove* them + +- See the full list of [eschewed features](https://github.com/kubernetes-sigs/kustomize/blob/master/docs/eschewedFeatures.md) for more details + +--- + +## Kustomize workflows + +- The Kustomize documentation proposes two different workflows + +- *Bespoke configuration* + + - base and overlays managed by the same team + +- *Off-the-shelf configuration* (OTS) + + - base and overlays managed by different teams + + - base is regularly updated by "upstream" (e.g. a vendor) + + - our overlays and patches should (hopefully!) apply cleanly + + - we may regularly update the base, or use a remote base + +--- + +## Remote bases + +- Kustomize can fetch remote bases using Hashicorp go-getter library + +- Examples: + + github.com/jpetazzo/kubercoins (remote git repository) + + github.com/jpetazzo/kubercoins?ref=kustomize (specific tag or branch) + + https://releases.hello.io/k/1.0.zip (remote archive) + + https://releases.hello.io/k/1.0.zip//some-subdir (subdirectory in archive) + +- See [hashicorp/go-getter URL format docs](https://github.com/hashicorp/go-getter#url-format) for more examples + +--- + +## Managing `kustomization.yaml` + +- There are many ways to manage `kustomization.yaml` files, including: + + - web wizards like [Replicated Ship](https://www.replicated.com/ship/) + + - the `kustomize` CLI + + - opening the file with our favorite text editor + +- Let's see these in action! --- @@ -200,7 +319,62 @@ Note: it might take a minute or two for the worker to start. +--- + +## Working with the `kustomize` CLI + +- This is another way to get started + +- General workflow: + + `kustomize create` to generate an empty `kustomization.yaml` file + + `kustomize edit add resource` to add Kubernetes YAML files to it + + `kustomize edit add patch` to add patches to said resources + + `kustomize build | kubectl apply -f-` or `kubectl apply -k .` + +--- + +## `kubectl apply -k` + +- Kustomize has been integrated in `kubectl` + +- The `kustomize` tool is still needed if we want to use `create`, `edit`, ... + +- Also, warning: `kubectl apply -k` is a slightly older version than `kustomize`! + +- In recent versions of `kustomize`, bases can be listed in `resources` + + (and `kustomize edit add base` will add its arguments to `resources`) + +- `kubectl apply -k` requires bases to be listed in `bases` + + (so after using `kustomize edit add base`, we need to fix `kustomization.yaml`) + +--- + +## Differences with Helm + +- Helm charts use placeholders `{{ like.this }}` + +- Kustomize "bases" are standard Kubernetes YAML + +- It is possible to use an existing set of YAML as a Kustomize base + +- As a result, writing a Helm chart is more work ... + +- ... But Helm charts are also more powerful; e.g. they can: + + - use flags to conditionally include resources or blocks + + - check if a given Kubernetes API group is supported + + - [and much more](https://helm.sh/docs/chart_template_guide/) + ??? :EN:- Packaging and running apps with Kustomize :FR:- *Packaging* d'applications avec Kustomize + From 3fafbb8d4e4c42700c7731c9565f6783f0f8d340 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 4 May 2020 16:47:26 +0200 Subject: [PATCH 25/41] Add kustomize CLI and completion --- prepare-vms/lib/commands.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/prepare-vms/lib/commands.sh b/prepare-vms/lib/commands.sh index 5493f62f..e6934124 100644 --- a/prepare-vms/lib/commands.sh +++ b/prepare-vms/lib/commands.sh @@ -246,6 +246,14 @@ EOF" helm completion bash | sudo tee /etc/bash_completion.d/helm fi" + # Install kustomize + pssh " + if [ ! -x /usr/local/bin/kustomize ]; then + curl -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v3.5.4/kustomize_v3.5.1_linux_amd64.tar.gz | + sudo tar -C /usr/local/bin -zx kustomize + echo complete -C /usr/local/bin/kustomize kustomize | sudo tee /etc/bash_completion.d/kustomize + fi" + # Install ship pssh " if [ ! -x /usr/local/bin/ship ]; then From 986d7eb9c22f4b2bf7c6fc9772088d0cbe3c0c5f Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Tue, 5 May 2020 17:23:42 +0200 Subject: [PATCH 26/41] Add foreword to operators design section --- slides/k8s/operators-design.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/slides/k8s/operators-design.md b/slides/k8s/operators-design.md index d64eb22b..3e481556 100644 --- a/slides/k8s/operators-design.md +++ b/slides/k8s/operators-design.md @@ -1,3 +1,35 @@ +# Designing an operator + +- Once we understand CRDs and operators, it's tempting to use them everywhere + +- Yes, we can do (almost) everything with operators ... + +- ... But *should we?* + +- Very often, the answer is **“no!”** + +- Operators are powerful, but significantly more complex than other solutions + +--- + +## When should we (not) use operators? + +- Operators are great if our app needs to react to cluster events + + (nodes or pods going down, and requiring extensive reconfiguration) + +- Operators *might* be helpful to encapsulate complexity + + (manipulate one single custom resource for an entire stack) + +- Operators are probably overkill if a Helm chart would suffice + +- That being said, if we really want to write an operator ... + + Read on! + +--- + ## What does it take to write an operator? - Writing a quick-and-dirty operator, or a POC/MVP, is easy From 0479ad2285424eb4eeb8e1ce0bb06f07a9ecf7d8 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Wed, 6 May 2020 17:22:13 +0200 Subject: [PATCH 27/41] Add force redirects --- slides/_redirects | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slides/_redirects b/slides/_redirects index 5c4d05bf..d6b7a527 100644 --- a/slides/_redirects +++ b/slides/_redirects @@ -1,7 +1,7 @@ # Uncomment and/or edit one of the the following lines if necessary. -#/ /kube-halfday.yml.html 200 -#/ /kube-fullday.yml.html 200 -#/ /kube-twodays.yml.html 200 +#/ /kube-halfday.yml.html 200! +#/ /kube-fullday.yml.html 200! +#/ /kube-twodays.yml.html 200! # And this allows to do "git clone https://container.training". /info/refs service=git-upload-pack https://github.com/jpetazzo/container.training/info/refs?service=git-upload-pack From 8f85332d8a688862c37757f31712887fc451c6d8 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Wed, 6 May 2020 17:25:03 +0200 Subject: [PATCH 28/41] Advanced Dockerfiles -> Advanced Dockerfile Syntax --- slides/containers/Advanced_Dockerfiles.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/slides/containers/Advanced_Dockerfiles.md b/slides/containers/Advanced_Dockerfiles.md index 58cb1713..770f9cbd 100644 --- a/slides/containers/Advanced_Dockerfiles.md +++ b/slides/containers/Advanced_Dockerfiles.md @@ -1,7 +1,7 @@ class: title -# Advanced Dockerfiles +# Advanced Dockerfile Syntax ![construction](images/title-advanced-dockerfiles.jpg) @@ -12,7 +12,10 @@ class: title We have seen simple Dockerfiles to illustrate how Docker build container images. -In this section, we will see more Dockerfile commands. +In this section, we will give a recap of the Dockerfile syntax, +and introduce advanced Dockerfile commands that we might +come across sometimes; or that we might want to use in some +specific scenarios. --- @@ -420,3 +423,8 @@ ONBUILD COPY . /src * You can't chain `ONBUILD` instructions with `ONBUILD`. * `ONBUILD` can't be used to trigger `FROM` instructions. + +??? + +:EN:- Advanced Dockerfile syntax +:FR:- Dockerfile niveau expert From eb9052ae9a25eb92715d3b7bcbb868a1e320ef1a Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 7 May 2020 13:24:35 +0200 Subject: [PATCH 29/41] Add twitch chat info --- slides/shared/chat-room-twitch.md | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 slides/shared/chat-room-twitch.md diff --git a/slides/shared/chat-room-twitch.md b/slides/shared/chat-room-twitch.md new file mode 100644 index 00000000..e89a1141 --- /dev/null +++ b/slides/shared/chat-room-twitch.md @@ -0,0 +1,37 @@ +## Use the chat! + +- We have set up a chat room on @@CHAT@@ + + (clicking the link above will take you to the chat room) + +- Don't hesitate to use it to ask questions, or get help, or share feedback + +- We will *not* use the Twitch chat room for Q&A + + (nothing wrong with it, but Gitter is more convenient for code snippets etc.) + +- Feel free to ask questions at any time + +- Sometimes we will wait a bit to answer ... + + ... but don't worry, we'll make sure to address all your questions! + +--- + +## Use non-verbal communication cues + +- ... wait, what?!? + +-- + +- In the chat room, you are welcome (even encouraged!) to use emojis! + +- Some of our favorites: + + .emoji[🤔✔️👍🏻👍🏼👍🏽👍🏾👍🏿⚠️🛑] + +- During the session, we'll often ask audience participation questions + +- Feel free to answer in the chat room, any way you like! + + (short message, emoji reaction ...) From 86b0380a7780a978cf3a7649a77881af8170a897 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Wed, 13 May 2020 20:29:59 +0200 Subject: [PATCH 30/41] Update operator links --- slides/k8s/operators.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slides/k8s/operators.md b/slides/k8s/operators.md index 46b471b8..d4b6c643 100644 --- a/slides/k8s/operators.md +++ b/slides/k8s/operators.md @@ -93,11 +93,11 @@ Examples: - Representing and managing external resources - (Example: [AWS Service Operator](https://operatorhub.io/operator/alpha/aws-service-operator.v0.0.1)) + (Example: [AWS S3 Operator](https://operatorhub.io/operator/awss3-operator-registry)) - Managing complex cluster add-ons - (Example: [Istio operator](https://operatorhub.io/operator/beta/istio-operator.0.1.6)) + (Example: [Istio operator](https://operatorhub.io/operator/istio)) - Deploying and managing our applications' lifecycles From 9467c7309e48ddecb98f4650c84011d78e45cbd4 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sun, 17 May 2020 20:21:15 +0200 Subject: [PATCH 31/41] Update shortlinks --- slides/_redirects | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/slides/_redirects b/slides/_redirects index d6b7a527..694ac990 100644 --- a/slides/_redirects +++ b/slides/_redirects @@ -13,5 +13,7 @@ # Shortlink for the QRCode /q /qrcode.html 200 -/next https://www.eventbrite.com/e/intensive-kubernetes-advanced-concepts-live-stream-tickets-102358725704 +# Shortlinks for next training in English and French +/next https://www.eventbrite.com/e/livestream-intensive-kubernetes-bootcamp-tickets-103262336428 +/hi5 https://enix.io/fr/services/formation/online/ From df4980750c795ce3759c6dfefe2fb694ac927e53 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Wed, 27 May 2020 17:41:22 +0200 Subject: [PATCH 32/41] Bump up ship version --- prepare-vms/lib/commands.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/prepare-vms/lib/commands.sh b/prepare-vms/lib/commands.sh index e6934124..c48a3166 100644 --- a/prepare-vms/lib/commands.sh +++ b/prepare-vms/lib/commands.sh @@ -255,10 +255,12 @@ EOF" fi" # Install ship + # Note: 0.51.3 is the last version that doesn't display GIN-debug messages + # (don't want to get folks confused by that!) pssh " if [ ! -x /usr/local/bin/ship ]; then ##VERSION## - curl -L https://github.com/replicatedhq/ship/releases/download/v0.40.0/ship_0.40.0_linux_amd64.tar.gz | + curl -L https://github.com/replicatedhq/ship/releases/download/v0.51.3/ship_0.51.3_linux_amd64.tar.gz | sudo tar -C /usr/local/bin -zx ship fi" From b9743a5f8cec1f0bab4ff82fb62004e6bcd6e779 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 1 Jun 2020 14:41:25 +0200 Subject: [PATCH 33/41] Simplify Portworx setup and update it for k8s 1.18 --- k8s/portworx.yaml | 886 ++++++++++++++++++++++++++++++++++++----- k8s/postgres.yaml | 5 +- slides/k8s/portworx.md | 215 ++++++---- 3 files changed, 938 insertions(+), 168 deletions(-) diff --git a/k8s/portworx.yaml b/k8s/portworx.yaml index f29a54c3..39816339 100644 --- a/k8s/portworx.yaml +++ b/k8s/portworx.yaml @@ -1,4 +1,4 @@ -# SOURCE: https://install.portworx.com/?mc=false&kbver=1.17.1&b=true&s=%2Fdev%2Floop4&j=auto&c=px-workshop&stork=true&csi=true&lh=true&st=k8s +# SOURCE: https://install.portworx.com/?mc=false&kbver=1.18.2&b=true&s=%2Fdev%2Floop4&j=auto&c=px-workshop&stork=true&csi=true&lh=true&st=k8s --- kind: Service apiVersion: v1 @@ -233,6 +233,9 @@ rules: - apiGroups: [""] resources: ["persistentvolumeclaims", "persistentvolumes"] verbs: ["get", "list"] +- apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list"] - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "update", "create"] @@ -246,6 +249,9 @@ rules: - apiGroups: ["stork.libopenstorage.org"] resources: ["backuplocations"] verbs: ["get", "list"] +- apiGroups: ["core.libopenstorage.org"] + resources: ["*"] + verbs: ["*"] - apiGroups: [""] resources: ["events"] verbs: ["create"] @@ -293,6 +299,7 @@ roleRef: name: px-role apiGroup: rbac.authorization.k8s.io --- + apiVersion: apps/v1 kind: DaemonSet metadata: @@ -300,8 +307,6 @@ metadata: namespace: kube-system labels: name: portworx - annotations: - portworx.com/install-source: "https://install.portworx.com/?mc=false&kbver=1.17.1&b=true&s=%2Fdev%2Floop4&j=auto&c=px-workshop&stork=true&csi=true&lh=true&st=k8s" spec: selector: matchLabels: @@ -331,7 +336,7 @@ spec: hostPID: false containers: - name: portworx - image: portworx/oci-monitor:2.3.2 + image: portworx/oci-monitor:2.5.1 imagePullPolicy: Always args: ["-c", "px-workshop", "-s", "/dev/loop4", "-secret_type", "k8s", "-j", "auto", "-b", @@ -341,7 +346,7 @@ spec: value: "1500" - name: "PX_TEMPLATE_VERSION" value: "v4" - - name: CSI_ENDPOINT + - name: CSI_ENDPOINT value: unix:///var/lib/kubelet/plugins/pxd.portworx.com/csi.sock livenessProbe: @@ -375,8 +380,6 @@ spec: mountPath: /etc/pwx - name: dev mountPath: /dev - - name: csi-driver-path - mountPath: /var/lib/kubelet/plugins/pxd.portworx.com - name: optpwx mountPath: /opt/pwx - name: procmount @@ -393,11 +396,11 @@ spec: mountPath: /var/run/dbus - name: csi-node-driver-registrar image: quay.io/k8scsi/csi-node-driver-registrar:v1.1.0 + imagePullPolicy: Always args: - "--v=5" - "--csi-address=$(ADDRESS)" - "--kubelet-registration-path=/var/lib/kubelet/plugins/pxd.portworx.com/csi.sock" - imagePullPolicy: Always env: - name: ADDRESS value: /csi/csi.sock @@ -507,7 +510,7 @@ rules: resources: ["secrets"] verbs: ["get", "list"] - apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshots", "volumesnapshotcontents", "volumesnapshotclasses", "volumesnapshots/status"] + resources: ["volumesnapshots", "volumesnapshotcontents", "volumesnapshotclasses", "volumesnapshots/status", "volumesnapshotcontents/status"] verbs: ["create", "get", "list", "watch", "update", "delete"] - apiGroups: [""] resources: ["nodes"] @@ -578,8 +581,8 @@ spec: serviceAccount: px-csi-account containers: - name: csi-external-provisioner + image: quay.io/openstorage/csi-provisioner:v1.6.0-1 imagePullPolicy: Always - image: quay.io/openstorage/csi-provisioner:v1.4.0-1 args: - "--v=5" - "--provisioner=pxd.portworx.com" @@ -595,7 +598,7 @@ spec: - name: socket-dir mountPath: /csi - name: csi-snapshotter - image: quay.io/k8scsi/csi-snapshotter:v2.0.0 + image: quay.io/k8scsi/csi-snapshotter:v2.1.0 imagePullPolicy: Always args: - "--v=3" @@ -609,9 +612,23 @@ spec: volumeMounts: - name: socket-dir mountPath: /csi + - name: csi-snapshot-controller + image: quay.io/k8scsi/snapshot-controller:v2.1.0 + imagePullPolicy: Always + args: + - "--v=3" + - "--leader-election=true" + env: + - name: ADDRESS + value: /csi/csi.sock + securityContext: + privileged: true + volumeMounts: + - name: socket-dir + mountPath: /csi - name: csi-resizer + image: quay.io/k8scsi/csi-resizer:v0.5.0 imagePullPolicy: Always - image: quay.io/k8scsi/csi-resizer:v0.3.0 args: - "--v=5" - "--csi-address=$(ADDRESS)" @@ -630,6 +647,510 @@ spec: path: /var/lib/kubelet/plugins/pxd.portworx.com type: DirectoryOrCreate --- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.5 + api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/260" + creationTimestamp: null + name: volumesnapshotclasses.snapshot.storage.k8s.io +spec: + additionalPrinterColumns: + - JSONPath: .driver + name: Driver + type: string + - JSONPath: .deletionPolicy + description: Determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass + should be deleted when its bound VolumeSnapshot is deleted. + name: DeletionPolicy + type: string + - JSONPath: .metadata.creationTimestamp + name: Age + type: date + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshotClass + listKind: VolumeSnapshotClassList + plural: volumesnapshotclasses + singular: volumesnapshotclass + preserveUnknownFields: false + scope: Cluster + subresources: {} + validation: + openAPIV3Schema: + description: VolumeSnapshotClass specifies parameters that a underlying storage + system uses when creating a volume snapshot. A specific VolumeSnapshotClass + is used by specifying its name in a VolumeSnapshot object. VolumeSnapshotClasses + are non-namespaced + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + deletionPolicy: + description: deletionPolicy determines whether a VolumeSnapshotContent created + through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot + is deleted. Supported values are "Retain" and "Delete". "Retain" means + that the VolumeSnapshotContent and its physical snapshot on underlying + storage system are kept. "Delete" means that the VolumeSnapshotContent + and its physical snapshot on underlying storage system are deleted. Required. + enum: + - Delete + - Retain + type: string + driver: + description: driver is the name of the storage driver that handles this + VolumeSnapshotClass. Required. + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + parameters: + additionalProperties: + type: string + description: parameters is a key-value map with storage driver specific + parameters for creating snapshots. These values are opaque to Kubernetes. + type: object + required: + - deletionPolicy + - driver + type: object + version: v1beta1 + versions: + - name: v1beta1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.5 + api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/260" + creationTimestamp: null + name: volumesnapshots.snapshot.storage.k8s.io +spec: + additionalPrinterColumns: + - JSONPath: .status.readyToUse + description: Indicates if a snapshot is ready to be used to restore a volume. + name: ReadyToUse + type: boolean + - JSONPath: .spec.source.persistentVolumeClaimName + description: Name of the source PVC from where a dynamically taken snapshot will + be created. + name: SourcePVC + type: string + - JSONPath: .spec.source.volumeSnapshotContentName + description: Name of the VolumeSnapshotContent which represents a pre-provisioned + snapshot. + name: SourceSnapshotContent + type: string + - JSONPath: .status.restoreSize + description: Represents the complete size of the snapshot. + name: RestoreSize + type: string + - JSONPath: .spec.volumeSnapshotClassName + description: The name of the VolumeSnapshotClass requested by the VolumeSnapshot. + name: SnapshotClass + type: string + - JSONPath: .status.boundVolumeSnapshotContentName + description: The name of the VolumeSnapshotContent to which this VolumeSnapshot + is bound. + name: SnapshotContent + type: string + - JSONPath: .status.creationTime + description: Timestamp when the point-in-time snapshot is taken by the underlying + storage system. + name: CreationTime + type: date + - JSONPath: .metadata.creationTimestamp + name: Age + type: date + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshot + listKind: VolumeSnapshotList + plural: volumesnapshots + singular: volumesnapshot + preserveUnknownFields: false + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + description: VolumeSnapshot is a user's request for either creating a point-in-time + snapshot of a persistent volume, or binding to a pre-existing snapshot. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + spec: + description: 'spec defines the desired characteristics of a snapshot requested + by a user. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots + Required.' + properties: + source: + description: source specifies where a snapshot will be created from. + This field is immutable after creation. Required. + properties: + persistentVolumeClaimName: + description: persistentVolumeClaimName specifies the name of the + PersistentVolumeClaim object in the same namespace as the VolumeSnapshot + object where the snapshot should be dynamically taken from. This + field is immutable. + type: string + volumeSnapshotContentName: + description: volumeSnapshotContentName specifies the name of a pre-existing + VolumeSnapshotContent object. This field is immutable. + type: string + type: object + volumeSnapshotClassName: + description: 'volumeSnapshotClassName is the name of the VolumeSnapshotClass + requested by the VolumeSnapshot. If not specified, the default snapshot + class will be used if one exists. If not specified, and there is no + default snapshot class, dynamic snapshot creation will fail. Empty + string is not allowed for this field. TODO(xiangqian): a webhook validation + on empty string. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshot-classes' + type: string + required: + - source + type: object + status: + description: 'status represents the current information of a snapshot. NOTE: + status can be modified by sources other than system controllers, and must + not be depended upon for accuracy. Controllers should only use information + from the VolumeSnapshotContent object after verifying that the binding + is accurate and complete.' + properties: + boundVolumeSnapshotContentName: + description: 'boundVolumeSnapshotContentName represents the name of + the VolumeSnapshotContent object to which the VolumeSnapshot object + is bound. If not specified, it indicates that the VolumeSnapshot object + has not been successfully bound to a VolumeSnapshotContent object + yet. NOTE: Specified boundVolumeSnapshotContentName alone does not + mean binding is valid. Controllers MUST always verify bidirectional + binding between VolumeSnapshot and VolumeSnapshotContent to + avoid possible security issues.' + type: string + creationTime: + description: creationTime is the timestamp when the point-in-time snapshot + is taken by the underlying storage system. In dynamic snapshot creation + case, this field will be filled in with the "creation_time" value + returned from CSI "CreateSnapshotRequest" gRPC call. For a pre-existing + snapshot, this field will be filled with the "creation_time" value + returned from the CSI "ListSnapshots" gRPC call if the driver supports + it. If not specified, it indicates that the creation time of the snapshot + is unknown. + format: date-time + type: string + error: + description: error is the last observed error during snapshot creation, + if any. This field could be helpful to upper level controllers(i.e., + application controller) to decide whether they should continue on + waiting for the snapshot to be created based on the type of error + reported. + properties: + message: + description: 'message is a string detailing the encountered error + during snapshot creation if specified. NOTE: message may be logged, + and it should not contain sensitive information.' + type: string + time: + description: time is the timestamp when the error was encountered. + format: date-time + type: string + type: object + readyToUse: + description: readyToUse indicates if a snapshot is ready to be used + to restore a volume. In dynamic snapshot creation case, this field + will be filled in with the "ready_to_use" value returned from CSI + "CreateSnapshotRequest" gRPC call. For a pre-existing snapshot, this + field will be filled with the "ready_to_use" value returned from the + CSI "ListSnapshots" gRPC call if the driver supports it, otherwise, + this field will be set to "True". If not specified, it means the readiness + of a snapshot is unknown. + type: boolean + restoreSize: + anyOf: + - type: integer + - type: string + description: restoreSize represents the complete size of the snapshot + in bytes. In dynamic snapshot creation case, this field will be filled + in with the "size_bytes" value returned from CSI "CreateSnapshotRequest" + gRPC call. For a pre-existing snapshot, this field will be filled + with the "size_bytes" value returned from the CSI "ListSnapshots" + gRPC call if the driver supports it. When restoring a volume from + this snapshot, the size of the volume MUST NOT be smaller than the + restoreSize if it is specified, otherwise the restoration will fail. + If not specified, it indicates that the size is unknown. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + required: + - spec + type: object + version: v1beta1 + versions: + - name: v1beta1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.5 + api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/260" + creationTimestamp: null + name: volumesnapshotcontents.snapshot.storage.k8s.io +spec: + additionalPrinterColumns: + - JSONPath: .status.readyToUse + description: Indicates if a snapshot is ready to be used to restore a volume. + name: ReadyToUse + type: boolean + - JSONPath: .status.restoreSize + description: Represents the complete size of the snapshot in bytes + name: RestoreSize + type: integer + - JSONPath: .spec.deletionPolicy + description: Determines whether this VolumeSnapshotContent and its physical snapshot + on the underlying storage system should be deleted when its bound VolumeSnapshot + is deleted. + name: DeletionPolicy + type: string + - JSONPath: .spec.driver + description: Name of the CSI driver used to create the physical snapshot on the + underlying storage system. + name: Driver + type: string + - JSONPath: .spec.volumeSnapshotClassName + description: Name of the VolumeSnapshotClass to which this snapshot belongs. + name: VolumeSnapshotClass + type: string + - JSONPath: .spec.volumeSnapshotRef.name + description: Name of the VolumeSnapshot object to which this VolumeSnapshotContent + object is bound. + name: VolumeSnapshot + type: string + - JSONPath: .metadata.creationTimestamp + name: Age + type: date + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshotContent + listKind: VolumeSnapshotContentList + plural: volumesnapshotcontents + singular: volumesnapshotcontent + preserveUnknownFields: false + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + description: VolumeSnapshotContent represents the actual "on-disk" snapshot + object in the underlying storage system + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + spec: + description: spec defines properties of a VolumeSnapshotContent created + by the underlying storage system. Required. + properties: + deletionPolicy: + description: deletionPolicy determines whether this VolumeSnapshotContent + and its physical snapshot on the underlying storage system should + be deleted when its bound VolumeSnapshot is deleted. Supported values + are "Retain" and "Delete". "Retain" means that the VolumeSnapshotContent + and its physical snapshot on underlying storage system are kept. "Delete" + means that the VolumeSnapshotContent and its physical snapshot on + underlying storage system are deleted. In dynamic snapshot creation + case, this field will be filled in with the "DeletionPolicy" field + defined in the VolumeSnapshotClass the VolumeSnapshot refers to. For + pre-existing snapshots, users MUST specify this field when creating + the VolumeSnapshotContent object. Required. + enum: + - Delete + - Retain + type: string + driver: + description: driver is the name of the CSI driver used to create the + physical snapshot on the underlying storage system. This MUST be the + same as the name returned by the CSI GetPluginName() call for that + driver. Required. + type: string + source: + description: source specifies from where a snapshot will be created. + This field is immutable after creation. Required. + properties: + snapshotHandle: + description: snapshotHandle specifies the CSI "snapshot_id" of a + pre-existing snapshot on the underlying storage system. This field + is immutable. + type: string + volumeHandle: + description: volumeHandle specifies the CSI "volume_id" of the volume + from which a snapshot should be dynamically taken from. This field + is immutable. + type: string + type: object + volumeSnapshotClassName: + description: name of the VolumeSnapshotClass to which this snapshot + belongs. + type: string + volumeSnapshotRef: + description: volumeSnapshotRef specifies the VolumeSnapshot object to + which this VolumeSnapshotContent object is bound. VolumeSnapshot.Spec.VolumeSnapshotContentName + field must reference to this VolumeSnapshotContent's name for the + bidirectional binding to be valid. For a pre-existing VolumeSnapshotContent + object, name and namespace of the VolumeSnapshot object MUST be provided + for binding to happen. This field is immutable after creation. Required. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an + entire object, this string should contain a valid JSON/Go field + access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen only + to have some well-defined way of referencing a part of an object. + TODO: this design is not final and this field is subject to change + in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is + made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + required: + - deletionPolicy + - driver + - source + - volumeSnapshotRef + type: object + status: + description: status represents the current information of a snapshot. + properties: + creationTime: + description: creationTime is the timestamp when the point-in-time snapshot + is taken by the underlying storage system. In dynamic snapshot creation + case, this field will be filled in with the "creation_time" value + returned from CSI "CreateSnapshotRequest" gRPC call. For a pre-existing + snapshot, this field will be filled with the "creation_time" value + returned from the CSI "ListSnapshots" gRPC call if the driver supports + it. If not specified, it indicates the creation time is unknown. The + format of this field is a Unix nanoseconds time encoded as an int64. + On Unix, the command `date +%s%N` returns the current time in nanoseconds + since 1970-01-01 00:00:00 UTC. + format: int64 + type: integer + error: + description: error is the latest observed error during snapshot creation, + if any. + properties: + message: + description: 'message is a string detailing the encountered error + during snapshot creation if specified. NOTE: message may be logged, + and it should not contain sensitive information.' + type: string + time: + description: time is the timestamp when the error was encountered. + format: date-time + type: string + type: object + readyToUse: + description: readyToUse indicates if a snapshot is ready to be used + to restore a volume. In dynamic snapshot creation case, this field + will be filled in with the "ready_to_use" value returned from CSI + "CreateSnapshotRequest" gRPC call. For a pre-existing snapshot, this + field will be filled with the "ready_to_use" value returned from the + CSI "ListSnapshots" gRPC call if the driver supports it, otherwise, + this field will be set to "True". If not specified, it means the readiness + of a snapshot is unknown. + type: boolean + restoreSize: + description: restoreSize represents the complete size of the snapshot + in bytes. In dynamic snapshot creation case, this field will be filled + in with the "size_bytes" value returned from CSI "CreateSnapshotRequest" + gRPC call. For a pre-existing snapshot, this field will be filled + with the "size_bytes" value returned from the CSI "ListSnapshots" + gRPC call if the driver supports it. When restoring a volume from + this snapshot, the size of the volume MUST NOT be smaller than the + restoreSize if it is specified, otherwise the restoration will fail. + If not specified, it indicates that the size is unknown. + format: int64 + minimum: 0 + type: integer + snapshotHandle: + description: snapshotHandle is the CSI "snapshot_id" of a snapshot on + the underlying storage system. If not specified, it indicates that + dynamic snapshot creation has either failed or it is still in progress. + type: string + type: object + required: + - spec + type: object + version: v1beta1 + versions: + - name: v1beta1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- kind: Service apiVersion: v1 metadata: @@ -711,29 +1232,6 @@ spec: podInfoOnMount: false --- apiVersion: v1 -kind: ConfigMap -metadata: - name: stork-config - namespace: kube-system -data: - policy.cfg: |- - { - "kind": "Policy", - "apiVersion": "v1", - "extenders": [ - { - "urlPrefix": "http://stork-service.kube-system:8099", - "apiVersion": "v1beta1", - "filterVerb": "filter", - "prioritizeVerb": "prioritize", - "weight": 5, - "enableHttps": false, - "nodeCacheCapable": false - } - ] - } ---- -apiVersion: v1 kind: ServiceAccount metadata: name: stork-account @@ -761,19 +1259,6 @@ roleRef: name: stork-role apiGroup: rbac.authorization.k8s.io --- -kind: Service -apiVersion: v1 -metadata: - name: stork-service - namespace: kube-system -spec: - selector: - name: stork - ports: - - protocol: TCP - port: 8099 - targetPort: 8099 ---- apiVersion: apps/v1 kind: Deployment metadata: @@ -801,23 +1286,6 @@ spec: name: stork tier: control-plane spec: - containers: - - command: - - /stork - - --driver=pxd - - --verbose - - --leader-elect=true - - --health-monitor-interval=120 - imagePullPolicy: Always - image: openstorage/stork:2.3.1 - env: - - name: "PX_SERVICE_NAME" - value: "portworx-api" - resources: - requests: - cpu: '0.1' - name: stork - hostPID: false affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -828,6 +1296,23 @@ spec: values: - stork topologyKey: "kubernetes.io/hostname" + hostPID: false + containers: + - command: + - /stork + - --driver=pxd + - --verbose + - --leader-elect=true + - --health-monitor-interval=120 + image: openstorage/stork:2.4.0 + imagePullPolicy: Always + env: + - name: "PX_SERVICE_NAME" + value: "portworx-api" + resources: + requests: + cpu: '0.1' + name: stork serviceAccountName: stork-account --- kind: StorageClass @@ -836,6 +1321,43 @@ metadata: name: stork-snapshot-sc provisioner: stork-snapshot --- +kind: Service +apiVersion: v1 +metadata: + name: stork-service + namespace: kube-system +spec: + selector: + name: stork + ports: + - protocol: TCP + port: 8099 + targetPort: 8099 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: stork-config + namespace: kube-system +data: + policy.cfg: |- + { + "kind": "Policy", + "apiVersion": "v1", + "extenders": [ + { + "urlPrefix": "http://stork-service.kube-system:8099", + "apiVersion": "v1beta1", + "filterVerb": "filter", + "prioritizeVerb": "prioritize", + "weight": 5, + "enableHttps": false, + "nodeCacheCapable": false, + "httpTimeout": 300000000000 + } + ] + } +--- apiVersion: v1 kind: ServiceAccount metadata: @@ -929,29 +1451,6 @@ spec: name: stork-scheduler name: stork-scheduler spec: - containers: - - command: - - /usr/local/bin/kube-scheduler - - --address=0.0.0.0 - - --leader-elect=true - - --scheduler-name=stork - - --policy-configmap=stork-config - - --policy-configmap-namespace=kube-system - - --lock-object-name=stork-scheduler - image: gcr.io/google_containers/kube-scheduler-amd64:v1.17.1 - livenessProbe: - httpGet: - path: /healthz - port: 10251 - initialDelaySeconds: 15 - name: stork-scheduler - readinessProbe: - httpGet: - path: /healthz - port: 10251 - resources: - requests: - cpu: '0.1' affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -963,6 +1462,30 @@ spec: - stork-scheduler topologyKey: "kubernetes.io/hostname" hostPID: false + containers: + - command: + - /usr/local/bin/kube-scheduler + - --address=0.0.0.0 + - --leader-elect=true + - --scheduler-name=stork + - --policy-configmap=stork-config + - --policy-configmap-namespace=kube-system + - --lock-object-name=stork-scheduler + image: gcr.io/google_containers/kube-scheduler-amd64:v1.18.2 + imagePullPolicy: Always + livenessProbe: + httpGet: + path: /healthz + port: 10251 + initialDelaySeconds: 15 + name: stork-scheduler + readinessProbe: + httpGet: + path: /healthz + port: 10251 + resources: + requests: + cpu: '0.1' serviceAccountName: stork-scheduler-account --- apiVersion: v1 @@ -1067,7 +1590,7 @@ spec: spec: initContainers: - name: config-init - image: portworx/lh-config-sync:2.0.5 + image: portworx/lh-config-sync:2.0.7 imagePullPolicy: Always args: - "init" @@ -1076,7 +1599,7 @@ spec: mountPath: /config/lh containers: - name: px-lighthouse - image: portworx/px-lighthouse:2.0.6 + image: portworx/px-lighthouse:2.0.7 imagePullPolicy: Always args: [ "-kubernetes", "true" ] ports: @@ -1086,7 +1609,7 @@ spec: - name: config mountPath: /config/lh - name: config-sync - image: portworx/lh-config-sync:2.0.5 + image: portworx/lh-config-sync:2.0.7 imagePullPolicy: Always args: - "sync" @@ -1094,13 +1617,135 @@ spec: - name: config mountPath: /config/lh - name: stork-connector - image: portworx/lh-stork-connector:2.0.5 + image: portworx/lh-stork-connector:2.0.7 imagePullPolicy: Always serviceAccountName: px-lh-account volumes: - name: config emptyDir: {} --- +apiVersion: v1 +kind: ConfigMap +metadata: + name: autopilot-config + namespace: kube-system +data: + config.yaml: |- + providers: + - name: default + type: prometheus + params: url=http://prometheus:9090 + min_poll_interval: 2 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: autopilot-account + namespace: kube-system +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: autopilot-role +rules: + - apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: autopilot-role-binding +subjects: +- kind: ServiceAccount + name: autopilot-account + namespace: kube-system +roleRef: + kind: ClusterRole + name: autopilot-role + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + scheduler.alpha.kubernetes.io/critical-pod: "" + labels: + tier: control-plane + name: autopilot + namespace: kube-system +spec: + selector: + matchLabels: + name: autopilot + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + replicas: 1 + template: + metadata: + annotations: + scheduler.alpha.kubernetes.io/critical-pod: "" + labels: + name: autopilot + tier: control-plane + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "name" + operator: In + values: + - autopilot + topologyKey: "kubernetes.io/hostname" + hostPID: false + containers: + - command: + - /autopilot + - -f + - ./etc/config/config.yaml + - -log-level + - debug + imagePullPolicy: Always + image: portworx/autopilot:1.2.0 + resources: + requests: + cpu: '0.1' + securityContext: + privileged: false + name: autopilot + volumeMounts: + - name: config-volume + mountPath: /etc/config + serviceAccountName: autopilot-account + volumes: + - name: config-volume + configMap: + name: autopilot-config + items: + - key: config.yaml + path: config.yaml +--- +apiVersion: v1 +kind: Service +metadata: + name: autopilot + namespace: kube-system + labels: + name: autopilot-service +spec: + ports: + - name: autopilot + protocol: TCP + port: 9628 + selector: + name: autopilot + tier: control-plane +--- # That one is an extra. # Create a default Storage Class to simplify Portworx setup. kind: StorageClass @@ -1113,4 +1758,59 @@ provisioner: kubernetes.io/portworx-volume parameters: repl: "2" priority_io: "high" - +--- +# This DaemonSet will set up the (virtual) block device +# used by portworx. +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: setup-loop4-for-portworx + namespace: kube-system +spec: + selector: + matchLabels: + app: setup-loop4-for-portworx + template: + metadata: + labels: + app: setup-loop4-for-portworx + spec: + volumes: + - name: hostfs + hostPath: + path: / + tolerations: + - effect: NoSchedule + operator: Exists + initContainers: + - name: setup-loop4-for-portworx + image: alpine + volumeMounts: + - name: hostfs + mountPath: /hostfs + securityContext: + privileged: true + command: + - chroot + - /hostfs + - /bin/sh + - -c + - | + set -e + if ! [ -f /portworx.blk ]; then + echo "Creating /portworx.blk..." + truncate --size 10G /portworx.blk + fi + if ! grep -q loop /proc/devices; then + echo "Loading loop module..." + modprobe loop + fi + echo "Checking /dev/loop4..." + if ! losetup /dev/loop4; then + echo "Associating /dev/loop4 with /portworx.blk..." + losetup /dev/loop4 /portworx.blk + fi + echo "Loop device setup complete." + containers: + - name: do-nothing + image: k8s.gcr.io/pause diff --git a/k8s/postgres.yaml b/k8s/postgres.yaml index a9331f2a..69c90c37 100644 --- a/k8s/postgres.yaml +++ b/k8s/postgres.yaml @@ -22,7 +22,10 @@ spec: command: ["sh", "-c", "if [ -d /vol/lost+found ]; then rmdir /vol/lost+found; fi"] containers: - name: postgres - image: postgres:11 + image: postgres:12 + env: + - name: POSTGRES_HOST_AUTH_METHOD + value: trust volumeMounts: - mountPath: /var/lib/postgresql/data name: postgres diff --git a/slides/k8s/portworx.md b/slides/k8s/portworx.md index 796d29e5..0a0badac 100644 --- a/slides/k8s/portworx.md +++ b/slides/k8s/portworx.md @@ -74,29 +74,78 @@ --- -## Portworx requirements +## Installing Portworx -- Kubernetes cluster ✔️ +- Portworx installation is relatively simple -- Optional key/value store (etcd or Consul) ❌ +- ... But we made it *even simpler!* -- At least one available block device ❌ +- We are going to use a YAML manifest that will take care of everything + +- Warning: this manifest is customized for a very specific setup + + (like the VMs that we provide during workshops and training sessions) + +- It will probably *not work* If you are using a different setup + + (like Docker Desktop, k3s, MicroK8S, Minikube ...) --- -## The key-value store +## The simplified Portworx installer -- In the current version of Portworx (1.4) it is recommended to use etcd or Consul +- The Portworx installation will take a few minutes -- But Portworx also has beta support for an embedded key/value store +- Let's start it, then we'll explain what happens behind the scenes -- For simplicity, we are going to use the latter option +.exercise[ - (but if we have deployed Consul or etcd, we can use that, too) +- Install Portworx: + ```bash + kubectl apply -f ~/container.training/k8s/portworx.yaml + ``` + +] + + + +*Note: this was tested with Kubernetes 1.18. Newer versions may or may not work.* --- -## One available block device +class: extra-details + +## What's in this YAML manifest? + +- Portworx installation itself, pre-configured for our setup + +- A default *Storage Class* using Portworx + +- A *Daemon Set* to create loop devices on each node of the cluster + +--- + +class: extra-details + +## Portworx installation + +- The official way to install Portworx is to use [PX-Central](https://central.portworx.com/) + + (this requires a free account) + +- PX-Central will ask us a few questions about our cluster + + (Kubernetes version, on-prem/cloud deployment, etc.) + +- Using our answers, it will generate a YAML manifest that we can use + +--- + +class: extra-details + +## Portworx storage configuration + +- Portworx needs at least one *block device* - Block device = disk or partition on a disk @@ -112,71 +161,41 @@ --- +class: extra-details + ## Setting up a loop device -- We are going to create a 10 GB (empty) file on each node +- Our `portworx.yaml` manifest includes a *Daemon Set* that will: -- Then make a loop device from it, to be used by Portworx + - create a 10 GB (empty) file on each node -.exercise[ + - load the `loop` module (if it's not already loaded) -- Create a 10 GB file on each node: - ```bash - for N in $(seq 1 4); do ssh node$N sudo truncate --size 10G /portworx.blk; done - ``` - (If SSH asks to confirm host keys, enter `yes` each time.) + - associate a loop device with the 10 GB file -- Associate the file to a loop device on each node: - ```bash - for N in $(seq 1 4); do ssh node$N sudo losetup /dev/loop4 /portworx.blk; done - ``` - -] - ---- - -## Installing Portworx - -- To install Portworx, we need to go to https://install.portworx.com/ - -- This website will ask us a bunch of questions about our cluster - -- Then, it will generate a YAML file that we should apply to our cluster - --- - -- Or, we can just apply that YAML file directly (it's in `k8s/portworx.yaml`) - -.exercise[ - -- Install Portworx: - ```bash - kubectl apply -f ~/container.training/k8s/portworx.yaml - ``` - -] +- After these steps, we have a block device that Portworx can use --- class: extra-details -## Generating a custom YAML file +## Implementation details -If you want to generate a YAML file tailored to your own needs, the easiest -way is to use https://install.portworx.com/. +- The file is `/portworx.blk` -FYI, this is how we obtained the YAML file used earlier: -``` -KBVER=$(kubectl version -o json | jq -r .serverVersion.gitVersion) -BLKDEV=/dev/loop4 -curl https://install.portworx.com/1.4/?kbver=$KBVER&b=true&s=$BLKDEV&c=px-workshop&stork=true&lh=true -``` -If you want to use an external key/value store, add one of the following: -``` -&k=etcd://`XXX`:2379 -&k=consul://`XXX`:8500 -``` -... where `XXX` is the name or address of your etcd or Consul server. + (it is a [sparse file](https://en.wikipedia.org/wiki/Sparse_file) created with `truncate`) + +- The loop device is `/dev/loop4` + +- This can be verified by running `sudo losetup` + +- The *Daemon Set* uses a privileged *Init Container* + +- We can check the logs of that container with: + ```bash + kubectl logs --selector=app=setup-loop4-for-portworx \ + -c setup-loop4-for-portworx + ``` --- @@ -276,11 +295,9 @@ parameters: priority_io: "high" ``` -- It says "use Portworx to create volumes" +- It says "use Portworx to create volumes and keep 2 replicas of these volumes" -- It tells Portworx to "keep 2 replicas of these volumes" - -- It marks the Storage Class as being the default one +- The annotation makes this Storage Class the default one --- @@ -323,7 +340,10 @@ spec: schedulerName: stork containers: - name: postgres - image: postgres:11 + image: postgres:12 + env: + - name: POSTGRES_HOST_AUTH_METHOD + value: trust volumeMounts: - mountPath: /var/lib/postgresql/data name: postgres @@ -401,14 +421,14 @@ autopilot prompt detection expects $ or # at the beginning of the line. - Populate it with `pgbench`: ```bash - pgbench -i -s 10 demo + pgbench -i demo ``` ] - The `-i` flag means "create tables" -- The `-s 10` flag means "create 10 x 100,000 rows" +- If you want more data in the test tables, add e.g. `-s 10` (to get 10x more rows) --- @@ -428,11 +448,55 @@ autopilot prompt detection expects $ or # at the beginning of the line. psql demo -c "select count(*) from pgbench_accounts" ``` - +- Check that `pgbench_history` is currently empty: + ```bash + psql demo -c "select count(*) from pgbench_history" + ``` ] -(We should see a count of 1,000,000 rows.) +--- + +## Testing the load generator + +- Let's use `pgbench` to generate a few transactions + +.exercise[ + +- Run `pgbench` for 10 seconds, reporting progress every second: + ```bash + pgbench -P 1 -T 10 demo + ``` + +- Check the size of the history table now: + ```bash + psql demo -c "select count(*) from pgbench_history" + ``` + +] + +Note: on small cloud instances, a typical speed is about 100 transactions/second. + +--- + +## Generating transactions + +- Now let's use `pgbench` to generate more transactions + +- While it's running, we will disrupt the database server + +.exercise[ + +- Run `pgbench` for 10 minutes, reporting progress every second: + ```bash + pgbench -P 1 -T 600 demo + ``` + +- You can use a longer time period if you need more time to run the next steps + + + +] --- @@ -522,15 +586,18 @@ By "disrupt" we mean: "disconnect it from the network". ```key ^J``` --> -- Check the number of rows in the `pgbench_accounts` table: +- Check how many transactions are now in the `pgbench_history` table: ```bash - psql demo -c "select count(*) from pgbench_accounts" + psql demo -c "select count(*) from pgbench_history" ``` ] +If the 10-second test that we ran earlier gave e.g. 80 transactions per second, +and we failed the node after 30 seconds, we should have about 2400 row in that table. + --- ## Double-check that the pod has really moved @@ -598,7 +665,7 @@ class: extra-details - If we need to see what's going on with Portworx: ``` - PXPOD=$(kubectl -n kube-system get pod -l name=portworx -o json | + PXPOD=$(kubectl -n kube-system get pod -l name=portworx -o json | jq -r .items[0].metadata.name) kubectl -n kube-system exec $PXPOD -- /opt/pwx/bin/pxctl status ``` From 4671a981a76f67a62534d8954bca34bc66beb154 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 1 Jun 2020 20:58:23 +0200 Subject: [PATCH 34/41] Add deployment automation steps The settings file can now specify an optional list of steps. After creating a bunch of instances, the steps are then automatically executed. This helps since virtually all deployments will be a sequence of 'start + deploy + otheractions'. It also helps to automatically excecute steps like webssh and tailhist (since I tend to forget them often). --- prepare-vms/lib/commands.sh | 49 ++++++++++++++++++++++---- prepare-vms/settings/fundamentals.yaml | 6 ++++ prepare-vms/settings/jerome.yaml | 7 ++++ 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/prepare-vms/lib/commands.sh b/prepare-vms/lib/commands.sh index c48a3166..b49e56dc 100644 --- a/prepare-vms/lib/commands.sh +++ b/prepare-vms/lib/commands.sh @@ -339,7 +339,7 @@ _cmd_maketag() { if [ -z $USER ]; then export USER=anonymous fi - MS=$(($(date +%N)/1000000)) + MS=$(($(date +%N | tr -d 0)/1000000)) date +%Y-%m-%d-%H-%M-$MS-$USER } @@ -493,6 +493,7 @@ _cmd_start() { --settings) SETTINGS=$2; shift 2;; --count) COUNT=$2; shift 2;; --tag) TAG=$2; shift 2;; + --students) STUDENTS=$2; shift 2;; *) die "Unrecognized parameter: $1." esac done @@ -504,8 +505,14 @@ _cmd_start() { die "Please add --settings flag to specify which settings file to use." fi if [ -z "$COUNT" ]; then - COUNT=$(awk '/^clustersize:/ {print $2}' $SETTINGS) - warning "No --count option was specified. Using value from settings file ($COUNT)." + CLUSTERSIZE=$(awk '/^clustersize:/ {print $2}' $SETTINGS) + if [ -z "$STUDENTS" ]; then + warning "Neither --count nor --students was specified." + warning "According to the settings file, the cluster size is $CLUSTERSIZE." + warning "Deploying one cluster of $CLUSTERSIZE nodes." + STUDENTS=1 + fi + COUNT=$(($STUDENTS*$CLUSTERSIZE)) fi # Check that the specified settings and infrastructure are valid. @@ -523,11 +530,41 @@ _cmd_start() { infra_start $COUNT sep info "Successfully created $COUNT instances with tag $TAG" - sep echo created > tags/$TAG/status - info "To deploy Docker on these instances, you can run:" - info "$0 deploy $TAG" + # If the settings.yaml file has a "steps" field, + # automatically execute all the actions listed in that field. + # If an action fails, retry it up to 10 times. + python -c 'if True: # hack to deal with indentation + import sys, yaml + settings = yaml.safe_load(sys.stdin) + print ("\n".join(settings.get("steps", []))) + ' < tags/$TAG/settings.yaml \ + | while read step; do + if [ -z "$step" ]; then + break + fi + sep + info "Automatically executing step '$step'." + TRY=1 + MAXTRY=10 + while ! $0 $step $TAG ; do + TRY=$(($TRY+1)) + if [ $TRY -gt $MAXTRY ]; then + error "This step ($step) failed after $MAXTRY attempts." + info "You can troubleshoot the situation manually, or terminate these instances with:" + info "$0 stop $TAG" + die "Giving up." + else + sep + info "Step '$step' failed. Let's wait 10 seconds and try again." + info "(Attempt $TRY out of $MAXTRY.)" + sleep 10 + fi + done + done + sep + info "Deployment successful." info "To terminate these instances, you can run:" info "$0 stop $TAG" } diff --git a/prepare-vms/settings/fundamentals.yaml b/prepare-vms/settings/fundamentals.yaml index 1c4000ce..3dc70a27 100644 --- a/prepare-vms/settings/fundamentals.yaml +++ b/prepare-vms/settings/fundamentals.yaml @@ -21,3 +21,9 @@ machine_version: 0.15.0 # Password used to connect with the "docker user" docker_user_password: training + +steps: + - deploy + - webssh + - tailhist + - cards diff --git a/prepare-vms/settings/jerome.yaml b/prepare-vms/settings/jerome.yaml index 626751c5..57470504 100644 --- a/prepare-vms/settings/jerome.yaml +++ b/prepare-vms/settings/jerome.yaml @@ -20,3 +20,10 @@ machine_version: 0.14.0 # Password used to connect with the "docker user" docker_user_password: training +steps: + - deploy + - webssh + - tailhist + - kube + - cards + - kubetest From 774c8a0e31b78ba4a79e36a170b527b53460463a Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Mon, 1 Jun 2020 23:43:33 +0200 Subject: [PATCH 35/41] Rewrite intro to the authn/authz module --- slides/k8s/authn-authz.md | 74 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/slides/k8s/authn-authz.md b/slides/k8s/authn-authz.md index 47fd3ea1..6d91dc51 100644 --- a/slides/k8s/authn-authz.md +++ b/slides/k8s/authn-authz.md @@ -1,6 +1,74 @@ # Authentication and authorization -*And first, a little refresher!* +- In this section, we will: + + - define authentication and authorization + + - explain how they are implemented in Kubernetes + + - talk about tokens, certificates, service accounts, RBAC ... + +- But first: why do we need all this? + +--- + +## The need for fine-grained security + +- The Kubernetes API should only be available for identified users + + - we don't want "guest access" (except in very rare scenarios) + + - we don't want strangers to use our compute resources, delete our apps ... + + - our keys and passwords should not be exposed to the public + +- Users will often have different access rights + + - cluster admin (similar to UNIX "root") can do everything + + - developer might access specific resources, or a specific namespace + + - supervision might have read only access to *most* resources + +--- + +## Example: custom HTTP load balancer + +- Let's imagine that we have a custom HTTP load balancer for multiple apps + +- Each app has its own *Deployment* resource + +- By default, the apps are "sleeping" and scaled to zero + +- When a request comes in, the corresponding app gets woken up + +- After some inactivity, the app is scaled down again + +- This HTTP load balancer needs API access (to scale up/down) + +- What if *a wild vulnerability appears*? + +--- + +## Consequences of vulnerability + +- If the HTTP load balancer has the same API access as we do: + + *full cluster compromise (easy data leak, cryptojacking...)* + +- If the HTTP load balancer has `update` permissions on the Deployments: + + *defacement (easy), MITM / impersonation (medium to hard)* + +- If the HTTP load balancer only has permission to `scale` the Deployments: + + *denial-of-service* + +- All these outcomes are bad, but some are worse than others + +--- + +## Definitions - Authentication = verifying the identity of a person @@ -147,7 +215,7 @@ class: extra-details (if their key is compromised, or they leave the organization) -- Option 1: re-create a new CA and re-issue everyone's certificates +- Option 1: re-create a new CA and re-issue everyone's certificates
→ Maybe OK if we only have a few users; no way otherwise @@ -631,7 +699,7 @@ class: extra-details - Let's look for these in existing ClusterRoleBindings: ```bash - kubectl get clusterrolebindings -o yaml | + kubectl get clusterrolebindings -o yaml | grep -e kubernetes-admin -e system:masters ``` From f960230f8e5551e354f2f8d06b71912e6318802c Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Tue, 2 Jun 2020 17:28:23 +0200 Subject: [PATCH 36/41] Reorganize managed options; add Scaleway --- slides/k8s/setup-managed.md | 368 ++++++++++++++++++++++++------------ 1 file changed, 247 insertions(+), 121 deletions(-) diff --git a/slides/k8s/setup-managed.md b/slides/k8s/setup-managed.md index 05dedb66..38e852c5 100644 --- a/slides/k8s/setup-managed.md +++ b/slides/k8s/setup-managed.md @@ -11,6 +11,8 @@ else to do it for you." (the goal is to show the actual steps to get started) +- The list is sorted alphabetically + - All the options mentioned here require an account with a cloud provider @@ -18,123 +20,6 @@ with a cloud provider --- -## EKS (the old way) - -- [Read the doc](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html) - -- Create service roles, VPCs, and a bunch of other oddities - -- Try to figure out why it doesn't work - -- Start over, following an [official AWS blog post](https://aws.amazon.com/blogs/aws/amazon-eks-now-generally-available/) - -- Try to find the missing Cloud Formation template - --- - -.footnote[(╯°□°)╯︵ ┻━┻] - ---- - -## EKS (the new way) - -- Install `eksctl` - -- Set the usual environment variables - - ([AWS_DEFAULT_REGION](https://docs.aws.amazon.com/general/latest/gr/rande.html#eks_region), AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY) - -- Create the cluster: - ```bash - eksctl create cluster - ``` - -- Wait 15-20 minutes (yes, it's sloooooooooooooooooow) - -- Add cluster add-ons - - (by default, it doesn't come with metrics-server, logging, etc.) - ---- - -## EKS (cleanup) - -- Delete the cluster: - ```bash - eksctl delete cluster - ``` - -- If you need to find the name of the cluster: - ```bash - eksctl get clusters - ``` - -.footnote[Note: the AWS documentation has been updated and now includes [eksctl instructions](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html).] - ---- - -## GKE (initial setup) - -- Install `gcloud` - -- Login: - ```bash - gcloud auth init - ``` - -- Create a "project": - ```bash - gcloud projects create my-gke-project - gcloud config set project my-gke-project - ``` - -- Pick a [region](https://cloud.google.com/compute/docs/regions-zones/) - - (example: `europe-west1`, `us-west1`, ...) - ---- - -## GKE (create cluster) - -- Create the cluster: - ```bash - gcloud container clusters create my-gke-cluster --region us-west1 --num-nodes=2 - ``` - - (without `--num-nodes` you might exhaust your IP address quota!) - -- The first time you try to create a cluster in a given project, you get an error - - - you need to enable the Kubernetes Engine API - - the error message gives you a link - - follow the link and enable the API (and billing) -
(it's just a couple of clicks and it's instantaneous) - -- Wait a couple of minutes (yes, it's faaaaaaaaast) - -- The cluster comes with many add-ons - ---- - -## GKE (cleanup) - -- List clusters (if you forgot its name): - ```bash - gcloud container clusters list - ``` - -- Delete the cluster: - ```bash - gcloud container clusters delete my-gke-cluster --region us-west1 - ``` - -- Delete the project (optional): - ```bash - gcloud projects delete my-gke-project - ``` - ---- - ## AKS (initial setup) - Install the Azure CLI @@ -168,8 +53,6 @@ with a cloud provider az aks get-credentials --resource-group my-aks-group --name my-aks-cluster ``` -- The cluster has useful components pre-installed, such as the metrics server - --- ## AKS (cleanup) @@ -190,6 +73,95 @@ with a cloud provider --- +## AKS (notes) + +- The cluster has useful components pre-installed, such as the metrics server + +- There is also a product called [AKS Engine](https://github.com/Azure/aks-engine): + + - leverages ARM (Azure Resource Manager) templates to deploy Kubernetes + + - it's "the library used by AKS" + + - fully customizable + + - think of it as "half-managed" Kubernetes option + +--- + +## Amazon EKS (the old way) + +- [Read the doc](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html) + +- Create service roles, VPCs, and a bunch of other oddities + +- Try to figure out why it doesn't work + +- Start over, following an [official AWS blog post](https://aws.amazon.com/blogs/aws/amazon-eks-now-generally-available/) + +- Try to find the missing Cloud Formation template + +-- + +.footnote[(╯°□°)╯︵ ┻━┻] + +--- + +## Amazon EKS (the new way) + +- Install `eksctl` + +- Set the usual environment variables + + ([AWS_DEFAULT_REGION](https://docs.aws.amazon.com/general/latest/gr/rande.html#eks_region), AWS_ACCESS_KEY, AWS_SECRET_ACCESS_KEY) + +- Create the cluster: + ```bash + eksctl create cluster + ``` + +- Cluster can take a long time to be ready (15-20 minutes is typical) + +- Add cluster add-ons + + (by default, it doesn't come with metrics-server, logging, etc.) + +--- + +## Amazon EKS (cleanup) + +- Delete the cluster: + ```bash + eksctl delete cluster + ``` + +- If you need to find the name of the cluster: + ```bash + eksctl get clusters + ``` + +.footnote[Note: the AWS documentation has been updated and now includes [eksctl instructions](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html).] + +--- + +## Amazon EKS (notes) + +- Convenient if you *have to* use AWS + +- Needs extra steps to be truly production-ready + +- [Versions tend to be outdated](https://twitter.com/jpetazzo/status/1252948707680686081) + +- The only officially supported pod network is the [Amazon VPC CNI plugin](https://docs.aws.amazon.com/eks/latest/userguide/pod-networking.html) + + - integrates tightly with security groups and VPC networking + + - not suitable for high density clusters (with many small pods on big nodes) + + - other plugins [should still work](https://docs.aws.amazon.com/eks/latest/userguide/alternate-cni-plugins.html) but will require extra work + +--- + ## Digital Ocean (initial setup) - Install `doctl` @@ -242,6 +214,162 @@ with a cloud provider --- +## GKE (initial setup) + +- Install `gcloud` + +- Login: + ```bash + gcloud auth init + ``` + +- Create a "project": + ```bash + gcloud projects create my-gke-project + gcloud config set project my-gke-project + ``` + +- Pick a [region](https://cloud.google.com/compute/docs/regions-zones/) + + (example: `europe-west1`, `us-west1`, ...) + +--- + +## GKE (create cluster) + +- Create the cluster: + ```bash + gcloud container clusters create my-gke-cluster --region us-west1 --num-nodes=2 + ``` + + (without `--num-nodes` you might exhaust your IP address quota!) + +- The first time you try to create a cluster in a given project, you get an error + + - you need to enable the Kubernetes Engine API + - the error message gives you a link + - follow the link and enable the API (and billing) +
(it's just a couple of clicks and it's instantaneous) + +- Clutser should be ready in a couple of minutes + +--- + +## GKE (cleanup) + +- List clusters (if you forgot its name): + ```bash + gcloud container clusters list + ``` + +- Delete the cluster: + ```bash + gcloud container clusters delete my-gke-cluster --region us-west1 + ``` + +- Delete the project (optional): + ```bash + gcloud projects delete my-gke-project + ``` + +--- + +## GKE (notes) + +- Well-rounded product overall + + (it used to be one of the best managed Kubernetes offerings available; + now that many other providers entered the game, that title is debatable) + +- The cluster comes with many add-ons + +- Versions lag a bit: + + - latest minor version (e.g. 1.18) tends to be unsupported + + - previous minor version (e.g. 1.17) supported through alpha channel + + - previous versions (e.g. 1.14-1.16) supported + +--- + +## Scaleway (initial setup) + +- After creating your account, make sure you set a password or get an API key + + (by default, it uses email "magic links" to sign in) + +- Install `scw` + + (you need [CLI v2](https://github.com/scaleway/scaleway-cli/tree/v2#Installation), which in beta as of May 2020) + +- Generate the CLI configuration with `scw init` + + (it will prompt for your API key, or email + password) + +--- + +## Scaleway (create cluster) + +- Create the cluster: + ```bash + k8s cluster create name=my-kapsule-cluster version=1.18.3 cni=cilium \ + default-pool-config.node-type=DEV1-M default-pool-config.size=3 + ``` + +- Get cluster ID: + ```bash + scw k8s cluster list + # or + CLUSTERID=$(scw k8s cluster list -o json | \ + jq -r '.[] | select(.name="my-kapsule-cluster") | .id') + ``` + +- Check cluster status with e.g. `scw k8s cluster list` on a wide terminal + +- After less than 5 minutes, status should be `ready` + +- Add connection information to your `.kube/config` file: + ```bash + scw k8s kubeconfig install $CLUSTERID + ``` + +--- + +## Scaleway (cleanup) + +- Get cluster ID (e.g. with `scw k8s cluster list`) + +- Delete the cluster: + ```bash + scw cluster delete cluster-id=$CLUSTERID + ``` + +- Warning: as of May 2020, load balancers have to be deleted separately! + +--- + +## Scaleway (notes) + +- The `create` command is a bit more complex than with other providers + + (you must specify the Kubernetes version, CNI plugin, and node type) + +- To see available versions and CNI plugins, run `scw k8s version list` + +- As of May 2020, Kapsule supports: + + - multiple CNI plugins, including: cilium, calico, weave, flannel + + - Kubernetes versions 1.15 to 1.18 + + - multiple container runtimes, including: Docker, containerd, CRI-O + +- To see available node types and their price, check their [pricing page]( +https://www.scaleway.com/en/pricing/) + +--- + ## More options - Alibaba Cloud @@ -250,8 +378,6 @@ with a cloud provider - OVH -- Scaleway - - ... ??? From 412d029d0c63e7f9d2f5b1044edaa1199067b5a1 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Tue, 2 Jun 2020 17:45:51 +0200 Subject: [PATCH 37/41] Tweak self-hosted options --- slides/k8s/setup-selfhosted.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/slides/k8s/setup-selfhosted.md b/slides/k8s/setup-selfhosted.md index f3c245fe..66b7073d 100644 --- a/slides/k8s/setup-selfhosted.md +++ b/slides/k8s/setup-selfhosted.md @@ -1,5 +1,15 @@ # Kubernetes distributions and installers +- Sometimes, we need to run Kubernetes ourselves + + (as opposed to "use a managed offering") + +- Beware: it takes *a lot of work* to set up and maintain Kubernetes + +- It might be necessary if you have specific security or compliance requirements + + (e.g. national security for states that don't have a suitable domestic cloud) + - There are [countless](https://kubernetes.io/docs/setup/pick-right-solution/) distributions available - We can't review them all @@ -78,13 +88,15 @@ ## And many more ... -- Docker Enterprise Edition - - [AKS Engine](https://github.com/Azure/aks-engine) +- Docker Enterprise Edition + - Pivotal Container Service (PKS) -- Tectonic by CoreOS +- Tectonic by CoreOS (now being integrated into Red Hat OpenShift) + +- VMware Tanzu Kubernetes Grid (TKG) - etc. From 14271a4df0abe43cfbaea74657c662f9ca576895 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Wed, 3 Jun 2020 16:54:41 +0200 Subject: [PATCH 38/41] Rehaul 'setup k8s' sections --- slides/k8s/setup-devel.md | 145 +++++++++++++++++++++++++ slides/k8s/setup-k8s.md | 106 ------------------ slides/k8s/setup-managed.md | 36 ++++--- slides/k8s/setup-overview.md | 192 +++++++++++++++++++++++++++++++++ slides/k8s/setup-selfhosted.md | 16 +-- slides/kadm-fullday.yml | 2 + slides/kadm-twodays.yml | 2 + slides/kube-fullday.yml | 5 +- slides/kube-halfday.yml | 5 +- slides/kube-selfpaced.yml | 5 +- slides/kube-twodays.yml | 5 +- 11 files changed, 391 insertions(+), 128 deletions(-) create mode 100644 slides/k8s/setup-devel.md delete mode 100644 slides/k8s/setup-k8s.md create mode 100644 slides/k8s/setup-overview.md diff --git a/slides/k8s/setup-devel.md b/slides/k8s/setup-devel.md new file mode 100644 index 00000000..8d31f295 --- /dev/null +++ b/slides/k8s/setup-devel.md @@ -0,0 +1,145 @@ +# Running a local development cluster + +- Let's review some options to run Kubernetes locally + +- There is no "best option", it depends what you value: + + - ability to run on all platforms (Linux, Mac, Windows, other?) + + - ability to run clusters with multiple nodes + + - ability to run multiple clusters side by side + + - ability to run recent (or even, unreleased) versions of Kubernetes + + - availability of plugins + + - etc. + +--- + +## Docker Desktop + +- Available on Mac and Windows + +- Gives you one cluster with one node + +- Rather old version of Kubernetes + +- Very easy to use if you are already using Docker Desktop: + + go to Docker Desktop preferences and enable Kubernetes + +- Ideal for Docker users who need good integration between both platforms + +--- + +## [k3d](https://k3d.io/) + +- Based on [K3s](https://k3s.io/) by Rancher Labs + +- Requires Docker + +- Runs Kubernetes nodes in Docker containers + +- Can deploy multiple clusters, with multiple nodes, and multiple master nodes + +- As of June 2020, two versions co-exist: stable (1.7) and beta (3.0) + +- They have different syntax and options, this can be confusing + + (but don't let that stop you!) + +--- + +## k3d in action + +- Get `k3d` beta 3 binary on https://github.com/rancher/k3d/releases + +- Create a simple cluster: + ```bash + k3d create cluster petitcluster --update-kubeconfig + ``` + +- Use it: + ```bash + kubectl config use-context k3d-petitcluster + ``` + +- Create a more complex cluster with a custom version: + ```bash + k3d create cluster groscluster --update-kubeconfig \ + --image rancher/k3s:v1.18.3-k3s1 --masters 3 --workers 5 --api-port 6444 + ``` + + (note: API port seems to be necessary when running multiple clusters) + +--- + +## [KinD](https://kind.sigs.k8s.io/) + +- Kubernetes-in-Docker + +- Requires Docker (obviously!) + +- Deploying a single node cluster using the latest version is simple: + ```bash + kind create cluster + ``` + +- More advanced scenarios require writing a short [config file](https://kind.sigs.k8s.io/docs/user/quick-start#configuring-your-kind-cluster) + + (to define multiple nodes, multiple master nodes, set Kubernetes versions ...) + +- Can deploy multiple clusters + +--- + +## [Minikube](https://minikube.sigs.k8s.io/docs/) + +- The "legacy" option! + + (note: this is not a bad thing, it means that it's very stable, has lots of plugins, etc.) + +- Supports many [drivers](https://minikube.sigs.k8s.io/docs/drivers/) + + (HyperKit, Hyper-V, KVM, VirtualBox, but also Docker and many others) + +- Can deploy a single cluster; recent versions can deploy multiple nodes + +- Great option if you want a "Kubernetes first" experience + + (i.e. if you don't already have Docker and/or don't want/need it) + +--- + +## [MicroK8s](https://microk8s.io/) + +- Available on Linux, and since recently, on Mac and Windows as well + +- The Linux version is installed through Snap + + (which is pre-installed on all recent versions of Ubuntu) + +- Also supports clustering (as in, multiple machines running MicroK8s) + +- DNS is not enabled by default; enable it with `microk8s enable dns` + +--- + +## VM with custom install + +- Choose your own adventure! + +- Pick any Linux distribution! + +- Build your cluster from scratch or use a Kubernetes installer! + +- Discover exotic CNI plugins and container runtimes! + +- The only limit is yourself, and the time you are willing to sink in! + +??? + +:EN:- Kubernetes options for local development +:FR:- Installation de Kubernetes pour travailler en local diff --git a/slides/k8s/setup-k8s.md b/slides/k8s/setup-k8s.md deleted file mode 100644 index 55b8748b..00000000 --- a/slides/k8s/setup-k8s.md +++ /dev/null @@ -1,106 +0,0 @@ -# Setting up Kubernetes - -- How did we set up these Kubernetes clusters that we're using? - --- - - - -- We used `kubeadm` on freshly installed VM instances running Ubuntu LTS - - 1. Install Docker - - 2. Install Kubernetes packages - - 3. Run `kubeadm init` on the first node (it deploys the control plane on that node) - - 4. Set up Weave (the overlay network) -
- (that step is just one `kubectl apply` command; discussed later) - - 5. Run `kubeadm join` on the other nodes (with the token produced by `kubeadm init`) - - 6. Copy the configuration file generated by `kubeadm init` - -- Check the [prepare VMs README](https://@@GITREPO@@/blob/master/prepare-vms/README.md) for more details - ---- - -## `kubeadm` drawbacks - -- Doesn't set up Docker or any other container engine - -- Doesn't set up the overlay network - -- [Some extra steps](https://kubernetes.io/docs/setup/independent/high-availability/) to support HA control plane - --- - -- "It's still twice as many steps as setting up a Swarm cluster 😕" -- Jérôme - ---- - -## Managed options - -- On AWS: [EKS](https://aws.amazon.com/eks/), - [eksctl](https://eksctl.io/) - -- On Azure: [AKS](https://azure.microsoft.com/services/kubernetes-service/) - -- On DigitalOcean: [DOK](https://www.digitalocean.com/products/kubernetes/) - -- On Google Cloud: [GKE](https://cloud.google.com/kubernetes-engine/) - -- On Linode: [LKE](https://www.linode.com/products/kubernetes/) - -- On OVHcloud: [Managed Kubernetes Service](https://www.ovhcloud.com/en/public-cloud/kubernetes/) - -- On Scaleway: [Kapsule](https://www.scaleway.com/en/kubernetes-kapsule/) - -- and much more! - ---- - -## Other deployment options - -- [kops](https://github.com/kubernetes/kops): - customizable deployments on AWS, Digital Ocean, GCE (beta), vSphere (alpha) - -- [minikube](https://kubernetes.io/docs/setup/minikube/), - [kubespawn](https://github.com/kinvolk/kube-spawn), - [Docker Desktop](https://docs.docker.com/docker-for-mac/kubernetes/), - [kind](https://kind.sigs.k8s.io): - for local development - -- [kubicorn](https://github.com/kubicorn/kubicorn), - the [Cluster API](https://blogs.vmware.com/cloudnative/2019/03/14/what-and-why-of-cluster-api/): - deploy your clusters declaratively, "the Kubernetes way" - ---- - -## Even more deployment options - -- If you like Ansible: - [kubespray](https://github.com/kubernetes-incubator/kubespray) - -- If you like Terraform: - [typhoon](https://github.com/poseidon/typhoon) - -- If you like Terraform and Puppet: - [tarmak](https://github.com/jetstack/tarmak) - -- You can also learn how to install every component manually, with - the excellent tutorial [Kubernetes The Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way) - - *Kubernetes The Hard Way is optimized for learning, which means taking the long route to ensure you understand each task required to bootstrap a Kubernetes cluster.* - -- There are also many commercial options available! - -- For a longer list, check the Kubernetes documentation: -
- it has a great guide to [pick the right solution](https://kubernetes.io/docs/setup/#production-environment) to set up Kubernetes. - -??? - -:EN:- Overview of the kubeadm installer -:FR:- Survol de kubeadm diff --git a/slides/k8s/setup-managed.md b/slides/k8s/setup-managed.md index 38e852c5..6f8e3356 100644 --- a/slides/k8s/setup-managed.md +++ b/slides/k8s/setup-managed.md @@ -1,4 +1,4 @@ -# Installing a managed cluster +# Deploying a managed cluster *"The easiest way to install Kubernetes is to get someone else to do it for you." @@ -317,7 +317,26 @@ with a cloud provider default-pool-config.node-type=DEV1-M default-pool-config.size=3 ``` -- Get cluster ID: +- After less than 5 minutes, cluster state will be `ready` + + (check cluster status with e.g. `scw k8s cluster list` on a wide terminal +) + +- Add connection information to your `.kube/config` file: + ```bash + scw k8s kubeconfig install `CLUSTERID` + ``` + + (the cluster ID is shown by `scw k8s cluster list`) + +--- + +class: extra-details + +## Scaleway (automation) + +- If you want to obtain the cluster ID programmatically, this will do it: + ```bash scw k8s cluster list # or @@ -325,15 +344,6 @@ with a cloud provider jq -r '.[] | select(.name="my-kapsule-cluster") | .id') ``` -- Check cluster status with e.g. `scw k8s cluster list` on a wide terminal - -- After less than 5 minutes, status should be `ready` - -- Add connection information to your `.kube/config` file: - ```bash - scw k8s kubeconfig install $CLUSTERID - ``` - --- ## Scaleway (cleanup) @@ -376,7 +386,9 @@ https://www.scaleway.com/en/pricing/) - [IBM Cloud](https://console.bluemix.net/docs/containers/cs_cli_install.html#cs_cli_install) -- OVH +- [Linode Kubernetes Engine (LKE)](https://www.linode.com/products/kubernetes/) + +- OVHcloud [Managed Kubernetes Service](https://www.ovhcloud.com/en/public-cloud/kubernetes/) - ... diff --git a/slides/k8s/setup-overview.md b/slides/k8s/setup-overview.md new file mode 100644 index 00000000..e6cff5bc --- /dev/null +++ b/slides/k8s/setup-overview.md @@ -0,0 +1,192 @@ +# Setting up Kubernetes + +- Kubernetes is made of many components that require careful configuration + +- Secure operation typically requires TLS certificates and a local CA + + (certificate authority) + +- Setting up everything manually is possible, but rarely done + + (except for learning purposes) + +- Let's do a quick overview of available options! + +--- + +## Local development + +- Are you writing code that will eventually run on Kubernetes? + +- Then it's a good idea to have a development cluster! + +- Development clusters only need one node + +- This simplifies their setup a lot: + + - pod networking doesn't even need CNI plugins, overlay networks, etc. + + - they can be fully contained (no pun intended) in an easy-to-ship VM image + + - some of the security aspects may be simplified (different threat model) + +- Examples: Docker Desktop, k3d, KinD, MicroK8s, Minikube + + (some of these also support clusters with multiple nodes) + +--- + +## Managed clusters + +- Many cloud providers and hosting providers offer "managed Kubernetes" + +- The deployment and maintenance of the cluster is entirely managed by the provider + + (ideally, clusters can be spun up automatically through an API, CLI, or web interface) + +- Given the complexity of Kubernetes, this approach is *strongly recommended* + + (at least for your first production clusters) + +- After working for a while with Kubernetes, you will be better equipped to decide: + + - whether to operate it yourself or use a managed offering + + - which offering or which distribution works best for you and your needs + +--- + +## Managed clusters details + +- Pricing models differ from one provider to another + + - nodes are generally charged at their usual price + + - control plane may be free or incur a small nominal fee + +- Beyond pricing, there are *huge* differences in features between providers + +- The "major" providers are not always the best ones! + +--- + +## Managed clusters differences + +- Most providers let you pick which Kubernetes version you want + + - some providers offer up-to-date versions + + - others lag significantly (sometimes by 2 or 3 minor versions) + +- Some providers offer multiple networking or storage options + +- Others will only support one, tied to their infrastructure + + (changing that is in theory possible, but might be complex or unsupported) + +- Some providers let you configure or customize the control plane + + (generally through Kubernetes "feature gates") + +--- + +## Kubernetes distributions and installers + +- If you want to run Kubernetes yourselves, there are many options + + (free, commercial, proprietary, open source ...) + +- Some of them are installers, while some are complete platforms + +- Some of them leverage other well-known deployment tools + + (like Puppet, Terraform ...) + +- A good starting point to explore these options is this [guide](https://v1-16.docs.kubernetes.io/docs/setup/#production-environment) + + (it defines categories like "managed", "turnkey" ...) + +--- + +## kubeadm + +- kubeadm is a tool part of Kubernetes to facilitate cluster setup + +- Many other installers and distributions use it (but not all of them) + +- It can also be used by itself + +- Excellent starting point to install Kubernetes on your own machines + + (virtual, physical, it doesn't matter) + +- It even supports highly available control planes, or "multi-master" + + (this is more complex, though, because it introduces the need for an API load balancer) + +--- + +## Manual setup + +- The resources below are mainly for educational purposes! + +- [Kubernetes The Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way) by Kelsey Hightower + + - step by step guide to install Kubernetes on Google Cloud + + - covers certificates, high availability ... + + - *“Kubernetes The Hard Way is optimized for learning, which means taking the long route to ensure you understand each task required to bootstrap a Kubernetes cluster.”* + +- [Deep Dive into Kubernetes Internals for Builders and Operators](https://www.youtube.com/watch?v=3KtEAa7_duA) + + - conference presentation showing step-by-step control plane setup + + - emphasis on simplicity, not on security and availability + +--- + +## About our training clusters + +- How did we set up these Kubernetes clusters that we're using? + +-- + +- We used `kubeadm` on freshly installed VM instances running Ubuntu LTS + + 1. Install Docker + + 2. Install Kubernetes packages + + 3. Run `kubeadm init` on the first node (it deploys the control plane on that node) + + 4. Set up Weave (the overlay network) with a single `kubectl apply` command + + 5. Run `kubeadm join` on the other nodes (with the token produced by `kubeadm init`) + + 6. Copy the configuration file generated by `kubeadm init` + +- Check the [prepare VMs README](https://@@GITREPO@@/blob/master/prepare-vms/README.md) for more details + +--- + +## `kubeadm` "drawbacks" + +- Doesn't set up Docker or any other container engine + + (this is by design, to give us choice) + +- Doesn't set up the overlay network + + (this is also by design, for the same reasons) + +- HA control plane requires [some extra steps](https://kubernetes.io/docs/setup/independent/high-availability/) + +- Note that HA control plane also requires setting up a specific API load balancer + + (which is beyond the scope of kubeadm) + +??? + +:EN:- Various ways to install Kubernetes +:FR:- Survol des techniques d'installation de Kubernetes diff --git a/slides/k8s/setup-selfhosted.md b/slides/k8s/setup-selfhosted.md index 66b7073d..11ee661e 100644 --- a/slides/k8s/setup-selfhosted.md +++ b/slides/k8s/setup-selfhosted.md @@ -18,7 +18,7 @@ --- -## kops +## [kops](https://github.com/kubernetes/kops) - Deploys Kubernetes using cloud infrastructure @@ -42,7 +42,7 @@ --- -## Kubespray +## [kubespray](https://github.com/kubernetes-incubator/kubespray) - Based on Ansible @@ -92,13 +92,17 @@ - Docker Enterprise Edition +- [Lokomotive](https://github.com/kinvolk/lokomotive), leveraging Terraform and [Flatcar Linux](https://www.flatcar-linux.org/) + - Pivotal Container Service (PKS) +- [Tarmak](https://github.com/jetstack/tarmak), leveraging Puppet and Terraform + - Tectonic by CoreOS (now being integrated into Red Hat OpenShift) -- VMware Tanzu Kubernetes Grid (TKG) +- [Typhoon](https://typhoon.psdn.io/), leveraging Terraform -- etc. +- VMware Tanzu Kubernetes Grid (TKG) --- @@ -123,5 +127,5 @@ ??? -:EN:- Various ways to set up Kubernetes -:FR:- Différentes méthodes pour installer Kubernetes +:EN:- Kubernetes distributions and installers +:FR:- L'offre Kubernetes "on premises" diff --git a/slides/kadm-fullday.yml b/slides/kadm-fullday.yml index 4e99906c..8ccebabf 100644 --- a/slides/kadm-fullday.yml +++ b/slides/kadm-fullday.yml @@ -36,6 +36,8 @@ content: - k8s/interco.md - - k8s/apilb.md + #- k8s/setup-overview.md + #- k8s/setup-devel.md #- k8s/setup-managed.md #- k8s/setup-selfhosted.md - k8s/cluster-upgrade.md diff --git a/slides/kadm-twodays.yml b/slides/kadm-twodays.yml index 699a8eb3..62f33dd1 100644 --- a/slides/kadm-twodays.yml +++ b/slides/kadm-twodays.yml @@ -34,6 +34,8 @@ content: - k8s/cni.md - k8s/interco.md - - k8s/apilb.md + - k8s/setup-overview.md + #- k8s/setup-devel.md - k8s/setup-managed.md - k8s/setup-selfhosted.md - k8s/cluster-upgrade.md diff --git a/slides/kube-fullday.yml b/slides/kube-fullday.yml index a4eb6917..3c663dac 100644 --- a/slides/kube-fullday.yml +++ b/slides/kube-fullday.yml @@ -53,7 +53,10 @@ content: #- k8s/exercise-wordsmith.md - - k8s/yamldeploy.md - - k8s/setup-k8s.md + - k8s/setup-overview.md + #- k8s/setup-devel.md + #- k8s/setup-managed.md + #- k8s/setup-selfhosted.md #- k8s/dashboard.md #- k8s/kubectlscale.md - k8s/scalingdockercoins.md diff --git a/slides/kube-halfday.yml b/slides/kube-halfday.yml index 0752d87b..0aaea969 100644 --- a/slides/kube-halfday.yml +++ b/slides/kube-halfday.yml @@ -40,7 +40,10 @@ content: - k8s/declarative.md - k8s/kubenet.md - k8s/kubectlget.md - - k8s/setup-k8s.md + - k8s/setup-overview.md + #- k8s/setup-devel.md + #- k8s/setup-managed.md + #- k8s/setup-selfhosted.md - - k8s/kubectl-run.md #- k8s/batch-jobs.md #- k8s/labels-annotations.md diff --git a/slides/kube-selfpaced.yml b/slides/kube-selfpaced.yml index 9eec5b79..aa5a2a2b 100644 --- a/slides/kube-selfpaced.yml +++ b/slides/kube-selfpaced.yml @@ -54,7 +54,10 @@ content: #- k8s/exercise-wordsmith.md - k8s/yamldeploy.md - - - k8s/setup-k8s.md + - k8s/setup-overview.md + - k8s/setup-devel.md + - k8s/setup-managed.md + - k8s/setup-selfhosted.md - k8s/dashboard.md #- k8s/kubectlscale.md - k8s/scalingdockercoins.md diff --git a/slides/kube-twodays.yml b/slides/kube-twodays.yml index a3e9a824..fec866fe 100644 --- a/slides/kube-twodays.yml +++ b/slides/kube-twodays.yml @@ -53,7 +53,10 @@ content: #- k8s/exercise-wordsmith.md - - k8s/yamldeploy.md - #- k8s/setup-k8s.md + - k8s/setup-overview.md + - k8s/setup-devel.md + #- k8s/setup-managed.md + #- k8s/setup-selfhosted.md - k8s/dashboard.md #- k8s/kubectlscale.md - k8s/scalingdockercoins.md From 0d065788a44b07e59dd973c5bfc5721634bf6686 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 4 Jun 2020 12:42:44 +0200 Subject: [PATCH 39/41] Improve how we display dates (sounds silly but with longer online events it becomes necessary) --- slides/index.py | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/slides/index.py b/slides/index.py index 2a5ad0ff..bf6ee076 100755 --- a/slides/index.py +++ b/slides/index.py @@ -141,13 +141,26 @@ import yaml items = yaml.safe_load(open("index.yaml")) + +def prettyparse(date): + months = [ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ] + month = months[date.month-1] + suffix = { + 1: "st", 2: "nd", 3: "rd", + 21: "st", 22: "nd", 23: "rd", + 31: "st"}.get(date.day, "th") + return date.year, month, "{}{}".format(date.day, suffix) + + # Items with a date correspond to scheduled sessions. # Items without a date correspond to self-paced content. # The date should be specified as a string (e.g. 2018-11-26). # It can also be a list of two elements (e.g. [2018-11-26, 2018-11-28]). # The latter indicates an event spanning multiple dates. -# The first date will be used in the generated page, but the event -# will be considered "current" (and therefore, shown in the list of +# The event will be considered "current" (shown in the list of # upcoming events) until the second date. for item in items: @@ -157,19 +170,23 @@ for item in items: date_begin, date_end = date else: date_begin, date_end = date, date - suffix = { - 1: "st", 2: "nd", 3: "rd", - 21: "st", 22: "nd", 23: "rd", - 31: "st"}.get(date_begin.day, "th") - # %e is a non-standard extension (it displays the day, but without a - # leading zero). If strftime fails with ValueError, try to fall back - # on %d (which displays the day but with a leading zero when needed). - try: - item["prettydate"] = date_begin.strftime("%B %e{}, %Y").format(suffix) - except ValueError: - item["prettydate"] = date_begin.strftime("%B %d{}, %Y").format(suffix) + y1, m1, d1 = prettyparse(date_begin) + y2, m2, d2 = prettyparse(date_end) + if (y1, m1, d1) == (y2, m2, d2): + # Single day event + pretty_date = "{} {}, {}".format(m1, d1, y1) + elif (y1, m1) == (y2, m2): + # Multi-day event within a single month + pretty_date = "{} {}-{}, {}".format(m1, d1, d2, y1) + elif y1 == y2: + # Multi-day event spanning more than a month + pretty_date = "{} {}-{} {}, {}".format(m1, d1, m2, d2, y1) + else: + # Event spanning the turn of the year (REALLY???) + pretty_date = "{} {}, {}-{} {}, {}".format(m1, d1, y1, m2, d2, y2) item["begin"] = date_begin item["end"] = date_end + item["prettydate"] = pretty_date item["flag"] = FLAGS.get(item.get("country"),"") today = datetime.date.today() From 2836b580780a4b98599e0f6cba826a5728591b31 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 4 Jun 2020 12:53:25 +0200 Subject: [PATCH 40/41] Add ENIX high five sessions --- slides/index.yaml | 61 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/slides/index.yaml b/slides/index.yaml index 9d68f82e..15890969 100644 --- a/slides/index.yaml +++ b/slides/index.yaml @@ -1,3 +1,56 @@ +- date: [2020-07-07, 2020-07-09] + country: www + city: streaming + event: Ardan Live + speaker: jpetazzo + title: Intensive Docker Bootcamp + attend: https://www.eventbrite.com/e/livestream-intensive-docker-bootcamp-tickets-103258886108 + +- date: [2020-06-15, 2020-06-16] + country: www + city: streaming + event: ENIX SAS + speaker: jpetazzo + title: Docker intensif (en français) + lang: fr + attend: https://enix.io/fr/services/formation/online/ + +- date: [2020-06-17, 2020-06-19] + country: www + city: streaming + event: ENIX SAS + speaker: jpetazzo + title: Fondamentaux Kubernetes (en français) + lang: fr + attend: https://enix.io/fr/services/formation/online/ + +- date: 2020-06-22 + country: www + city: streaming + event: ENIX SAS + speaker: jpetazzo + title: Packaging pour Kubernetes (en français) + lang: fr + attend: https://enix.io/fr/services/formation/online/ + +- date: [2020-06-23, 2020-06-24] + country: www + city: streaming + event: ENIX SAS + speaker: jpetazzo + title: Kubernetes avancé (en français) + lang: fr + attend: https://enix.io/fr/services/formation/online/ + +- date: [2020-06-25, 2020-06-26] + country: www + city: streaming + event: ENIX SAS + speaker: jpetazzo + title: Opérer Kubernetes (en français) + lang: fr + attend: https://enix.io/fr/services/formation/online/ + - date: [2020-06-09, 2020-06-11] country: www city: streaming @@ -6,14 +59,6 @@ title: Intensive Kubernetes Bootcamp attend: https://www.eventbrite.com/e/livestream-intensive-kubernetes-bootcamp-tickets-103262336428 -- date: [2020-05-19, 2020-05-21] - country: www - city: streaming - event: Ardan Live - speaker: jpetazzo - title: Intensive Docker Bootcamp - attend: https://www.eventbrite.com/e/livestream-intensive-docker-bootcamp-tickets-103258886108 - - date: [2020-05-04, 2020-05-08] country: www city: streaming From 276a2dbdda6ee818e46181257369a0975c391cd1 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 4 Jun 2020 12:55:42 +0200 Subject: [PATCH 41/41] Fix titles --- slides/index.py | 4 ++-- slides/index.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/slides/index.py b/slides/index.py index bf6ee076..bfba3bfb 100755 --- a/slides/index.py +++ b/slides/index.py @@ -22,7 +22,7 @@ TEMPLATE=""" {{ title }} Note: while some workshops are delivered in other languages, slides are always in English. - Free video of our latest workshop + Free Kubernetes intro course Getting Started With Kubernetes and Container Orchestration @@ -40,7 +40,7 @@ TEMPLATE=""" {% if coming_soon %} - Coming soon near you + Coming soon {% for item in coming_soon %} diff --git a/slides/index.yaml b/slides/index.yaml index 15890969..45677214 100644 --- a/slides/index.yaml +++ b/slides/index.yaml @@ -74,7 +74,7 @@ speaker: jpetazzo title: Intensive Docker and Kubernetes attend: https://www.eventbrite.com/e/ardan-labs-live-worldwide-march-30-april-2-2020-tickets-100331129108# - slides: https://https://2020-03-ardan.container.training/ + slides: https://2020-03-ardan.container.training/ - date: 2020-03-06 country: uk