πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Observability beginner ⏱ 15 minutes K8s 1.28+

K8s Metrics Server: Install and Configure

Install and configure Kubernetes Metrics Server for kubectl top, HPA autoscaling, and resource monitoring. Troubleshoot common metrics-server errors and TL.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: Metrics Server is a lightweight, in-memory aggregator of resource metrics (CPU/memory) from kubelets. Install with kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml. It powers kubectl top, HPA, and VPA. For self-managed clusters, you may need --kubelet-insecure-tls if kubelet certificates are self-signed.

The Problem

Without Metrics Server, kubectl top pods returns β€œMetrics API not available,” HPA can’t scale on CPU/memory, and VPA can’t recommend resource sizes. Metrics Server is not installed by default on kubeadm or bare-metal clusters (managed services like EKS/GKE/AKS typically include it).

flowchart LR
    KUBELET["Kubelets<br/>(every node)"] -->|"Resource metrics<br/>(CPU, memory)"| MS["Metrics Server<br/>(aggregator)"]
    MS -->|"metrics.k8s.io API"| API["API Server"]
    API --> TOP["kubectl top"]
    API --> HPA["HPA Controller"]
    API --> VPA["VPA Recommender"]

The Solution

Install Metrics Server

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

# Verify
kubectl get deployment metrics-server -n kube-system
kubectl get apiservice v1beta1.metrics.k8s.io

Fix TLS Issues (Self-Managed Clusters)

# If metrics-server logs show:
# "x509: cannot validate certificate for <IP> because it doesn't contain any IP SANs"

# Option A: Add --kubelet-insecure-tls (dev/test only)
kubectl patch deployment metrics-server -n kube-system --type=json \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'

# Option B: Proper kubelet certificates (production)
# Ensure kubelet serving certs are signed by a trusted CA
# and include node IP SANs

Helm Installation

helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm install metrics-server metrics-server/metrics-server \
  --namespace kube-system \
  --set args[0]=--kubelet-preferred-address-types=InternalIP \
  --set args[1]=--kubelet-insecure-tls    # Only if needed

Verify It Works

# Check node metrics
kubectl top nodes
# NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
# worker-1       450m         11%    3200Mi          41%
# worker-2       820m         20%    5100Mi          65%

# Check pod metrics
kubectl top pods -n my-app
# NAME                     CPU(cores)   MEMORY(bytes)
# web-app-abc123           150m         256Mi
# web-app-def456           180m         312Mi

# Check API service health
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml | grep -A3 "conditions:"

High Availability Configuration

# HA metrics-server for production
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metrics-server
  namespace: kube-system
spec:
  replicas: 2                        # HA: 2 replicas
  strategy:
    rollingUpdate:
      maxUnavailable: 1
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  k8s-app: metrics-server
              topologyKey: kubernetes.io/hostname
      containers:
        - name: metrics-server
          image: registry.k8s.io/metrics-server/metrics-server:v0.7.2
          args:
            - --cert-dir=/tmp
            - --secure-port=10250
            - --kubelet-preferred-address-types=InternalIP
            - --kubelet-use-node-status-port
            - --metric-resolution=15s       # Default: 60s
          resources:
            requests:
              cpu: 100m
              memory: 200Mi
            limits:
              cpu: 500m
              memory: 500Mi

Common Issues

IssueCauseFix
Metrics API not availableMetrics Server not installedInstall with kubectl apply or Helm
x509: cannot validate certificateSelf-signed kubelet certsAdd --kubelet-insecure-tls or fix certs
kubectl top shows no dataMetrics Server just startedWait 60s for first scrape cycle
unable to fully scrape metricsKubelet not reachableCheck node firewall, port 10250
HPA shows <unknown> targetMetrics API returning errorsCheck kubectl get apiservice status

Best Practices

  • Always install in production clusters β€” HPA and VPA depend on it
  • Use proper TLS in production β€” --kubelet-insecure-tls is for dev only
  • Deploy 2 replicas for HA β€” with pod anti-affinity across nodes
  • Set resource requests β€” Metrics Server itself needs CPU/memory
  • Metrics Server β‰  Prometheus β€” it provides current metrics only (no history)
  • Check metric-resolution β€” default 60s; lower to 15s for faster HPA response

Key Takeaways

  • Metrics Server provides real-time CPU/memory metrics from kubelets
  • Powers kubectl top, HPA, and VPA β€” essential for autoscaling
  • Not installed by default on kubeadm clusters; pre-installed on most managed K8s
  • TLS issues are the #1 installation problem on self-managed clusters
  • Use Prometheus for historical metrics; Metrics Server for current resource usage
#metrics-server #monitoring #kubectl-top #hpa #resource-monitoring
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens