diff --git a/prepare-vms/lib/ips-txt-to-html.py b/prepare-vms/lib/ips-txt-to-html.py index fd576afc..5bc1873c 100755 --- a/prepare-vms/lib/ips-txt-to-html.py +++ b/prepare-vms/lib/ips-txt-to-html.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import os import sys import yaml diff --git a/prepare-vms/settings/admin-dmuc.yaml b/prepare-vms/settings/admin-dmuc.yaml index 70ac6ec6..a7d776a8 100644 --- a/prepare-vms/settings/admin-dmuc.yaml +++ b/prepare-vms/settings/admin-dmuc.yaml @@ -5,7 +5,7 @@ clustersize: 1 clusterprefix: dmuc # Jinja2 template to use to generate ready-to-cut cards -cards_template: admin.html +cards_template: cards.html # Use "Letter" in the US, and "A4" everywhere else paper_size: A4 diff --git a/prepare-vms/settings/admin-kubenet.yaml b/prepare-vms/settings/admin-kubenet.yaml index 8256fc65..52046831 100644 --- a/prepare-vms/settings/admin-kubenet.yaml +++ b/prepare-vms/settings/admin-kubenet.yaml @@ -5,7 +5,7 @@ clustersize: 3 clusterprefix: kubenet # Jinja2 template to use to generate ready-to-cut cards -cards_template: admin.html +cards_template: cards.html # Use "Letter" in the US, and "A4" everywhere else paper_size: A4 diff --git a/prepare-vms/settings/admin-kuberouter.yaml b/prepare-vms/settings/admin-kuberouter.yaml index 3f903065..f894c5f4 100644 --- a/prepare-vms/settings/admin-kuberouter.yaml +++ b/prepare-vms/settings/admin-kuberouter.yaml @@ -5,7 +5,7 @@ clustersize: 3 clusterprefix: kuberouter # Jinja2 template to use to generate ready-to-cut cards -cards_template: admin.html +cards_template: cards.html # Use "Letter" in the US, and "A4" everywhere else paper_size: A4 diff --git a/prepare-vms/settings/admin-test.yaml b/prepare-vms/settings/admin-test.yaml index ac9679be..57d1339b 100644 --- a/prepare-vms/settings/admin-test.yaml +++ b/prepare-vms/settings/admin-test.yaml @@ -5,7 +5,7 @@ clustersize: 3 clusterprefix: test # Jinja2 template to use to generate ready-to-cut cards -cards_template: admin.html +cards_template: cards.html # Use "Letter" in the US, and "A4" everywhere else paper_size: A4 diff --git a/prepare-vms/settings/enix.yaml b/prepare-vms/settings/enix.yaml deleted file mode 100644 index 075efb34..00000000 --- a/prepare-vms/settings/enix.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Number of VMs per cluster -clustersize: 1 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: node - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: enix.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: A4 - -# Feel free to reduce this if your printer can handle it -paper_margin: 0.2in - -# Note: paper_size and paper_margin only apply to PDF generated with pdfkit. -# If you print (or generate a PDF) using ips.html, they will be ignored. -# (The equivalent parameters must be set from the browser's print dialog.) - -# This can be "test" or "stable" -engine_version: stable - -# These correspond to the version numbers visible on their respective GitHub release pages -compose_version: 1.21.1 -machine_version: 0.14.0 - -# Password used to connect with the "docker user" -docker_user_password: training - diff --git a/prepare-vms/settings/jerome.yaml b/prepare-vms/settings/jerome.yaml index 62e8a08f..78014b55 100644 --- a/prepare-vms/settings/jerome.yaml +++ b/prepare-vms/settings/jerome.yaml @@ -5,7 +5,7 @@ clustersize: 4 clusterprefix: node # Jinja2 template to use to generate ready-to-cut cards -cards_template: jerome.html +cards_template: cards.html # Use "Letter" in the US, and "A4" everywhere else paper_size: Letter diff --git a/prepare-vms/settings/kube101.yaml b/prepare-vms/settings/kube101.yaml index 8f742e54..4f89305c 100644 --- a/prepare-vms/settings/kube101.yaml +++ b/prepare-vms/settings/kube101.yaml @@ -7,7 +7,7 @@ clustersize: 3 clusterprefix: node # Jinja2 template to use to generate ready-to-cut cards -cards_template: kube101.html +cards_template: cards.html # Use "Letter" in the US, and "A4" everywhere else paper_size: Letter diff --git a/prepare-vms/setup-admin-clusters.sh b/prepare-vms/setup-admin-clusters.sh index b93f0da3..a4719d7a 100755 --- a/prepare-vms/setup-admin-clusters.sh +++ b/prepare-vms/setup-admin-clusters.sh @@ -1,15 +1,20 @@ #!/bin/sh set -e -INFRA=infra/aws-eu-west-3 +export AWS_INSTANCE_TYPE=t3a.small + +INFRA=infra/aws-us-west-2 STUDENTS=2 -TAG=admin-dmuc +PREFIX=$(date +%Y-%m-%d-%H-%M) + +SETTINGS=admin-dmuc +TAG=$PREFIX-$SETTINGS ./workshopctl start \ --tag $TAG \ --infra $INFRA \ - --settings settings/$TAG.yaml \ + --settings settings/$SETTINGS.yaml \ --count $STUDENTS ./workshopctl deploy $TAG @@ -17,11 +22,12 @@ TAG=admin-dmuc ./workshopctl kubebins $TAG ./workshopctl cards $TAG -TAG=admin-kubenet +SETTINGS=admin-kubenet +TAG=$PREFIX-$SETTINGS ./workshopctl start \ --tag $TAG \ --infra $INFRA \ - --settings settings/$TAG.yaml \ + --settings settings/$SETTINGS.yaml \ --count $((3*$STUDENTS)) ./workshopctl deploy $TAG @@ -29,11 +35,12 @@ TAG=admin-kubenet ./workshopctl disableaddrchecks $TAG ./workshopctl cards $TAG -TAG=admin-kuberouter +SETTINGS=admin-kuberouter +TAG=$PREFIX-$SETTINGS ./workshopctl start \ --tag $TAG \ --infra $INFRA \ - --settings settings/$TAG.yaml \ + --settings settings/$SETTINGS.yaml \ --count $((3*$STUDENTS)) ./workshopctl deploy $TAG @@ -41,11 +48,12 @@ TAG=admin-kuberouter ./workshopctl disableaddrchecks $TAG ./workshopctl cards $TAG -TAG=admin-test +SETTINGS=admin-test +TAG=$PREFIX-$SETTINGS ./workshopctl start \ --tag $TAG \ --infra $INFRA \ - --settings settings/$TAG.yaml \ + --settings settings/$SETTINGS.yaml \ --count $((3*$STUDENTS)) ./workshopctl deploy $TAG diff --git a/prepare-vms/templates/admin.html b/prepare-vms/templates/admin.html deleted file mode 100644 index 9684a55c..00000000 --- a/prepare-vms/templates/admin.html +++ /dev/null @@ -1,124 +0,0 @@ -{# Feel free to customize or override anything in there! #} -{%- set url = "http://FIXME.container.training" -%} -{%- set pagesize = 9 -%} -{%- if clustersize == 1 -%} - {%- set workshop_name = "Docker workshop" -%} - {%- set cluster_or_machine = "machine virtuelle" -%} - {%- set this_or_each = "cette" -%} - {%- set plural = "" -%} - {%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%} -{%- else -%} - {%- set workshop_name = "Kubernetes workshop" -%} - {%- set cluster_or_machine = "cluster" -%} - {%- set this_or_each = "chaque" -%} - {%- set plural = "s" -%} - {%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%} - {%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%} - {%- set image_src = image_src_kube -%} -{%- endif -%} - - - - -{% for cluster in clusters %} - {% if loop.index0>0 and loop.index0%pagesize==0 %} - - {% endif %} -
- -

- Voici les informations permettant de se connecter à un - des environnements utilisés pour cette formation. - Vous pouvez vous connecter à {{ this_or_each }} machine - virtuelle avec n'importe quel client SSH. -

- -

- - - - - - - - -
cluster:
{{ clusterprefix }}
identifiant:
docker
mot de passe:
{{ docker_user_password }}
-

- -

- Adresse{{ plural }} IP : - - - {% for node in cluster %} - - {% endfor %} -
{{ clusterprefix }}{{ loop.index }}:{{ node }}
-

-

Le support de formation est à l'adresse suivante : -

{{ url }}
-

-
-{% endfor %} - - diff --git a/prepare-vms/templates/cards.html b/prepare-vms/templates/cards.html index dc977b65..1f58b8f6 100644 --- a/prepare-vms/templates/cards.html +++ b/prepare-vms/templates/cards.html @@ -1,29 +1,88 @@ {# Feel free to customize or override anything in there! #} -{%- set url = "http://container.training/" -%} -{%- set pagesize = 12 -%} -{%- if clustersize == 1 -%} - {%- set workshop_name = "Docker workshop" -%} - {%- set cluster_or_machine = "machine" -%} - {%- set this_or_each = "this" -%} - {%- set machine_is_or_machines_are = "machine is" -%} - {%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%} -{%- else -%} - {%- set workshop_name = "orchestration workshop" -%} - {%- set cluster_or_machine = "cluster" -%} - {%- set this_or_each = "each" -%} - {%- set machine_is_or_machines_are = "machines are" -%} - {%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%} - {%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%} - {%- set image_src = image_src_swarm -%} + +{%- set url = "http://FIXME.container.training/" -%} +{%- set pagesize = 9 -%} +{%- set lang = "en" -%} +{%- set event = "training session" -%} +{%- set backside = False -%} +{%- set image = "kube" -%} +{%- set clusternumber = 100 -%} + +{%- set image_src = { + "docker": "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png", + "swarm": "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png", + "kube": "https://avatars1.githubusercontent.com/u/13629408", + "enix": "https://enix.io/static/img/logos/logo-domain-cropped.png", + }[image] -%} +{%- if lang == "en" and clustersize == 1 -%} + {%- set intro -%} + Here is the connection information to your very own + machine for this {{ event }}. + You can connect to this VM with any SSH client. + {%- endset -%} + {%- set listhead -%} + Your machine is: + {%- endset -%} +{%- endif -%} +{%- if lang == "en" and clustersize != 1 -%} + {%- set intro -%} + Here is the connection information to your very own + cluster for this {{ event }}. + You can connect to each VM with any SSH client. + {%- endset -%} + {%- set listhead -%} + Your machines are: + {%- endset -%} +{%- endif -%} +{%- if lang == "fr" and clustersize == 1 -%} + {%- set intro -%} + Voici les informations permettant de se connecter à votre + machine pour cette formation. + Vous pouvez vous connecter à cette machine virtuelle + avec n'importe quel client SSH. + {%- endset -%} + {%- set listhead -%} + Adresse IP: + {%- endset -%} +{%- endif -%} +{%- if lang == "en" and clusterprefix != "node" -%} + {%- set intro -%} + Here is the connection information for the + {{ clusterprefix }} environment. + {%- endset -%} +{%- endif -%} +{%- if lang == "fr" and clustersize != 1 -%} + {%- set intro -%} + Voici les informations permettant de se connecter à votre + cluster pour cette formation. + Vous pouvez vous connecter à chaque machine virtuelle + avec n'importe quel client SSH. + {%- endset -%} + {%- set listhead -%} + Adresses IP: + {%- endset -%} +{%- endif -%} +{%- if lang == "en" -%} + {%- set slides_are_at -%} + You can find the slides at: + {%- endset -%} +{%- endif -%} +{%- if lang == "fr" -%} + {%- set slides_are_at -%} + Le support de formation est à l'adresse suivante : + {%- endset -%} {%- endif -%} {% for cluster in clusters %} - {% if loop.index0>0 and loop.index0%pagesize==0 %} - - {% endif %}
- -

- Here is the connection information to your very own - {{ cluster_or_machine }} for this {{ workshop_name }}. - You can connect to {{ this_or_each }} VM with any SSH client. -

+

{{ intro }}

+ {% if clusternumber != None %} + + + {% endif %} @@ -90,17 +175,44 @@ img {

- Your {{ machine_is_or_machines_are }}: + {{ listhead }}

cluster:
{{ clusternumber + loop.index }}
login:
docker
password:
{% for node in cluster %} - + + + + {% endfor %}
node{{ loop.index }}:{{ node }}
{{ clusterprefix }}{{ loop.index }}:{{ node }}

-

You can find the slides at: + +

+ {{ slides_are_at }}

{{ url }}

+ {% if loop.index%pagesize==0 or loop.last %} + + {% if backside %} + {% for x in range(pagesize) %} +
+
+

You got this at the workshop + "Getting Started With Kubernetes and Container Orchestration" + during QCON London (March 2019).

+

If you liked that workshop, + I can train your team or organization + on Docker, container, and Kubernetes, + with curriculums of 1 to 5 days. +

+

Interested? Contact me at:

+

jerome.petazzoni@gmail.com

+

Thank you!

+
+ {% endfor %} + + {% endif %} + {% endif %} {% endfor %} diff --git a/prepare-vms/templates/enix.html b/prepare-vms/templates/enix.html deleted file mode 100644 index e84c0d7c..00000000 --- a/prepare-vms/templates/enix.html +++ /dev/null @@ -1,121 +0,0 @@ -{# Feel free to customize or override anything in there! #} -{%- set url = "http://FIXME.container.training" -%} -{%- set pagesize = 9 -%} -{%- if clustersize == 1 -%} - {%- set workshop_name = "Docker workshop" -%} - {%- set cluster_or_machine = "machine virtuelle" -%} - {%- set this_or_each = "cette" -%} - {%- set plural = "" -%} - {%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%} -{%- else -%} - {%- set workshop_name = "Kubernetes workshop" -%} - {%- set cluster_or_machine = "cluster" -%} - {%- set this_or_each = "chaque" -%} - {%- set plural = "s" -%} - {%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%} - {%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%} - {%- set image_src = image_src_kube -%} -{%- endif -%} - - - - -{% for cluster in clusters %} - {% if loop.index0>0 and loop.index0%pagesize==0 %} - - {% endif %} -
- -

- Voici les informations permettant de se connecter à votre - {{ cluster_or_machine }} pour cette formation. - Vous pouvez vous connecter à {{ this_or_each }} machine virtuelle - avec n'importe quel client SSH. -

-

- - - - - - -
identifiant:
docker
mot de passe:
{{ docker_user_password }}
- -

-

- Adresse{{ plural }} IP : - - - {% for node in cluster %} - - {% endfor %} -
node{{ loop.index }}:{{ node }}
-

-

Le support de formation est à l'adresse suivante : -

{{ url }}
-

-
-{% endfor %} - - diff --git a/prepare-vms/templates/jerome.html b/prepare-vms/templates/jerome.html deleted file mode 100644 index 9f0263b8..00000000 --- a/prepare-vms/templates/jerome.html +++ /dev/null @@ -1,134 +0,0 @@ -{# Feel free to customize or override anything in there! #} -{%- set url = "http://qconuk2019.container.training/" -%} -{%- set pagesize = 9 -%} -{%- if clustersize == 1 -%} - {%- set workshop_name = "Docker workshop" -%} - {%- set cluster_or_machine = "machine" -%} - {%- set this_or_each = "this" -%} - {%- set machine_is_or_machines_are = "machine is" -%} - {%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%} -{%- else -%} - {%- set workshop_name = "Kubernetes workshop" -%} - {%- set cluster_or_machine = "cluster" -%} - {%- set this_or_each = "each" -%} - {%- set machine_is_or_machines_are = "machines are" -%} - {%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%} - {%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%} - {%- set image_src = image_src_kube -%} -{%- endif -%} - - - - -{% for cluster in clusters %} -
- -

- Here is the connection information to your very own - {{ cluster_or_machine }} for this {{ workshop_name }}. - You can connect to {{ this_or_each }} VM with any SSH client. -

-

- - - - - - -
login:
docker
password:
{{ docker_user_password }}
- -

-

- Your {{ machine_is_or_machines_are }}: - - {% for node in cluster %} - - {% endfor %} -
node{{ loop.index }}:{{ node }}
-

-

You can find the slides at: -

{{ url }}
-

-
- {% if loop.index%pagesize==0 or loop.last %} - - {% for x in range(pagesize) %} -
-
-

You got this at the workshop - "Getting Started With Kubernetes and Container Orchestration" - during QCON London (March 2019).

-

If you liked that workshop, - I can train your team or organization - on Docker, container, and Kubernetes, - with curriculums of 1 to 5 days. -

-

Interested? Contact me at:

-

jerome.petazzoni@gmail.com

-

Thank you!

-
- {% endfor %} - - {% endif %} -{% endfor %} - - diff --git a/prepare-vms/templates/kube101.html b/prepare-vms/templates/kube101.html deleted file mode 100644 index 1a937818..00000000 --- a/prepare-vms/templates/kube101.html +++ /dev/null @@ -1,106 +0,0 @@ -{# Feel free to customize or override anything in there! #} -{%- set url = "http://container.training/" -%} -{%- set pagesize = 12 -%} -{%- if clustersize == 1 -%} - {%- set workshop_name = "Docker workshop" -%} - {%- set cluster_or_machine = "machine" -%} - {%- set this_or_each = "this" -%} - {%- set machine_is_or_machines_are = "machine is" -%} - {%- set image_src = "https://s3-us-west-2.amazonaws.com/www.breadware.com/integrations/docker.png" -%} -{%- else -%} - {%- set workshop_name = "Kubernetes workshop" -%} - {%- set cluster_or_machine = "cluster" -%} - {%- set this_or_each = "each" -%} - {%- set machine_is_or_machines_are = "machines are" -%} - {%- set image_src_swarm = "https://cdn.wp.nginx.com/wp-content/uploads/2016/07/docker-swarm-hero2.png" -%} - {%- set image_src_kube = "https://avatars1.githubusercontent.com/u/13629408" -%} - {%- set image_src = image_src_kube -%} -{%- endif -%} - - - - -{% for cluster in clusters %} - {% if loop.index0>0 and loop.index0%pagesize==0 %} - - {% endif %} -
- -

- Here is the connection information to your very own - {{ cluster_or_machine }} for this {{ workshop_name }}. - You can connect to {{ this_or_each }} VM with any SSH client. -

-

- - - - - - -
login:
docker
password:
{{ docker_user_password }}
- -

-

- Your {{ machine_is_or_machines_are }}: - - {% for node in cluster %} - - {% endfor %} -
node{{ loop.index }}:{{ node }}
-

-

You can find the slides at: -

{{ url }}
-

-
-{% endfor %} - - diff --git a/slides/containers/Container_Network_Model.md b/slides/containers/Container_Network_Model.md index fd77c3bd..87cf044f 100644 --- a/slides/containers/Container_Network_Model.md +++ b/slides/containers/Container_Network_Model.md @@ -474,7 +474,7 @@ When creating a network, extra options can be provided. * `--ip-range` (in CIDR notation) indicates the subnet to allocate from. -* `--aux-address` allows to specify a list of reserved addresses (which won't be allocated to containers). +* `--aux-address` allows specifying a list of reserved addresses (which won't be allocated to containers). --- @@ -556,7 +556,7 @@ General idea: * So far, we have specified which network to use when starting the container. -* The Docker Engine also allows to connect and disconnect while the container runs. +* The Docker Engine also allows connecting and disconnecting while the container is running. * This feature is exposed through the Docker API, and through two Docker CLI commands: diff --git a/slides/containers/Namespaces_Cgroups.md b/slides/containers/Namespaces_Cgroups.md index 46d1ac06..09b90561 100644 --- a/slides/containers/Namespaces_Cgroups.md +++ b/slides/containers/Namespaces_Cgroups.md @@ -86,13 +86,13 @@ class: extra-details, deep-dive - the `unshare()` system call. -- The Linux tool `unshare` allows to do that from a shell. +- The Linux tool `unshare` allows doing that from a shell. - A new process can re-use none / all / some of the namespaces of its parent. - It is possible to "enter" a namespace with the `setns()` system call. -- The Linux tool `nsenter` allows to do that from a shell. +- The Linux tool `nsenter` allows doing that from a shell. --- @@ -138,11 +138,11 @@ class: extra-details, deep-dive - gethostname / sethostname -- Allows to set a custom hostname for a container. +- Allows setting a custom hostname for a container. - That's (mostly) it! -- Also allows to set the NIS domain. +- Also allows setting the NIS domain. (If you don't know what a NIS domain is, you don't have to worry about it!) @@ -392,13 +392,13 @@ class: extra-details - Processes can have their own root fs (à la chroot). -- Processes can also have "private" mounts. This allows to: +- Processes can also have "private" mounts. This allows: - - isolate `/tmp` (per user, per service...) + - isolating `/tmp` (per user, per service...) - - mask `/proc`, `/sys` (for processes that don't need them) + - masking `/proc`, `/sys` (for processes that don't need them) - - mount remote filesystems or sensitive data, + - mounting remote filesystems or sensitive data,
but make it visible only for allowed processes - Mounts can be totally private, or shared. @@ -570,7 +570,7 @@ Check `man 2 unshare` and `man pid_namespaces` if you want more details. ## User namespace -- Allows to map UID/GID; e.g.: +- Allows mapping UID/GID; e.g.: - UID 0→1999 in container C1 is mapped to UID 10000→11999 on host - UID 0→1999 in container C2 is mapped to UID 12000→13999 on host @@ -947,7 +947,7 @@ Killed (i.e., "this group of process used X seconds of CPU0 and Y seconds of CPU1".) -- Allows to set relative weights used by the scheduler. +- Allows setting relative weights used by the scheduler. --- @@ -1101,9 +1101,9 @@ See `man capabilities` for the full list and details. - Original seccomp only allows `read()`, `write()`, `exit()`, `sigreturn()`. -- The seccomp-bpf extension allows to specify custom filters with BPF rules. +- The seccomp-bpf extension allows specifying custom filters with BPF rules. -- This allows to filter by syscall, and by parameter. +- This allows filtering by syscall, and by parameter. - BPF code can perform arbitrarily complex checks, quickly, and safely. diff --git a/slides/containers/Resource_Limits.md b/slides/containers/Resource_Limits.md index c74d2ebe..bb04e9de 100644 --- a/slides/containers/Resource_Limits.md +++ b/slides/containers/Resource_Limits.md @@ -72,7 +72,7 @@ - For memory usage, the mechanism is part of the *cgroup* subsystem. -- This subsystem allows to limit the memory for a process or a group of processes. +- This subsystem allows limiting the memory for a process or a group of processes. - A container engine leverages these mechanisms to limit memory for a container. diff --git a/slides/index.yaml b/slides/index.yaml index e7721610..668fdbe2 100644 --- a/slides/index.yaml +++ b/slides/index.yaml @@ -31,6 +31,7 @@ title: Kubernetes for administrators and operators speaker: jpetazzo attend: https://conferences.oreilly.com/velocity/vl-ca/public/schedule/detail/75313 + slides: https://kadm-2019-06.container.training/ - date: 2019-05-01 country: us diff --git a/slides/k8s/architecture.md b/slides/k8s/architecture.md index e3bf8c86..705548ac 100644 --- a/slides/k8s/architecture.md +++ b/slides/k8s/architecture.md @@ -356,9 +356,9 @@ We demonstrated *update* and *watch* semantics. - we create a Deployment object - - the Deployment controller notices it, creates a ReplicaSet + - the Deployment controller notices it, and creates a ReplicaSet - - the ReplicaSet controller notices it, creates a Pod + - the ReplicaSet controller notices the ReplicaSet, and creates a Pod --- diff --git a/slides/k8s/authn-authz.md b/slides/k8s/authn-authz.md index 30c77d3c..a2c0c431 100644 --- a/slides/k8s/authn-authz.md +++ b/slides/k8s/authn-authz.md @@ -22,7 +22,7 @@ - When the API server receives a request, it tries to authenticate it - (it examines headers, certificates ... anything available) + (it examines headers, certificates... anything available) - Many authentication methods are available and can be used simultaneously @@ -34,7 +34,7 @@ - the user ID - a list of groups -- The API server doesn't interpret these; it'll be the job of *authorizers* +- The API server doesn't interpret these; that'll be the job of *authorizers* --- @@ -50,7 +50,7 @@ - [HTTP basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication) - (carrying user and password in a HTTP header) + (carrying user and password in an HTTP header) - Authentication proxy @@ -88,7 +88,7 @@ (i.e. they are not stored in etcd or anywhere else) -- Users can be created (and given membership to groups) independently of the API +- Users can be created (and added to groups) independently of the API - The Kubernetes API can be set up to use your custom CA to validate client certs @@ -193,7 +193,7 @@ class: extra-details (the kind that you can view with `kubectl get secrets`) -- Service accounts are generally used to grant permissions to applications, services ... +- Service accounts are generally used to grant permissions to applications, services... (as opposed to humans) @@ -217,7 +217,7 @@ class: extra-details .exercise[ -- The resource name is `serviceaccount` or `sa` in short: +- The resource name is `serviceaccount` or `sa` for short: ```bash kubectl get sa ``` @@ -309,7 +309,7 @@ class: extra-details - The API "sees" us as a different user -- But neither user has any right, so we can't do nothin' +- But neither user has any rights, so we can't do nothin' - Let's change that! @@ -339,9 +339,9 @@ class: extra-details - A rule is a combination of: - - [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb) like create, get, list, update, delete ... + - [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb) like create, get, list, update, delete... - - resources (as in "API resource", like pods, nodes, services ...) + - resources (as in "API resource," like pods, nodes, services...) - resource names (to specify e.g. one specific pod instead of all pods) @@ -375,13 +375,13 @@ class: extra-details - We can also define API resources ClusterRole and ClusterRoleBinding -- These are a superset, allowing to: +- These are a superset, allowing us to: - specify actions on cluster-wide objects (like nodes) - operate across all namespaces -- We can create Role and RoleBinding resources within a namespaces +- We can create Role and RoleBinding resources within a namespace - ClusterRole and ClusterRoleBinding resources are global @@ -389,13 +389,13 @@ class: extra-details ## Pods and service accounts -- A pod can be associated to a service account +- A pod can be associated with a service account - - by default, it is associated to the `default` service account + - by default, it is associated with the `default` service account - - as we've seen earlier, this service account has no permission anyway + - as we saw earlier, this service account has no permissions anyway -- The associated token is exposed into the pod's filesystem +- The associated token is exposed to the pod's filesystem (in `/var/run/secrets/kubernetes.io/serviceaccount/token`) @@ -460,7 +460,7 @@ class: extra-details ] -It's important to note a couple of details in these flags ... +It's important to note a couple of details in these flags... --- @@ -493,13 +493,13 @@ It's important to note a couple of details in these flags ... - again, the command would have worked fine (no error) - - ... but our API requests would have been denied later + - ...but our API requests would have been denied later - What's about the `default:` prefix? - that's the namespace of the service account - - yes, it could be inferred from context, but ... `kubectl` requires it + - yes, it could be inferred from context, but... `kubectl` requires it --- @@ -590,7 +590,7 @@ class: extra-details *In many situations, these roles will be all you need.* -*You can also customize them if needed!* +*You can also customize them!* --- @@ -652,7 +652,7 @@ class: extra-details kubectl describe clusterrolebinding cluster-admin ``` -- This binding associates `system:masters` to the cluster role `cluster-admin` +- This binding associates `system:masters` with the cluster role `cluster-admin` - And the `cluster-admin` is, basically, `root`: ```bash @@ -667,7 +667,7 @@ class: extra-details - For auditing purposes, sometimes we want to know who can perform an action -- Here is a proof-of-concept tool by Aqua Security, doing exactly that: +- There is a proof-of-concept tool by Aqua Security which does exactly that: https://github.com/aquasecurity/kubectl-who-can diff --git a/slides/k8s/cni.md b/slides/k8s/cni.md index 306c4302..3970f119 100644 --- a/slides/k8s/cni.md +++ b/slides/k8s/cni.md @@ -26,7 +26,7 @@ The reference plugins are available [here]. -Look into each plugin's directory for its documentation. +Look in each plugin's directory for its documentation. [here]: https://github.com/containernetworking/plugins/tree/master/plugins @@ -98,7 +98,7 @@ class: extra-details - CNI_NETNS: path to network namespace file - - CNI_IFNAME: how the network interface should be named + - CNI_IFNAME: what the network interface should be named - The network configuration must be provided to the plugin on stdin @@ -188,12 +188,16 @@ class: extra-details - ... But this time, the controller manager will allocate `podCIDR` subnets -- We will start kube-router with a DaemonSet + (so that we don't have to manually assign subnets to individual nodes) -- This DaemonSet will start one instance of kube-router on each node +- We will create a DaemonSet for kube-router + +- We will join nodes to the cluster + +- The DaemonSet will automatically start a kube-router pod on each node --- - + ## Logging into the new cluster .exercise[ @@ -221,7 +225,7 @@ class: extra-details - It is similar to the one we used with the `kubenet` cluster - The API server is started with `--allow-privileged` - + (because we will start kube-router in privileged pods) - The controller manager is started with extra flags too: @@ -254,7 +258,7 @@ class: extra-details --- -## The kube-router DaemonSet +## The kube-router DaemonSet - In the same directory, there is a `kuberouter.yaml` file @@ -300,12 +304,10 @@ Note: the DaemonSet won't create any pods (yet) since there are no nodes (yet). - Generate the kubeconfig file (replacing `X.X.X.X` with the address of `kuberouter1`): ```bash - kubectl --kubeconfig ~/kubeconfig config \ - set-cluster kubenet --server http://`X.X.X.X`:8080 - kubectl --kubeconfig ~/kubeconfig config \ - set-context kubenet --cluster kubenet - kubectl --kubeconfig ~/kubeconfig config\ - use-context kubenet + kubectl config set-cluster cni --server http://`X.X.X.X`:8080 + kubectl config set-context cni --cluster cni + kubectl config use-context cni + cp ~/.kube/config ~/kubeconfig ``` ] @@ -487,8 +489,8 @@ What does that mean? - First, get the container ID, with `docker ps` or like this: ```bash - CID=$(docker ps - --filter label=io.kubernetes.pod.namespace=kube-system + CID=$(docker ps -q \ + --filter label=io.kubernetes.pod.namespace=kube-system \ --filter label=io.kubernetes.container.name=kube-router) ``` @@ -599,13 +601,13 @@ done ## Updating kube-router configuration -- We need to add two command-line flags to the kube-router process +- We need to pass two command-line flags to the kube-router process .exercise[ - Edit the `kuberouter.yaml` file -- Add the following flags to the kube-router arguments,: +- Add the following flags to the kube-router arguments: ``` - "--peer-router-ips=`X.X.X.X`" - "--peer-router-asns=64512" diff --git a/slides/k8s/concepts-k8s.md b/slides/k8s/concepts-k8s.md index 32e241bb..0e27a464 100644 --- a/slides/k8s/concepts-k8s.md +++ b/slides/k8s/concepts-k8s.md @@ -177,7 +177,7 @@ class: extra-details - In that case, there is no "master node" -*For this reason, it is more accurate to say "control plane" rather than "master".* +*For this reason, it is more accurate to say "control plane" rather than "master."* --- diff --git a/slides/k8s/configuration.md b/slides/k8s/configuration.md index d1e57a6a..47b23ca7 100644 --- a/slides/k8s/configuration.md +++ b/slides/k8s/configuration.md @@ -22,7 +22,7 @@ - There are many ways to pass configuration to code running in a container: - - baking it in a custom image + - baking it into a custom image - command-line arguments @@ -125,7 +125,7 @@ - We can also use a mechanism called the *downward API* -- The downward API allows to expose pod or container information +- The downward API allows exposing pod or container information - either through special files (we won't show that for now) @@ -436,7 +436,7 @@ We should see connections served by Google, and others served by IBM. - We are going to store the port number in a configmap -- Then we will expose that configmap to a container environment variable +- Then we will expose that configmap as a container environment variable --- diff --git a/slides/k8s/csr-api.md b/slides/k8s/csr-api.md index aec66fdc..2673c4a1 100644 --- a/slides/k8s/csr-api.md +++ b/slides/k8s/csr-api.md @@ -46,7 +46,7 @@ (and vice versa) -- If I use someone's public key to encrypt / decrypt their messages, +- If I use someone's public key to encrypt/decrypt their messages,
I can be certain that I am talking to them / they are talking to me @@ -58,7 +58,7 @@ This is what I do if I want to obtain a certificate. -1. Create public and private key. +1. Create public and private keys. 2. Create a Certificate Signing Request (CSR). @@ -84,7 +84,7 @@ The CA (or anyone else) never needs to know my private key. (= upload a CSR to the Kubernetes API) -- Then, using the Kubernetes API, we can approve / deny the request +- Then, using the Kubernetes API, we can approve/deny the request - If we approve the request, the Kubernetes API generates a certificate @@ -122,7 +122,7 @@ The CA (or anyone else) never needs to know my private key. - Users can then retrieve their certificate from their CSR object -- ... And use that certificate for subsequent interactions +- ...And use that certificate for subsequent interactions --- @@ -387,7 +387,7 @@ The command above generates: ## What's missing? -We shown, step by step, a method to issue short-lived certificates for users. +We have just shown, step by step, a method to issue short-lived certificates for users. To be usable in real environments, we would need to add: @@ -417,7 +417,7 @@ To be usable in real environments, we would need to add: - This provides enhanced security: - - the long-term credentials can use long passphrases, 2FA, HSM ... + - the long-term credentials can use long passphrases, 2FA, HSM... - the short-term credentials are more convenient to use diff --git a/slides/k8s/dmuc.md b/slides/k8s/dmuc.md index a00d940c..d70972aa 100644 --- a/slides/k8s/dmuc.md +++ b/slides/k8s/dmuc.md @@ -584,7 +584,7 @@ Our pod is still `Pending`. 🤔 Which is normal: it needs to be *scheduled*. -(i.e., something needs to decide on which node it should go.) +(i.e., something needs to decide which node it should go on.) --- @@ -658,7 +658,7 @@ class: extra-details - This is actually how the scheduler works! -- It watches pods, takes scheduling decisions, creates Binding objects +- It watches pods, makes scheduling decisions, and creates Binding objects --- @@ -686,7 +686,7 @@ We should see the `Welcome to nginx!` page. ## Exposing our Deployment -- We can now create a Service associated to this Deployment +- We can now create a Service associated with this Deployment .exercise[ @@ -711,11 +711,11 @@ This won't work. We need kube-proxy to enable internal communication. ## Starting kube-proxy -- kube-proxy also needs to connect to API server +- kube-proxy also needs to connect to the API server - It can work with the `--master` flag - (even though that will be deprecated in the future) + (although that will be deprecated in the future) .exercise[ @@ -832,6 +832,6 @@ class: extra-details - By default, the API server expects to be running directly on the nodes - (it could be as a bare process, or in a container/pod using host network) + (it could be as a bare process, or in a container/pod using the host network) - ... And it expects to be listening on port 6443 with TLS diff --git a/slides/k8s/healthchecks.md b/slides/k8s/healthchecks.md index 2563da68..a72fedbf 100644 --- a/slides/k8s/healthchecks.md +++ b/slides/k8s/healthchecks.md @@ -108,7 +108,7 @@ (as opposed to merely started) -- Containers in a broken state gets killed and restarted +- Containers in a broken state get killed and restarted (instead of serving errors or timeouts) diff --git a/slides/k8s/helm.md b/slides/k8s/helm.md index 004abb58..5c895daa 100644 --- a/slides/k8s/helm.md +++ b/slides/k8s/helm.md @@ -158,7 +158,7 @@ Where do these `--set` options come from? ] -The chart's metadata includes an URL to the project's home page. +The chart's metadata includes a URL to the project's home page. (Sometimes it conveniently points to the documentation for the chart.) diff --git a/slides/k8s/horizontal-pod-autoscaler.md b/slides/k8s/horizontal-pod-autoscaler.md index 38e363f6..6e660900 100644 --- a/slides/k8s/horizontal-pod-autoscaler.md +++ b/slides/k8s/horizontal-pod-autoscaler.md @@ -34,7 +34,7 @@ `TargetNumOfPods = ceil(sum(CurrentPodsCPUUtilization) / Target)` -- It scales up/down the related object to this target number of pods +- It scales the related object up/down to this target number of pods --- diff --git a/slides/k8s/ingress.md b/slides/k8s/ingress.md index 3188de96..9ccfdd8c 100644 --- a/slides/k8s/ingress.md +++ b/slides/k8s/ingress.md @@ -88,7 +88,7 @@ - the control loop watches over ingress resources, and configures the LB accordingly -- Step 2: setup DNS +- Step 2: set up DNS - associate DNS entries with the load balancer address @@ -126,7 +126,7 @@ - We could use pods specifying `hostPort: 80` - ... but with most CNI plugins, this [doesn't work or require additional setup](https://github.com/kubernetes/kubernetes/issues/23920) + ... but with most CNI plugins, this [doesn't work or requires additional setup](https://github.com/kubernetes/kubernetes/issues/23920) - We could use a `NodePort` service @@ -142,7 +142,7 @@ (sometimes called sandbox or network sandbox) -- An IP address is associated to the pod +- An IP address is assigned to the pod - This IP address is routed/connected to the cluster network @@ -239,7 +239,7 @@ class: extra-details - an error condition on the node
- (for instance: "disk full", do not start new pods here!) + (for instance: "disk full," do not start new pods here!) - The `effect` can be: @@ -501,11 +501,11 @@ spec: (as long as it has access to the cluster subnet) -- This allows to use external (hardware, physical machines...) load balancers +- This allows the use of external (hardware, physical machines...) load balancers - Annotations can encode special features - (rate-limiting, A/B testing, session stickiness, etc.) + (rate-limiting, A/B testing, session stickiness, etc.) --- diff --git a/slides/k8s/kubectlget.md b/slides/k8s/kubectlget.md index 66a1fac1..44566b26 100644 --- a/slides/k8s/kubectlget.md +++ b/slides/k8s/kubectlget.md @@ -132,7 +132,7 @@ class: extra-details - short (e.g. `no`, `svc`, `deploy`) -- Some resources do not have a short names +- Some resources do not have a short name - `Endpoints` only have a plural form @@ -466,4 +466,4 @@ class: extra-details - For more details, see [KEP-0009] or the [node controller documentation] [KEP-0009]: https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/0009-node-heartbeat.md -[node controller documentation]: https://kubernetes.io/docs/concepts/architecture/nodes/#node-controller \ No newline at end of file +[node controller documentation]: https://kubernetes.io/docs/concepts/architecture/nodes/#node-controller diff --git a/slides/k8s/kubectlproxy.md b/slides/k8s/kubectlproxy.md index 749f8c0e..fa7f7505 100644 --- a/slides/k8s/kubectlproxy.md +++ b/slides/k8s/kubectlproxy.md @@ -77,9 +77,9 @@ If we wanted to talk to the API, we would need to: - This is a great tool to learn and experiment with the Kubernetes API -- ... And for serious usages as well (suitable for one-shot scripts) +- ... And for serious uses as well (suitable for one-shot scripts) -- For unattended use, it is better to create a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) +- For unattended use, it's better to create a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) --- diff --git a/slides/k8s/kubenet.md b/slides/k8s/kubenet.md index 0bb7c624..bc470475 100644 --- a/slides/k8s/kubenet.md +++ b/slides/k8s/kubenet.md @@ -54,7 +54,7 @@ (15 are listed in the Kubernetes documentation) -- Pods have level 3 (IP) connectivity, but *services* are level 4 +- Pods have level 3 (IP) connectivity, but *services* are level 4 (TCP or UDP) (Services map to a single UDP or TCP port; no port ranges or arbitrary IP packets) diff --git a/slides/k8s/kubercoins.md b/slides/k8s/kubercoins.md new file mode 100644 index 00000000..3220f5fa --- /dev/null +++ b/slides/k8s/kubercoins.md @@ -0,0 +1,244 @@ +# Deploying a sample application + +- We will connect to our new Kubernetes cluster + +- We will deploy a sample application, "DockerCoins" + +- That app features multiple micro-services and a web UI + +--- + +## Connecting to our Kubernetes cluster + +- Our cluster has multiple nodes named `node1`, `node2`, etc. + +- We will do everything from `node1` + +- We have SSH access to the other nodes, but won't need it + + (but we can use it for debugging, troubleshooting, etc.) + +.exercise[ + +- Log into `node1` + +- Check that all nodes are `Ready`: + ```bash + kubectl get nodes + ``` + +] + +--- + +## Cloning some repos + +- We will need two repositories: + + - the first one has the "DockerCoins" demo app + + - the second one has 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: + ```bash + git clone https://@@GITREPO@@ + ``` + +] + +--- + +## Running the application + +Without further ado, let's start this application! + +.exercise[ + +- Apply all the manifests from the kubercoins repository: + ```bash + kubectl apply -f kubercoins/ + ``` + +] + +--- + +## What's this application? + +-- + +- It is a DockerCoin miner! .emoji[💰🐳📦🚢] + +-- + +- No, you can't buy coffee with DockerCoins + +-- + +- How DockerCoins works: + + - generate a few random bytes + + - hash these bytes + + - increment a counter (to keep track of speed) + + - repeat forever! + +-- + +- DockerCoins is *not* a cryptocurrency + + (the only common points are "randomness", "hashing", and "coins" in the name) + +--- + +## DockerCoins in the microservices era + +- DockerCoins is made of 5 services: + + - `rng` = web service generating random bytes + + - `hasher` = web service computing hash of POSTed data + + - `worker` = background process calling `rng` and `hasher` + + - `webui` = web interface to watch progress + + - `redis` = data store (holds a counter updated by `worker`) + +- These 5 services are visible in the application's Compose file, + [docker-compose.yml]( + https://@@GITREPO@@/blob/master/dockercoins/docker-compose.yml) + +--- + +## How DockerCoins works + +- `worker` invokes web service `rng` to generate random bytes + +- `worker` invokes web service `hasher` to hash these bytes + +- `worker` does this in an infinite loop + +- every second, `worker` updates `redis` to indicate how many loops were done + +- `webui` queries `redis`, and computes and exposes "hashing speed" in our browser + +*(See diagram on next slide!)* + +--- + +class: pic + +![Diagram showing the 5 containers of the applications](images/dockercoins-diagram.svg) + +--- + +## Service discovery in container-land + +How does each service find out the address of the other ones? + +-- + +- We do not hard-code IP addresses in the code + +- We do not hard-code FQDNs in the code, either + +- We just connect to a service name, and container-magic does the rest + + (And by container-magic, we mean "a crafty, dynamic, embedded DNS server") + +--- + +## Example in `worker/worker.py` + +```python +redis = Redis("`redis`") + + +def get_random_bytes(): + r = requests.get("http://`rng`/32") + return r.content + + +def hash_bytes(data): + r = requests.post("http://`hasher`/", + data=data, + headers={"Content-Type": "application/octet-stream"}) +``` + +(Full source code available [here]( +https://@@GITREPO@@/blob/8279a3bce9398f7c1a53bdd95187c53eda4e6435/dockercoins/worker/worker.py#L17 +)) + +--- + +## Show me the code! + +- You can check the GitHub repository with all the materials of this workshop: +
https://@@GITREPO@@ + +- The application is in the [dockercoins]( + https://@@GITREPO@@/tree/master/dockercoins) + subdirectory + +- The Compose file ([docker-compose.yml]( + https://@@GITREPO@@/blob/master/dockercoins/docker-compose.yml)) + lists all 5 services + +- `redis` is using an official image from the Docker Hub + +- `hasher`, `rng`, `worker`, `webui` are each built from a Dockerfile + +- Each service's Dockerfile and source code is in its own directory + + (`hasher` is in the [hasher](https://@@GITREPO@@/blob/master/dockercoins/hasher/) directory, + `rng` is in the [rng](https://@@GITREPO@@/blob/master/dockercoins/rng/) + directory, etc.) + +--- + +## Our application at work + +- We can check the logs of our application's pods + +.exercise[ + +- Check the logs of the various components: + ```bash + kubectl logs deploy/worker + kubectl logs deploy/hasher + ``` + +] + +--- + +## Connecting to the web UI + +- "Logs are exciting and fun!" (No-one, ever) + +- The `webui` container exposes a web dashboard; let's view it + +.exercise[ + +- Check the NodePort allocated to the web UI: + ```bash + kubectl get svc webui + ``` + +- Open that in a web browser + +] + +A drawing area should show up, and after a few seconds, a blue +graph will appear. diff --git a/slides/k8s/kustomize.md b/slides/k8s/kustomize.md index 60641b4a..664f82f3 100644 --- a/slides/k8s/kustomize.md +++ b/slides/k8s/kustomize.md @@ -70,7 +70,7 @@ - We need to run `ship init` in a new directory -- `ship init` requires an URL to a remote repository containing Kubernetes YAML +- `ship init` requires a URL to a remote repository containing Kubernetes YAML - It will clone that repository and start a web UI diff --git a/slides/k8s/localkubeconfig.md b/slides/k8s/localkubeconfig.md index e95977dc..ff3c84b0 100644 --- a/slides/k8s/localkubeconfig.md +++ b/slides/k8s/localkubeconfig.md @@ -75,9 +75,9 @@ Platform:"linux/amd64"} --- -## Moving away the existing `~/.kube/config` +## Preserving the existing `~/.kube/config` -- If you already have a `~/.kube/config` file, move it away +- If you already have a `~/.kube/config` file, rename it (we are going to overwrite it in the following slides!) @@ -192,4 +192,4 @@ class: extra-details ] -We can now utilize the cluster exactly as we did before, ignoring that it's remote. +We can now utilize the cluster exactly as we did before, except that it's remote. diff --git a/slides/k8s/logs-centralized.md b/slides/k8s/logs-centralized.md index 6cdddda8..07af0ce3 100644 --- a/slides/k8s/logs-centralized.md +++ b/slides/k8s/logs-centralized.md @@ -73,12 +73,12 @@ and a few roles and role bindings (to give fluentd the required permissions). - Fluentd runs on each node (thanks to a daemon set) -- It binds-mounts `/var/log/containers` from the host (to access these files) +- It bind-mounts `/var/log/containers` from the host (to access these files) - It continuously scans this directory for new files; reads them; parses them - Each log line becomes a JSON object, fully annotated with extra information: -
container id, pod name, Kubernetes labels ... +
container id, pod name, Kubernetes labels... - These JSON objects are stored in ElasticSearch diff --git a/slides/k8s/logs-cli.md b/slides/k8s/logs-cli.md index aa7ffdc2..fe12f466 100644 --- a/slides/k8s/logs-cli.md +++ b/slides/k8s/logs-cli.md @@ -1,6 +1,6 @@ # Accessing logs from the CLI -- The `kubectl logs` commands has limitations: +- The `kubectl logs` command has limitations: - it cannot stream logs from multiple pods at a time @@ -12,7 +12,7 @@ ## Doing it manually -- We *could* (if we were so inclined), write a program or script that would: +- We *could* (if we were so inclined) write a program or script that would: - take a selector as an argument @@ -72,11 +72,11 @@ Exactly what we need! ## Using Stern -- There are two ways to specify the pods for which we want to see the logs: +- There are two ways to specify the pods whose logs we want to see: - `-l` followed by a selector expression (like with many `kubectl` commands) - - with a "pod query", i.e. a regex used to match pod names + - with a "pod query," i.e. a regex used to match pod names - These two ways can be combined if necessary diff --git a/slides/k8s/multinode.md b/slides/k8s/multinode.md index 09c9801a..0efb7dc5 100644 --- a/slides/k8s/multinode.md +++ b/slides/k8s/multinode.md @@ -104,12 +104,10 @@ class: extra-details - Generate the `kubeconfig` file: ```bash - kubectl --kubeconfig ~/kubeconfig config \ - set-cluster kubenet --server http://`X.X.X.X`:8080 - kubectl --kubeconfig ~/kubeconfig config \ - set-context kubenet --cluster kubenet - kubectl --kubeconfig ~/kubeconfig config\ - use-context kubenet + kubectl config set-cluster kubenet --server http://`X.X.X.X`:8080 + kubectl config set-context kubenet --cluster kubenet + kubectl config use-context kubenet + cp ~/.kube/config ~/kubeconfig ``` ] diff --git a/slides/k8s/namespaces.md b/slides/k8s/namespaces.md index 13500990..51bbf774 100644 --- a/slides/k8s/namespaces.md +++ b/slides/k8s/namespaces.md @@ -26,7 +26,7 @@ - We cannot have two resources *of the same kind* with the same name - (but it's OK to have a `rng` service, a `rng` deployment, and a `rng` daemon set) + (but it's OK to have an `rng` service, an `rng` deployment, and an `rng` daemon set) -- diff --git a/slides/k8s/podsecuritypolicy.md b/slides/k8s/podsecuritypolicy.md index 90f542d1..fea1d100 100644 --- a/slides/k8s/podsecuritypolicy.md +++ b/slides/k8s/podsecuritypolicy.md @@ -8,12 +8,18 @@ - Then we will explain how to avoid this with PodSecurityPolicies -- We will illustrate this by creating a non-privileged user limited to a namespace +- We will enable PodSecurityPolicies on our cluster + +- We will create a couple of policies (restricted and permissive) + +- Finally we will see how to use them to improve security on our cluster --- ## Setting up a namespace +- For simplicity, let's work in a separate namespace + - Let's create a new namespace called "green" .exercise[ @@ -32,168 +38,9 @@ --- -## Using limited credentials - -- When a namespace is created, a `default` ServiceAccount is added - -- By default, this ServiceAccount doesn't have any access rights - -- We will use this ServiceAccount as our non-privileged user - -- We will obtain this ServiceAccount's token and add it to a context - -- Then we will give basic access rights to this ServiceAccount - ---- - -## Obtaining the ServiceAccount's token - -- The token is stored in a Secret - -- The Secret is listed in the ServiceAccount - -.exercise[ - -- Obtain the name of the Secret from the ServiceAccount:: - ```bash - SECRET=$(kubectl get sa default -o jsonpath={.secrets[0].name}) - ``` - -- Extract the token from the Secret object: - ```bash - TOKEN=$(kubectl get secrets $SECRET -o jsonpath={.data.token} - | base64 -d) - ``` - -] - ---- - -class: extra-details - -## Inspecting a Kubernetes token - -- Kubernetes tokens are JSON Web Tokens - - (as defined by [RFC 7519](https://tools.ietf.org/html/rfc7519)) - -- We can view their content (and even verify them) easily - -.exercise[ - -- Display the token that we obtained: - ```bash - echo $TOKEN - ``` - -- Copy paste the token in the verification form on https://jwt.io - -] - ---- - -## Authenticating using the ServiceAccount token - -- Let's create a new *context* accessing our cluster with that token - -.exercise[ - -- First, add the token credentials to our kubeconfig file: - ```bash - kubectl config set-credentials green --token=$TOKEN - ``` - -- Then, create a new context using these credentials: - ```bash - kubectl config set-context green --user=green --cluster=kubernetes - ``` - -- Check the results: - ```bash - kubectl config get-contexts - ``` - -] - ---- - -## Using the new context - -- Normally, this context doesn't let us access *anything* (yet) - -.exercise[ - -- Change to the new context with one of these two commands: - ```bash - kctx green - kubectl config use-context green - ``` - -- Also change to the green namespace in that context: - ```bash - kns green - ``` - -- Confirm that we don't have access to anything: - ```bash - kubectl get all - ``` - -] - ---- - -## Giving basic access rights - -- Let's bind the ClusterRole `edit` to our ServiceAccount - -- To allow access only to the namespace, we use a RoleBinding - - (instead of a ClusterRoleBinding, which would give global access) - -.exercise[ - -- Switch back to `cluster-admin`: - ```bash - kctx - - ``` - -- Create the Role Binding: - ```bash - kubectl create rolebinding green --clusterrole=edit --serviceaccount=green:default - ``` - -] - ---- - -## Verifying access rights - -- Let's switch back to the `green` context and check that we have rights - -.exercise[ - -- Switch back to `green`: - ```bash - kctx green - ``` - -- Check our permissions: - ```bash - kubectl get all - ``` - -] - -We should see an empty list. - -(Better than a series of permission errors!) - ---- - ## Creating a basic Deployment -- Just to demonstrate that everything works correctly, deploy NGINX +- Just to check that everything works correctly, deploy NGINX .exercise[ @@ -474,12 +321,65 @@ We can get hints at what's happening by looking at the ReplicaSet and Events. --- +## Check that we can create Pods again + +- We haven't bound the policy to any user yet + +- But `cluster-admin` can implicitly `use` all policies + +.exercise[ + +- Check that we can now create a Pod directly: + ```bash + kubectl run testpsp3 --image=nginx --restart=Never + ``` + +- Create a Deployment as well: + ```bash + kubectl run testpsp4 --image=nginx + ``` + +- Confirm that the Deployment is *not* creating any Pods: + ```bash + kubectl get all + ``` + +] + +--- + +## What's going on? + +- We can create Pods directly (thanks to our root-like permissions) + +- The Pods corresponding to a Deployment are created by the ReplicaSet controller + +- The ReplicaSet controller does *not* have root-like permissions + +- We need to either: + + - grant permissions to the ReplicaSet controller + + *or* + + - grant permissions to our Pods' ServiceAccount + +- The first option would allow *anyone* to create pods + +- The second option will allow us to scope the permissions better + +--- + ## Binding the restricted policy - Let's bind the role `psp:restricted` to ServiceAccount `green:default` (aka the default ServiceAccount in the green Namespace) +- This will allow Pod creation in the green Namespace + + (because these Pods will be using that ServiceAccount automatically) + .exercise[ - Create the following RoleBinding: @@ -495,18 +395,17 @@ We can get hints at what's happening by looking at the ReplicaSet and Events. ## Trying it out -- Let's switch to the `green` context, and try to create resources +- The Deployments that we created earlier will *eventually* recover + + (the ReplicaSet controller will retry to create Pods once in a while) + +- If we create a new Deployment now, it should work immediately .exercise[ -- Switch to the `green` context: - ```bash - kctx green - ``` - - Create a simple Deployment: ```bash - kubectl create deployment web --image=nginx + kubectl create deployment testpsp5 --image=nginx ``` - Look at the Pods that have been created: diff --git a/slides/k8s/prometheus.md b/slides/k8s/prometheus.md index b78b1884..68ef6ca1 100644 --- a/slides/k8s/prometheus.md +++ b/slides/k8s/prometheus.md @@ -340,7 +340,7 @@ container_cpu_usage_seconds_total - that it's the total used since the container creation -- Since it's a "total", it is an increasing quantity +- Since it's a "total," it is an increasing quantity (we need to compute the derivative if we want e.g. CPU % over time) @@ -495,7 +495,7 @@ class: extra-details ## Querying labels -- What if we want to get metrics for containers belong to pod tagged `worker`? +- What if we want to get metrics for containers belonging to a pod tagged `worker`? - The cAdvisor exporter does not give us Kubernetes labels diff --git a/slides/k8s/resource-limits.md b/slides/k8s/resource-limits.md index e641fe78..047f29af 100644 --- a/slides/k8s/resource-limits.md +++ b/slides/k8s/resource-limits.md @@ -392,7 +392,7 @@ These quotas will apply to the namespace where the ResourceQuota is created. count/roles.rbac.authorization.k8s.io: 10 ``` -(The `count/` syntax allows to limit arbitrary objects, including CRDs.) +(The `count/` syntax allows limiting arbitrary objects, including CRDs.) --- diff --git a/slides/k8s/rollout.md b/slides/k8s/rollout.md index 31331985..958ad5e2 100644 --- a/slides/k8s/rollout.md +++ b/slides/k8s/rollout.md @@ -5,9 +5,9 @@ - new pods are created - old pods are terminated - + - ... all at the same time - + - if something goes wrong, ¯\\\_(ツ)\_/¯ --- @@ -212,7 +212,7 @@ class: extra-details ## Checking the dashboard during the bad rollout -If you haven't deployed the Kubernetes dashboard earlier, just skip this slide. +If you didn't deploy the Kubernetes dashboard earlier, just skip this slide. .exercise[ @@ -255,7 +255,7 @@ Note the `3xxxx` port. ``` --> -- Cancel the deployment and wait for the dust to settle down: +- Cancel the deployment and wait for the dust to settle: ```bash kubectl rollout undo deploy worker kubectl rollout status deploy worker diff --git a/slides/k8s/setup-managed.md b/slides/k8s/setup-managed.md index ccc1b084..919bd2da 100644 --- a/slides/k8s/setup-managed.md +++ b/slides/k8s/setup-managed.md @@ -20,7 +20,7 @@ with a cloud provider ## EKS (the hard way) -- [Read the doc](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) +- [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 @@ -69,6 +69,8 @@ with a cloud provider 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) diff --git a/slides/k8s/volumes.md b/slides/k8s/volumes.md index dc7c355a..58b6849a 100644 --- a/slides/k8s/volumes.md +++ b/slides/k8s/volumes.md @@ -28,11 +28,11 @@ class: extra-details
but it refers to Docker 1.7, which was released in 2015!) -- Docker volumes allow to share data between containers running on the same host +- Docker volumes allow us to share data between containers running on the same host - Kubernetes volumes allow us to share data between containers in the same pod -- Both Docker and Kubernetes volumes allow us access to storage systems +- Both Docker and Kubernetes volumes enable access to storage systems - Kubernetes volumes are also used to expose configuration and secrets @@ -60,7 +60,7 @@ class: extra-details - correspond to concrete volumes (e.g. on a SAN, EBS, etc.) - - cannot be associated to a Pod directly; but through a Persistent Volume Claim + - cannot be associated with a Pod directly; but through a Persistent Volume Claim - won't be discussed further in this section diff --git a/slides/sfsf.yml b/slides/sfsf.yml index 5a517d31..081503ab 100644 --- a/slides/sfsf.yml +++ b/slides/sfsf.yml @@ -40,7 +40,8 @@ chapters: - k8s/operators.md - k8s/operators-design.md - k8s/owners-and-dependents.md -- - k8s/logs-cli.md +- - k8s/kubercoins.md + - k8s/logs-cli.md - k8s/logs-centralized.md - k8s/healthchecks.md - k8s/healthchecks-more.md diff --git a/slides/shared/connecting.md b/slides/shared/connecting.md index 11f9568a..2e83d996 100644 --- a/slides/shared/connecting.md +++ b/slides/shared/connecting.md @@ -84,14 +84,14 @@ You will need a Docker ID to use Play-With-Docker. - Unless instructed, **all commands must be run from the first VM, `node1`** -- We will only checkout/copy the code on `node1` +- We will only check out/copy the code on `node1` - During normal operations, we do not need access to the other nodes - If we had to troubleshoot issues, we would use a combination of: - SSH (to access system logs, daemon status...) - + - Docker API (to check running containers and container engine status) --- diff --git a/slides/shared/prereqs.md b/slides/shared/prereqs.md index 52684b34..9daca01a 100644 --- a/slides/shared/prereqs.md +++ b/slides/shared/prereqs.md @@ -90,7 +90,7 @@ class: in-person ## Why don't we run containers locally? -- Installing that stuff can be hard on some machines +- Installing this stuff can be hard on some machines (32 bits CPU or OS... Laptops without administrator access... etc.) diff --git a/slides/shared/sampleapp.md b/slides/shared/sampleapp.md index cd9db553..0636d2de 100644 --- a/slides/shared/sampleapp.md +++ b/slides/shared/sampleapp.md @@ -80,7 +80,7 @@ and displays aggregated logs. - DockerCoins is *not* a cryptocurrency - (the only common points are "randomness", "hashing", and "coins" in the name) + (the only common points are "randomness," "hashing," and "coins" in the name) --- @@ -134,7 +134,7 @@ How does each service find out the address of the other ones? - We do not hard-code IP addresses in the code -- We do not hard-code FQDN in the code, either +- We do not hard-code FQDNs in the code, either - We just connect to a service name, and container-magic does the rest @@ -173,7 +173,7 @@ class: extra-details - Compose file version 2+ makes each container reachable through its service name -- Compose file version 1 did require "links" sections +- Compose file version 1 required "links" sections to accomplish this - Network aliases are automatically namespaced