Kubeflow for Poets · Part 5 of 8
Kubernetes
27 March 2019Updated 14 October 20269 min read
This part explains the components of a Kubernetes cluster and the objects in a deployment file. It deploys an nginx web server on a local Minikube cluster and on Google Kubernetes Engine.
When a microservice application runs in production, it usually has many running containers. Each container needs the right amount of resources as user demand changes. The containers must also stay online and be able to communicate with one another. Kubernetes grew out of the need to manage and coordinate clusters of containerized applications.
Kubernetes is a software system that deploys, scales and monitors containers. For this reason it is called a container orchestrator. Other container orchestrators include Docker Swarm and HashiCorp Nomad.
Google built Kubernetes and released it as open-source software. The Cloud Native Computing Foundation (CNCF) now manages the project. Google Cloud offers a managed Kubernetes service called Google Kubernetes Engine (GKE). Amazon Elastic Kubernetes Service (EKS) is another managed Kubernetes service.
Features of Kubernetes
- Horizontal autoscaling: adds or removes pod replicas based on resource use.
- Self-healing: restarts containers that crash or fail their health checks. When a node dies, Kubernetes creates replacement pods on healthy nodes.
- Load balancing: distributes requests across the pods behind a Service.
- Rollouts and rollbacks: updates a deployment to a new container image, or reverts to a previous version, without application downtime.
- DNS service discovery: gives each Service a DNS name so that other pods can find it.
Components of Kubernetes
A Kubernetes cluster has two main parts:
- Control plane: manages the cluster. Older documentation calls the machines that run it master nodes. In a high-availability setup, the control plane runs on several machines for fault tolerance.
- Worker nodes: the machines that run containerized applications. Applications are scheduled onto nodes as pods.
The illustration below gives an overview of the Kubernetes architecture. We briefly go through each component next.
Control Plane
- etcd: a consistent and highly available key-value store that holds the state of the cluster. It can run on the control plane machines or on separate machines.
- kube-apiserver: exposes the Kubernetes API and handles all administrative tasks. It receives requests from users through the
kubectlcommand-line tool, REST calls or a web UI. It validates each request and stores the new cluster state in etcd. - kube-scheduler: assigns new pods to suitable worker nodes based on the resources they need.
- kube-controller-manager: runs the controllers that keep the current state of the cluster in line with the desired state. You declare the desired state in a YAML or JSON file.
- cloud-controller-manager: an optional component that connects the cluster to the API of a cloud provider.
Worker Nodes
- kubelet: an agent that runs on each node. It connects the node to the API server, receives instructions from it and makes sure that the containers in each pod are running and healthy.
- kube-proxy: a network proxy that runs on each node. It maintains the network rules that route traffic for a Service to the right pods.
- Container runtime: the software that runs the containers, such as containerd.
- Pods: a pod holds one or more containers that share network and storage resources. A pod is the smallest deployable unit in Kubernetes.
Writing a Kubernetes Deployment File
A deployment file declares the desired state of Kubernetes objects. Examples of Kubernetes objects are:
- Pod: a group of one or more containers.
- ReplicaSet: keeps a specified number of replicas of a pod running at any given time.
- Deployment: creates and manages ReplicaSets. It updates pods in a controlled way and makes the current state of the application match the desired state.
- Namespace: divides a cluster into virtual sub-clusters, for example one for each team or project.
- Service: exposes a group of pods as a network service with a stable address and a policy for reaching them.
- Service types: the type sets how the Service is exposed. The types are
ClusterIP,NodePort,LoadBalancerandExternalName. For example,LoadBalancerexposes the Service outside the cluster through a cloud provider's load balancer.
- Service types: the type sets how the Service is exposed. The types are
Other important fields in a deployment file are:
- apiVersion and kind: the API version and the type of the object.
- metadata: information about the object, such as its name and labels.
- spec: the desired state of the object.
- labels: key-value pairs that describe an object.
- selector: picks a set of objects by their labels.
Deployment files are usually written in YAML.
The example below deploys the nginx web server image that we pushed to Docker Hub in the previous part. The image is available at hub.docker.com/r/ekababisong/ebisong-nginx-server. The deployment file is in the kubernetes-intro folder of the source repository.
The image on Docker Hub was built for the amd64 processor architecture. On a machine with an Arm processor, such as a Mac with Apple silicon, build the image from the Dockerfile in the previous part. Push it under your own Docker Hub username and use that image name in the deployment file.
The Deployment File
The file kubernetes-intro/deployment.yaml holds two objects. A line of three dashes (---) separates them. The first object is a Service and the second is a Deployment.
yamlapiVersion: v1 kind: Service metadata: name: nginx-server-service spec: # the service sends traffic to pods with the label app: nginx-server selector: app: nginx-server ports: - protocol: TCP # port inside the cluster port: 8080 # port on the container inside the pod targetPort: 80 # port on each node, reachable from outside the cluster nodePort: 30001 # expose the service through a load balancer type: LoadBalancer --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-server-deployment spec: # run 5 replicas of the pod replicas: 5 selector: matchLabels: app: nginx-server template: metadata: labels: app: nginx-server spec: containers: - name: nginx-server image: ekababisong/ebisong-nginx-server ports: - containerPort: 80
The Deployment uses the apps/v1 API. Kubernetes stopped serving the older extensions/v1beta1 API for Deployments in version 1.16. In apps/v1, the selector field is required and must match the labels in the pod template.
Running Kubernetes on a Local Machine with Minikube
Minikube runs a local Kubernetes cluster on your machine. It needs at least 2 CPUs, 2 GB of free memory, 20 GB of free disk space and a container or virtual machine manager such as Docker, Podman or VirtualBox.
-
Install a container manager such as Docker. We installed Docker in the previous part.
-
Install
kubectl, the Kubernetes command-line tool. The Install Tools page covers Linux, macOS and Windows. On macOS with Homebrew, run:bashbrew install kubectlCheck the installed version:
bashkubectl version --client -
Install Minikube. On macOS with Homebrew, run:
bashbrew install minikubeOn Linux (x86-64), download the binary and install it:
bashcurl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64
Overview of Minikube Commands
| Command | Description |
|---|---|
minikube status |
Check whether Minikube is running. |
minikube start |
Create and start a local Kubernetes cluster. |
minikube stop |
Stop the local Kubernetes cluster. |
minikube delete |
Delete the local Kubernetes cluster. |
minikube dashboard |
Open the Kubernetes Dashboard in a browser. |
minikube ip |
Print the IP address of the cluster node. |
minikube service [SERVICE_NAME] --url |
Print a URL for reaching a NodePort Service from the local machine. |
minikube tunnel |
Create a network route so that LoadBalancer Services get an external IP. |
The Kubernetes Dashboard project was archived in January 2026 and is no longer maintained. Its maintainers suggest Headlamp as a web UI for Kubernetes. In this part we work with kubectl.
Overview of kubectl Commands
| Command | Description |
|---|---|
kubectl get all |
List the common resources in the current namespace. |
kubectl get pods |
List pods. |
kubectl get services |
List services. |
kubectl get deployments --all-namespaces |
List deployments in all namespaces. |
kubectl get nodes |
List the nodes of the cluster. |
kubectl apply -f [DEPLOYMENT_FILE.yaml] |
Create the resources in the file, or update them if they already exist. |
kubectl create -f [DEPLOYMENT_FILE.yaml] |
Create the resources in the file. The command fails if they already exist. |
kubectl delete -f [DEPLOYMENT_FILE.yaml] |
Delete the resources in the file. |
kubectl delete deployment [DEPLOYMENT_NAME] |
Delete the deployment named [DEPLOYMENT_NAME]. |
kubectl delete service [SERVICE_NAME] |
Delete the service named [SERVICE_NAME]. |
kubectl delete pod [POD_NAME] |
Delete the pod named [POD_NAME]. |
Deploying to Minikube with kubectl
Start a local cluster. Minikube also configures kubectl to use the new cluster.
bash# create and start a local kubernetes cluster minikube start
Create the resources in the deployment file.
bash# move to the folder with the deployment file cd kubernetes-intro/ # create the service and the deployment kubectl apply -f deployment.yaml
textservice/nginx-server-service created deployment.apps/nginx-server-deployment created
List the pods. The output shows five pods whose names begin with nginx-server-deployment. Each pod shows the status Running once its container starts.
bash# list pods kubectl get pods
Running the Web Page on Pods Orchestrated by Kubernetes
Ask Minikube for a URL to the Service:
bash# print a url for the service minikube service nginx-server-service --url
Open the printed URL in a browser to see the web page. On Linux, the URL points to the node IP and port 30001. With the Docker driver on macOS or Windows, Minikube opens a tunnel and prints a local address instead. Keep that terminal open while you use the page.
Delete the Deployment and Stop Minikube
bash# delete the service and the deployment kubectl delete -f deployment.yaml # stop the local cluster minikube stop
Deploying to Google Kubernetes Engine
To create resources on Google Cloud from a local shell, install and initialize the Google Cloud CLI. Then install kubectl and the GKE authentication plugin. kubectl needs the plugin to connect to GKE clusters.
bash# install kubectl and the gke authentication plugin gcloud components install kubectl gcloud components install gke-gcloud-auth-plugin
A simpler option is Google Cloud Shell. It runs in the browser and already has gcloud and kubectl installed.
Creating a GKE Cluster
GKE has two modes of operation. In Autopilot mode, Google manages the nodes and their configuration. In Standard mode, you create and manage the nodes yourself. Google recommends Autopilot unless you need the extra control of Standard mode. See Choose a GKE mode of operation for details.
We create an Autopilot cluster in the us-central1 region. Replace [PROJECT_ID] with your project ID.
bash# set the default project gcloud config set project [PROJECT_ID] # enable the kubernetes engine api gcloud services enable container.googleapis.com # create an autopilot cluster gcloud container clusters create-auto ekaba-gke-cluster \ --location=us-central1
The command takes a few minutes. When it finishes, gcloud adds the cluster credentials to your kubectl configuration. To fetch the credentials again later, for example from another machine, run:
bash# configure kubectl to use the gke cluster gcloud container clusters get-credentials ekaba-gke-cluster \ --location=us-central1
To learn more, see Create an Autopilot cluster.
bash# list the nodes of the cluster kubectl get nodes
An Autopilot cluster adds nodes when pods need them. The node list can be short or empty before you deploy anything.
Deploy the nginx Web Server on GKE
bash# move to the folder with the deployment file cd kubernetes-intro/ # create the service and the deployment kubectl apply -f deployment.yaml
textservice/nginx-server-service created deployment.apps/nginx-server-deployment created
The Workloads and Services pages of the Kubernetes Engine section in the Google Cloud console show the deployment, its pods and the Service.
List the pods:
bash# list pods kubectl get pods
The five pods reach the status Running after Autopilot provisions nodes for them. This can take a few minutes.
Get the External IP of the Service
bash# list services kubectl get services
The nginx-server-service row has the type LoadBalancer. Its EXTERNAL-IP column shows <pending> until Google Cloud creates the load balancer. Then it shows a public IP address. The PORT(S) column shows 8080:30001/TCP.
Application Running on GKE
Open http://[EXTERNAL_IP]:8080 in a browser. Use the external IP from the previous command.
Delete the Deployment on GKE
bash# delete the service and the deployment kubectl delete -f deployment.yaml
Delete the GKE Cluster
The cluster costs money while it runs. Delete it when you are done.
bash# delete the gke cluster gcloud container clusters delete ekaba-gke-cluster \ --location=us-central1
gcloud asks you to confirm before it deletes the cluster.

Ekaba Bisong is a Ph.D. researcher at the University of Victoria and the founder of SiliconBlast. More about me