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