How to Deploy Kubernetes Cluster

How to Deploy Kubernetes Cluster Kubernetes has become the de facto standard for container orchestration in modern cloud-native environments. Whether you're managing microservices, scaling applications dynamically, or deploying across hybrid and multi-cloud infrastructures, Kubernetes provides the automation, resilience, and flexibility required to run production-grade workloads efficiently. Deplo

Oct 30, 2025 - 12:21
Oct 30, 2025 - 12:21
 0

How to Deploy Kubernetes Cluster

Kubernetes has become the de facto standard for container orchestration in modern cloud-native environments. Whether you're managing microservices, scaling applications dynamically, or deploying across hybrid and multi-cloud infrastructures, Kubernetes provides the automation, resilience, and flexibility required to run production-grade workloads efficiently. Deploying a Kubernetes cluster, however, is not a trivial taskit requires understanding of infrastructure, networking, security, and operational best practices. This comprehensive guide walks you through every critical phase of deploying a Kubernetes cluster, from planning and setup to optimization and troubleshooting. By the end of this tutorial, you will have the knowledge and confidence to deploy a secure, scalable, and production-ready Kubernetes cluster using industry-standard tools and methodologies.

Step-by-Step Guide

1. Understand Your Requirements and Choose the Right Deployment Model

Before you begin deploying a Kubernetes cluster, it's essential to define your use case and infrastructure constraints. Kubernetes can be deployed in multiple ways:

  • On-premises Using bare metal servers or virtual machines within your data center.
  • Cloud-managed Leveraging managed Kubernetes services like Amazon EKS, Google GKE, or Azure AKS.
  • Self-managed Installing and maintaining Kubernetes yourself using tools like kubeadm, kubespray, or RKE.

For learning and small-scale deployments, managed services offer simplicity and reduced operational overhead. For full control, compliance, or cost optimization, self-managed clusters are preferred. This guide focuses on deploying a self-managed cluster using kubeadm, the official Kubernetes tool for bootstrapping clusters, because it provides the most educational value and is widely adopted in enterprise environments.

2. Prepare Your Infrastructure

A typical Kubernetes cluster consists of at least one control plane node and one or more worker nodes. For a minimal production-like setup, we recommend:

  • 3 control plane nodes (for high availability)
  • 3 worker nodes (for workload distribution)

Each node should meet the following minimum requirements:

  • 2 vCPUs
  • 2 GB RAM
  • 20 GB disk space
  • Ubuntu 20.04 or 22.04 LTS (recommended)
  • Static IP addresses assigned to each node
  • Full network connectivity between all nodes (ports 6443, 23792380, 10250, 10251, 10252 must be open)

Ensure that each node has a unique hostname. Set hostnames using:

sudo hostnamectl set-hostname control-plane-01

sudo hostnamectl set-hostname worker-01

Update your /etc/hosts file on all nodes to map IP addresses to hostnames:

192.168.1.10 control-plane-01

192.168.1.11 control-plane-02

192.168.1.12 control-plane-03

192.168.1.20 worker-01

192.168.1.21 worker-02

192.168.1.22 worker-03

3. Install Container Runtime (containerd)

Kubernetes requires a container runtime to manage containers. While Docker was once the default, Kubernetes now supports any CRI-compliant runtime. containerd is the recommended choice due to its lightweight nature and direct integration with the Kubernetes CRI.

On all nodes, run the following commands:

sudo apt update

sudo apt install -y containerd

sudo mkdir -p /etc/containerd

containerd config default | sudo tee /etc/containerd/config.toml

sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml

sudo systemctl restart containerd

sudo systemctl enable containerd

Verify containerd is running:

sudo systemctl status containerd

4. Disable Swap

Kubernetes does not support swap memory because it interferes with the schedulers ability to make resource allocation decisions. Disable swap permanently:

sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/

\1/g' /etc/fstab

5. Install Kubernetes Components

Install the Kubernetes binaries: kubeadm, kubelet, and kubectl.

Add the Kubernetes GPG key and repository:

sudo apt-get update

sudo apt-get install -y apt-transport-https ca-certificates curl

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

Install the components:

sudo apt-get update

sudo apt-get install -y kubelet kubeadm kubectl

sudo apt-mark hold kubelet kubeadm kubectl

Verify installation:

kubeadm version

kubectl version --client

6. Initialize the Control Plane

On the first control plane node (e.g., control-plane-01), initialize the cluster using kubeadm:

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

This command performs multiple tasks:

  • Generates certificates for secure communication
  • Sets up the API server, scheduler, and controller manager
  • Configures etcd for distributed state storage
  • Creates kubeconfig files for admin and kubelet access

Upon successful completion, youll see output similar to:

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

Follow the instructions to configure kubectl for your user:

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

Verify the control plane is running:

kubectl get nodes

At this stage, the node will show as NotReady because the network plugin hasnt been installed yet.

7. Deploy a Pod Network Add-on

Kubernetes requires a Container Network Interface (CNI) plugin to enable communication between pods across nodes. Popular options include Calico, Flannel, and Cilium.

We recommend Calico for production environments due to its performance, network policy enforcement, and scalability.

Apply Calico:

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml

Wait a few moments and verify that all pods in the kube-system namespace are running:

kubectl get pods -n kube-system

You should see calico-node, kube-apiserver, kube-controller-manager, kube-scheduler, and kube-proxy in a Running state.

8. Join Worker Nodes to the Cluster

On each worker node, run the kubeadm join command displayed in the output of kubeadm init. It will look like:

sudo kubeadm join 192.168.1.10:6443 --token abcdef.1234567890abcdef \

--discovery-token-ca-cert-hash sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef

If you lost the join command, regenerate it on the control plane node:

kubeadm token create --print-join-command

Run the generated command on each worker node. After a few seconds, check from the control plane:

kubectl get nodes

All nodes should now show as Ready.

9. Verify Cluster Health

Run the following commands to validate cluster health:

  • kubectl get nodes -o wide Check node status and IPs
  • kubectl get pods --all-namespaces Ensure all system pods are running
  • kubectl cluster-info Confirm API server endpoint
  • kubectl describe nodes Inspect resource allocation and conditions

For deeper diagnostics, install kube-state-metrics and metrics-server to enable horizontal pod autoscaling and resource monitoring:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Verify metrics-server is working:

kubectl top nodes

kubectl top pods -A

10. Deploy a Test Application

To confirm your cluster is fully functional, deploy a simple Nginx application:

kubectl create deployment nginx --image=nginx:latest

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

kubectl get services

Access the application by visiting http://<worker-node-ip>:<node-port> in your browser. You should see the Nginx welcome page.

Best Practices

1. Use Role-Based Access Control (RBAC) Strictly

Never use the default cluster-admin role for daily operations. Create granular roles and bind them to service accounts or users based on the principle of least privilege. For example:

kubectl create role pod-reader --verb=get,list --resource=pods

kubectl create rolebinding read-pods --role=pod-reader --user=alice

Use Kubernetes namespaces to isolate teams, environments, or applications. Avoid deploying everything in the default namespace.

2. Secure the API Server

Ensure the Kubernetes API server is not exposed to the public internet. Use firewall rules, private networks, and VPNs for administrative access. Enable audit logging:

sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml

Add these flags:

--audit-log-path=/var/log/kube-apiserver-audit.log

--audit-policy-file=/etc/kubernetes/audit-policy.yaml

Use TLS certificates issued by a trusted CA, not self-signed ones, especially in production.

3. Harden Node Security

Disable root login over SSH. Use SSH key-based authentication only. Apply the CIS Kubernetes Benchmark guidelines:

  • Disable unnecessary services
  • Use AppArmor or SELinux
  • Regularly update OS and Kubernetes components
  • Limit kernel parameters (e.g., disable IP forwarding unless needed)

4. Manage Secrets Securely

Never store secrets (passwords, API keys, tokens) in plain text within manifests. Use Kubernetes Secrets, but remember they are base64-encoded, not encrypted. For true encryption, use:

  • External Secret Stores HashiCorp Vault, AWS Secrets Manager
  • Secrets Encryption at Rest Enable in kube-apiserver using a Key Management Service (KMS)

Example: Enable encryption in /etc/kubernetes/manifests/kube-apiserver.yaml:

--encryption-provider-config=/etc/kubernetes/encryption-config.yaml

Create /etc/kubernetes/encryption-config.yaml:

apiVersion: apiserver.config.k8s.io/v1

kind: EncryptionConfiguration

resources:

- resources:

- secrets

providers:

- aescbc:

keys:

- name: key1

secret: c2VjcmV0X2tleV93aXRoXzMyX2J5dGVzX211c3RfYmVfYmFzZTY0X2VuY29kZWRfYXNfY29udGFpbmVk

- identity: {}

5. Implement Resource Limits and Requests

Always define resources.requests and resources.limits in your deployments. This prevents resource starvation and enables the scheduler to make intelligent placement decisions.

resources:

requests:

memory: "64Mi"

cpu: "250m"

limits:

memory: "128Mi"

cpu: "500m"

6. Use Liveness and Readiness Probes

Configure probes to ensure your applications are healthy and ready to serve traffic:

livenessProbe:

httpGet:

path: /healthz

port: 8080

initialDelaySeconds: 30

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: 8080

initialDelaySeconds: 5

periodSeconds: 5

7. Automate Backups of etcd

etcd stores the entire state of your cluster. Regular backups are critical. Use kubeadms built-in backup tool:

sudo ETCDCTL_API=3 etcdctl \

--endpoints=https://127.0.0.1:2379 \

--cacert=/etc/kubernetes/pki/etcd/ca.crt \

--cert=/etc/kubernetes/pki/etcd/server.crt \

--key=/etc/kubernetes/pki/etcd/server.key \

snapshot save /backup/etcd-snapshot-db

Automate this with a cron job and store snapshots off-node.

8. Monitor and Log Everything

Deploy a full observability stack:

  • Metrics Prometheus + Grafana
  • Logging Fluentd + Elasticsearch + Kibana (EFK) or Loki
  • Tracing Jaeger or Tempo

Use tools like kubectl top, kubectl describe, and kubectl logs for quick diagnostics, but rely on centralized systems for long-term analysis.

Tools and Resources

Core Tools

  • kubeadm Official tool for bootstrapping clusters. Ideal for learning and production.
  • kubectl Command-line interface for interacting with the cluster.
  • containerd Lightweight, production-ready container runtime.
  • Calico High-performance CNI with network policy support.
  • etcd Distributed key-value store for cluster state.

Infrastructure as Code (IaC)

For repeatable, version-controlled deployments, use:

  • Terraform Provision VMs, networks, and load balancers across cloud providers.
  • Ansible Automate configuration of nodes (e.g., installing containerd, disabling swap).
  • Kustomize Customize Kubernetes manifests without templates.
  • Helm Package and deploy applications using charts (e.g., Prometheus, WordPress).

Managed Kubernetes Services

If you prefer to offload operational complexity:

  • Amazon EKS Fully managed, integrates with AWS IAM and VPC.
  • Google GKE Best-in-class autoscaling, security, and monitoring.
  • Azure AKS Tight integration with Azure Active Directory and Monitor.
  • Red Hat OpenShift Enterprise-grade with built-in CI/CD and developer portal.

Learning Resources

Security and Compliance Tools

  • Kube-Bench Checks your cluster against CIS benchmarks.
  • Kube-Hunter Penetration testing tool for Kubernetes clusters.
  • Trivy Scans container images for vulnerabilities.
  • OPA Gatekeeper Enforces policies using Open Policy Agent.

Real Examples

Example 1: Deploying a Multi-Tier Application on Kubernetes

Lets walk through deploying a real-world application: a blog platform with WordPress (frontend) and MySQL (database).

Create a namespace:

kubectl create namespace blog

Deploy MySQL with persistent storage:

apiVersion: v1

kind: Secret

metadata:

name: mysql-secret

namespace: blog

type: Opaque

data: password: bXlwYXNzd29yZA==

"mysqlpassword" in base64

---

apiVersion: v1

kind: Service

metadata:

name: mysql

namespace: blog

spec:

selector:

app: mysql

ports:

- protocol: TCP

port: 3306

targetPort: 3306

type: ClusterIP

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: mysql

namespace: blog

spec:

selector:

matchLabels:

app: mysql

replicas: 1

template:

metadata:

labels:

app: mysql

spec:

containers:

- name: mysql

image: mysql:8.0

env:

- name: MYSQL_ROOT_PASSWORD

valueFrom:

secretKeyRef:

name: mysql-secret

key: password

ports:

- containerPort: 3306

volumeMounts:

- name: mysql-persistent-storage

mountPath: /var/lib/mysql

volumes:

- name: mysql-persistent-storage

persistentVolumeClaim:

claimName: mysql-pv-claim

---

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

name: mysql-pv-claim

namespace: blog

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 20Gi

Deploy WordPress:

apiVersion: v1

kind: Service

metadata:

name: wordpress

namespace: blog

spec:

selector:

app: wordpress

ports:

- protocol: TCP

port: 80

targetPort: 80

type: LoadBalancer

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: wordpress

namespace: blog

spec:

selector:

matchLabels:

app: wordpress

replicas: 2

template:

metadata:

labels:

app: wordpress

spec:

containers:

- name: wordpress

image: wordpress:latest

ports:

- containerPort: 80

env:

- name: WORDPRESS_DB_HOST

value: mysql:3306

- name: WORDPRESS_DB_PASSWORD

valueFrom:

secretKeyRef:

name: mysql-secret

key: password

volumeMounts:

- name: wordpress-persistent-storage

mountPath: /var/www/html

volumes:

- name: wordpress-persistent-storage

persistentVolumeClaim:

claimName: wordpress-pv-claim

---

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

name: wordpress-pv-claim

namespace: blog

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 10Gi

Apply the manifests:

kubectl apply -f mysql-deployment.yaml

kubectl apply -f wordpress-deployment.yaml

After a few minutes, get the external IP:

kubectl get service wordpress -n blog

Visit the IP in your browser. Youll see the WordPress setup wizard.

Example 2: Scaling Based on CPU Usage

Deploy a Horizontal Pod Autoscaler (HPA) to automatically scale the WordPress deployment:

kubectl autoscale deployment wordpress --cpu-percent=50 --min=2 --max=10 -n blog

Test it by generating load:

kubectl run -i --rm load-generator --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://wordpress.blog; done"

Monitor scaling:

kubectl get hpa -n blog

kubectl get pods -n blog -w

Youll see pods scale up under load and scale down when traffic drops.

FAQs

What is the difference between kubeadm, kops, and RKE?

kubeadm is the official, lightweight tool for bootstrapping clusters. Its ideal for learning and on-prem deployments. kops (Kubernetes Operations) is designed for AWS and automates complex infrastructure provisioning. RKE (Rancher Kubernetes Engine) simplifies cluster management on any Linux node and integrates with Rancher UI. Choose kubeadm for control, kops for AWS, RKE for multi-cloud with UI.

Can I run Kubernetes on my laptop?

Yes, using tools like Minikube or Kind (Kubernetes in Docker). These are perfect for development and testing. Minikube creates a single-node cluster inside a VM. Kind runs a cluster inside Docker containers. Neither is suitable for production.

How do I upgrade my Kubernetes cluster?

Use kubeadm upgrade. First, upgrade kubeadm on control plane nodes:

sudo apt-get update && sudo apt-get install -y kubeadm=1.29.0-00

sudo kubeadm upgrade plan

sudo kubeadm upgrade apply v1.29.0

Then upgrade kubelet and kubectl:

sudo apt-get install -y kubelet=1.29.0-00 kubectl=1.29.0-00

sudo systemctl restart kubelet

Finally, drain and upgrade each worker node.

Why is my node stuck in NotReady state?

Common causes:

  • Missing CNI plugin Install Calico, Flannel, or Cilium.
  • Firewall blocking ports Ensure 6443, 10250, 23792380 are open.
  • Swap enabled Run swapoff -a and disable in /etc/fstab.
  • Time sync issues Use NTP (chrony or ntpd) on all nodes.

Check logs with: journalctl -xeu kubelet

How do I backup and restore a Kubernetes cluster?

Back up etcd as described in the best practices section. For application state, use Velero an open-source tool for backing up and restoring Kubernetes resources and persistent volumes. Install Velero and configure it to back up to S3, GCS, or Azure Blob Storage.

Is Kubernetes secure by default?

No. Kubernetes has many attack surfaces: exposed APIs, default service accounts, unsecured etcd, and misconfigured RBAC. Always apply security hardening: disable anonymous access, enable audit logging, use network policies, scan images, and rotate certificates regularly.

How many nodes do I need for production?

Minimum: 3 control plane nodes (for HA) and 3 worker nodes. For high availability, distribute nodes across availability zones. For large-scale applications, use node pools with auto-scaling.

Conclusion

Deploying a Kubernetes cluster is a foundational skill for modern DevOps and platform engineering teams. While the process involves multiple componentscontainer runtime, control plane, networking, security, and monitoringit becomes manageable when approached methodically. This guide provided a complete, step-by-step walkthrough using kubeadm, along with essential best practices, real-world examples, and tools to ensure your cluster is not only functional but also secure, scalable, and maintainable.

Remember: Kubernetes is not a one-time setup. It requires continuous monitoring, patching, scaling, and optimization. As your applications grow, so too should your operational maturity. Leverage automation, embrace infrastructure as code, and prioritize observability. Whether youre running on bare metal, in the cloud, or at the edge, a well-deployed Kubernetes cluster becomes the backbone of your digital infrastructureenabling agility, resilience, and innovation.

Start small, validate each step, document your configuration, and never underestimate the value of testing in a staging environment before deploying to production. With the knowledge in this guide, youre now equipped to deploy, manage, and evolve Kubernetes clusters with confidence.