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
Minikube is an open source solution to manage Kubernetes cluster locally.
In your bash run
$ brew install minikube
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.
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.
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.
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.
A pod is a set of one or multiple running containers. You will usually define one container per Pod.
A service is used to open and handle traffic between pods.
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.
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
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 servicesNow 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 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
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
As the service allow only traffic within the server, we can run the following command to test It. We will
$ 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
To stop the local minikube cluster (because It uses resources while running) :
$ minikube stop