{"id":14975851,"url":"https://github.com/pfnet-research/k8s-cluster-simulator","last_synced_at":"2025-10-27T14:31:30.973Z","repository":{"id":86583155,"uuid":"160111248","full_name":"pfnet-research/k8s-cluster-simulator","owner":"pfnet-research","description":"Kubernetes cluster simulator for evaluating schedulers.","archived":false,"fork":false,"pushed_at":"2020-07-21T02:12:00.000Z","size":29997,"stargazers_count":125,"open_issues_count":41,"forks_count":19,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-09-28T21:03:26.334Z","etag":null,"topics":["k8s","kubernetes","scheduler","simulator"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pfnet-research.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-03T00:40:53.000Z","updated_at":"2024-05-04T00:30:47.000Z","dependencies_parsed_at":"2024-06-18T19:38:50.468Z","dependency_job_id":null,"html_url":"https://github.com/pfnet-research/k8s-cluster-simulator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pfnet-research%2Fk8s-cluster-simulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pfnet-research%2Fk8s-cluster-simulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pfnet-research%2Fk8s-cluster-simulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pfnet-research%2Fk8s-cluster-simulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pfnet-research","download_url":"https://codeload.github.com/pfnet-research/k8s-cluster-simulator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219861084,"owners_count":16556007,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["k8s","kubernetes","scheduler","simulator"],"created_at":"2024-09-24T13:52:45.906Z","updated_at":"2025-10-27T14:31:23.970Z","avatar_url":"https://github.com/pfnet-research.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kubernetes cluster simulator\n\n[![GoDoc][godoc-image]][godoc-link]\n[![Build Status][build-image]][build-link]\n[![Coverage Status][cov-image]][cov-link]\n\nKubernetes cluster simulator for evaluating schedulers.\n\n## Usage\n\nSee [example](example) directory.\n\n```go\n// 1. Create a KubeSim with a pod queue and a scheduler.\nqueue := queue.NewPriorityQueue()\nsched := buildScheduler() // see below\nkubesim := kubesim.NewKubeSimFromConfigPathOrDie(configPath, queue, sched)\n\n// 2. Register one or more pod submitters to KubeSim.\nnumOfSubmittingPods := 8\nkubesim.AddSubmitter(newMySubmitter(numOfSubmittingPods))\n\n// 3. Run the main loop of KubeSim.\n//    In each execution of the loop, KubeSim\n//      1) stores pods submitted from the registered submitters to its queue,\n//      2) invokes scheduler with pending pods and cluster state,\n//      3) emits cluster metrics to designated location(s) if enabled\n//      4) progresses the simulated clock\nif err := kubesim.Run(ctx); err != nil \u0026\u0026 errors.Cause(err) != context.Canceled {\n    log.L.Fatal(err)\n}\n\nfunc buildScheduler() scheduler.Scheduler {\n    // 1. Create a generic scheduler that mimics a kube-scheduler.\n    sched := scheduler.NewGenericScheduler( /* preemption enabled */ true)\n\n    // 2. Register extender(s)\n    sched.AddExtender(\n        scheduler.Extender{\n            Name:             \"MyExtender\",\n            Filter:           filterExtender,\n            Prioritize:       prioritizeExtender,\n            Weight:           1,\n            NodeCacheCapable: true,\n        },\n    )\n\n    // 2. Register plugin(s)\n    // Predicate\n    sched.AddPredicate(\"GeneralPredicates\", predicates.GeneralPredicates)\n    // Prioritizer\n    sched.AddPrioritizer(priorities.PriorityConfig{\n        Name:   \"BalancedResourceAllocation\",\n        Map:    priorities.BalancedResourceAllocationMap,\n        Reduce: nil,\n        Weight: 1,\n    })\n    sched.AddPrioritizer(priorities.PriorityConfig{\n        Name:   \"LeastRequested\",\n        Map:    priorities.LeastRequestedPriorityMap,\n        Reduce: nil,\n        Weight: 1,\n    })\n\n    return \u0026sched\n}\n```\n\n### Pod submitter interface\n\nSee [pkg/submitter/submitter.go](pkg/submitter/submitter.go).\n\n```go\n// Submitter defines the submitter interface.\ntype Submitter interface {\n\t// Submit submits pods to a simulated cluster.\n\t// The return value is a list of submitter events.\n\t// Submitters are called serially in the same order that they are registered to the simulated\n\t// cluster.\n\t// This method must never block.\n    Submit(clock clock.Clock, nodeLister algorithm.NodeLister, metrics metrics.Metrics) ([]Event, error)\n}\n\n// Event defines the interface of a submitter event.\n// Submit can returns any type in a list that implements this interface.\ntype Event interface {\n\tIsSubmitterEvent() bool\n}\n\n// SubmitEvent represents an event of submitting a pod to a cluster.\ntype SubmitEvent struct {\n\tPod *v1.Pod\n}\n\n// DeleteEvent represents an event of deleting a pod from a cluster.\ntype DeleteEvent struct {\n\tPodName      string\n\tPodNamespace string\n}\n\n// UpdateEvent represents an event of updating the manifest of a pending pod.\ntype UpdateEvent struct {\n\tPodName      string\n\tPodNamespace string\n\tNewPod       *v1.Pod\n}\n\n// TerminateSubmitterEvent represents an event of terminating the submission process.\ntype TerminateSubmitterEvent struct {\n}\n```\n\n### `kube-scheduler`-compatible scheduler interface\n\nSee [pkg/scheduler/generic_scheduler.go](pkg/scheduler/generic_scheduler.go) and\n[pkg/scheduler/extender.go](pkg/scheduler/extender.go).\n\nk8s-cluster-simulator provides `GenericScheduler`, which follows the behavior of kube-scheduler's\n`genericScheduler`.\n`GenericScheduler` makes scheduling decision for each given pod in the one-by-one manner, with\npredicates and prioritizers.\n\nThe interfaces of predicates and prioritizers are similar to those of kube-scheduler.\n\n```go\n// NewGenericScheduler creates a new GenericScheduler.\nfunc NewGenericScheduler(preeptionEnabled bool) GenericScheduler {\n\treturn GenericScheduler{\n\t\tpredicates:        map[string]predicates.FitPredicate{},\n\t\tpreemptionEnabled: preeptionEnabled,\n\t}\n}\n\n// AddExtender adds an extender to this GenericScheduler.\nfunc (sched *GenericScheduler) AddExtender(extender Extender) {\n\tsched.extenders = append(sched.extenders, extender)\n}\n\n// AddPredicate adds a predicate plugin to this GenericScheduler.\nfunc (sched *GenericScheduler) AddPredicate(name string, predicate predicates.FitPredicate) {\n\tsched.predicates[name] = predicate\n}\n\n// AddPrioritizer adds a prioritizer plugin to this GenericScheduler.\nfunc (sched *GenericScheduler) AddPrioritizer(prioritizer priorities.PriorityConfig) {\n\tsched.prioritizers = append(sched.prioritizers, prioritizer)\n}\n\n// Extender reperesents a scheduler extender.\ntype Extender struct {\n\t// Name identifies this Extender.\n\tName string\n\n\t// Filter filters out the nodes that cannot run the given pod in api.ExtenderArgs.\n\t// This function can be nil.\n\tFilter func(api.ExtenderArgs) api.ExtenderFilterResult\n\n\t// Prioritize ranks each node that has passes the filtering stage.\n\t// The weighted scores are summed up and the total score is used for the node selection.\n\tPrioritize func(api.ExtenderArgs) api.HostPriorityList\n\tWeight     int\n\n\t// NodeCacheCapable specifies that this Extender is capable of caching node information, so the\n\t// scheduler should only send minimal information about the eligible nodes assuming that the\n\t// extender already cached full details of all nodes in the cluster.\n\t// Specifically, ExtenderArgs.NodeNames is populated iff NodeCacheCapable == true, and\n\t// ExtenderArgs.Nodes.Items is populated iff NodeCacheCapable == false.\n\tNodeCacheCapable bool\n\n\t// Ignorable specifies whether the extender is ignorable (i.e. the scheduler process should not\n\t// fail when this extender returns an error).\n\tIgnorable bool\n}\n```\n\n### Lowest-level scheduler interface\n\nSee [pkg/scheduler/scheduler.go](pkg/scheduler/scheduler.go).\n\nk8s-cluster-simulator also supports the lowest-level scheduler interface, which makes scheduling\ndecisions for (subset of) pending pods and running pods, given the cluster state at a clock.\n\n```go\n// Scheduler defines the lowest-level scheduler interface.\ntype Scheduler interface {\n\t// Schedule makes scheduling decisions for (subset of) pending pods and running pods.\n\t// The return value is a list of scheduling events.\n\t// This method must never block.\n\tSchedule(\n\t\tclock clock.Clock,\n\t\tpodQueue queue.PodQueue,\n\t\tnodeLister algorithm.NodeLister,\n\t\tnodeInfoMap map[string]*nodeinfo.NodeInfo) ([]Event, error)\n}\n\n// Event defines the interface of a scheduling event.\n// Submit can returns any type in a list that implements this interface.\ntype Event interface {\n\tIsSchedulerEvent() bool\n}\n\n// BindEvent represents an event of deciding the binding of a pod to a node.\ntype BindEvent struct {\n\tPod            *v1.Pod\n\tScheduleResult core.ScheduleResult\n}\n\n// DeleteEvent represents an event of the deleting a bound pod on a node.\ntype DeleteEvent struct {\n\tPodNamespace string\n\tPodName      string\n\tNodeName     string\n}\n```\n\n### How to specify the resource usage of each pod\n\nEmbed a YAML in the `annotations` field of the pod manifest. e.g.,\n\n```yaml\nmetadata:\n  name: nginx-sim\n  annotations:\n    simSpec: |\n- seconds: 5        # an execution phase of this pod\n  resourceUsage:    # resource usage (not request, nor limit)\n    cpu: 1\n    memory: 2Gi\n    nvidia.com/gpu: 0\n- seconds: 10       # another phase that follows the previous one\n  resourceUsage:\n    cpu: 2\n    memory: 4Gi\n    nvidia.com/gpu: 1\n```\n\n## Supported `v1.Pod` fields\n\nThese fields are populated or used by the simulator.\n\n```go\nv1.Pod{\n    ObjectMeta: metav1.ObjectMeta{\n        UID,                // populated when this pod is submitted to the simulator\n        CreationTimestamp,  // populated when this pod is submitted to the simulator\n        DeletionTimestamp,  // populated when a deletion event for this pod has been accepted by the simulator\n    },\n    Spec: v1.PodSpec {\n        NodeName,                       // populated when the cluster binds this pod to a node\n        TerminationGracePeriodSeconds,  // read when this pod is deleted\n        Priority,                       // read by PriorityQueue to sort pods,\n                                        // and read when the scheduler trys to schedule this pod\n    },\n    Status: v1.PodStatus{\n        Phase,              // populated by the simulator. Pending -\u003e Running -\u003e Succeeded xor Failed\n        Conditions,         // populated by the simulator\n        Reason,             // populated by the simulator\n        Message,            // populated by the simulator\n        StartTime,          // populated by the simulator when this pod has started its execution\n        ContainerStatuses,  // populated by the simulator\n    },\n}\n```\n\n## Supported `v1.Node` fields\n\nThese fields are populated and used by the simulator.\n\n```go\nv1.Node{\n    TypeMeta: metav1.TypeMeta{\n        Kind:       \"Node\",\n        APIVersion: \"v1\",\n    },\n    ObjectMeta: // determined by the config\n    Spec:       // determined by the config\n    Status: v1.NodeStatus{\n        Capacity:                           // Determined by the config\n        Allocatable:                        // Same as Capacity\n        Conditions:  []v1.NodeCondition{    // populated by the simulator\n            {\n                Type:               v1.NodeReady,\n                Status:             v1.ConditionTrue,\n                LastHeartbeatTime:  // clock,\n                LastTransitionTime: // clock,\n                Reason:             \"KubeletReady\",\n                Message:            \"kubelet is posting ready status\",\n            },\n            {\n                Type:               v1.NodeOutOfDisk,\n                Status:             v1.ConditionFalse,\n                LastHeartbeatTime:  // clock,\n                LastTransitionTime: // clock,\n                Reason:             \"KubeletHasSufficientDisk\",\n                Message:            \"kubelet has sufficient disk space available\",\n            },\n            {\n                Type:               v1.NodeMemoryPressure,\n                Status:             v1.ConditionFalse,\n                LastHeartbeatTime:  // clock,\n                LastTransitionTime: // clock,\n                Reason:             \"KubeletHasSufficientMemory\",\n                Message:            \"kubelet has sufficient memory available\",\n            },\n            {\n                Type:               v1.NodeDiskPressure,\n                Status:             v1.ConditionFalse,\n                LastHeartbeatTime:  // clock,\n                LastTransitionTime: // clock,\n                Reason:             \"KubeletHasNoDiskPressure\",\n                Message:            \"kubelet has no disk pressure\",\n            },\n            {\n                Type:               v1.NodePIDPressure,\n                Status:             v1.ConditionFalse,\n                LastHeartbeatTime:  // clock,\n                LastTransitionTime: // clock,\n                Reason:             \"KubeletHasSufficientPID\",\n                Message:            \"kubelet has sufficient PID available\",\n            },\n        },\n    },\n}\n```\n\n## Related projects\n\nThe design and implementation of this project are inherently inspired by\n[kubernetes](https://github.com/kubernetes/kubernetes), which is licensed under Apache-2.0.\nMoreover, functions in the following files were obtained from Kubernetes project and modified so\nthat they would be compatible with k8s-cluster-simulator.\nPlease see each file for more detail.\n\n* [pkg/scheduler/generic_scheduler_k8s.go](pkg/scheduler/generic_scheduler_k8s.go)\n* [pkg/queue/priority_queue_k8s.go](pkg/queue/priority_queue_k8s.go)\n* [pkg/util/util_k8s.go](pkg/util/util_k8s.go)\n\n\n[build-image]: https://travis-ci.com/pfnet-research/k8s-cluster-simulator.svg\n[build-link]:  http://travis-ci.com/pfnet-research/k8s-cluster-simulator\n[cov-image]:   https://coveralls.io/repos/github/pfnet-research/k8s-cluster-simulator/badge.svg?branch=master\n[cov-link]:    https://coveralls.io/github/pfnet-research/k8s-cluster-simulator?branch=master\n[godoc-image]: https://godoc.org/github.com/pfnet-research/k8s-cluster-simulator/pkg?status.svg\n[godoc-link]:  https://godoc.org/github.com/pfnet-research/k8s-cluster-simulator/pkg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpfnet-research%2Fk8s-cluster-simulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpfnet-research%2Fk8s-cluster-simulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpfnet-research%2Fk8s-cluster-simulator/lists"}