Skip to content
Skoleni Kubernetes
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
images README - Add better header Sep 8, 2019
.editorconfig add editorconfig Aug 8, 2019
.gitignore Fix helm package example (name, add content) Sep 6, 2019
01_pod.yml [generated] Apply editorconfig rules Aug 8, 2019
02_pod.yml Be atomic about updates. Prevent empty file Sep 6, 2019
03_01_replica_set.yml [generated] Apply editorconfig rules Aug 8, 2019
03_02_replica_set.yml [generated] Apply editorconfig rules Aug 8, 2019
04_01_deployment.yml [generated] Apply editorconfig rules Aug 8, 2019
04_02_deployment.yml [generated] Apply editorconfig rules Aug 8, 2019
06_nodeport_service.yml 06_nodeport_service - specify node port Apr 26, 2019
07_counter.yml counter, weodpress - use stateful set @ databases Sep 5, 2019
08_namespace.yml [generated] Apply editorconfig rules Aug 8, 2019
09_wordpress.yml wordpress - fix stateful set & deployment Sep 6, 2019
10_ingress.yml Improve Ingress example Jan 28, 2019
10_wordpress_nfs.yml Volumes - update from 100Mi to 1Gi (for DigitalOcean) Jun 24, 2019
11_secret.yml secrets - add stringData (plain text declaration of secert) #43 Sep 8, 2019
12_config_map.yml [generated] Apply editorconfig rules Aug 8, 2019
13_secret_example.yml secrets - add stringData (plain text declaration of secert) #43 Sep 8, 2019
14_admin.yml Add RBAC example (cluster admin) Feb 7, 2019
15_read.yml read user - fix namespace May 6, 2019
16_namespace_admin.yml Add namespace admin example Feb 12, 2019 README - add name to head Sep 8, 2019
configmap_envfrom.yml Add example of envFrom (configmap, secret) #44 Sep 8, 2019
cronjob.yml [generated] Apply editorconfig rules Aug 8, 2019
emptydir.yml Add examples of emptydir volume (emptydir in memory) #42 Sep 8, 2019
emptydir_memory.yml Add examples of emptydir volume (emptydir in memory) #42 Sep 8, 2019
helm-counter.yaml Fix helm package example (name, add content) Sep 6, 2019
hpa.yml Volumes - update from 100Mi to 1Gi (for DigitalOcean) Jun 24, 2019
hpa_v1.yml Add Autoscaling (HPA) Examples May 6, 2019
job.yml [generated] Apply editorconfig rules Aug 8, 2019
key.txt [generated] Apply editorconfig rules Aug 8, 2019
loadbalancer.yml Add LoadBalancer (service) example Jun 24, 2019
nodename.yml add node selector & affinity #8 Sep 8, 2019
nodeselector.yml add node selector & affinity #8 Sep 8, 2019
one-image-apache-values.yml Update helm demo chart from awefull simple-image to new nice one-image Aug 9, 2019
one-image-nginx-values.yml Update helm demo chart from awefull simple-image to new nice one-image Aug 9, 2019
parallel_jobs.yml [generated] Apply editorconfig rules Aug 8, 2019
private_pod.yml [generated] Apply editorconfig rules Aug 8, 2019
probes_liveness.yml probes_*.yml - add services to probe examples Sep 6, 2019
probes_readiness.yml probes_*.yml - add services to probe examples Sep 6, 2019
pv_nfs.yml pv_nfs - update nfs server, add examples of all reclaim policy Aug 9, 2019
pvc_default.yml [generated] Apply editorconfig rules Aug 8, 2019
pvc_mount_example.yml [generated] Apply editorconfig rules Aug 8, 2019
pvc_nfs.yml [generated] Apply editorconfig rules Aug 8, 2019
strategy_ramped.yml [generated] Apply editorconfig rules Aug 8, 2019
strategy_ramped_2.yml [generated] Apply editorconfig rules Aug 8, 2019
webservers.yml [generated] Apply editorconfig rules Aug 8, 2019

Ondrej Sika ( | | go to course -> | install kubernetes ->

Kubernetes Training

Ondrej Sika <>

Code examples for my Kubernetes Training.

About Course

Kubernetes training in Czech Republic

Kubernetes training in Europe

Related Courses


Any Questions?

Write me mail to

Install Kubernetes

You have to install these tools:


Kubectl on Mac

brew install kubernetes-cli

If it doesn't work correctly (for instance you have Docker installed) you need to point kubectl to the right binary.

rm /usr/local/bin/kubectl
brew link --overwrite kubernetes-cli

Helm on Mac

brew install kubernetes-helm

Minikube on Mac

brew cask install minikube

If you dont have VirtualBox, you can install it using Brew.

brew cask install virtualbox


Kubectl on Linux

curl -LO$(curl -s && chmod +x ./kubectl && sudo mv ./kubectl /usr/local/bin/kubectl

Helm on Linux


Install using snap:

sudo snap install helm --classic

Or oneliner for Linux:

curl | bash

Minikube on Linux (Linux on host)

Also requires Virtual Box

curl -Lo minikube && chmod +x minikube && sudo cp minikube /usr/local/bin/ && rm minikube

Minikube on Linux (Linux in virtual machine)

If you want run Kubernetes inside of custom virtual machine, you can also use minikube with VM Driver none.

curl -Lo minikube && chmod +x minikube && sudo cp minikube /usr/local/bin/ && rm minikube

You can start Kubernetes cluster using

minikube start --vm-driver=none on Linux (Linux in virtual machine)

If you run Ubuntu (or another linux with snap), you can use

sudo snap install microk8s --classic

See more information at

k3s (minimalistic kubernetes for Linux)

If you can't run minikube (with VirtualBox or VM driver none) or microk8s, you can try k3s.

See more on


Kubectl for Windows

choco install kubernetes-cli

Helm for Windows

choco install kubernetes-helm

Minikube for Windows

choco install minikube

Bash Completion

source <(kubectl completion bash)
source <(minikube completion bash)
source <(helm completion bash)

Or save to .bashrc

echo "source <(kubectl completion bash)" >> ~/.bashrc
echo "source <(minikube completion bash)" >> ~/.bashrc
echo "source <(helm completion bash)" >> ~/.bashrc

Also work for zsh, eg.: source <(kubectl completion zsh)

Start Minikube

minikube start

Run with Hyper-V (on Windows) -

minikube start --vm-driver hyperv --hyperv-virtual-switch "Primary Virtual Switch"

Verify cluster health by

kubectl get cs

If you see something like this


Your cluster is up and running. Good job!

Connect My Demo Cluster

Download & use my Digital Ocean Kubernetes confing (repository ondrejsika/kubeconfig-sikademo). This Kubernetes cluster is created by ondrejsika/terraform-do-kubernetes-example on Digital Ocean.


Set KUBECONFIG environment variable to this file.

On Unix:

export KUBECONFIG=kubeconfig

On Windows (in PowerShell):

Set-Variable -Name "KUBECONFIG" -Value "kubeconfig"

On Windows (in CMD):


Or save it to .kube/config:

mv kubeconfig ~/.kube/config

Create own namespace (eg.: ondrejsika) and set it as default

kubectl create ns ondrejsika
kubectl config set-context do-fra1-sikademo --namespace=ondrejsika



Check Cluster Status

Validate cluster health after setup

kubectl get cs

Get Nodes

kubectl get nodes

Proxy to cluster

Start proxy

kubectl proxy

Create Pod

kubectl apply -f 01_pod.yml
kubectl apply -f 02_pod.yml

List Pods

kubectl get pods
kubectl get po


Exec (Connect) Pod

kubectl exec -ti multi-container-pod bash

Pod Logs

kubectl logs simple-hello-world

or following logs

kubectl logs simple-hello-world -f

Expose Pod (Create Service)

kubectl expose pod simple-hello-world
kubectl expose pod multi-container-pod --type=NodePort

Connect your services

Or using minikube service (just for NodePort)

minikube service multi-container-pod

Assigning Pods to Nodes

Docs -

See node labels

kubectl get nodes --show-labels

Create new labels

You can create own labels

kubectl label nodes <node-name> <label-key>=<label-value>


kubectl label nodes minikube node=primary

Select by node name (nodeName)

kubectl apply -f nodename.yml

Select by label (nodeSelector)

kubectl apply -f nodeselector.yml

Affinity and anti-affinity

If you need more than nodeSelector, you can try Affinity and anti-affinity

Delete Pod

kubectl delete -f 01_pod.yml -f 02_pod.yml

# or
kubectl delete po/simple-hello-world
kubectl delete po/multi-container-pod

and delete services (creaded by kubectl expose)

kubectl delete svc/simple-hello-world svc/multi-container-pod

Private Container Registry

Deploy private pod

kubectl apply -f private_pod.yml


See config file

echo $(kubectl get secret private-registry-credentials -o jsonpath="{.data.\.dockerconfigjson}" | base64 --decode)

And see credentials (of example

echo $(kubectl get secret private-registry-credentials -o jsonpath="{.data.\.dockerconfigjson}" | base64 --decode | jq '.auths[""].auth' -r | base64 --decode)


kubectl delete -f private_pod.yml

Create Replica Set

kubectl apply -f 03_01_replica_set.yml

List Replica Sets

kubectl get replicasets
kubectl get rs
kubectl get rs,po

Expose Replica Set (Create Service)

kubectl expose rs hello-world-rs --type=NodePort


Or using minikube service (just for NodePort)

minikube service hello-world-rs

Update Replica Set

See the difference

vimdiff 03_01_replica_set.yml 03_02_replica_set.yml
kubectl apply -f 03_02_replica_set.yml

Delete Replica Set

kubectl delete -f 03_01_replica_set.yml

# or
kubectl delete rs/hello-world-rs

# and the service
kubectl delete svc/hello-world-rs

Create Deployment

kubectl apply -f 04_01_deployment.yml

List Deployments

kubectl get deployments
kubectl get deploy
kubectl get po,rs,deploy

Expose Deployment Set (Create Service)

kubectl expose deploy hello-world --type=NodePort


Or using minikube service (just for NodePort)

minikube service hello-world

Update Deployment

See the difference

vimdiff 04_01_deployment.yml 04_02_deployment.yml
kubectl apply -f 04_02_deployment.yml


History of deployments

kubectl rollout history deploy hello-world

Rollback (Rollout)

One version back

kubectl rollout undo deploy hello-world

To specific revision

kubectl rollout undo deploy hello-world --to-revision=2

Delete Deployment

kubectl delete -f 04_01_deployment.yml

# or
kubectl delete deploy/hello-world

# and service
kubectl delete svc/hello-world

Create Job

Create job:

kubectl apply -f job.yml

Create parallel job:

kubectl apply -f parallel_jobs.yml

Create Cron Job

kubectl apply -f cronjob.yml

Delete Jobs

kubectl delete -f job.yml -f parallel_jobs.yml -f cronjob.yml

kubectl run

Create deployment from command line

kubectl run -it --rm --image=debian --generator=run-pod/v1 my-debian -- bash

Cleanup is not necessary, because --rm parameter deletes deployment after container exits.

Create Service ClusterIP

Create deploymnet again:

kubectl apply -f 04_02_deployment.yml

And create service:

kubectl apply -f 05_clusterip_service.yml


Create Service NodePort

kubectl apply -f 06_nodeport_service.yml


Create LoadBalancer Service (Public Cloud only)

kubectl apply -f loadbalancer.yml

Wait until get external IP address. Works only in public clouds (like Digital Ocean, AWS) NOT in minikube.

List Services

kubectl get services
kubectl get svc
kubectl get po,rs,deploy,svc
kubectl get all

Delete Service

kubectl delete -f 05_clusterip_service.yml
kubectl delete -f 06_nodeport_service.yml

# or
kubectl delete svc/hello-world-nodeport
kubectl delete svc/hello-world-clusterip

# and deployment
kubectl delete deploy/hello-world

Deploy Application (Multiple Deployments and Services)

kubectl apply -f 07_counter.yml


List components

kubectl get all -l project=counter

Open in Browser

minikube service counter

Delete Application

kubectl delete -f 07_counter.yml

Create Namespace

kubectl create namespace counter


kubectl apply -f 08_namespace.yml

List Namespaces

kubectl get namespaces
kubectl get ns

Deploy to Namespace

kubectl apply -f 07_counter.yml -n counter


Switch Namespace in Current Context

kubectl config set-context $(kubectl config current-context) --namespace=counter

Delete Namespace

kubectl delete -f 08_namespace.yml

# or
kubectl delete ns/counter

Wordpress Example


kubectl create namespace wp
kubectl -n wp apply -f 09_wordpress.yml



minikube -n wp service wordpress

Stop & delete

kubectl delete namespace wp


Enable Ingress on Minikube

minikube addons enable ingress

Traefik Ingress Controller

See ondrejsika/kubernetes-ingress-traefik

Install Traefik Ingress Controller:

kubect apply -f

Create Ingress

Create some services (& deploymnets)

kubectl apply -f webservers.yml


Create Ingress

kubectl apply -f 10_ingress.yml



kubectl delete -f webservers.yml -f 10_ingress.yml

PersistentVolume & PersistentVolumeClaim



Stored on disk

kubectl apply -f emptydir.yaml

Empty dir volemes are stored in /var/lib/kubelet/pods/<pod uid>/volumes/

See volumes on node:

tree /var/lib/kubelet/pods/$(kubectl get pods/emptydir -o jsonpath='{.metadata.uid}')/volumes/

Stored in memory (ramdisk)

kubectl apply -f emptydir_memory.yaml

If you use in memory volumes, files stored there counts into container's memory limit.

Claim default PV

From default StorageClass (kubectl get storageclass)

kubectl apply -f pvc_default.yml

See PV and PVC

kubectl get pv,pvc

Delete claim & volume

kubectl delete -f pvc_default.yml
kubectl get pv,pvc

Create PV

For example NFS storage

kubectl apply -f pv_nfs.yml

See PV

kubectl get pv

Claim PV

kubectl apply -f pvc_nfs.yml


kubectl get pv,pvc


kubectl apply -f pvc_mount_example.yml


Clean up

kubectl delete -f pv_nfs.yml -f pvc_nfs.yml -f pvc_mount_example.yml

ConfigMaps & Secrets

Create Secrets

kubectl create secret generic my-secret \
    --from-file=key=key.txt \

Create secret form config file

kubectl apply -f 11_secret.yml

Get Values

Base64 encoded

echo $(kubectl get secret my-secret -o jsonpath="{.data.key}")
echo $(kubectl get secret my-secret -o jsonpath="{.data.token}")


echo $(kubectl get secret my-secret -o jsonpath="{.data.key}" | base64 --decode)
echo $(kubectl get secret my-secret -o jsonpath="{.data.token}" | base64 --decode)

Create ConfigMap

kubectl apply -f 12_config_map.yml

Example usage

kubectl apply -f 13_secret_example.yml



Mount every variables from ConfigMap or Secret. See example:

kubectl apply -f configmap_envfrom.yml
kubectl logs envfrom


See / export kubeconfig

kubectl config view


  • --raw - by default, sensitive data are redacted, see raw config unsing --raw
  • --flatten - embed certificates for portable kubeconfig
  • --minify - see / export only actual context


kubectl config view --raw
kubectl config view --raw --flatten
kubectl config view --raw --flatten --minify


Show all api resources (with verbs)

kubectl api-resources -o wide

Create cluster admin

kubectl apply -f 14_admin.yml

Create kubeconfig for admin

Export actual config

kubectl config view --raw > config

Get token:

kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')

Set token to user:

kubectl --kubeconfig=config config set-credentials admin --token=<token>

Set new user to context:

kubectl --kubeconfig=config config set-context --user=admin --cluster=minikube admin

Use new user to context:

kubectl --kubeconfig=config config use-context admin

And try:

kubectl --kubeconfig=config get nodes,svc

Join multiple kubeconfigs

KUBECONFIG=.kube/config:kuberners-config-new.yml kubectl config view --raw > .kube/config

Create pod reader

kubectl apply -f 15_read.yml

Add to user to config and change context user

kubectl --kubeconfig=config config set-credentials read --token=<token>
kubectl --kubeconfig=config config set-context --user=read --cluster=minikube read
kubectl --kubeconfig=config config use-context read

Create Namespace Admin

kubectl apply -f 16_namespace_admin.yml

And create user, also with default namespace changed to devel

kubectl --kubeconfig=config config set-credentials devel --token=<token>
kubectl --kubeconfig=config config set-context --user=devel --cluster=minikube  --namespace=devel devel
kubectl --kubeconfig=config config use-context devel

Liveness & Readiness Probes


Liveness Probe

kubectl apply -f probes_liveness.yml

Readiness Probe

kubectl apply -f probes_readiness.yml


kubectl delete -f probes_liveness.yml -f probes_readiness.yml

Autoscaling (Horizontal Pod Autoscaler)

We have to have metrics server enabled

minikube addons enable metrics-server

optionaly, you can enabled heapster for Grafana charts

minikube addons enable heapster

Create HPA (command)

Create deployment & service

kubectl apply -f 04_01_deployment.yml


kubectl autoscale deployment hello-world --min=2 --max=5 --cpu-percent=80

Create HPA (YAML)

Api v1 (same as kubectl autoscale)

kubectl apply -f hpa_v1.yml

Api v2

kubectl apply -f hpa.yml

Get HPAs

kubectl get hpa

Test Autoscaling

Run AB

ab -kc 20 -t 60 $(minikube service apache --url)/

And see

kubectl get hpa,po

Delete HPA

kubectl delete -f hpa.yml

and clean up

kubectl delete hpa/hello-world -f 04_01_deployment.yml

Deployment Strategies

Great resources by Container Solutions

Ramped (without downtime)

Create deployment & service

kubectl apply -f strategy_ramped.yml

See update

vimdiff strategy_ramped.yml strategy_ramped_2.yml

Update without downtime

kubectl apply -f strategy_ramped_2.yml

Clean up

kubectl delete -f strategy_ramped.yml


Init Helm & Tiller

helm init

If you have Tiller installed on your cluster, you can init helm client only.

helm init --client-only

Create Service Account for Tiller

kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'

Search Package

helm search db
helm search redis

Inspect Package

helm inspect stable/redis

Install Package

helm install stable/redis
helm install stable/redis --name redis

Or dry run (see the Kubernetes config)

helm install stable/redis --dry-run --debug
helm install stable/redis --dry-run --debug --name redis

Upgrade Package

If you want to upgrade instance of chart, you have to call:

helm upgrade redis stable/redis --set pullPolicy=Always

Install or Upgrade

You can add --install to helm upgrade to install package if not exists. When chart exists, it will be upgraded.

helm upgrade --install redis stable/redis --set pullPolicy=Always

List Installed Packages

helm ls
helm ls -q

List all (not jutst DEPLOYED)

helm ls --all
helm ls -a -q

Status of Package

helm status redis

Inspect Values

helm inspect values stable/redis

Delete Package

helm del redis
helm del redis --purge

Delete all & purge

helm del --purge $(helm ls -a -q)

Helm Repositiories

List repositories

helm repo list

Add repository

helm repo add ondrejsika

helm search ondrejsika

Install ondrejsika/one-image

Sources of Chart ondrejsika/one-image are

Inspect Package

helm inspect ondrejsika/one-image

Install with values in args

helm install ondrejsika/one-image --name hello-world --set

Install with values file

helm install ondrejsika/one-image --name nginx --values one-image-nginx-values.yml
helm install ondrejsika/one-image --name apache --values one-image-apache-values.yml

Install with values file and values args

helm install ondrejsika/one-image --name nginx2 --values one-image-nginx-values.yml --set

Own Helm Package

You can init package using

helm create counter

See what's inside

cd counter

This default manifests are too much complicated, if you want simple examle, check out my ondrejsika/one-image-helm.

We can try create helm package for our Wordpress example (09_wordpress.yml).

We have to replace few names & labes with {{ .Release.Name }} to allow multiple deployments (installations) of chart. For labels, I use release: {{ .Release.Name }}, it works, it's simple and make sense.

I also replace all variable part with values like image: {{ .Values.image }}, which I can overwrite.

See example (one-image/deployment.yaml)

apiVersion: apps/v1
kind: Deployment
  name: {{ .Release.Name }}
  {{ if .Values.changeCause }}
  annotations: {{ .Values.changeCause }}
  {{ end }}
    release: {{ .Release.Name }}
  replicas: 1
      release: {{ .Release.Name }}
        release: {{ .Release.Name }}
        - name: {{ .Chart.Name }}
          image: {{ .Values.image }}
            - name: http
              containerPort: 80
              protocol: TCP

You can also split your components to own files, it will be easier to read.

If you're lazy, you can just use helm-counter.yaml.

Just remove everything in templates dir & copy there that prepared file.

rm -rf templates/*
cp ../helm-counter.yaml templates/counter.yml

See Template

helm template .
helm template . --name hello --set


helm install . --name hello --set

Build Package

cd ..
helm package hello-world

Create own repository

mkdir repo
mv hello-world-*.tgz repo/
helm repo index repo/

Publish it!

scp repo/*

Use it

Delete previous deployment

helm del --purge hello

Add repo

helm repo add sikademo

Install package

helm install sikademo/hello-world --name hello --set


Thank you & Questions

Ondrej Sika

Do you like the course? Write me recommendation on Twitter (with handle @ondrejsika) and LinkedIn. Thanks.

You can’t perform that action at this time.