serverless-agent: serverless, minus the container
A Go worker that unpacks code, drops privileges, clamps memory with cgroups v2, and streams execution logs through Redis.
- `serverless-agent` treats a function as a Linux process first and a serverless workload second, which cuts out the container runtime entirely.
- Its privileged setup phase exists only to build the boundary, then execution drops to an unprivileged user inside a per-invocation cgroup.
- Redis is part of the execution path, not a sidecar, because it carries logs, metadata, and execution records back to the control plane.
- The design is intentionally narrow, Linux-specific, and fast, which makes its trade-offs easier to defend than a generic FaaS stack.
No container starts here
serverless-agent makes a blunt choice: it runs a function as an ordinary Linux process, then uses cgroups v2 and a privilege drop to keep that process in a cage. There is no container runtime in the path, which is exactly the point.
That choice changes the shape of serverless. Instead of paying for images, namespaces, and orchestration overhead, the worker spends its effort on a narrower problem: unpack code, fence it in, run it, and tear it down cleanly.
Why this worker exists
This repo is the node-side executor in a larger Serverless Fabric system. The control plane talks gRPC, the node reads YAML config, uses mTLS, and hands function work to this agent.
The interesting part is not that it can execute code, but that it does so with a small amount of machinery. Redis carries function metadata, execution state, and live log updates back to the rest of the platform, so the agent stays focused on local execution.
What happens when a function lands
A deploy request lands as a zip archive. `DeployFunction` unpacks it into the runner directory, fixes ownership and permissions, and prepares it for execution.
`ExecuteFunction` then creates a fresh cgroup v2 node for the invocation, sets a memory ceiling, and launches the handler after dropping from root to the unprivileged `flux-runner` user. If the process misbehaves, the agent kills the process group, removes the cgroup, and writes the final status back out.
Live output is not a side channel. Stdout and stderr are wrapped by an `io.Writer`, streamed into Redis, and turned into execution records with a TTL so the control plane can fetch them later.
Root opens the door, then walks away
This is the repo's sharpest security move. Root is used only long enough to set up boundaries, then execution drops to `flux-runner` before any user code runs.
That split keeps the trusted part of the agent small. The privileged surface is creation and cleanup, not the runtime path itself.
Redis is the memory layer
Redis is doing more than acting as a cache. It is the bridge between a transient local process and a distributed control plane.
The agent stores execution records, function configuration, and live log state there, which means the platform can query what happened without keeping the entire history on the node. That is a practical choice when the node's main job is to run and dispose of work quickly.
Why this beats the usual stack
| Execution unit | Startup path | Isolation strength | Filesystem overhead | Operational complexity | Best fit |
|---|---|---|---|---|---|
| serverless-agent | Linux process plus cgroup v2 | Medium, kernel boundary plus UID separation | Low | Low | Linux-native workers that need fast startup |
| Docker-based FaaS | Container | Strong, with namespaces and image isolation | Medium to high | Medium to high | General-purpose multi-tenant serverless |
| Firecracker microVM | MicroVM | Strong | Medium | Medium | Tight isolation with less weight than a full VM |
| VM-based runners | Full VM | Very strong | High | High | Highly isolated agent sessions or bespoke tooling |
The point is not that containers are obsolete. It is that a process plus cgroup can be enough when you care more about cold-start simplicity and Linux control than about the full isolation surface of a container or VM.
If your workload expects custom kernels or cross-platform portability, this design narrows the runway on purpose. That makes the trade-off easier to read, not weaker.
The limits are part of the design
This approach assumes Linux, cgroups v2, and a trustworthy host setup. That is a narrow target, but it is also the reason the implementation can stay lean.
It also leans on memory limits more than a broad resource policy. No CPU pinning, no disk quota, and no attempt to pretend portability is free. That makes `serverless-agent` feel narrower than Docker or microVM platforms, but cleaner for the exact problem it is trying to solve.





