Kubernetes Basics - Part I

Points to cover

  • Building Docker Images
  • Creating Pods
  • Scaling Pods With ReplicaSets
  • Using Services To Enable Communication Between Pods
  • Deploying Releases With Zero-Downtime
  • Using Ingress To Forward Traffic

Prerequisites

This guide borrows heavily from the workshops created by Viktor Farcic.

The examples below are build on top of his example repository, so make sure you clone that.

1
2
git clone https://github.com/vfarcic/k8s-specs.git
cd k8s-specs

Build docker images

Docker

BuildKit

Alternatives

Pod

View Yaml

1
cat pod/db.yml

Create

1
kubectl create -f pod/db.yml

View Pod

1
kubectl get pods

View Pod Alternatives

1
kubectl get pods
1
kubectl get pod
1
kubectl get po
1
kubectl get po db -o yaml
1
kubectl get po db -o json
1
kubectl get pod db -o jsonpath="{.metadata.name}"

Describe Pod

1
kubectl describe pod db

Update Pod

1
kubectl create -f pod/db.yml

This should yield an error!

1
Error from server (AlreadyExists): error when creating "pod/db.yml": pods "db" already exists

The create command is imperative and in this case not idempotent.

To update we would either have to patch the resource in the cluster, or apply an updated version of the yaml file.

1
kubectl apply -f pod/db.yml

Enter the Pod

1
kubectl exec db ps aux
1
kubectl exec -it db sh

The command below should be executed from inside the pod. If you get something like command not found: mongo, double check the above command's success.

1
echo 'db.stats()' | mongo localhost:27017/test
1
exit
1
kubectl logs db
1
kubectl exec -it db pkill mongod
1
kubectl get pods -w

Cleanup

1
kubectl delete -f pod/db.yml

ReplicaSet

View YAML

1
cat rs/go-demo-2.yml

Create ReplicaSet

1
kubectl create -f rs/go-demo-2.yml

View ReplicaSet

1
kubectl get rs
1
kubectl describe -f rs/go-demo-2.yml

Which should look something like this, notice the highlighted lines?

1
2
3
4
5
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  9s    replicaset-controller  Created pod: go-demo-2-4mw79
  Normal  SuccessfulCreate  9s    replicaset-controller  Created pod: go-demo-2-bcv5n

View Pods

Delete Pod

1
kubectl get pods
1
2
POD_NAME=$(kubectl get pods -o name | tail -1)
kubectl delete $POD_NAME
1
kubectl get pods

Cleanup

1
kubectl delete -f rs/go-demo-2.yml

Labels

Create a Pods

1
2
kubectl create -f rs/go-demo-2.yml
kubectl create -f pod/db.yml

Get Pods

1
kubectl get pods

Get it by Label

1
kubectl get pods -l type=backend

Get it by multiple labels

1
kubectl get pods -l type=backend,language=go

Show Labels

1
kubectl get pods --show-labels

Cleanup

1
2
kubectl delete -f rs/go-demo-2.yml
kubectl delete -f pod/db.yml

Service

View

1
cat svc/go-demo-2-lb.yml
1
cat svc/go-demo-2.yml

Create

1
kubectl create -f svc/go-demo-2-lb.yml
1
kubectl create -f svc/go-demo-2.yml

Inspect

1
kubectl get -f svc/go-demo-2.yml

Get LB IP

1
2
3
#!/bin/bash
IP=$(kubectl get svc go-demo-2-api \
    -o jsonpath="{.status.loadBalancer.ingress[0].hostname}")
1
2
3
#!/bin/bash
IP=$(kubectl get svc go-demo-2-api \
    -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
1
2
#!/bin/bash
IP=$(minikube ip)
1
echo $IP

Get Port

1
PORT=8080
1
2
PORT=$(kubectl get svc go-demo-2-api \
    -o jsonpath="{.spec.ports[0].nodePort}")

Call Application

1
curl -i "http://$IP:$PORT/demo/hello"
1
http "$IP:$PORT/demo/hello"

Cleanup

1
kubectl delete -f svc/go-demo-2.yml

Deployment

1
cat deploy/go-demo-2.yml
1
kubectl create -f deploy/go-demo-2.yml --record --save-config
1
kubectl describe deploy go-demo-2-api
1
kubectl get all

Zero downtime deployment

1
2
kubectl set image deploy go-demo-2-api api=vfarcic/go-demo-2:2.0 \
    --record
1
kubectl rollout status -w deploy go-demo-2-api
1
kubectl describe deploy go-demo-2-api
1
kubectl rollout history deploy go-demo-2-api
1
kubectl get rs

Rollback / Rollforward

1
kubectl rollout undo deploy go-demo-2-api
1
kubectl describe deploy go-demo-2-api
1
kubectl rollout history deploy go-demo-2-api
1
kubectl rollout undo -f deploy/go-demo-2-api.yml --to-revision=2
1
kubectl rollout history deploy go-demo-2-api

Scaling

1
kubectl scale deployment go-demo-2-api --replicas 8 --record
1
kubectl get pods

Cleanup

1
kubectl delete -f deploy/go-demo-2.yml

Ingress

Install ingress controller

1
2
3
4
5
kubectl apply \
    -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

kubectl apply \
    -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml
1
minikube addons enable ingress

Confirm ingress works

Info

As we're waiting for the LoadBalancer to be created by the Cloud Provider, we might have to repeat the command until we get a valid IP address as response.

1
2
3
4
IP=$(kubectl -n ingress-nginx get svc ingress-nginx \
    -o jsonpath="{.status.loadBalancer.ingress[0].ip}")

echo $IP
1
2
IP=$(minikube ip)
curl -i "http://$IP/healthz"

Ingress based on paths

1
cat ingress/go-demo-2.yml
1
kubectl create -f ingress/go-demo-2.yml --record --save-config
1
kubectl rollout status deployment go-demo-2-api
1
curl -i "http://$IP/demo/hello"

Ingress based on domains

1
cat ingress/devops-toolkit-dom.yml
1
kubectl apply -f ingress/devops-toolkit-dom.yml --record
1
kubectl rollout status deployment devops-toolkit
1
curl -I -H "Host: devopstoolkitseries.com" "http://$IP"
1
curl -I -H "Host: acme.com" "http://$IP/demo/hello"

Ingress with default backends

1
curl -I -H "Host: acme.com" "http://$IP"
1
cat ingress/default-backend.yml
1
kubectl create -f ingress/default-backend.yml
1
curl -I -H "Host: acme.com" "http://$IP"
1
open "http://$IP"

Cleanup

1
2
3
kubectl delete -f ingress/default-backend.yml
kubectl delete -f ingress/devops-toolkit-dom.yml
kubectl delete -f ingress/go-demo-2.yml