Understanding Pod Bin Packing

Ashis PadhiAshis Padhi
4 min read

"Think of moving to a new apartment. You've got to pack furniture, kitchenware, books, and clothes into a limited number of boxes. To do it efficiently, you need to plan. You don't want some boxes half-empty while others are overflowing—that's wasteful and inefficient."

Similar thing applies to Kubernetes. The "bins" are your nodes, and the "items" are your pods. Pod bin packing is about efficiently placing pods onto nodes, ensuring you're not wasting resources while avoiding overload.

Why is this important ?

Imagine you're managing a large Kubernetes cluster. Poor bin packing means underused nodes, high infrastructure costs, and inefficient energy use. Good bin packing, however, optimizes resources, reduces the number of nodes you need, and balances workloads for resilience and flexibility.

Overview

The goal is to implement a plugin that helps place pods onto nodes in a way that optimizes resource utilization, minimizing resource fragmentation and reducing overall node count. This guide assumes some familiarity with Go programming and Kubernetes architecture.

Prerequisites

  • A working Kubernetes cluster

  • Knowledge of Go programming

  • Kubernetes development environment set up (e.g., Minikube, kind)

  • Basic understanding of Kubernetes scheduler plugins

1: Set Up the Project

Create a new Go project and set up dependencies for Kubernetes plugin development.

Add necessary dependencies for Kubernetes plugin development:

mkdir binpacking-scheduler
cd binpacking-scheduler
go mod init binpacking-scheduler
go get -u k8s.io/kubernetes

2: Implement the Custom Plugin

Create a new Go file (plugin.go) to define the custom scheduling plugin for pod bin packing.

package main

import (
    "context"
    "fmt"
    "k8s.io/kubernetes/pkg/scheduler/framework"
    "k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
)

// BinPackingPlugin is our custom plugin for bin packing.
type BinPackingPlugin struct {
    handle framework.Handle
}

// Name returns the name of the plugin.
func (b *BinPackingPlugin) Name() string {
    return "BinPackingPlugin"
}

// Score scores the nodes based on resource utilization.
func (b *BinPackingPlugin) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int32, *framework.Status) {
    // Simple example: Give a higher score to nodes with more available resources.
    // This logic should be more complex for real-world scenarios.
    nodeInfo, err := b.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
    if err != nil {
        return 0, framework.NewStatus(framework.Error, fmt.Sprintf("Error getting node info: %v", err))
    }

    // Example logic: Nodes with more available resources get higher scores.
    availableCpu := nodeInfo.Allocatable.MilliCPU - nodeInfo.Requested.MilliCPU
    availableMem := nodeInfo.Allocatable.Memory - nodeInfo.Requested.Memory

    // This simple scoring function uses a weighted sum of available CPU and memory.
    score := int32(availableCpu/100 + availableMem/1024)

    return score, nil
}

// ScoreExtensions returns nil, as we don't need additional scoring behavior.
func (b *BinPackingPlugin) ScoreExtensions() framework.ScoreExtensions {
    return nil
}

// Register the plugin with the framework.
func NewBinPackingPlugin(_ *framework.PluginsConfig, handle framework.Handle) (framework.Plugin, error) {
    return &BinPackingPlugin{handle: handle}, nil
}

3: Configure Kubernetes to Use the Custom Plugin

After defining the custom plugin, configure Kubernetes to use it. This involves setting up a new scheduler configuration to integrate the plugin.

  1. Create a new configuration file (scheduler-config.yaml):

     apiVersion: kubescheduler.config.k8s.io/v1
     kind: KubeSchedulerConfiguration
     profiles:
     - schedulerName: default-scheduler
       plugins:
         score:
           enabled:
           - name: BinPackingPlugin
    
  2. Run the Kubernetes scheduler with the custom configuration:

    • Deploy a custom Kubernetes scheduler that uses the configuration file you created.

    • This typically involves running a separate scheduler in your Kubernetes cluster and setting the KUBE_SCHEDULER_CONFIG environment variable to point to the configuration file.

4: Test and Monitor the Custom Plugin

After deploying the custom plugin, ensure that it's functioning as expected:

  1. Deploy Test Pods:

    • Create a deployment or set of pods to verify that the scheduler uses your custom plugin to assign pods to nodes.
  2. Monitor Scheduling:

    • Use Kubernetes tools like kubectl get pods -o wide to check where pods are scheduled.

    • Use observability tools like Prometheus or Grafana to monitor resource utilization and ensure that the custom plugin is optimizing pod placement.

Conclusion

This guide provides a basic framework for creating a custom pod bin packing plugin for Kubernetes. In real-world scenarios, custom plugins typically require more complex logic and rigorous testing to ensure reliability and stability. Further reading on Kubernetes scheduling, Go development, and plugin integration is recommended for deeper understanding and robust implementation.

11
Subscribe to my newsletter

Read articles from Ashis Padhi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ashis Padhi
Ashis Padhi