Introduction
Kubernetes has become the de facto standard for container orchestration, enabling organizations to deploy, scale, and manage containerized applications efficiently. This comprehensive guide will walk you through installing, setting up, and configuring a Kubernetes cluster from scratch, complete with practical labs to solidify your understanding.
What is Kubernetes?
Kubernetes (K8s) is an open-source container orchestration platform that automates the deployment, scaling, and management of containerized applications. It provides a robust framework for running distributed systems resiliently, handling scaling and failover for your applications.
Key Components
Control Plane Components:
- kube-apiserver: The API server that serves the Kubernetes API
- etcd: Consistent and highly-available key-value store for cluster data
- kube-scheduler: Assigns pods to nodes based on resource requirements
- kube-controller-manager: Runs controller processes that regulate cluster state
Node Components:
- kubelet: Agent that runs on each node and manages containers
- kube-proxy: Network proxy that maintains network rules
- Container Runtime: Software responsible for running containers (Docker, containerd, CRI-O)
Prerequisites
Before starting, ensure you have:
- Ubuntu 20.04/22.04 or CentOS 8/Rocky Linux 8 (minimum 2 GB RAM, 2 CPUs)
- Root or sudo access
- Network connectivity between nodes
- Unique hostname, MAC address, and product_uuid for each node
Installation Methods Overview
We’ll cover three primary installation approaches:
- kubeadm: Production-ready installation tool
- Minikube: Local development clusters
- Kind: Kubernetes in Docker for testing
Method 1: Installing Kubernetes with kubeadm
Step 1: Prepare the Environment
First, disable swap on all nodes (Kubernetes requires swap to be disabled):
# Disable swap temporarily
sudo swapoff -a
# Disable swap permanently
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
Configure kernel modules:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
Set up required sysctl parameters:
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
Step 2: Install Container Runtime (containerd)
# Install containerd
sudo apt-get update
sudo apt-get install -y containerd
# Create containerd configuration
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# Configure systemd cgroup driver
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
# Restart containerd
sudo systemctl restart containerd
sudo systemctl enable containerd
Step 3: Install Kubernetes Components
Add the Kubernetes repository:
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/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.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
Install kubelet, kubeadm, and kubectl:
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Step 4: Initialize the Control Plane
On the master node, initialize the cluster:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=<MASTER_IP>
After successful initialization, configure kubectl:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Step 5: Install a Pod Network Add-on
Install Flannel for pod networking:
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Step 6: Join Worker Nodes
On each worker node, run the join command provided by kubeadm init:
sudo kubeadm join <MASTER_IP>:6443 --token <TOKEN> --discovery-token-ca-cert-hash sha256:<HASH>
Method 2: Installing Minikube for Local Development
Minikube is perfect for local development and testing:
# Install Minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Start Minikube
minikube start --driver=docker
# Verify installation
kubectl get nodes
Method 3: Installing Kind (Kubernetes in Docker)
Kind runs Kubernetes clusters in Docker containers:
# Install Kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Create a cluster
kind create cluster --name my-cluster
# Verify installation
kubectl cluster-info --context kind-my-cluster
Configuration Deep Dive
Cluster Configuration
The cluster configuration is stored in /etc/kubernetes/admin.conf
. Key configuration areas include:
API Server Configuration:
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: <base64-encoded-ca-cert>
server: https://<master-ip>:6443
name: kubernetes
Network Configuration: Pod and service network ranges are crucial for cluster networking:
- Pod CIDR: 10.244.0.0/16 (Flannel default)
- Service CIDR: 10.96.0.0/12 (Kubernetes default)
Security Configuration
RBAC (Role-Based Access Control):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
Network Policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Hands-On Labs
Lab 1: Deploy Your First Application
Objective: Deploy and expose a simple web application
Create a deployment:
# nginx-deployment.yaml
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.21
ports:
- containerPort: 80
Apply the deployment:
kubectl apply -f nginx-deployment.yaml
kubectl get deployments
kubectl get pods
Expose the deployment:
kubectl expose deployment nginx-deployment --type=NodePort --port=80
kubectl get services
Expected Output: You should see three nginx pods running and a service exposing them on a random port.
Lab 2: ConfigMaps and Secrets
Objective: Learn to manage configuration data securely
Create a ConfigMap:
kubectl create configmap app-config --from-literal=database_url=postgresql://localhost:5432/mydb
Create a Secret:
kubectl create secret generic app-secret --from-literal=database_password=supersecret
Use them in a deployment:
# app-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-config
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: busybox
command: ['sh', '-c', 'echo "Database URL: $DATABASE_URL" && echo "Password: $DATABASE_PASSWORD" && sleep 3600']
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database_url
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: database_password
Lab 3: Persistent Storage
Objective: Work with persistent volumes and claims
Create a PersistentVolume:
# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /tmp/data
Create a PersistentVolumeClaim:
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Use the PVC in a pod:
# pod-with-storage.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-with-storage
spec:
containers:
- name: container
image: nginx
volumeMounts:
- name: storage
mountPath: /usr/share/nginx/html
volumes:
- name: storage
persistentVolumeClaim:
claimName: my-pvc
Lab 4: Services and Ingress
Objective: Understand different service types and ingress controllers
Create different service types:
# services.yaml
apiVersion: v1
kind: Service
metadata:
name: clusterip-service
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nodeport-service
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080
---
apiVersion: v1
kind: Service
metadata:
name: loadbalancer-service
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80
Install NGINX Ingress Controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
Create an Ingress resource:
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-deployment
port:
number: 80
Monitoring and Maintenance
Health Checks
Monitor cluster health:
kubectl get nodes
kubectl get pods --all-namespaces
kubectl top nodes
kubectl top pods
Troubleshooting Common Issues
Pod stuck in Pending state:
kubectl describe pod <pod-name>
kubectl get events --sort-by=.metadata.creationTimestamp
Node not ready:
kubectl describe node <node-name>
journalctl -u kubelet
Network issues:
kubectl get pods -n kube-system
kubectl logs -n kube-system <flannel-pod-name>
Backup and Recovery
Backup etcd data:
ETCDCTL_API=3 etcdctl snapshot save snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key=/etc/kubernetes/pki/etcd/healthcheck-client.key
Best Practices
Security Best Practices
- Enable RBAC: Always use role-based access control
- Use Network Policies: Restrict pod-to-pod communication
- Scan Images: Use tools like Trivy or Clair for vulnerability scanning
- Limit Resources: Set resource requests and limits for all containers
- Use Secrets: Never hardcode sensitive data in manifests
Operational Best Practices
- Use Namespaces: Organize resources logically
- Label Everything: Use consistent labeling strategies
- Monitor Resources: Implement comprehensive monitoring
- Regular Backups: Backup etcd and persistent data regularly
- Update Regularly: Keep Kubernetes and components updated
Performance Optimization
- Node Sizing: Right-size your nodes based on workload requirements
- Pod Disruption Budgets: Ensure high availability during updates
- Horizontal Pod Autoscaling: Automatically scale based on metrics
- Resource Quotas: Prevent resource exhaustion
Next Steps
After completing this guide, consider exploring:
- Advanced Networking: Calico, Cilium, or Istio service mesh
- Monitoring Stack: Prometheus, Grafana, and Alertmanager
- CI/CD Integration: GitOps with ArgoCD or Flux
- Advanced Scheduling: Node affinity, taints, and tolerations
- Custom Resources: Operators and Custom Resource Definitions (CRDs)
Conclusion
Kubernetes provides a powerful platform for container orchestration, but proper installation and configuration are crucial for success. This guide covered the fundamental concepts and provided hands-on experience with real-world scenarios. The labs demonstrate practical applications of Kubernetes features, from basic deployments to advanced configuration management.
Remember that Kubernetes is a complex system that requires ongoing learning and practice. Start with simple deployments and gradually incorporate more advanced features as your understanding grows. The community resources, documentation, and hands-on practice will help you master this essential technology.
Continue experimenting with different configurations, explore the vast ecosystem of Kubernetes tools, and consider pursuing official certifications like CKA (Certified Kubernetes Administrator) or CKAD (Certified Kubernetes Application Developer) to validate your skills.
The journey to Kubernetes mastery is ongoing, but with this foundation, you’re well-equipped to deploy, manage, and scale containerized applications in production environments.