Home

Awesome

<p align="center"> <img src="files/static/k8logo.png" height="30%" width="30%" /> <br> <img src="files/static/in.png" height="30%" width="30%" /> <br> <img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/r0hi7/k8s-In-30Mins"> <img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/r0hi7/k8s-In-30Mins"> <img alt="GitHub" src="https://img.shields.io/github/license/r0hi7/k8s-In-30Mins"> <br> <img alt="GitHub issues" src="https://img.shields.io/github/issues-raw/r0hi7/k8s-In-30Mins"> <img alt="GitHub stars" src="https://img.shields.io/github/stars/r0hi7/k8s-In-30Mins"> <img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/sec_r0?style=social"> <img alt="GitHub followers" src="https://img.shields.io/github/followers/r0hi7?style=social"> <br> <a target="_blank" href="https://twitter.com/intent/tweet?text=Learn Kubernetes in 30 mins, with single node cluster @sec_r0. https://github.com/r0hi7/k8s-In-30Mins" title="Share on Twitter"><img src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social&label=Share%20on%20Twitter"></a> </p>

K8s in 30 mins

This is not a comprehensive guide to learn Kubernetes from scratch, rather this is just a small guide/cheat sheet to quickly setup and run applications with Kubernetes and deploy a very simple application on single workload VM. This repo can be served as quick learning manual to understand Kubernetes.

Prerequisite

Table of Contents:

  1. Setting up Kubernetes cluster in VM (NOT MINIKUBE) : 1 VM cluster
    • Spining up a virtual machine with Vagrant : 2GB RAM + 2CPU cores (at least)
    • Understanding:
      • kubeadm
      • kubelet
      • kubectl
  2. Kuberenetes pods: How are they different than Docker containers.
  3. Kubernetes Resource:
  4. Kubernetes network manager
    • I will pick up the plugin called Flannel.
  5. Stateless Workload
    • Replicasets & Deployments
  6. Stateful Workloads
  7. Deploying End-to-End Service in Kubernetes cluster
  8. Understanding advance kubernetes resources:
  9. Cheat sheet
  10. Next steps

Setting up Kubernetes cluster in VM

  1. Download the Vagrant File.
  2. Download Virtual box and install from here.
  3. Download and install Vagrant.
  4. In the terminal, run the two command to get the VM up and running, with out any configuration :smile:
    # In the same directory where you have downloaded Vagrantfile, run
    vagrant up
    vagrant ssh
    
    This will download the Ubuntu box image and do the entire setup for you with the help of virtual box. It just need virtual box installed.
  5. The Vagrantfile comes preconfigured with kubeadm, kubelet, kubectl
  6. Check if kubernetes cluster is perfectly installed.
    root@vagrant:/home/vagrant# kubectl version -o json
    {
      "clientVersion": {
        "major": "1",
        "minor": "19",
        "gitVersion": "v1.19.2",
        "gitCommit": "f5743093fd1c663cb0cbc89748f730662345d44d",
        "gitTreeState": "clean",
        "buildDate": "2020-09-16T13:41:02Z",
        "goVersion": "go1.15",
        "compiler": "gc",
        "platform": "linux/amd64"
      },
      "serverVersion": {
        "major": "1",
        "minor": "19",
        "gitVersion": "v1.19.2",
        "gitCommit": "f5743093fd1c663cb0cbc89748f730662345d44d",
        "gitTreeState": "clean",
        "buildDate": "2020-09-16T13:32:58Z",
        "goVersion": "go1.15",
        "compiler": "gc",
        "platform": "linux/amd64"
      }
    }
    
  7. Start the Kubernetes cluster master node.
    # This will spin up Kubernetes cluster with CIDR: 10.244.0.0/16
    root@vagrant:/home/vagrant# kubeadm init --pod-network-cidr=10.244.0.0/16
    kubeadm join 10.0.2.15:6443 --token 3m5dsc.toup1iv7670ya7wc --discovery-token-ca-cert-hash sha256:73f4983d43f9618522eaccf014205f969e3bacd76c98dd0c
    
    root@vagrant:/home/vagrant# mkdir -p $HOME/.kube
    root@vagrant:/home/vagrant# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    root@vagrant:/home/vagrant# sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
  8. Conenct other VM to this cluster: Not required in case of single VM cluster. For this run perfectly, make sure:
    • VM to VM connectivity is there.
    • All there kube-* are installed in VM.
    kubeadm join 10.0.2.15:6443 --token 3m5dsc.toup1iv7670ya7wc --discovery-token-ca-cert-hash sha256:73f4983d43f9618522eaccf014205f969e3bacd76c98dd0c
    
  9. At this point, Kubernetes is installed and cluster master is up, but still we need a agent to provision and manager network for new nodes for us, This is where Flannel comes to rescue. Install Flannel to manager docker network for pods.
    kubectl apply -f \
        https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    
  10. This step applies, if we wish to use, our master node as worker as well. Which is yes in our case:
    root@vagrant:/home/vagrant# kubectl taint nodes $(hostname) node-role.kubernetes.io/master:NoSchedule-
    
    # If everything goes well, you will see something like this.
    root@vagrant:/home/vagrant# kubectl get node
    NAME      STATUS   ROLES    AGE     VERSION
    vagrant   Ready    master   3m40s   v1.19.2
    

Run all the commands from root shell.

What are kube*

Kubernetes runs in client server model, similar to the way the docker runs. Kubernetes server exposes kubernetes-api, and each of kubeadm, kubelet and kubectl connect with this kubernetes server api to get the task done. In the master slave model, there are two entities:

Control Plane : Connects with Worker nodes for resource allocation.
Worker nodes : Cluster entitiy that actually allocates tasks and run Pods.

  1. kubeadm:
    • Sets-up the cluster
    • Connect various worker nodes togather.
  2. kubectl:
    • It is a client cli.
    • Connects with control plane kubernetes api server and send execution requests to control plane.
  3. kubelet:
    • Receives request from control planes.
    • Runs in Worker nodes.
    • Runs task over worker nodes.
    • Maintain Pod lifecycle. Not just for pods, but all Kubernetes resources lifecycle.

Kubernetes pods

How to create a pod

You can create a simple nginx pod with following yaml spec. Save this in file name : pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
Key nameKey Description
apiVersionKubernetes server API
kindKubernetes Resource type: Pod
metadata.nameName of Kubernetes Pod
spec.container.nameName of Container which will run in a Pod
spec.container.nameName of docker image to run

Run this Pod spec with. kubectl apply -f pod.yml

root@vagrant:/home/vagrant/kubedata# kubectl apply -f pod.yaml
pod/nginx created

# If everything goes OK, you will se something like this.

root@vagrant:/home/vagrant/kubedata# kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          43s
root@vagrant:/home/vagrant/kubedata#

Use : kubectl get pods to get the list of all Pods.

  1. Running command into container, running inside Pod. kubectl exec -it <pod_name> -c <container_name> -- <command>
    root@vagrant:/home/vagrant/kubedata# kubectl exec -it nginx -c nginx -- whoami
    root
    
    root@vagrant:/home/vagrant/kubedata# kubectl exec -it nginx -c nginx -- /bin/sh
    # cat /etc/*-release
    PRETTY_NAME="Debian GNU/Linux 10 (buster)"
    NAME="Debian GNU/Linux"
    VERSION_ID="10"
    VERSION="10 (buster)"
    VERSION_CODENAME=buster
    ID=debian
    HOME_URL="https://www.debian.org/"
    SUPPORT_URL="https://www.debian.org/support"
    BUG_REPORT_URL="https://bugs.debian.org/"
    
  2. Running multiple container in one pod.
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
      - name: curl
        image: appropriate/curl
        stdin: true
        tty: true
        command: ["/bin/sh"]
    
    Save this into pod-with-two-containers.yml.
    Run this : kubectl apply -f pod-with-two-containers.yml
  3. Delete a running pod. kubectl delete -f pod-with-two-containers.yml. This will remove the pod mentioned in spec file.
  4. Container in a Pod can connect to another container in same pod with spec.containers.name.
    root@vagrant:/home/vagrant/kubedata# kubectl exec -it nginx -c curl -- /bin/sh
    # curl nginx
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    #
    

Kubernetes Resources

Pods

Deployments

Replicasets

  1. Run deployments in replicas.

  2. Create file with following specification.

    apiVersion: apps/v1
    
    kind: Deployment
    metadata:
      name: nginx
    
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-app
      template:
        metadata:
          labels:
            app: nginx-app
        spec:
          containers:
          - name: nginx
            image: nginx
    

    Notice the difference.

    -- kind: Pod
    ++ kind: Deployment
    
    ++ spec:
    ++  replicas: 3
    ++  selector:
    ++    matchLabels:
    ++      app: nginx-app
    
  3. Remove existing pods(if any) kubectl delete pods --all, and create deployment.

    root@vagrant:/home/vagrant/kubedata# kubectl apply -f deployment-replica.yml
    deployment.apps/nginx created
    
    root@vagrant:/home/vagrant/kubedata# kubectl get deployments
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    nginx   0/3     3            0           7s
    
    root@vagrant:/home/vagrant/kubedata# kubectl get deployments -w
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    nginx   1/3     3            1           14s
    nginx   2/3     3            2           20s
    
  4. Get the list of all deployments: kubectl get deployments or kubectl get deploy

  5. Get the list of all replicaset : kubectl get replicaset or kubectl get rs

    root@vagrant:/home/vagrant/kubedata# kubectl get pods
    NAME                    READY   STATUS    RESTARTS   AGE
    nginx-d6ff45774-f84l8   1/1     Running   0          4m59s
    nginx-d6ff45774-gzxfz   1/1     Running   0          4m59s
    nginx-d6ff45774-t69mw   1/1     Running   0          4m59s
    
    root@vagrant:/home/vagrant/kubedata# kubectl get deploy
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    nginx   3/3     3            3           162m
    
    root@vagrant:/home/vagrant/kubedata# kubectl get replicaset
    NAME              DESIRED   CURRENT   READY   AGE
    nginx-d6ff45774   3         3         3       162m
    
    root@vagrant:/home/vagrant/kubedata#
    
  6. Print a detailed description of the selected resources, including related resources such as events or controllers: kubectl describe <resource_type> <resouce_name>

  7. Get deployment configuration in JSON format: kubectl get deployment nginx -o yaml.

Services

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx
        image: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
root@vagrant:/home/vagrant/kubedata# kubectl apply -f nginx-service.yml
deployment.apps/nginx unchanged
service/nginx created

root@vagrant:/home/vagrant/kubedata#

Loadbalancer Service

Stateless workloads

Stateful workloads

Persistent Volumes

Persistent Volume Claims

Access ModeMeaning
ReadWriteOncevolume can be mounted as read-write by a single node
ReadOnlyManyvolume can be mounted read-only by many nodes
ReadWriteManyvolume can be mounted as read-write by many nodes
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-with-pvc
spec:
  volumes:
    - name: nginx-pv-storage
      persistentVolumeClaim:
        claimName: pv-claim
  containers:
    - name: nginx-with-pv
      image: nginx
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: nginx-pv-storage
root@vagrant:/home/vagrant/kubedata# kubectl get pods nginx-pod-with-pvc
NAME                 READY   STATUS    RESTARTS   AGE
nginx-pod-with-pvc   1/1     Running   0          16s

root@vagrant:/home/vagrant/kubedata# kubectl exec -it nginx-pod-with-pvc -c nginx-with-pv -- /bin/bash
root@nginx-pod-with-pvc:/# curl localhost
Hi PV

Summary

                                +--------------------------------------+
                                |     +------------+                   |
                                |     |    POD     |        +--------------->
                                |     +-----+------+        |          |    |
                                |           |               |          |    |
                                |           |         +-----+------+   |    v
                                |           |         |     PV     |   |   /data
                                |           |         +------+-----+   |
                                |     +-----v------+         ^         |
                                |     |    PVC     +---------+         |
                                |     +------------+                   |
                                |                                      |
                                +--------------------------------------+

Sample Application Example

  1. This End to End setup will include:
  2. MySQL setup through PV and PVC.
  3. Building Custom Dockerfile for sprinboot application.
  4. Creating Deployment for SpringBoot application. 1. Setup the environment for application to connect to DB. 2. Setting up PVC setup in deployment. 3. Creating Serivce for springboot application access outside pod.
    1. Service setup through LB

Once we create spec.yml in bits, we will create a big spec to show our Infrastructure as a Code and deploy that :smile:.

MySQL Resource

Step 1: Create PV for MYSQL DB

kind: PersistentVolume
apiVersion: v1
metadata:
  name: mysql-pv
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/mysql"   

Step 2: Create PVC for PV

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

Step 3: Create MySQL deployment Spec

apiVersion: apps/v1 
kind: Deployment
metadata:
  name: dbserver
  labels:
    app: dbserver
spec:
  selector:
    matchLabels:
      app: dbserver
  template:
    metadata:
      labels:
        app: dbserver
    spec:
      containers:
      - image: mysql
        name: mysql
        imagePullPolicy: Never
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: mysecretpassword
        ports:
        - containerPort: 3306
          name: dbserver
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pvc

Step 4: Expose MySQL server via Service

apiVersion: v1
kind: Service
metadata:
  name: dbservice
spec:
  selector:
    app: dbserver
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306

Springboot Application

Step 1: Build and Deploy AppServer

Step 2: Expose AppServer service via Service type LB to host.

apiVersion: v1
kind: Service
metadata:
  name: contacts
spec:
  type: LoadBalancer
  selector:
    app: appserver
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Infrastructure as a Code

MySQL Full Spec

AppServer Full Spec

Understanding Advance Kubernetes Resources

Namespace

Namespace are software level cluster virtualization over same physical k8s cluster.

  root@vagrant:/home/vagrant# kubectl get ns
  NAME              STATUS   AGE
  default           Active   19d
  kube-node-lease   Active   19d
  kube-public       Active   19d
  kube-system       Active   19d

Kubernetes starts with 4 namespaces:

  1. default: The default namespace for objects with no other namespace.
  2. kube-system: The namespace for objects created by the Kubernetes system.
  3. kube-public: This namespace is created automatically and is readable by all users (including those not authenticated). This namespace is mostly reserved for cluster usage, in case that some resources should be visible and readable publicly throughout the whole cluster. The public aspect of this namespace is only a convention, not a requirement.
  4. kube-node-lease: This namespace for the lease objects associated with each node which improves the performance of the node heartbeats as the cluster scales.

Get Pods from specific namespace kubectl get pods --namespace=default OR kubectl get pods -n default

root@vagrant:/home/vagrant# kubectl get pods --namespace=kube-system
NAME                              READY   STATUS    RESTARTS   AGE
coredns-f9fd979d6-g9wxg           1/1     Running   5          19d
coredns-f9fd979d6-zrdvs           1/1     Running   5          19d
etcd-vagrant                      1/1     Running   5          19d
kube-apiserver-vagrant            1/1     Running   5          19d
kube-controller-manager-vagrant   1/1     Running   7          19d
kube-flannel-ds-64l2p              1/1     Running   6          19d
kube-proxy-4j4kw                  1/1     Running   5          19d
kube-scheduler-vagrant            1/1     Running   7          19d

Creating Namespace & Adding resource

Context

CheatSheet

Next Steps