Skip to content

beam-thunder integration - #1814

Open
rohanphadnis-thunder wants to merge 60 commits into
beam-cloud:mainfrom
Thunder-Compute:main
Open

beam-thunder integration#1814
rohanphadnis-thunder wants to merge 60 commits into
beam-cloud:mainfrom
Thunder-Compute:main

Conversation

@rohanphadnis-thunder

@rohanphadnis-thunder rohanphadnis-thunder commented Jul 29, 2026

Copy link
Copy Markdown

Beam-Thunder Integration

This PR is for integrating beta9 with Thunder Compute. Key changes:

Phase 1: gpu_virtualized

gpu_virtualized, a boolean value is propagated from the Python beam client SDK to the beam gateway to each individual worker. Note that this is still a temporary change, preserved for its usefulness in prototyping. Eventually, GPU virtualization is controlled at the level of the pool. If a pool is virtualized, all its containers would be virtualized as well.

Phase 2: Beam Worker

The beam worker implements beta9/pkg/worker/thunder.go. This contains the ContainerThunderManager, a struct which implements the GPUManager interface. It mounts nvidia-smi, libcuda.so, and libnvidia-ml.so into the container from the host, but blocks the mounting of any physical GPU. For assigning and unassigning GPUs, it will use the gateway's thunder service and mint/revoke enrollment tokens as needed. Finally, when the container starts, the worker will run the curl installer in the container.

Phase 3: Beam Agent

The beam agent change is very easy.

  1. Tailscale is initialized on the host node. This was already the case. Thunder will simply need an IP address which is discoverable to all nodes and container clients in the pool. It will read the IP address of the tailscale0 interface.
  2. Next, the gateway will use newly added RPC call CreateNodeEnrollment to get a node enrollment token and run the node curl installer.
  3. Once the installer is run, the agent can continue its setup.

Phase 4: Beam Gateway

The beam gateway provides RPC calls to the beam agent and the beam worker in order to mint these enrollment tokens. It acts as a central client for the Thunder Compute API. This design ensures that the global API token isn't propagated to each beam agent/worker.

To make the Thunder information stateful, 3 new redis maps are added:

  1. for mapping client id to enrollment token id. This is so that when the client is unenrolled (ie during sandbox teardown), the thunder client's enrollment can be revoked.
  2. for mapping machine id to enrollment token id. This is so that if nodes ever need to be unregistered, the enrollment tokens for the nodes can be revoked.
  3. for mapping beam pools to thunder zone IDs. Each pool gets its own Thunder Zone ID.

Summary by cubic

Integrates Thunder virtual GPUs with pool-level control and startup safety. Previously only physical GPUs were used and containers published “started” immediately; now pools can enable virtualization, workers choose Thunder per request, and “started” waits until the Thunder installer completes.

  • Pool control: adds WorkerPoolConfig.gpuVirtualized (surfaced in OpenAPI and Python SDK) and propagates to workers via WORKER_GPU_VIRTUALIZED.

  • Agent flow: queries pool mode with GetAgentPoolVirtualization, discovers a cache-local private thunderd IP, installs via CreateNodeEnrollment, and uninstalls on shutdown (ExecStopPost); increases TimeoutStopSec to 60s and soft-fails with logs if unavailable.

  • Worker behavior: selects Thunder vs physical GPUs per request, injects Thunder LD_PRELOAD, mounts nvidia-smi, libcuda.so.1, libnvidia-ml.so.1, and the Thunder library, and uses pre-init/startup hooks so “started” is withheld until install finishes; creates/revokes client enrollments on start/teardown.

  • Gateway: registers a new ThunderService (Redis-backed) using github.com/Thunder-Compute/thunder-sdk for client/node enrollments and per-pool zones; exposes CreateNodeEnrollment/DeleteNodeEnrollment via agent-token auth and returns a clear error if Thunder is disabled; adds consistent Redis keys and a pool lock.

  • Tooling: generates pkg/gateway/services/thunder/thunder.proto, adds NewThunderServiceClient, and updates bin/gen_proto.sh; updates GPU manager interfaces to accept context/request.

  • Migration

    • Set THUNDER_API_URL and THUNDER_API_TOKEN in the gateway environment.
    • Ensure agents can resolve a private IP for thunderd; node enrollment runs automatically.
    • Enable virtualization per pool via WorkerPoolConfig.gpuVirtualized.
    • Expect container “started” events to delay until the Thunder install completes.

Written for commit 5ab900b. Summary will update on new commits.

Review in cubic

@luke-lombardi luke-lombardi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High level this looks good, mostly just some nit-picks around code organization

Comment thread pkg/abstractions/common/instance.go Outdated
request := &types.ContainerRequest{
Cpu: i.StubConfig.Runtime.Cpu,
GpuCount: uint32(gpuCount),
GpuVirtualized: i.StubConfig.Runtime.GpuVirtualized,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still required? I know we talked about removing from the client, but I feel like it should also be removed from the container request as well.

Comment thread pkg/worker/lifecycle.go Outdated
}

func (s *Worker) deleteContainer(containerId string) {
s.thunderSetupTracker.Delete(containerId)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels like the thundersetuptracker calls could be pushed down into the runtime layer potentially? feels like it could get confusing having those calls up here next to the core container lifecycle pieces

Comment thread pkg/worker/lifecycle.go Outdated
}()

exitCode, _ = s.runContainer(ctx, request, outputLogger, outputWriter, startedChan, checkpointPIDChan, opts.StartupStartedAt, opts.StartupPortBindings, opts.CheckpointFilesystemRestore)
exitCode, _ = s.runContainer(ctx, request, outputLogger, outputWriter, startedChan, checkpointPIDChan, thunderInstallResult, opts.StartupStartedAt, opts.StartupPortBindings, opts.CheckpointFilesystemRestore)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above, if theres a way to get this to be jammed into a runtime (under pkg/runtime) I think that would be cleaner

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 13 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread pkg/gateway/services/compute/agent.go
Comment thread pkg/agent/transport.go Outdated
Comment thread pkg/abstractions/pod/pod.go Outdated
gpuCount = 1
}

log.Info().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this log required? we log this in the scheduler too I think

Comment thread pkg/agent/transport.go Outdated
Comment thread pkg/gateway/services/thunder/db.go Outdated
return err
}

func (r *RedisRepository) DeleteZone(ctx context.Context, workspaceID, poolName string) error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may make sense to push this into the repository layer. repository/thunder_redis.go or something

Comment thread pkg/runtime/startup_hook_wrapper.go Outdated
"github.com/opencontainers/runtime-spec/specs-go"
)

const startupHookShutdownTimeout = 5 * time.Second

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code can probably also live inside startup_hook.go maybe?

Comment thread pkg/worker/lifecycle.go
Comment thread pkg/worker/thunder.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants