feat: schedule hosted agent sandboxes alongside MCP server pods - #7484
Open
ibuildthecloud wants to merge 1 commit into
Open
feat: schedule hosted agent sandboxes alongside MCP server pods#7484ibuildthecloud wants to merge 1 commit into
ibuildthecloud wants to merge 1 commit into
Conversation
Hosted agent sandboxes share the MCP namespace but set no affinity, tolerations, or runtimeClassName, so a deployment that sets a node pool aside for MCP servers -- selected by affinity and reached through a taint -- got its MCP pods there and its sandboxes anywhere. That matters more for a sandbox than for a single MCP pod: the pool volume binds to the node the first sandbox lands on, so one misplaced sandbox strands the whole pool off the intended nodes. Sandboxes now take those three settings from the same K8sSettings singleton the MCP backend reads, rather than from settings of their own. A second set of chart values would only give the two a way to disagree, and reading the singleton per apply is what lets an admin retarget both at once on an install where the settings did not come from Helm. The backend takes this as a provider function rather than plain fields, so the package keeps its one Obot dependency and does not learn where the settings live -- and so placement is re-read on each apply instead of being captured at startup. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011egKVweRVwSS79iMK1887y
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the hosted agent Kubernetes backend so sandbox pods inherit the same scheduling constraints (affinity, tolerations, runtimeClassName) as MCP server pods, ensuring both workloads co-locate on the intended node pool and preventing unintended PVC binding to the wrong nodes.
Changes:
- Added a
Schedulingstruct andOptions.Schedulingprovider to supply per-reconcile pod placement settings. - Updated sandbox object generation to apply affinity/tolerations/runtimeClassName to the sandbox
PodSpec. - Wired the provider from
pkg/services/config.goby reading theK8sSettingssingleton; added/updated unit tests and Helm values comments.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pkg/services/config.go | Adds a scheduling provider that reads K8sSettings per call and injects it into the hosted agent Kubernetes backend. |
| pkg/services/config_test.go | Updates the hosted agent backend constructor call for the new parameter. |
| pkg/agentbackend/kubernetes/backend.go | Introduces Scheduling + Options.Scheduling provider hook to supply sandbox pod placement. |
| pkg/agentbackend/kubernetes/instance.go | Applies scheduling values to the sandbox pod spec and threads ctx into instanceObjects. |
| pkg/agentbackend/kubernetes/objects_test.go | Adds scheduling propagation tests and updates existing tests for the new ctx parameter. |
| pkg/agentbackend/kubernetes/subdir_test.go | Updates calls to instanceObjects to pass a context. |
| pkg/agentbackend/kubernetes/podsecurity_test.go | Updates calls to instanceObjects to pass a context. |
| chart/values.yaml | Clarifies via comments that MCP scheduling values also govern hosted agent sandbox pods. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+102
to
+105
| // Scheduling supplies the placement every sandbox pod is created with. It is | ||
| // read per apply rather than captured once, because the settings it comes | ||
| // from are editable while the server runs. Nil, or a nil return, means the | ||
| // scheduler places sandboxes with no constraints of Obot's own. |
thedadams
approved these changes
Aug 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Hosted agent sandboxes share the MCP namespace, but their pod spec sets no
affinity,tolerations, orruntimeClassName— seeinstance.go, which sets onlyPriorityClassName, security context, volumes, and pull secrets.So on a deployment that sets a node pool aside for MCP servers — selected by
mcpServerDefaults.affinityand reached through a taint tolerated bymcpServerDefaults.tolerations— MCP server pods land there and sandboxes land anywhere.That matters more for a sandbox than for a single MCP pod. The pool PVC uses
volumeBindingMode: WaitForFirstConsumerand binds to whichever node the first sandbox is placed on, so one misplaced sandbox strands the entire pool off the intended nodes for as long as the volume lives.Approach
Sandboxes now take those three settings from the same
K8sSettingssingletonpkg/mcp/kubernetes.goreads, rather than from chart values of their own.A second set of values would only give the two a way to disagree, and an operator would have to keep them in sync by hand to get the co-location they already asked for once. Reading the singleton per apply — rather than capturing it at startup — is also what lets an admin retarget both at once through the settings API on an install where the values did not come from Helm (
SetViaHelmfalse).The backend takes this as an
Options.Scheduling func(context.Context) Schedulingprovider rather than plain fields.pkg/agentbackend/kubernetescurrently imports exactly one Obot package, and injecting a storage client instead would pullstorage/apis/obot.obot.ai/v1andsysteminto a package that so far speaks only inagentbackendand raw Kubernetes types. The provider returns a plain struct, so knowledge of where the settings live stays inpkg/services/config.go.A failed read logs and falls back to unconstrained placement, matching what the MCP backend does on the same error — a settings read that fails should not stop a sandbox from starting.
Changes
pkg/agentbackend/kubernetes/backend.go—Schedulingstruct and theOptions.Schedulingproviderpkg/agentbackend/kubernetes/instance.go—instanceObjectstakes actxand applies all three to the sandboxPodSpecpkg/services/config.go—hostedAgentsSchedulingreads theK8sSettingssingletonchart/values.yaml— comments only;mcpServerDefaults' three scheduling values now govern sandboxes too. No new values or env vars.Tests
TestInstanceObjectsApplySchedulingasserts all three reach the pod spec;TestInstanceObjectsWithoutSchedulingAreUnconstrainedpins the nil-provider behaviour.Not included
The cleanup Job pod in
instance.gostill sets no tolerations. It runs in the pool and has to reach the pool volume's node, so on a node pool reached through a taint it will be unschedulable and instance deletion never completes —BackoffLimit: 4does not help, since the pod is never placed at all. Left out to keep this PR to the sandbox path; happy to fold it in here if preferred.🤖 Generated with Claude Code
https://claude.ai/code/session_011egKVweRVwSS79iMK1887y