{
  "slug": "kubernetes-node-bin-packing",
  "title": "Kubernetes Node Bin-Packing Calculator",
  "heading": "Kubernetes Node Bin-Packing Calculator",
  "category": "financial",
  "url": "https://www.revenuelab.fyi/toolbox/kubernetes-node-bin-packing",
  "summary": "Figure out how many nodes you actually need for a given pod fleet.",
  "description": "Kubernetes scheduling is a bin-packing problem: each node has a fixed amount of allocatable CPU and memory (slightly less than total, after reserving capacity for the kubelet and system daemons), and each pod requests a slice of both. This calculator computes how many pods fit per node based on whichever resource — CPU or memory — runs out first, then divides your total pod count by that packing density to estimate node count, and multiplies by node hourly cost for a monthly estimate. It also reports the 'wasted' capacity on the bottleneck resource, which is almost always non-zero because pod requests rarely divide evenly into node capacity. This is the same math cluster autoscalers use internally, and knowing it helps you size instance types deliberately — sometimes a slightly larger node type packs more efficiently and lowers total node count and cost even though its hourly price is higher.",
  "formula": "Pods per node = min(floor(node CPU ÷ pod CPU request), floor(node memory ÷ pod memory request)); nodes needed = ceil(total pods ÷ pods per node).",
  "dateModified": "2026-09-30",
  "run_url": "https://www.revenuelab.fyi/api/public/calc?tool=kubernetes-node-bin-packing",
  "inputs": [
    {
      "id": "nodeCpu",
      "label": "Node allocatable CPU",
      "kind": "number",
      "hint": null,
      "default": 8,
      "unit": "vCPU",
      "min": 0.5,
      "max": null
    },
    {
      "id": "nodeMemory",
      "label": "Node allocatable memory",
      "kind": "number",
      "hint": null,
      "default": 32,
      "unit": "GB",
      "min": 0.5,
      "max": null
    },
    {
      "id": "podCpu",
      "label": "Pod CPU request",
      "kind": "number",
      "hint": null,
      "default": 0.5,
      "unit": "vCPU",
      "min": 0.01,
      "max": null
    },
    {
      "id": "podMemory",
      "label": "Pod memory request",
      "kind": "number",
      "hint": null,
      "default": 1,
      "unit": "GB",
      "min": 0.05,
      "max": null
    },
    {
      "id": "podCount",
      "label": "Total pods to schedule",
      "kind": "number",
      "hint": null,
      "default": 200,
      "unit": null,
      "min": 1,
      "max": null
    },
    {
      "id": "nodeHourlyRate",
      "label": "Node hourly cost",
      "kind": "number",
      "hint": null,
      "default": 0.384,
      "unit": "$",
      "min": 0,
      "max": null
    }
  ],
  "outputs": [
    {
      "id": "nodesNeeded",
      "label": "Nodes needed",
      "format": "number",
      "hint": null,
      "primary": true
    },
    {
      "id": "podsPerNode",
      "label": "Pods per node",
      "format": "number",
      "hint": null,
      "primary": false
    },
    {
      "id": "monthlyCost",
      "label": "Estimated monthly node cost",
      "format": "currency",
      "hint": null,
      "primary": false
    },
    {
      "id": "bottleneck",
      "label": "Bottleneck resource",
      "format": "raw",
      "hint": null,
      "primary": false
    },
    {
      "id": "wastedCpuPct",
      "label": "Unused CPU per node",
      "format": "percent",
      "hint": null,
      "primary": false
    },
    {
      "id": "wastedMemPct",
      "label": "Unused memory per node",
      "format": "percent",
      "hint": null,
      "primary": false
    }
  ],
  "worked_example": {
    "inputs": [
      "Node allocatable CPU: 8 vCPU",
      "Node allocatable memory: 32 GB",
      "Pod CPU request: 0.5 vCPU",
      "Pod memory request: 1 GB",
      "Total pods to schedule: 200",
      "Node hourly cost: 0.384 $"
    ],
    "outputs": [
      "Nodes needed: 13",
      "Pods per node: 16",
      "Estimated monthly node cost: $3,644.16",
      "Bottleneck resource: CPU",
      "Unused CPU per node: 0.0%",
      "Unused memory per node: 50.0%"
    ]
  },
  "how_to": {
    "title": "How to use this",
    "steps": [
      "Enter node allocatable cpu (vCPU).",
      "Enter node allocatable memory (GB).",
      "Enter pod cpu request (vCPU).",
      "Enter pod memory request (GB).",
      "Enter total pods to schedule.",
      "Enter node hourly cost ($).",
      "Read your nodes needed on the right — it updates as you type.",
      "Hit Share to keep the scenario or send it to someone."
    ]
  },
  "scenarios": [
    {
      "name": "Conservative",
      "description": "Lower-end numbers — what if things land soft?",
      "values": {
        "nodeCpu": 4.8,
        "nodeMemory": 19.2,
        "podCpu": 0.3,
        "podMemory": 0.6,
        "podCount": 120,
        "nodeHourlyRate": 0.2304
      }
    },
    {
      "name": "Typical",
      "description": "Defaults — the most common real-world setup.",
      "values": {
        "nodeCpu": 8,
        "nodeMemory": 32,
        "podCpu": 0.5,
        "podMemory": 1,
        "podCount": 200,
        "nodeHourlyRate": 0.384
      }
    },
    {
      "name": "Ambitious",
      "description": "Higher-end numbers — what if things really pop?",
      "values": {
        "nodeCpu": 12.8,
        "nodeMemory": 51.2,
        "podCpu": 0.8,
        "podMemory": 1.6,
        "podCount": 320,
        "nodeHourlyRate": 0.6144000000000001
      }
    }
  ],
  "limitations": [
    "Results are estimates before tax, fees, and inflation unless an input explicitly covers them.",
    "Rates are treated as fixed for the whole period — variable-rate products will drift from this projection.",
    "This is educational maths, not financial advice. Check anything contractual with the lender or your accountant."
  ],
  "faq": [
    {
      "q": "Why does 'allocatable' matter instead of total node capacity?",
      "a": "Every node reserves a slice of CPU and memory for the kubelet, container runtime, and OS itself before any pods can be scheduled — typically 5-10% of memory and a few hundred millicores of CPU. Cloud providers publish allocatable capacity per instance type separately from raw specs; use that number, not the raw vCPU/RAM spec sheet, or you'll overestimate how many pods actually fit."
    },
    {
      "q": "Why would a bigger, more expensive node type lower total cost?",
      "a": "Bin-packing waste is per-node, so more nodes means more total wasted capacity. A node type that packs pod requests evenly (little remainder on both CPU and memory) can need fewer total nodes for the same pod count than a cheaper node type that leaves each node with 20-30% stranded capacity, and the fewer-larger-nodes total often costs less overall."
    },
    {
      "q": "Should I size nodes around requests or actual usage?",
      "a": "The scheduler only sees requests, so bin-packing math always runs on requests, not real usage. But if your requests are set far above real usage (a common anti-pattern), you're paying for stranded capacity that never gets used — audit with a tool like Kubecost or the metrics-server to right-size requests before doing node capacity planning."
    }
  ],
  "related": [
    "https://www.revenuelab.fyi/toolbox/cloud-vm-monthly-cost",
    "https://www.revenuelab.fyi/toolbox/reserved-vs-on-demand-savings",
    "https://www.revenuelab.fyi/toolbox/serverless-invocation-cost"
  ],
  "license": "CC-BY-4.0",
  "citation": "RevenueLab — Kubernetes Node Bin-Packing Calculator (https://www.revenuelab.fyi/toolbox/kubernetes-node-bin-packing)"
}