Slide 1

Slide 1 text

@m_holtermann An Introduction To Kubernetes

Slide 2

Slide 2 text

@m_holtermann What is Kubernetes?

Slide 3

Slide 3 text

@m_holtermann Hi, I’m Markus Holtermann

Slide 4

Slide 4 text

@m_holtermann Hi, I’m Markus Holtermann W e're hiring

Slide 5

Slide 5 text

@m_holtermann A system to run containers

Slide 6

Slide 6 text

@m_holtermann An API server you interact with using kubectl

Slide 7

Slide 7 text

@m_holtermann Eventually consistent

Slide 8

Slide 8 text

@m_holtermann @m_holtermann Cluster

Slide 9

Slide 9 text

@m_holtermann @m_holtermann Cluster Node 1 Node 2 Node 3

Slide 10

Slide 10 text

@m_holtermann @m_holtermann Cluster Node 1 Node 2 Node 3 Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod

Slide 11

Slide 11 text

@m_holtermann @m_holtermann Cluster Node 1 Node 2 Node 3 Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod Pod

Slide 12

Slide 12 text

@m_holtermann @m_holtermann Cluster Node 1 Node 2 Node 3 Pod Container Pod Container Container Pod Container Pod Container Pod Container Pod Container Pod Container Container Pod Container Container Pod Container Container Pod Container Container Pod Container Pod Container Pod Container

Slide 13

Slide 13 text

@m_holtermann Concepts

Slide 14

Slide 14 text

@m_holtermann Everything is a resource

Slide 15

Slide 15 text

@m_holtermann Key attributes: kind, apiVersion, meta, spec

Slide 16

Slide 16 text

@m_holtermann cluster-scoped or namespace-scoped

Slide 17

Slide 17 text

@m_holtermann Building Blocks https://kubernetes.io/docs/reference/kubernetes-api/

Slide 18

Slide 18 text

@m_holtermann Namespaces

Slide 19

Slide 19 text

@m_holtermann @m_holtermann apiVersion: v1 kind: Namespace metadata: name: myapp $ kubectl get namespaces NAME STATUS AGE default Active 32d kube-system Active 32d $ kubectl apply -f k8s-namespace.yaml namespace/myapp created $ kubectl get namespaces NAME STATUS AGE default Active 32d kube-system Active 32d myapp Active 5s

Slide 20

Slide 20 text

@m_holtermann Pods

Slide 21

Slide 21 text

@m_holtermann @m_holtermann apiVersion: v1 kind: Pod metadata: name: whoami namespace: myapp labels: app.kubernetes.io/instance: whoami spec: containers: - image: traefik/whoami:latest name: whoami ports: - containerPort: 80 name: http protocol: TCP $ kubectl -n myapp get pods No resources found in myapp namespace. $ kubectl apply -f k8s-pod.yaml pod/whoami created $ kubectl -n myapp get pods NAME READY STATUS RESTARTS AGE whoami 1/1 Running 0 8s

Slide 22

Slide 22 text

@m_holtermann Services

Slide 23

Slide 23 text

@m_holtermann @m_holtermann apiVersion: v1 kind: Service metadata: name: whoami namespace: myapp spec: ports: - name: http port: 8080 protocol: TCP targetPort: http selector: app.kubernetes.io/instance: whoami $ kubectl -n myapp get services No resources found in myapp namespace. $ kubectl apply -f k8s-service.yaml service/whoami created $ kubectl -n myapp get services NAME TYPE CLUSTER-IP PORT(S) AGE whoami ClusterIP 10.240.28.82 8080/TCP 2s

Slide 24

Slide 24 text

@m_holtermann Ingresses

Slide 25

Slide 25 text

@m_holtermann @m_holtermann apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: whoami namespace: myapp spec: rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: whoami port: name: http $ kubectl -n myapp get ingress No resources found in myapp namespace. $ kubectl -n myapp apply -f k8s-ingress.yaml ingress.networking.k8s.io/whoami created $ kubectl -n myapp get ingress NAME HOSTS ADDRESS PORTS AGE whoami example.com 80 3s

Slide 26

Slide 26 text

@m_holtermann Configmaps & Secrets

Slide 27

Slide 27 text

@m_holtermann @m_holtermann apiVersion: v1 kind: ConfigMap metadata: name: whoami namespace: myapp data: WHOAMI_NAME: "Darth Vader" $ kubectl -n myapp get configmaps No resources found in myapp namespace. $ kubectl -n myapp apply -f k8s-configmap.yaml configmap/whoami created $ kubectl -n myapp get configmaps NAME DATA AGE whoami 1 3s apiVersion: v1 kind: Secret metadata: name: whoami namespace: myapp type: Opaque data: a-key: THVrZSwgSSdtIHlvdXIgZmF0aGVyIQo= $ kubectl -n myapp get secrets No resources found in myapp namespace. $ kubectl -n myapp apply -f k8s-secret.yaml secret/whoami created $ kubectl -n myapp get secrets NAME TYPE DATA AGE whoami Opaque 1 3s

Slide 28

Slide 28 text

@m_holtermann Deployments

Slide 29

Slide 29 text

@m_holtermann @m_holtermann apiVersion: apps/v1 kind: Deployment ... spec: replicas: 3 selector: matchLabels: app.kubernetes.io/instance: whoami template: metadata: labels: app.kubernetes.io/instance: whoami spec: containers: - image: traefik/whoami:latest name: whoami env: - name: SOME_SECRET valueFrom: secretKeyRef: name: whoami key: a-key envFrom: - configMapRef: name: whoami ports: - containerPort: 80 name: http protocol: TCP $ kubectl -n myapp get deployments No resources found in myapp namespace. $ kubectl -n myapp apply -f k8s-deployment.yaml deployment.apps/whoami created $ kubectl -n myapp get deployments NAME READY UP-TO-DATE AVAILABLE AGE whoami 3/3 3 3 4s $ kubectl -n myapp get pods NAME READY STATUS RESTART AGE whoami 1/1 Running 0 10m Whoami-66bc5b-jtpjs 1/1 Running 0 23s whoami-66bc5b-pv7kv 1/1 Running 0 23s Whoami-66bc5b-sk2f8 1/1 Running 0 23s

Slide 30

Slide 30 text

@m_holtermann Kubernetes & Django

Slide 31

Slide 31 text

@m_holtermann @m_holtermann --- apiVersion: v1 kind: ConfigMap metadata: name: myapp namespace: mynamespace data: ALLOWED_HOSTS: "myapp.com,myapp.mynamespace.svc.cluster.local " --- apiVersion: v1 kind: Secret metadata: name: myapp namespace: mynamespace type: Opaque data: # postgres://user:pw@pgserver:5432/dbname DATABASE_URL: cG9zdGdyZXM6Ly91c2VyOnB3QHBnc2VydmVyOjU0MzIvZGJuYW1l= SECRET_KEY: KzVAYmpkbXhqd2koYjQoeHFrOWwkdCZidjB5QCF4bXpfI2k3PSVlKmhpdnUqdTdmXng=

Slide 32

Slide 32 text

@m_holtermann @m_holtermann import os import dj_database_url SECRET_KEY = os.environ["SECRET_KEY"] DEBUG = os.getenv("DEBUG", "") == "true" ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",") DATABASES = {"default": dj_database_url. config()}

Slide 33

Slide 33 text

@m_holtermann @m_holtermann apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: mynamespace spec: replicas: 2 selector: matchLabels: app.kubernetes.io/name : myapp template: metadata: labels: app.kubernetes.io/name : myapp spec: containers: - envFrom: - configMapRef: name: myapp - secretRef: name: myapp image: path.to.my/docker/image:tag imagePullPolicy : IfNotPresent name: web ports: - containerPort: 8080 name: http protocol: TCP restartPolicy: Always

Slide 34

Slide 34 text

@m_holtermann @m_holtermann # Dockerfile # ... ENTRYPOINT ["/entrypoint.sh "] CMD ["gunicorn", "-b", ":8080", "-w", "4", "--log-level", "INFO", "--access-logfile ", "-", "--error-logfile ", "-", "myapp.wsgi"] # ... # /entrypoint.sh #!/bin/sh set -e cmd="$@" until django-admin dbshell -- --command '\q'; do >&2 echo "Postgres is unavailable - sleeping " sleep 5 done django-admin migrate -v 2 django-admin collectstatic -v 2 --no-input exec $cmd

Slide 35

Slide 35 text

@m_holtermann This is Kubernetes!