Nicolas Kovacs

Nicolas Kovacs

kubernetes-workshop-1 thumbnail image

Kubernetes Workshop - Part 1

k8s

Kubernetes is an open source library that will allow you to deploy, maintain and manage containers in infrastructures, It can be done locally (with minikube) or remotely (GKE , AKS, etc.).

Prerequisites and objectives

We will assume here that you are on macOS with at least 20GB of free disk space. This workshop can be followed with linux also. You might have homebrew (package manager for macOS) installed. You also need to understand what are containers and what is Docker.

Let's do it

Install minikube

Minikube is an open source solution to manage Kubernetes cluster locally.

In your bash run

$ brew install minikube

Install VirtualBox

VirtualBox is an hypervisor that will allow us to create and manage virtual machines. We will rely on It to create the Kubernetes cluster, instead of using the default macOS one. The user experience will be smoother, also, some features are not available with the default hypervisor.

Click here and follow the instructions. Be sure VirtualBox is installed correctly.

Be sure to have VirtualBox installed correctly (on macOS there is some Security/Privacy restrictions), look here to learn more about It and how to correct the issue

Create the cluster

We will now create the Kubernetes cluster thanks to Minikube. In your bash run the following commands.

$ minikube start --memory=8196 --cpus=2 --disk-size 20GB --vm-driver=VirtualBox

You maybe have to override default configuration and parameters above to match your computer specifications.

  • minikube : is the CLI

  • start : is the command to launch (or implicitly create) a cluster

  • --memory=8196 : is the quantity or RAM we want to allocate to the Virtual Machine (VM)

  • --cpus=2 : is the quantity of core we want to allocate

  • --disk-size 20GB : is the size of the disk space we want to allocate

  • --vm-driver=VirtualBox : explicitly ask to create the K8S cluster within a virtual box VM

Once it's done, the cluster is launched within a fresh new virtual machine. The next time you want to start your K8S cluster, you can just do minikube start without any arguments.

Under the hood, minikube create a profile named minikube. You can have multiple profiles (multiple cluster with different spec) locally. Learn more here.

We can now interact with our minikube cluster. See more command here.

# Start the cluster
$ minikube start

# Stop the cluster
$ minikube stop

# Connect to the minikube shell inside the VM
$ minikube ssh

Manage the cluster with kubectl

Kubectl is a CLI that will allow you to interact with a Kubernetes cluster. It's installed by default with minikube ( homebrew dependency).

By default, when you run minikube start, It set the current kubectl context to minikube. Like minikube profiles, you can have multiple context with kubectl. For example, a minikube context and a remote context to interact with a remote K8S cluster.

You can use kubectx to switch your k8s context easily. It also provides a kubens command to switch namespace (see below) within the context.

Kubernetes objects

A Kubernetes cluster is composed of multiple objects. Each one has Its utility and will have specifications. Here we will use the most basic ones, but you can learn more here.

NAMESPACE

By default, when you create a minikube cluster, It implicitly creates a default namespace. You can have multiple namespaces to handle multiple K8S objects. Like so, you can clearly separate resources from each other. Learn more here.

DEPLOYMENTS

A deployment is like a recipe of how pods are created and handled. You will usually not create pods manually, but you will use deployment to specify your needs.

PODS

A pod is a set of one or multiple running containers. You will usually define one container per Pod.

SERVICES

A service is used to open and handle traffic between pods.

Creating Objects

You can interact with kubernetes cluster implicitly or declarative. You will usually create and maintain files to administrate for K8S cluster (declarative), and apply these configurations with kubectl. For doing other kind of operations you will use kubectl directly.

kubectl can read configuration from YAML files, It will kinda act like docker-compose.

DEPLOYMENT

We are going to create here a web server (nginx) deployment. The deployment will then create and administrate 1 or more pods and each pod will be composed of 1 container (can be more, see schema above).

  • Create a new folder to store all your files

  • Create a new one inside called nginx-deployment.yml (it can be .yml or .yaml)

  • Paste the code bellow

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.7.9
          ports:
            - containerPort: 80
  • apiVersion: apps/v1 : is the api we want to use. Basically each version gives access to some features, each version follows specs, directed by Kubernetes with a schema.

  • kind: Deployment : is the type of object we want

  • metadata : is used to identify the object. Here, name is important

  • spec : define the Deployment

  • replicas: 3 : is the number of pods we want for this Deployment

  • selector : define how we can select pods (with label app:nginx)

  • containers : define containers

Once it's done, we can ask kubectl to apply this file into the cluster.

$ kubectl apply -f nginx-deployment.yml

The output should be

deployment.apps/nginx-deployment created

Now we can see and list what we have done

$ kubectl get deployments
$ kubectl get pods
# List all deployments object
$ kubectl get deployments

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           2m16s

# List all pods
$ kubectl get pods

NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-5d59d67564-dw8zj   1/1     Running   0          2m38s
nginx-deployment-5d59d67564-ltj8s   1/1     Running   0          2m38s
nginx-deployment-5d59d67564-nrn9f   1/1     Running   0          2m38s

For the get command you will basically put in parameter the kind of object, for example, to list all services objects you will have to run kubectl get services Now we have 1 deployment with 3 pods running

We can also see some logs :

# -f for follow mode
# Empty for now, It will output pod's container stdout logs
$ kubectl logs -f nginx-deployment-5d59d67564-dw8zj

Another useful command is describe, It will output the kubernetes objects and give more information.

$ kubectl describe pod nginx-deployment-5d59d67564-dw8zj
Name: nginx-deployment-5d59d67564-dw8zj
Namespace: default
Priority: 0
Node: doc/192.168.99.101
Start Time: Tue, 20 Apr 2021 16:23:48 +0400
Labels: app=nginx
  pod-template-hash=5d59d67564
Annotations: <none>
Status: Running
IP: 172.17.0.3
IPs:
  IP: 172.17.0.3
Controlled By: ReplicaSet/nginx-deployment-5d59d67564
Containers:
  nginx:
    Container ID: docker://4f5c48141c4a5ed425d401e815afa4f76cb102c079d65c9b8c71053911362bc7
    Image: nginx:1.7.9
    Image ID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
    Port: 80/TCP
    Host Port: 0/TCP
    State: Running
      Started: Tue, 20 Apr 2021 16:24:12 +0400
    Ready: True
    Restart Count: 0
    Environment: <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5mvmb (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-5mvmb:
    Type: Secret (a volume populated by a Secret)
    SecretName: default-token-5mvmb
    Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
  node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  8m3s   default-scheduler  Successfully assigned default/nginx-deployment-5d59d67564-dw8zj to doc
  Normal  Pulling    8m2s   kubelet            Pulling image "nginx:1.7.9"
  Normal  Pulled     7m39s  kubelet            Successfully pulled image "nginx:1.7.9" in 22.390300786s
  Normal  Created    7m39s  kubelet            Created container nginx
  Normal  Started    7m39s  kubelet            Started container nginx

Services

Services will let us allow some traffic between pods. By default, we will use here a ClusterIP to made it available through the cluster only. Like containers, initially, pods cannot communicate with each others.

  • Create a new file called nginx-service.yml

  • Paste the code below

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  • selector : select pods with app: nginx label, see Deployment above

  • port : port we want to serve

  • targetPort : port we want to serve to, it will target the containerPort

Once again we can ask kubectl to apply this file into the cluster.

$ kubectl apply -f nginx-service.yml

The output should be

service/nginx created

We can display current services

$ kubectl get services # or kubectl get svc

NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   54m
nginx        ClusterIP   10.105.68.32   <none>        80/TCP    5s

Now, pods in other deployments can access the nginx server with port 80

EXAMPLE

As the service allow only traffic within the server, we can run the following command to test It. We will use $ kubectl run (kinda like docker run)

$ kubectl run -it --rm debug --image=busybox --restart=Never -- sh
  • -it : (-i -tty) interactive , current shell will be plugged

  • --rm : remove pod after exit

  • debug : name of the pod

  • --image=busybox : docker image

  • --restart=Never : never restart the pod

  • -- : command separator

  • sh : command to run within the pod's container

Try in another tab of your terminal, without closing the current on within pod's container, you will see the debug pod

$ kubectl get pods

NAME                                READY   STATUS    RESTARTS   AGE
debug                               1/1     Running   0          4m4s
nginx-deployment-5d59d67564-dw8zj   1/1     Running   0          60m
nginx-deployment-5d59d67564-ltj8s   1/1     Running   0          60m
nginx-deployment-5d59d67564-nrn9f   1/1     Running   0          60m

Go back to the shell on pod's container and run the following command

$ wget http://nginx

Connecting to nginx (10.105.68.32:80)
saving to 'index.html'
index.html           100% |**************************************************************************************|   612  0:00:00 ETA
'index.html' saved

We are doing a wget command on http://nginx, as you see, the service generated an alias available within the cluster matching the service name nginx to pod's containers

To quit the current shell, use Ctrl + D

Stopping minikube

To stop the local minikube cluster (because It uses resources while running) :

$ minikube stop
← Back to home