Intro to Kubernetes
- Originally Written : July, 2021
Kubernetes
, often referred to as K8s, is an open-source platform designed to automate the deployment, scaling, and management of containerized applications. It groups containers that make up an application into logical units for easy management and discovery. Initially developed by Google based on their experience of running applications at scale, Kubernetes is now maintained by the Cloud Native Computing Foundation. It provides the flexibility of running applications on public cloud platforms, private clouds, or on-premise servers, making it a popular choice for organizations implementing a multi-cloud strategy. It's built to work with a range of container tools, including Docker.
Kubernetes is often referred to as K8s
as a form of abbreviation where numbers are used to shorten a word. In this case, the number 8 stands for the eight letters between the "K" and "s" in Kubernetes. You might also see i18n
for Internationalization, l10n
for Localization, and o11y
for Observability.
In the next few exercises we will explore some of the key concepts behind Kubernetes, starting with building a cluster. This lab starts with the basics and often overlooked topics in the order I wish I started with. e.g. how to access a cluster
Pre-requisities
If you intend to run this lab on your own machine you should have the following installed
- Git
- Minikube
- Docker Desktop
- kubectl
Labs
- Starting Minikube
- Introduction to kubectl
- Starting a Pod -
kubectl run
- Self-healing Kubernetes (not a lab)
- Outsourcing (not a lab)
- Kubernetes Resources (not a lab)
- Deploying an app -
kubectl apply
- Stateless vs Stateful Apps
- Kubernetes Storage (not a lab)
- Troubleshooting
- Stopping Minikube
Getting Started
If you are using Killercoda you will not need to use the minikube tunnel
command. Make sure to look at the instructions for the Killercoda kubectl port-forward
command
- Clone the lab repository to your local machine
Setting up minikube
Minikube is an open-source tool that makes it easy to run Kubernetes locally on your machine. It runs a single-node Kubernetes cluster inside a virtual machine on compute, making it ideal for you to try out Kubernetes or develop and test containerized applications.
- If you haven't already, follow the instructions from the Minikube website to install and start Minikube
https://minikube.sigs.k8s.io/docs/start/
Info
Remember to start Docker Desktop if using docker as driver
- Start Minikube and set the CNI flag to Calico
- Wait for all system pods to be in the
Running 1/1
state
Introduction to kubectl
You can interact with Kubernetes via CLI tool, Kubectl which would be installed on your local machine. Kubectl talks to the Kubernetes API. When starting Minikube, kubectl will automatically be configured to connect to the minikube cluster using the kubeconfig
file.
The kubectl
command-line tool uses kubeconfig
files to find the information it needs to choose a cluster and communicate with the API server of a cluster
https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/
The default local for kubeconfig
is ~/.kube/config
A Kubernetes cluster is made up of a number of control plane and worker nodes.
- View the Kubernetes nodes that make up the cluster
- View more details using the
-o wide
flag
- Describe the nodes to see more details
- You can also describe an individual node (or other Kubernetes resource) using the node name found in the
kubectl get nodes
command.
Info
Namespaces are a logical way to group resources in a cluster into separate spaces
- Take a look at which namespaces exist by default in a Minikube cluster
Info
Pods are the smallest deployable units of computing that you can create and manage in Kubernetes. They contain one or more containers.
- View the pods in the default namespace by using the
-n <namespace name>
flag
- If you don't specify a namespace, the
kubectl
comma will apply to thedefault
namespace
- If you want to search all namespaces you can use the
-A
flag
- View all the Kubernetes system pods which implement the Kubernetes functionality
Starting a Pod - kubectl run
- You can start a pod using the
kubectl run
command and the formatkubectl run NAME --image=image
whereNAME
is what you want to call your pod andimage
is the name of the image you want to run
- Confirm the pod is running
Killercoda
To make this pod accessible from outside the cluster, you need to port-forward.
Minikube
To make this pod accessible from outside the cluster, you need to create a service.
- Check the Kubernetes service has been created. You should see the
EXTERNAL-IP
is in<pending>
status
Minikube has built-in functionality to allow you to access this traffic from the local machine.
- Open a new terminal/cmd instance
-
You might have to wait a few seconds before the tunnel is established. There will be no dynamic output.
-
You should see
Starting tunnel for service firstpod
which indicates the tunnel was established. -
Confirm that the service was created and and an
EXTERNAL-IP
was assigned. You may see127.0.0.1
as the IP address
- Open localhost:8000 in the browser of your choice.
This simple app displays the hostname of the container you are connected to. Since you only have one right now, this won't change when refreshing the page.
- You can now observe the resources
- Clean up the app resources
- Confirm that the resources have been removed
Self-healing Kubernetes
Kubernetes possesses a self-healing property that always tries to ensure that the required number of pods are always running and available. Traffic will only be sent to those resources that are available. This applies not only to pods but many other resources including nodes.
This is known as a control loop and the functionality is implemented by the relevant controller (e.g. node controller). Scroll up to the system pods and notice again there exists a kube-controller-manager
pod which embeds the core control loops.
You may have seen the Ready
and Restarts
fields when viewing the output of a pod. This is Kubernetes watching the state of a cluster, and attempting to move the current state closer to the desired state (i.e. the number of pods required vs the number in a ready state).
Outsourcing
Kubernetes orchestrates pods running across multiple nodes, however it doesn't do this alone. Some functionality such as networking, storage, and actually running a container is outsourced to third party applications. It achieves this through:
Container Networking Interface
or CNI plugin for networkingContainer Storage Interface
or CSI plugin for provisioning underlying storageContainer Runtime Interface
or CRI interface for creating pods
You have already seen two of these when starting Minikube. The CNI Calico
and CRI Docker
. Calico configures the routing table, IP Address Management, and any tunnels or bridges to permit forwarding.
When you deploy a new pod, Kubernetes tells Docker to start a new container matching the specifications you desire. Docker then manages the lifecycle (start, stop, delete) of those containers.
There are many CRI, CSI, and CNIs available, each with their own advantages and disadvantages
Kubernetes Resources
So far you've seen the Kubernetes Pod
however Kubernetes also provides many more resources. Here are a few examples.
You've also seen the concept of a namespace
which allows you to segment resources. You can apply security policies to namespaces to achieve Role Based Access Control.
Deploying an app - kubectl apply
Although you can create and manage resources such as pods through the kubectl command directly, in a real world environment you may want to store this configuration in a file. You can then apply the configuration to the cluster using the kubectl apply -f <my-configuration>.yaml
command.
The resources that you require can be defined in one or more YAML
files. YAML
, which stands for "YAML Ain't Markup Language," is another human-friendly data serialization standard that is often used in configuration files and in applications where data is being stored or transmitted.
When you first see a Kubernetes YAML configuration file it can be overwhelming, however there is a common structure.
Tip
You can use the -o yaml
flag to output in YAML so you don't need to create these files by hand.
Alternatively you can find an example on https://kubernetes.io and use it as a starting point.
This section will again deploy the hostname application (with 2 replicas) but the settings will be stored in a configuration file rather than from the command line.
- Change the directory into the
demo04
folder
-
Look through the files in the folder
hostname-namespace.yaml
hostname-deployment.yaml
hostname-service.yaml
-
Apply the configuration
- You can look at individual resources or all resources together
- Confirm that two pods are running
Info
Your minikube tunnel
session should still be open for this. Start a new one if it is closed, or if it is not working within a few seconds.
In a separate terminal window run minikube tunnel
- Take note of the address and port the app is running on.
-
In your browser open localhost on the port you see in the service we just created
-
Refresh the page on your browser (ctrl/cmd + shift + r) to show change between pods.
Info
Every now and then the hostname should change to show that the LoadBalancer is directing traffic to a new Pod. Caching mechanisms might prevent the page from refreshing properly to see the hostname change.
- If you don't see the hostname change and both hostname pods are running, try
curl http://localhost:port
in your Terminal to see the LoadBalancing mechanism switch between the pods.
-
Edit the
hostname-deployment.yaml
file to have 3 replicas -
Change the number next to
replicas:
to3
and save the file -
Update the configuration on your cluster
You should see an output: deployment.apps/hostname configured
- Confirm that three pods are now running
- Cleanup the resources
Warning
Deleting a namespace will delete all resources within it (it might take some time as the pods terminate)
- Confirm that the resources have been removed
Kubernetes Networking
Since this lab doesn't cover Kubernetes networking concepts in details here are two additional resources on how Kubernetes networking is implemented.
Kubernetes Storage
There are a few important storage related points to be aware of when working Kubernetes
- On-disk files in a container are ephemeral
- Container state is not saved
- When a container crashes or is stopped all files that were created or modified during the lifetime of the container are lost
- During a crash, Kubernetes restarts the container with a clean state
Warning
Don’t forget your to save your work by using persistent volumes!
Stateless vs Stateful Apps
Stateful Sets are like a deployment but:
- Provides guarantees about the ordering and uniqueness of Pods.
- Maintains a sticky identity for each of its Pods
- Each has a persistent identifier that it maintains across any rescheduling.
- Identifiers make it easier to match existing volumes to new Pods that replace any that have failed
Let's now deploy a stateful application and observe what happens when pods are deleted
- Change directory into
demo05
-
Look at
message-board-all-in-one.yaml
-
Apply the configuration
- Check the resources were created
- Watch the resources as they're created by using the
-w
flag
-
Wait for the pod to be
running
-
Once the pods are running, press
ctrl + c
to go back.
Killercoda
First update the message-board-all-in-one.yaml. Change the from storageClassName: standard
to storageClassName: local-path
To make this pod accessible from outside the cluster, you need to port-forward.
Info
Your minikube tunnel
session should still be open for this. Start a new one if it is closed, or if it is not working within a few seconds.
In a separate terminal window run minikube tunnel
-
Open localhost:5000
-
Sign up to the message board, log in, and write a message
-
Refresh the page and confirm that the message still remains
-
Delete the pod, confirm it was deleted and that a new one is starting
-
Reload the page
-
Confirm that the message is still there.
Info
This is because the message was saved in a Persistent Volume, which gets attached to the pod.
- Cleanup the resources
- Confirm that the resources have been removed
Troubleshooting
This last section will provide and introduction into some common errors you may see when deploying applications to a Kubernetes cluster. It is by no means and extensive list of errors or troubleshooting steps.
Following Pod Logs
- If the
minikube tunnel
from previous sections was closed then open a new one
- Create a new Nginx pods
- Confirm the pod is running
Killercoda
To make this pod accessible from outside the cluster, you need to port-forward.
Minikube
To make this pod accessible from outside the cluster, you need to create a service.
Access a browser on http://localhost:30001
and refresh the page a couple of times. You should see the Nginx welcome page
- Watch the Nginx logs as you access a browser
-
Go back to your terminal and confirm you can see the logs updating as you refresh the page
-
Cleanup the resources
- Confirm that the resources have been removed
Troubleshooting Image and Storage Errors
- Change directory into
demo06
-
Look at
message-board-all-in-one-troubleshooting.yaml
-
Apply the configuration
- Check if the pods have started
Question
If the pod is not in running
status check the events for any errors. What do you find?
- Check the storage has been provisioned
Question
If the status is pending
check the events for errors. What do you find?
- Cleanup the resources
- Confirm that the resources have been removed
Stopping Minikube
- If you are finished with the lab you can stop the cluster
-
This stops the minikube cluster, but retains the state for when you start the cluster again via
minikube start
. -
To completely delete the cluster you can run
minikube delete
Resources
Official Kubernetes.io CheatSheet Page