Agent Runtime Modes
The chart runs the agent in one of three modes, or not at all (agent.mode):
agent.mode | Pods | Use |
|---|---|---|
daemonset (default) | one pod per managed node (charts/joulie/templates/agent-daemonset.yaml) | real hardware |
pool | a StatefulSet whose pods each run many logical per-node agents (agent-statefulset.yaml) | KWOK experiments over the simulator’s HTTP API |
emulated | one Deployment per node of the simulated cluster (agent-emulated.yaml), reading that node’s emulated /sys and GPU tools | the simulated cluster |
none | no agent |
DaemonSet mode (real hardware)
Required runtime settings
securityContext.privileged: true- Host mount:
- host path
/sys-> container path/host-sys
- host path
- Env:
NODE_NAMEfromspec.nodeNameAGENT_MODE=daemonset(default)- optional
RECONCILE_INTERVAL(default20s) - optional
SIMULATE_ONLY=true(skip host writes, log requested actions) - optional
METRICS_ADDR(default:8080)
Pool mode (KWOK / simulation)
Pool mode preserves per-node semantics but shards logical node controllers across replicas.
Required env vars:
AGENT_MODE=poolPOOL_NODE_SELECTOR(for examplejoulie.io/managed=true)POOL_SHARDS(total shards)POOL_SHARD_ID(orPOD_NAMEfrom StatefulSet ordinal)
Sharding function:
owns(node) = fnv32(nodeName) % POOL_SHARDS == POOL_SHARD_ID
In chart values:
agent:
mode: pool
pool:
replicas: 2
shards: 2
nodeSelector: "joulie.io/managed=true"
Use daemonset mode for real /host-sys enforcement and pool mode for KWOK-scale simulation: pool mode runs KWOK experiments over the simulator’s HTTP API (KWOK and Standalone Modes), with a real controller manager and scheduler and no physical hardware.
Emulated mode (simulated cluster)
With agent.mode: emulated the chart renders one Deployment joulie-agent-emu-<i> per entry of agent.emulated.nodes, on the node that runs the simulator in emulate mode. Each runs the unmodified agent binary for one node, with that node’s emulated tree mounted where the agent reads /sys, /proc/cpuinfo and the GPU tools, a literal NODE_NAME, and no host network or privileges. The simulated cluster scripts write agent.emulated.nodes for you; the values are under Agent chart values.
Managed node selector
joulie.io/managed=true
This label defines managed scope for both controller manager and agent by default.
- Pool mode:
- uses
POOL_NODE_SELECTOR(chart default:joulie.io/managed=true).
- uses
- DaemonSet mode:
- chart default sets
agent.daemonset.nodeSelector.joulie.io/managed: "true".
- chart default sets
Default behavior:
- nodes without
joulie.io/managed=trueare outside controller manager policy scope; - no DaemonSet agent pod is scheduled on unlabeled nodes;
- every labelled node gets an agent pod whatever its taints, since the chart’s
agent.tolerationstolerates every taint, and whatever its architecture,amd64orarm64. A managed node the agent still does not reach reportsAgentReportingFalseon itsNodeTwin(Managed nodes without an agent).
Override example (if you need a different scope):
agent:
daemonset:
nodeSelector:
custom.scope/energy-managed: "true"
RBAC
Agent needs:
nodesnodetwins.joulie.io
Pool mode uses the same API permissions.
NFD labels used by agent
CPU vendor:
feature.node.kubernetes.io/cpu-vendor(if present)feature.node.kubernetes.io/cpu-model.vendor_id(fallback, common with NFD)
GPU vendor discovery hints:
feature.node.kubernetes.io/pci-10de.present(NVIDIA)feature.node.kubernetes.io/pci-1002.present(AMD)feature.node.kubernetes.io/pci-8086.present(Intel)- and the class-specific forms
pci-<class>_<vendor>.present, NFD’s default, for the classes GPUs enumerate as:0300(VGA),0302(3D controller),0380(other display controller) and1200(processing accelerator, such as an AMD Instinct MI300X)
GPU labels are used for capability detection, and GPU cap intents are enforced when a supported backend is available.
Desired-state source
On each node, agent resolves desired state only from:
NodeTwin.specmatchingspec.nodeName=<this-node>.