<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Getting Started on Joulie</title><link>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/</link><description>Recent content in Getting Started on Joulie</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/index.xml" rel="self" type="application/rss+xml"/><item><title>Core Concepts</title><link>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/core-concepts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/core-concepts/</guid><description>&lt;p&gt;Before installing Joulie, understand the control model.&lt;/p&gt;
&lt;h2 id="what-joulie-is"&gt;What Joulie is&lt;/h2&gt;
&lt;p&gt;Joulie is a Kubernetes-native energy management system that uses &lt;strong&gt;per-node digital twins&lt;/strong&gt; to optimize data center power consumption.&lt;/p&gt;
&lt;p&gt;It continuously ingests telemetry from every node (CPU/GPU power draw via RAPL and NVML/DCGM, per-pod resource utilization via cAdvisor, and optional energy counters from &lt;a href="https://github.com/sustainable-computing-io/kepler"&gt;Kepler&lt;/a&gt;) to maintain an up-to-date model of each node&amp;rsquo;s thermal and power state.&lt;/p&gt;
&lt;p&gt;These per-node digital twins drive two outcomes:&lt;/p&gt;</description></item><item><title>Quickstart</title><link>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/quickstart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/quickstart/</guid><description>&lt;p&gt;This page is the fastest path to run Joulie.
For conceptual context first, read &lt;a href="https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/core-concepts/"&gt;Core Concepts&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Kubernetes cluster with worker nodes&lt;/li&gt;
&lt;li&gt;Node Feature Discovery (NFD) deployed&lt;/li&gt;
&lt;li&gt;Optional for real enforcement: nodes exposing writable power interfaces
&lt;ul&gt;
&lt;li&gt;RAPL power limit files, or&lt;/li&gt;
&lt;li&gt;cpufreq sysfs interfaces&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="install-from-release-recommended"&gt;Install from release (recommended)&lt;/h2&gt;
&lt;p&gt;Install directly from OCI chart release:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm upgrade --install joulie oci://registry.cern.ch/mbunino/joulie/joulie &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --version &amp;lt;version&amp;gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -n joulie-system &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --create-namespace &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -f values/joulie.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="label-nodes-managed-by-the-operator"&gt;Label nodes managed by the operator&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Joulie will only target nodes with a specific label, and ignore
all the others. By default, install does not auto-select nodes.
Default expected selector value is:&lt;/p&gt;</description></item><item><title>Pod Compatibility for Joulie</title><link>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/workload-compatibility/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/workload-compatibility/</guid><description>&lt;p&gt;Joulie uses a single pod annotation to express workload placement intent:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;joulie.io/workload-class: performance | standard
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The scheduler extender reads this annotation and steers pods accordingly. No node affinity rules are needed.&lt;/p&gt;
&lt;h2 id="workload-classes"&gt;Workload classes&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Class&lt;/th&gt;
 &lt;th&gt;Behavior&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;performance&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Must run on full-power nodes. The extender hard-rejects eco nodes.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;standard&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Default. Can run on any node. Adaptive scoring steers toward eco when performance nodes are congested.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If no annotation is present, the extender treats it as &lt;code&gt;standard&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Agent Runtime Modes</title><link>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/daemonset/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/daemonset/</guid><description>&lt;p&gt;The agent supports two runtime modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;daemonset&lt;/code&gt;: real-hardware mode, one pod per real node.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pool&lt;/code&gt;: simulation mode, one pod hosts many logical per-node controllers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chart templates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;charts/joulie/templates/agent-daemonset.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;charts/joulie/templates/agent-statefulset.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="daemonset-mode-real-hardware"&gt;DaemonSet mode (real hardware)&lt;/h2&gt;
&lt;h3 id="required-runtime-settings"&gt;Required runtime settings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;securityContext.privileged: true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Host mount:
&lt;ul&gt;
&lt;li&gt;host path &lt;code&gt;/sys&lt;/code&gt; -&amp;gt; container path &lt;code&gt;/host-sys&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Env:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NODE_NAME&lt;/code&gt; from &lt;code&gt;spec.nodeName&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AGENT_MODE=daemonset&lt;/code&gt; (default)&lt;/li&gt;
&lt;li&gt;optional &lt;code&gt;RECONCILE_INTERVAL&lt;/code&gt; (default &lt;code&gt;20s&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;optional &lt;code&gt;SIMULATE_ONLY=true&lt;/code&gt; (skip host writes, log requested actions)&lt;/li&gt;
&lt;li&gt;optional &lt;code&gt;METRICS_ADDR&lt;/code&gt; (default &lt;code&gt;:8080&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pool-mode-kwok--simulation"&gt;Pool mode (KWOK / simulation)&lt;/h2&gt;
&lt;p&gt;Pool mode preserves per-node semantics but shards logical node controllers across replicas.&lt;/p&gt;</description></item><item><title>Configuration Reference</title><link>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/05-configuration-reference/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/stable/docs/getting-started/05-configuration-reference/</guid><description>&lt;p&gt;Complete reference for all Joulie environment variables. These are set via Helm values or directly in the Deployment/DaemonSet manifests.&lt;/p&gt;
&lt;p&gt;Defaults listed below are the &lt;strong&gt;code defaults&lt;/strong&gt;. The Helm chart (&lt;code&gt;charts/joulie/values.yaml&lt;/code&gt;) overrides some of them — notably, the operator &lt;code&gt;NODE_SELECTOR&lt;/code&gt; defaults to &lt;code&gt;joulie.io/managed=true&lt;/code&gt; in the chart even though the code default is &lt;code&gt;node-role.kubernetes.io/worker&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="agent"&gt;Agent&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;AGENT_MODE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;daemonset&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;daemonset&lt;/code&gt; (one agent per node) or &lt;code&gt;pool&lt;/code&gt; (shared agents with sharding)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;NODE_NAME&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(required in daemonset mode)&lt;/td&gt;
 &lt;td&gt;Name of the node this agent manages&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RECONCILE_INTERVAL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;20s&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;How often the agent reconciles desired state&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;METRICS_ADDR&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;:8080&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address for the Prometheus metrics endpoint&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;SIMULATE_ONLY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;If &lt;code&gt;true&lt;/code&gt;, agent discovers hardware but does not apply power caps&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;HARDWARE_CATALOG_PATH&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;simulator/catalog/hardware.yaml&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Path to the hardware inventory catalog YAML&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="agent-pool-mode"&gt;Agent pool mode&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;POOL_NODE_SELECTOR&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;joulie.io/managed=true&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Label selector for nodes managed by pool agents&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;POOL_SHARDS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Total number of shards for pool mode partitioning&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;POOL_SHARD_ID&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(from pod ordinal)&lt;/td&gt;
 &lt;td&gt;Shard ID for this agent instance&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="agent-dvfs-control"&gt;Agent DVFS control&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DVFS_EMA_ALPHA&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.3&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Exponential moving average smoothing factor for power tracking&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DVFS_HIGH_MARGIN_W&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;10.0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Power above cap (watts) to trigger frequency reduction&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DVFS_LOW_MARGIN_W&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;15.0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Power below cap (watts) to trigger frequency increase&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DVFS_STEP_PCT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Frequency throttle step size (%)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DVFS_COOLDOWN&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;20s&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Minimum duration between DVFS adjustments&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DVFS_TRIP_COUNT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Consecutive samples outside margin before acting&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DVFS_MIN_FREQ_KHZ&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1500000&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Floor frequency for DVFS throttling (kHz)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="agent-telemetry-and-control-backends"&gt;Agent telemetry and control backends&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_CPU_SOURCE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;host&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;CPU telemetry source: &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;prometheus&lt;/code&gt;, &lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_CPU_CONTROL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;host&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;CPU control backend: &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_GPU_CONTROL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;host&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;GPU control backend: &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_CPU_HTTP_ENDPOINT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;HTTP endpoint for CPU telemetry (e.g., &lt;code&gt;http://sim:18080/telemetry/{node}&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_CPU_CONTROL_HTTP_ENDPOINT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;HTTP endpoint for CPU control (e.g., &lt;code&gt;http://sim:18080/control/{node}&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_CPU_CONTROL_MODE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;CPU control mode override&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_GPU_CONTROL_HTTP_ENDPOINT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;HTTP endpoint for GPU control (e.g., &lt;code&gt;http://sim:18080/control/{node}&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_GPU_CONTROL_MODE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;GPU control mode override&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TELEMETRY_HTTP_TIMEOUT_SECONDS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;HTTP client timeout for telemetry/control requests&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="operator"&gt;Operator&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RECONCILE_INTERVAL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1m&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;How often the operator reconciles cluster state&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;METRICS_ADDR&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;:8081&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address for the Prometheus metrics endpoint&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;NODE_SELECTOR&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;node-role.kubernetes.io/worker&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Label selector for managed nodes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RESERVED_LABEL_KEY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;joulie.io/reserved&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Label key for nodes excluded from policy decisions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;POWER_PROFILE_LABEL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;joulie.io/power-profile&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Node label key for the active power profile&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;OPERATOR_NODE_POWER_SOURCE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;static&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Node power data source: &lt;code&gt;static&lt;/code&gt;, &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;prometheus&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;OPERATOR_NODE_POWER_HTTP_ENDPOINT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;HTTP endpoint for per-node power readings&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;OPERATOR_NODE_POWER_PROMETHEUS_ADDRESS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;Prometheus address for per-node power queries&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;OPERATOR_NODE_POWER_PROMETHEUS_QUERY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;PromQL query for per-node power readings&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="power-cap-configuration"&gt;Power cap configuration&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;PERFORMANCE_CAP_WATTS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;5000&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Absolute CPU power cap for performance nodes (watts)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ECO_CAP_WATTS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;120&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Absolute CPU power cap for eco nodes (watts)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CPU_PERFORMANCE_CAP_PCT_OF_MAX&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;100&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;CPU cap as percentage of max for performance nodes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CPU_ECO_CAP_PCT_OF_MAX&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;60&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;CPU cap as percentage of max for eco nodes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CPU_WRITE_ABSOLUTE_CAPS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;If &lt;code&gt;true&lt;/code&gt;, write absolute watts instead of percentage&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;GPU_PERFORMANCE_CAP_PCT_OF_MAX&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;100&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;GPU cap as percentage of max for performance nodes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;GPU_ECO_CAP_PCT_OF_MAX&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;60&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;GPU cap as percentage of max for eco nodes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;GPU_WRITE_ABSOLUTE_CAPS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;If &lt;code&gt;true&lt;/code&gt;, write absolute GPU watts instead of percentage&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;GPU_MODEL_CAPS_JSON&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;JSON map of GPU model name to &lt;code&gt;{&amp;quot;minCapWatts&amp;quot;: N, &amp;quot;maxCapWatts&amp;quot;: M}&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;GPU_PRODUCT_LABEL_KEYS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;joulie.io/gpu.product,...&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Comma-separated node label keys to read GPU product name&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="policy-configuration"&gt;Policy configuration&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;POLICY_TYPE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;static_partition&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Policy algorithm: &lt;code&gt;static_partition&lt;/code&gt;, &lt;code&gt;queue_aware_v1&lt;/code&gt;, or &lt;code&gt;rule_swap_v1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;STATIC_HP_FRAC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.50&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Fraction of nodes allocated to performance in &lt;code&gt;static_partition&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;QUEUE_HP_BASE_FRAC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.60&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Base fraction of performance nodes in &lt;code&gt;queue_aware_v1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;QUEUE_HP_MIN&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Minimum performance nodes in &lt;code&gt;queue_aware_v1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;QUEUE_HP_MAX&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1000000&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Maximum performance nodes in &lt;code&gt;queue_aware_v1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;QUEUE_PERF_PER_HP_NODE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Performance pods per performance node ratio in &lt;code&gt;queue_aware_v1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="facility-metrics"&gt;Facility metrics&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Variable&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ENABLE_FACILITY_METRICS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Enable polling data-center-level metrics from Prometheus&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACILITY_PROMETHEUS_ADDRESS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;http://prometheus-operated.monitoring:9090&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Prometheus endpoint for facility metric queries&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACILITY_POLL_INTERVAL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;30s&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;How often facility metrics are polled&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACILITY_AMBIENT_TEMP_METRIC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;datacenter_ambient_temperature_celsius&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PromQL metric name for ambient temperature&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACILITY_IT_POWER_METRIC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;datacenter_total_it_power_watts&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PromQL metric name for total IT power draw&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACILITY_COOLING_POWER_METRIC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;datacenter_cooling_power_watts&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PromQL metric name for cooling infrastructure power&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACILITY_ZONE_AMBIENT_METRIC_TEMPLATE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;PromQL template for per-zone ambient temperature, e.g. &lt;code&gt;datacenter_ambient_temperature_celsius{zone=&amp;quot;%s&amp;quot;}&lt;/code&gt;. Use &lt;code&gt;%s&lt;/code&gt; as the zone name placeholder. Empty = disabled. (planned — not yet wired to env vars)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACILITY_RACK_POWER_METRIC_TEMPLATE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;(empty)&lt;/td&gt;
 &lt;td&gt;PromQL template for per-rack power draw, e.g. &lt;code&gt;datacenter_rack_power_watts{rack=&amp;quot;%s&amp;quot;}&lt;/code&gt;. Use &lt;code&gt;%s&lt;/code&gt; as the rack name placeholder. Empty = disabled. (planned — not yet wired to env vars)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="node-topology"&gt;Node topology&lt;/h3&gt;
&lt;p&gt;Joulie supports optional per-rack PSU stress and per-zone cooling stress. This is activated by adding standard node labels:&lt;/p&gt;</description></item></channel></rss>