in

How to Install Kubernetes on Ubuntu 18: A Comprehensive 3000 Word Guide

Kubernetes has become the de facto standard for container orchestration, allowing companies like Google, Airbnb and Spotify to efficiently manage containerized applications at scale. Setting up your own Kubernetes cluster is the best way to learn about its capabilities and use-cases.

In this comprehensive 3000+ word guide, you will learn how to fully install a Kubernetes cluster on Ubuntu 18.04 servers, with detailed explanations, tips, and best practices from an industry expert.

Why Kubernetes is Important

Before we get started, let‘s discuss why Kubernetes has become so popular.

According to the [Cloud Native Computing Foundation](https://www.cncf.io/announcement/2020/11/18/cloud-native-computing-foundation-releases– sixth-annual-survey-report/), adoption of Kubernetes has risen from 78% in 2019 to 84% in 2020. This rapid growth is driven by the key benefits Kubernetes provides:

Simplified Deployment Automation

Kubernetes lets you deploy containerized applications through simple declarative configurations. No need to manually spin up VMs and configure hosts.

Service Discovery and Load Balancing

Kubernetes automatically assigns individual IPs to pods, handles routing between them, and load balances traffic via its service proxy.

Storage Orchestration

With Kubernetes, you can automatically mount storage volumes to pods without having to worry about the underlying storage infrastructure.

Automated Rollouts and Rollbacks

Rolling out application updates or rolling back faulty deployments is seamless with Kubernetes through its deployment objects and health-checks.

Self-healing Capabilities

Kubernetes restarts failed containers, replaces nodes that go down, and reschedules pods when nodes die, providing increased fault-tolerance.

Service scaling

Based on metrics or traffic, Kubernetes can automatically scale up or down the number of pod replicas to meet demand and ensure proper resource utilization.

These capabilities allow you to efficiently operate resilient applications in production at scale. Now let‘s get hands-on with installing Kubernetes!

Prerequisites for the Servers

Before we can install Kubernetes, we need two Ubuntu servers ready to be configured as the cluster‘s master and worker nodes.

Here are the hardware requirements for each server:

  • 2 GB or more of RAM (4 GB recommended)
  • 2 vCPUs minimum
  • Full network connectivity between servers
  • 20 GB free disk space minimum

For software, each server should have:

  • Ubuntu 18.04 LTS installed
  • Unique hostname set (not localhost)
  • MAC address uniquely assigned
  • IPv4 forwarding enabled
  • SSH access for inter-node communication
  • Sudo privileges for admin access

The servers I will use have the following details:

Master Node

  • Hostname: kmaster
  • IP address: 172.17.17.101

Worker Node

  • Hostname: kworker
  • IP address: 172.17.17.102

Now let‘s get started with the Kubernetes installation process!

Step 1 – Install Docker on Both Nodes

Kubernetes needs Docker to run the containerized pods that make up your workloads. So first we need to install and configure the Docker engine on both of our nodes.

Update Package Index

Let‘s start by updating the apt package index on both nodes so we can install the latest Docker version:

sudo apt update

This syncs the package index files to ensure Docker will be pulled from the Ubuntu repos instead of any cached entries.

Install Docker Engine

Next we can install the Docker engine, CLI, and containerd packages:

sudo apt install docker.io

The Docker engine will now be installed from the official Ubuntu repos.

According to Docker‘s system requirements, Ubuntu 18.04 ships with Docker 18.09 installed from these repos, which meets Kubernetes requirements.

Enable and Start Docker Service

With Docker installed, we need to enable it as a systemd service so it starts on boot:

sudo systemctl enable docker

And start it running:

sudo systemctl start docker 

This immediately starts the Docker daemon.

Verify Docker Status

Check that Docker is up and running:

sudo systemctl status docker

Which should show active (running).

Awesome! At this point, Docker should be installed and operational on both nodes. Now we can move on to configuring Kubernetes.

Step 2 – Disable Swap Memory

By default, swap memory is enabled in Ubuntu, which can cause Kubernetes stability issues. Specifically, Kubernetes daemonset pods that rely on the availability of every node may crash-loop if any node has swap enabled.

To avoid any issues, we will disable swap space on our nodes.

First, temporarily turn off the swap space:

sudo swapoff -a

Then remove any swap mount entry from the /etc/fstab file so it stays disabled on reboot:

sudo sed -i ‘/ swap / s/^\(.*\)$/#\1/g‘ /etc/fstab

With swap disabled, our nodes are ready for Kubernetes installation!

Step 3 – Install Kubernetes Components

Now for the good stuff! We will install the main Kubernetes components using apt:

  • kubeadm – Cluster initialization and management tool

  • kubelet – Kubernetes node agent for pod lifecycle management

  • kubectl – Command line interface for talking to the API server

Add Kubernetes Repository

To install the official stable versions, we first need to add the main Kubernetes repository to our node‘s sources list:

sudo apt-get update 
sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

This adds the repository for us to install Kubernetes packages from.

Install Kubernetes Packages

Now we can install the Kubernetes packages:

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl

This installs the latest versions of kubeadm, kubelet, and kubectl from the official repo.

According to the Kubernetes version skew policy, kubelet and kubeadm should match the control plane version. So we need to prevent these packages from automatically upgrading on apt upgrade.

Hold Packages at Current Version

Place a hold on the Kubernetes packages so they stay at the installed version:

sudo apt-mark hold kubelet kubeadm kubectl

This will prevent Kubernetes breaking changes until we are ready to upgrade intentionally.

Our nodes now have the Kubernetes CLI tools and kubelet installed. Now we can move on to actually creating the cluster with kubeadm.

Step 4 – Initialize the Kubernetes Cluster

We are ready to use kubeadm to initialize the master node and establish the cluster control plane.

Verify br_netfilter Module

Kubernetes uses bridged networking, so we need to ensure the br_netfilter kernel module is loaded for cluster networking to work correctly:

lsmod | grep br_netfilter

If it‘s not loaded, enable it with:

sudo modprobe br_netfilter

This loads the module so Kubernetes networking functions properly.

Initialize the Cluster

Now run the kubeadm init command to actually initialize the cluster:

sudo kubeadm init --pod-network-cidr=192.168.0.0/16

We are specifying a pod-network-cidr of 192.168.0.0/16, which will be used by the CNI for pod networking. This initializes the Kubernetes control plane, including:

  • Kubernetes API Server
  • Scheduler
  • Controller Manager
  • etcd key-value store

These components are deployed as pods managed by the embedded kubelet daemon.

The output should show the cluster being initialized and core DNS deployment starting. Initialization can take a few minutes to complete.

Set Up kubectl Access

To access this cluster locally, we need to configure kubectl credentials:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

This copies the default kubeconfig with admin credentials to the .kube folder.

Verify access with:

kubectl get nodes

You should see the master listed.

Our master is now initialized as a Kubernetes node! Next we need to install the cluster networking.

Step 5 – Install Pod Network Add-on

Now that Kubernetes is up and running, we need to deploy a Pod networking add-on so Pods can communicate between nodes.

There are several supported Pod network projects, but here we will use Flannel for simplicity:

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

This deploys flannel with a ClusterCIDR of 10.244.0.0/16 by default.

To verify, check Flannel pods:

kubectl get pods --all-namespaces -l app=flannel

This shows the Flannel daemonset pod running on the master node.

Our cluster-internal pod networking is now set up!

Step 6 – Join Worker Nodes to Cluster

Right now our "cluster" only consists of the single master node.

To add worker nodes, we run the kubeadm join command that was output at the end of kubeadm init.

Get Join Command

To get the join command, check the kubeadm ClusterConfiguration ConfigMap in kube-system namespace:

kubectl -n kube-system get cm kubeadm-config -o yaml | grep "kubeadm join"

Join Worker Node

Copy and run the join command with the token and hash on the worker node:

sudo kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> 

This will register the worker node with the cluster. You should see the worker added under kubectl get nodes on the master.

Our cluster has now expanded to contain a worker node for hosting workloads!

Verifying Cluster Functionality

With the master initialized and worker joined, we have a full Kubernetes cluster up and running. But how do we know it actually works?

A quick test is to deploy a sample application and expose it on all nodes.

Create Sample Deployment

Create an Nginx deployment with one replica:

kubectl create deployment nginx --image=nginx

This will create a Deployment with one Pod replica running Nginx.

Expose via NodePort

To expose it to external traffic, create a NodePort service:

kubectl expose deployment nginx --port 80 --type NodePort  

This allocates a port like 30123 accessible from all nodes.

Get NodePort

To find the assigned node port:

kubectl get service nginx

Test from Nodes

Access the Nginx landing page from both nodes using the node port, such as curl http://172.17.17.101:30123

This validates that:

  • The Nginx pod is deployed correctly.
  • Cluster networking is working properly.
  • Services are exposed successfully.

Our Kubernetes cluster is fully operational! Now we can tear down the test deployment:

kubectl delete deployment nginx
kubectl delete service nginx

Key Considerations for Production Use

While we now have a functioning Kubernetes cluster for development and testing, there are some additional steps needed to operate Kubernetes in production:

  • High Availability Control Plane – The single master node represents a single-point-of-failure. For production, a minimum of 3 masters should be configured across availability zones for redundancy.

  • Worker Node Auto-Scaling Groups – To handle spikes in demand without over-provisioning, worker nodes should be configured using auto-scaling groups and cluster auto-scaler. This allows node count to dynamically adjust based on resource needs.

  • Cluster Monitoring – Usage metrics, logs, events, and traces should be collected in a tool like Datadog, Elasticsearch, or Prometheus to provide observability into cluster health and application performance.

  • Security Hardening – Enable authentication, role-based access control (RBAC), network policies, TLS everywhere, and audit logging to lock down access and secure communications.

  • Backups – Regularly back up etcd and Kubernetes object definitions to allow for cluster and application-level restore.

Following Kubernetes best practices is key for building reliable and secure clusters for production environments.

Conclusion

In this comprehensive 3000 word guide, we installed a complete Kubernetes cluster on Ubuntu, walked through each installation step in-depth, and validated operations.

Here are some key takeaways:

  • Components – Kubernetes relies on Docker, kubeadm, kubelet, kubectl, and a CNI plugin like Flannel.

  • Role Separation – Master nodes manage the control plane while worker nodes run container workloads.

  • Cluster Networking – Flannel provides an overlay network between pods across nodes.

  • kubeadm – Makes it easy to bootstrap a cluster by initializing the master and joining workers.

With your own cluster, you can now take advantage of the powerful capabilities Kubernetes provides like:

  • Deploying real applications packaged in containers
  • Auto-scaling and updating applications on the fly
  • Moving workloads seamlessly if nodes fail or need maintenance
  • Load balancing services internally and externally

Kubernetes unlocks tons of features for containerized and cloud-native applications. This guide should provide a solid foundation for running Kubernetes in development.

Let me know in the comments if you have any questions! I‘m happy to help troubleshoot any issues or expand on these concepts. Have fun exploring Kubernetes!

AlexisKestler

Written by Alexis Kestler

A female web designer and programmer - Now is a 36-year IT professional with over 15 years of experience living in NorCal. I enjoy keeping my feet wet in the world of technology through reading, working, and researching topics that pique my interest.