Configure namespace resource quotas, container resource limits, and limit ranges to ensure fair resource allocation and prevent resource exhaustion in multi-tenant Kubernetes clusters.
Prerequisites
- Running Kubernetes cluster
- kubectl configured with admin permissions
- Basic understanding of Kubernetes concepts
What this solves
Kubernetes resource quotas and limits prevent individual workloads from consuming excessive cluster resources and ensure fair resource allocation across namespaces. Without proper resource management, a single workload can starve other applications of CPU, memory, or storage, leading to cluster-wide performance issues and potential outages.
Step-by-step configuration
Install and verify Kubernetes cluster
Ensure you have a running Kubernetes cluster with proper administrative access. This tutorial assumes you have kubectl configured and cluster admin permissions.
kubectl cluster-info
kubectl get nodes
kubectl auth can-i create resourcequotas --all-namespaces
Create test namespaces for demonstration
Create separate namespaces to demonstrate resource isolation and quota enforcement. These namespaces will simulate different teams or applications in your cluster.
kubectl create namespace production
kubectl create namespace development
kubectl create namespace testing
Configure namespace resource quotas
Create resource quotas to limit total resource consumption at the namespace level. This prevents any namespace from consuming more resources than allocated.
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
persistentvolumeclaims: "10"
pods: "20"
services: "10"
secrets: "20"
configmaps: "20"
Create development and testing quotas
Configure smaller resource quotas for development and testing environments to ensure production workloads get priority access to cluster resources.
apiVersion: v1
kind: ResourceQuota
metadata:
name: development-quota
namespace: development
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
limits.cpu: "4"
limits.memory: 8Gi
persistentvolumeclaims: "5"
pods: "10"
services: "5"
apiVersion: v1
kind: ResourceQuota
metadata:
name: testing-quota
namespace: testing
spec:
hard:
requests.cpu: "1"
requests.memory: 2Gi
limits.cpu: "2"
limits.memory: 4Gi
persistentvolumeclaims: "3"
pods: "5"
services: "3"
Apply resource quotas to namespaces
Deploy the resource quota configurations to enforce limits on namespace resource consumption.
kubectl apply -f production-quota.yaml
kubectl apply -f development-quota.yaml
kubectl apply -f testing-quota.yaml
Create limit ranges for pod and container constraints
Configure LimitRange objects to set default resource requests and limits for containers, and enforce minimum and maximum boundaries per pod.
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "1Gi"
defaultRequest:
cpu: "100m"
memory: "256Mi"
min:
cpu: "50m"
memory: "128Mi"
max:
cpu: "2"
memory: "4Gi"
- type: Pod
max:
cpu: "4"
memory: "8Gi"
- type: PersistentVolumeClaim
min:
storage: "1Gi"
max:
storage: "100Gi"
Create limit ranges for development and testing
Configure smaller limit ranges for non-production environments to prevent resource waste and encourage efficient resource usage during development.
apiVersion: v1
kind: LimitRange
metadata:
name: development-limits
namespace: development
spec:
limits:
- type: Container
default:
cpu: "200m"
memory: "512Mi"
defaultRequest:
cpu: "50m"
memory: "128Mi"
min:
cpu: "25m"
memory: "64Mi"
max:
cpu: "1"
memory: "2Gi"
- type: Pod
max:
cpu: "2"
memory: "4Gi"
apiVersion: v1
kind: LimitRange
metadata:
name: testing-limits
namespace: testing
spec:
limits:
- type: Container
default:
cpu: "100m"
memory: "256Mi"
defaultRequest:
cpu: "25m"
memory: "64Mi"
min:
cpu: "10m"
memory: "32Mi"
max:
cpu: "500m"
memory: "1Gi"
- type: Pod
max:
cpu: "1"
memory: "2Gi"
Apply limit ranges
Deploy the limit range configurations to enforce container and pod resource constraints within each namespace.
kubectl apply -f production-limits.yaml
kubectl apply -f development-limits.yaml
kubectl apply -f testing-limits.yaml
Create test deployment with resource specifications
Deploy a sample application to demonstrate how resource limits and requests work in practice. This deployment explicitly defines resource requirements.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test
namespace: production
labels:
app: nginx-test
spec:
replicas: 3
selector:
matchLabels:
app: nginx-test
template:
metadata:
labels:
app: nginx-test
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "1Gi"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
Deploy test application
Apply the test deployment to verify that resource quotas and limits are properly enforced by the cluster.
kubectl apply -f test-deployment.yaml
kubectl get pods -n production
kubectl describe deployment nginx-test -n production
Create resource monitoring script
Set up a monitoring script to track resource usage across namespaces and identify potential quota violations or resource pressure.
#!/bin/bash
echo "=== Namespace Resource Quotas ==="
for namespace in production development testing; do
echo "\n--- $namespace ---"
kubectl describe quota -n $namespace 2>/dev/null || echo "No quota found"
done
echo "\n\n=== Namespace Resource Usage ==="
for namespace in production development testing; do
echo "\n--- $namespace ---"
kubectl top pods -n $namespace --no-headers 2>/dev/null | \
awk '{cpu+=$2; mem+=$3} END {printf "Total CPU: %.0fm, Total Memory: %.0fMi\n", cpu, mem}' || echo "No pods running"
done
echo "\n\n=== Limit Ranges ==="
for namespace in production development testing; do
echo "\n--- $namespace ---"
kubectl get limitrange -n $namespace -o wide 2>/dev/null || echo "No limit ranges"
done
chmod 755 monitor-resources.sh
Monitor and troubleshoot resource constraints
Monitor resource quota usage
Check current resource consumption against configured quotas to identify namespaces approaching their limits and plan capacity accordingly.
kubectl describe quota production-quota -n production
kubectl describe quota development-quota -n development
kubectl get resourcequota --all-namespaces
Analyze pod resource consumption
Monitor actual resource usage by pods to optimize resource requests and limits based on real consumption patterns.
kubectl top pods --all-namespaces
kubectl top pods -n production --sort-by=cpu
kubectl top pods -n production --sort-by=memory
Test quota enforcement
Create a deployment that exceeds namespace quotas to verify that resource constraints are properly enforced by the cluster.
apiVersion: apps/v1
kind: Deployment
metadata:
name: resource-hog
namespace: testing
spec:
replicas: 10
selector:
matchLabels:
app: resource-hog
template:
metadata:
labels:
app: resource-hog
spec:
containers:
- name: stress
image: nginx:1.25
resources:
requests:
cpu: "200m"
memory: "512Mi"
kubectl apply -f quota-test.yaml
kubectl get events -n testing --sort-by=.metadata.creationTimestamp
Verify your setup
# Check all resource quotas
kubectl get resourcequota --all-namespaces
Check all limit ranges
kubectl get limitrange --all-namespaces
Verify quota status
kubectl describe quota --all-namespaces
Check pod resource usage
kubectl top pods --all-namespaces
Run monitoring script
./monitor-resources.sh
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Pods stuck in Pending state | ResourceQuota exceeded | Check quota usage with kubectl describe quota -n namespace and adjust limits or delete unused resources |
| "exceeded quota" error when creating pods | Namespace resource quota limits reached | Increase quota limits or reduce resource requests in pod specifications |
| Containers using default resource limits | No resource requests/limits specified in pod spec | LimitRange applies defaults automatically, or explicitly set resources in deployment |
| Resource quota not enforced | Quota applied after pod creation | Resource quotas only affect new pods, restart existing deployments to apply quotas |
| OOMKilled container restarts | Memory limit set too low | Increase memory limits or optimize application memory usage |
| CPU throttling affects performance | CPU limit set too restrictively | Increase CPU limits or optimize application CPU usage patterns |
Next steps
- Monitor container performance with Prometheus and cAdvisor for comprehensive metrics collection
- Configure Kubernetes persistent volumes with NFS storage for container data persistence
- Implement Kubernetes monitoring with Prometheus and Helm charts for comprehensive cluster observability
- Configure Kubernetes horizontal pod autoscaler for dynamic scaling based on resource metrics
- Implement Kubernetes network policies for pod-to-pod security and traffic isolation
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Global variables
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMP_DIR=""
KUBECTL_VERSION="v1.28.4"
# Usage function
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -h, --help Show this help message"
echo " -v, --kubectl-version Kubectl version to install (default: ${KUBECTL_VERSION})"
echo ""
echo "This script installs kubectl and configures Kubernetes resource quotas and limits"
echo "for namespace isolation and workload management."
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1" >&2; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" >&2; }
log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
# Cleanup function
cleanup() {
if [[ -n "${TEMP_DIR:-}" && -d "${TEMP_DIR}" ]]; then
rm -rf "${TEMP_DIR}"
fi
}
# Error handler
error_handler() {
log_error "Script failed on line $1"
cleanup
exit 1
}
trap 'error_handler ${LINENO}' ERR
trap cleanup EXIT
# Check if running as root or with sudo
check_privileges() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
}
# Detect OS distribution
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
log_error "Cannot detect OS distribution"
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf check-update || true"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum check-update || true"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_info "Detected distribution: $ID"
}
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
exit 0
;;
-v|--kubectl-version)
KUBECTL_VERSION="$2"
shift 2
;;
*)
log_error "Unknown option: $1"
usage
exit 1
;;
esac
done
}
# Install prerequisites
install_prerequisites() {
echo "[1/9] Installing prerequisites..."
$PKG_UPDATE
case "$PKG_MGR" in
apt)
$PKG_INSTALL curl wget ca-certificates apt-transport-https gpg
;;
dnf|yum)
$PKG_INSTALL curl wget ca-certificates
;;
esac
log_info "Prerequisites installed successfully"
}
# Install kubectl
install_kubectl() {
echo "[2/9] Installing kubectl ${KUBECTL_VERSION}..."
# Download kubectl binary
curl -LO "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"
curl -LO "https://dl.k8s.io/${KUBECTL_VERSION}/bin/linux/amd64/kubectl.sha256"
# Verify checksum
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check
# Install kubectl
chmod 755 kubectl
mv kubectl /usr/local/bin/
# Verify installation
kubectl version --client
log_info "kubectl installed successfully"
}
# Check cluster connectivity
check_cluster() {
echo "[3/9] Checking Kubernetes cluster connectivity..."
if ! kubectl cluster-info &>/dev/null; then
log_warn "kubectl is not configured or cluster is not accessible"
log_warn "Please configure kubectl with your cluster credentials before proceeding"
return 0
fi
if ! kubectl auth can-i create resourcequotas --all-namespaces &>/dev/null; then
log_warn "Insufficient permissions to create resource quotas cluster-wide"
log_warn "Please ensure you have cluster admin permissions"
return 0
fi
log_info "Cluster connectivity verified"
}
# Create namespaces
create_namespaces() {
echo "[4/9] Creating test namespaces..."
TEMP_DIR=$(mktemp -d)
for ns in production development testing; do
kubectl create namespace "$ns" --dry-run=client -o yaml > "${TEMP_DIR}/${ns}-namespace.yaml"
kubectl apply -f "${TEMP_DIR}/${ns}-namespace.yaml" || true
log_info "Namespace '$ns' created/updated"
done
}
# Create resource quotas
create_resource_quotas() {
echo "[5/9] Creating resource quotas..."
# Production quota
cat > "${TEMP_DIR}/production-quota.yaml" << 'EOF'
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
persistentvolumeclaims: "10"
pods: "20"
services: "10"
secrets: "20"
configmaps: "20"
EOF
# Development quota
cat > "${TEMP_DIR}/development-quota.yaml" << 'EOF'
apiVersion: v1
kind: ResourceQuota
metadata:
name: development-quota
namespace: development
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
limits.cpu: "4"
limits.memory: 8Gi
persistentvolumeclaims: "5"
pods: "10"
services: "5"
EOF
# Testing quota
cat > "${TEMP_DIR}/testing-quota.yaml" << 'EOF'
apiVersion: v1
kind: ResourceQuota
metadata:
name: testing-quota
namespace: testing
spec:
hard:
requests.cpu: "1"
requests.memory: 2Gi
limits.cpu: "2"
limits.memory: 4Gi
persistentvolumeclaims: "3"
pods: "5"
services: "3"
EOF
log_info "Resource quota manifests created"
}
# Apply resource quotas
apply_resource_quotas() {
echo "[6/9] Applying resource quotas..."
for quota in production development testing; do
kubectl apply -f "${TEMP_DIR}/${quota}-quota.yaml"
log_info "${quota} resource quota applied"
done
}
# Create limit ranges
create_limit_ranges() {
echo "[7/9] Creating limit ranges..."
# Production limits
cat > "${TEMP_DIR}/production-limits.yaml" << 'EOF'
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "1Gi"
defaultRequest:
cpu: "100m"
memory: "256Mi"
min:
cpu: "50m"
memory: "128Mi"
max:
cpu: "2"
memory: "4Gi"
- type: Pod
max:
cpu: "4"
memory: "8Gi"
- type: PersistentVolumeClaim
min:
storage: "1Gi"
max:
storage: "100Gi"
EOF
# Development limits
cat > "${TEMP_DIR}/development-limits.yaml" << 'EOF'
apiVersion: v1
kind: LimitRange
metadata:
name: development-limits
namespace: development
spec:
limits:
- type: Container
default:
cpu: "200m"
memory: "512Mi"
defaultRequest:
cpu: "50m"
memory: "128Mi"
min:
cpu: "25m"
memory: "64Mi"
max:
cpu: "1"
memory: "2Gi"
- type: Pod
max:
cpu: "2"
memory: "4Gi"
EOF
# Testing limits
cat > "${TEMP_DIR}/testing-limits.yaml" << 'EOF'
apiVersion: v1
kind: LimitRange
metadata:
name: testing-limits
namespace: testing
spec:
limits:
- type: Container
default:
cpu: "100m"
memory: "256Mi"
defaultRequest:
cpu: "25m"
memory: "64Mi"
min:
cpu: "10m"
memory: "32Mi"
max:
cpu: "500m"
memory: "1Gi"
- type: Pod
max:
cpu: "1"
memory: "2Gi"
EOF
log_info "Limit range manifests created"
}
# Apply limit ranges
apply_limit_ranges() {
echo "[8/9] Applying limit ranges..."
for limits in production development testing; do
kubectl apply -f "${TEMP_DIR}/${limits}-limits.yaml"
log_info "${limits} limit range applied"
done
}
# Verify installation
verify_installation() {
echo "[9/9] Verifying installation..."
log_info "Checking resource quotas..."
for ns in production development testing; do
if kubectl get resourcequota -n "$ns" &>/dev/null; then
log_info "✓ Resource quota configured for namespace: $ns"
else
log_warn "✗ Resource quota missing for namespace: $ns"
fi
done
log_info "Checking limit ranges..."
for ns in production development testing; do
if kubectl get limitrange -n "$ns" &>/dev/null; then
log_info "✓ Limit range configured for namespace: $ns"
else
log_warn "✗ Limit range missing for namespace: $ns"
fi
done
log_info "Kubernetes resource quotas and limits configuration completed successfully!"
}
# Main execution
main() {
parse_args "$@"
check_privileges
detect_distro
install_prerequisites
install_kubectl
check_cluster
create_namespaces
create_resource_quotas
apply_resource_quotas
create_limit_ranges
apply_limit_ranges
verify_installation
}
main "$@"
Review the script before running. Execute with: bash install.sh