<?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/versions/v0.2.4/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/versions/v0.2.4/docs/getting-started/index.xml" rel="self" type="application/rss+xml"/><item><title>Core Concepts</title><link>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/getting-started/core-concepts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/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, read from Prometheus as the OpenTelemetry hardware metrics &lt;code&gt;hw.energy&lt;/code&gt; and &lt;code&gt;hw.power&lt;/code&gt; or as &lt;a href="https://github.com/sustainable-computing-io/kepler"&gt;Kepler&lt;/a&gt; energy counters, and per-pod resource utilization via cAdvisor) to maintain an up-to-date model of each node&amp;rsquo;s thermal and power state.&lt;/p&gt;</description></item><item><title>Quickstart</title><link>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/getting-started/quickstart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/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/versions/v0.2.4/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;li&gt;Prometheus, for measured node power. The chart reads node power from Prometheus by default (&lt;code&gt;NODE_POWER_SOURCE=prometheus&lt;/code&gt;): it expects Prometheus at &lt;code&gt;http://prometheus-operated.monitoring:9090&lt;/code&gt; with its OTLP receiver on (&lt;code&gt;--web.enable-otlp-receiver&lt;/code&gt;), receiving &lt;code&gt;hw.energy&lt;/code&gt; or &lt;code&gt;hw.power&lt;/code&gt; for each node. Without that data every node reads 0 W, with source &lt;code&gt;prometheus-no-data&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;values/prometheus-grafana.yaml&lt;/code&gt; configures kube-prometheus-stack this way (&lt;a href="https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/architecture/telemetry/#prometheus-settings"&gt;Prometheus settings&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/joulie-k8s/Joulie/tree/main/examples/11-otel-collector-bridge"&gt;&lt;code&gt;examples/11-otel-collector-bridge&lt;/code&gt;&lt;/a&gt; converts Kepler, dcgm-exporter and AMD device-metrics-exporter metrics into those names.&lt;/li&gt;
&lt;li&gt;To run without it, set &lt;code&gt;controllerManager.env.NODE_POWER_SOURCE=static&lt;/code&gt; (0 W for every node).&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;</description></item><item><title>Pod Compatibility for Joulie</title><link>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/getting-started/workload-compatibility/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/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/versions/v0.2.4/docs/getting-started/daemonset/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/getting-started/daemonset/</guid><description>&lt;p&gt;The chart runs the agent in one of three modes, or not at all (&lt;code&gt;agent.mode&lt;/code&gt;):&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;code&gt;agent.mode&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;Pods&lt;/th&gt;
 &lt;th&gt;Use&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;daemonset&lt;/code&gt; (default)&lt;/td&gt;
 &lt;td&gt;one pod per managed node (&lt;code&gt;charts/joulie/templates/agent-daemonset.yaml&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;real hardware&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;pool&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;a StatefulSet whose pods each run many logical per-node agents (&lt;code&gt;agent-statefulset.yaml&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;KWOK experiments over the simulator&amp;rsquo;s HTTP API&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;emulated&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;one Deployment per node of the simulated cluster (&lt;code&gt;agent-emulated.yaml&lt;/code&gt;), reading that node&amp;rsquo;s emulated &lt;code&gt;/sys&lt;/code&gt; and GPU tools&lt;/td&gt;
 &lt;td&gt;the &lt;a href="https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/simulator/simulated-cluster/"&gt;simulated cluster&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;no agent&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&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/versions/v0.2.4/docs/getting-started/05-configuration-reference/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/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 controller manager &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;p&gt;&lt;strong&gt;Booleans.&lt;/strong&gt; The agent, the controller manager and the simulator read every on/off variable the same way: &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;yes&lt;/code&gt; or &lt;code&gt;on&lt;/code&gt;, and &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;no&lt;/code&gt; or &lt;code&gt;off&lt;/code&gt;, in any case, with surrounding spaces ignored. Unset or empty means the default. Any other value keeps the default and logs one warning naming the variable, so a typo never flips a switch. The exceptions are &lt;code&gt;SIM_OTEL_FILE_METRICS&lt;/code&gt;, &lt;code&gt;OTEL_SDK_DISABLED&lt;/code&gt; and &lt;code&gt;fakesmi&lt;/code&gt;&amp;rsquo;s &lt;code&gt;HWEMU_UNPRIVILEGED&lt;/code&gt;, whose rows say how they are read.&lt;/p&gt;</description></item><item><title>Upgrading</title><link>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/getting-started/06-upgrading/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://joulie-k8s.github.io/Joulie/versions/v0.2.4/docs/getting-started/06-upgrading/</guid><description>&lt;p&gt;What to check when you upgrade a Joulie installation from v0.2 to v0.3. Go through the list before running &lt;code&gt;helm upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="before-the-upgrade"&gt;Before the upgrade&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Apply the new CRDs.&lt;/strong&gt; &lt;code&gt;helm upgrade&lt;/code&gt; never updates CRDs, and the API server prunes every field the installed CRD does not know, such as the governor fields of &lt;code&gt;NodeTwin&lt;/code&gt; and &lt;code&gt;NodeHardware&lt;/code&gt;. Apply them first:&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;kubectl apply -f charts/joulie/crds/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Without a checkout, take them from the release chart: &lt;code&gt;helm pull oci://registry.cern.ch/joulie/joulie --version &amp;lt;version&amp;gt; --untar --untardir /tmp/joulie-chart&lt;/code&gt;, then &lt;code&gt;kubectl apply -f /tmp/joulie-chart/joulie/crds/&lt;/code&gt;.&lt;/p&gt;</description></item></channel></rss>