<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Todea</title>
    <description>The latest articles on DEV Community by Todea (todea).</description>
    <link>https://dev.to/todea</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F13221%2F83088152-d0ae-4dd0-af1c-10e137e83c9c.png</url>
      <title>DEV Community: Todea</title>
      <link>https://dev.to/todea</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/todea"/>
    <language>en</language>
    <item>
      <title>HAMi Explained: Why Your GPUs Sit Idle While Your Bill Doesn't</title>
      <dc:creator>Ivan Porta</dc:creator>
      <pubDate>Tue, 14 Jul 2026 16:32:43 +0000</pubDate>
      <link>https://dev.to/todea/hami-explained-why-your-gpus-sit-idle-while-your-bill-doesnt-5bgl</link>
      <guid>https://dev.to/todea/hami-explained-why-your-gpus-sit-idle-while-your-bill-doesnt-5bgl</guid>
      <description>&lt;p&gt;Before the release of &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/dynamic-resource-allocation/" rel="noopener noreferrer"&gt;Dynamic Resource Allocation&lt;/a&gt; and its alpha partitionable-device and consumable-capacity extensions, Kubernetes scheduled GPUs only as whole cards, with no native option to allocate a fraction of a device. For example, if a pod requires only 4 GB of an 80 GB H100, it still reserves the entire GPU for its lifetime. This leads to significant underutilization of expensive hardware in shared clusters. Chatbots designed for peak traffic may remain idle on dedicated cards during off-peak hours; multiple inference services often run on separate GPUs despite low usage, and monitoring dashboards may show all GPUs allocated while tools like &lt;code&gt;nvidia-smi&lt;/code&gt; often reveal minimal actual utilization. As a result, new budget requests for additional GPUs arise because the cluster appears to be at capacity. DRA narrows this gap by preventing over-committing a device's declared budget, but it does not natively enforce resource limits once a pod is running, which remains the device driver's responsibility. This is where HAMi provides value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://project-hami.io/" rel="noopener noreferrer"&gt;HAMi&lt;/a&gt; (Heterogeneous AI Computing Virtualization Middleware) closes the gap by allowing pods to request an exact portion of a GPU’s memory and compute, with an in-container enforcement layer that holds them to it, with no changes to applications or images. Companies like SNOW and NIO run HAMi in production, and the project reached CNCF Incubating in July 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is HAMi, actually?
&lt;/h2&gt;

&lt;p&gt;HAMi is an &lt;a href="https://github.com/Project-HAMi/HAMi" rel="noopener noreferrer"&gt;open-source&lt;/a&gt; GPU virtualization layer for Kubernetes. It lets a pod request a precise amount of memory and an AI accelerator’s compute, then schedules the pod onto a device with that much free capacity, binding it to that slice at runtime. The same model spans many accelerators, including NVIDIA GPUs, Cambricon MLUs, Hygon DCUs, Ascend NPUs, Moore Threads, MetaX, and others, each via its own device plugin and isolation backend. On NVIDIA, for example, HAMi replaces the stock device plugin and enforces the memory cap by intercepting the CUDA driver API within the container; other vendors provide analogous library- or hardware-level isolation.&lt;/p&gt;

&lt;p&gt;The user experience is deliberately simple: the standard device resource request is extended with one or more limits that the scheduler reads at scheduling time to find a card with sufficient free memory and compute resources. On NVIDIA, you keep requesting &lt;code&gt;nvidia.com/gpu&lt;/code&gt; and add the two extended resources beside it: &lt;code&gt;nvidia.com/gpumem&lt;/code&gt; and &lt;code&gt;nvidia.com/gpucores&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;       
    &lt;span class="na"&gt;nvidia.com/gpumem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8000&lt;/span&gt; 
    &lt;span class="na"&gt;nvidia.com/gpucores&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two comparisons put that isolation model in context. &lt;a href="https://docs.nvidia.com/datacenter/tesla/mig-user-guide/latest/introduction.html" rel="noopener noreferrer"&gt;MIG&lt;/a&gt; draws a hardware boundary: each instance gets its own SMs and a dedicated route through L2 cache slices, memory controllers, and DRAM channels. HAMi’s boundary is a fence, not a wall. Its limits are enforced in software inside the container, which reliably holds workloads to their budgets but cannot contain a device-level failure: a hung process, a driver reset, or an XID error on the shared card still hits every tenant on it. The two work at different layers, though, and they can be complementary rather than competing; we will come back to how HAMi can drive MIG directly.&lt;/p&gt;

&lt;p&gt;Compared with &lt;a href="https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-sharing.html" rel="noopener noreferrer"&gt;time-slicing&lt;/a&gt;, however, HAMi offers significant improvements in stability. Time-slicing simply advertises multiple schedulable replicas of a single card and interleaves their workloads on the compute engine, without per-replica memory caps or isolation. That makes it dangerously easy for one workload to allocate past its notional share and take the others down with it. HAMi refuses the excess allocation instead. The following log shows PyTorch reporting a total capacity matching the 1000 MB limit set by &lt;code&gt;nvidia.com/gpumem&lt;/code&gt;; when the pod tried to exceed it, the allocator stopped it with an OOM error, leaving the other vGPU tenants unaffected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;EngineCore &lt;span class="nv"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;95&lt;span class="o"&gt;)&lt;/span&gt; ERROR 07-11 21:15:46 &lt;span class="o"&gt;[&lt;/span&gt;core.py:1231] torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 20.00 MiB. GPU 0 has a total capacity of 1000.00 MiB of which 12.00 MiB is free. Including non-PyTorch memory, this process has 1020.00 MiB memory &lt;span class="k"&gt;in &lt;/span&gt;use. Of the allocated memory 864.68 MiB is allocated by PyTorch, and 41.32 MiB is reserved by PyTorch but unallocated. If reserved but unallocated memory is large try setting &lt;span class="nv"&gt;PYTORCH_CUDA_ALLOC_CONF&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;expandable_segments:True to avoid fragmentation.  See documentation &lt;span class="k"&gt;for &lt;/span&gt;Memory Management  &lt;span class="o"&gt;(&lt;/span&gt;https://docs.pytorch.org/docs/stable/notes/cuda.html#optimizing-memory-usage-with-pytorch-cuda-alloc-conf&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How a shared-GPU request flows through HAMi
&lt;/h2&gt;

&lt;p&gt;From manifest to enforced slice, a request passes through four hands, shown in the diagram below: the device plugin advertises each card’s capacity, the mutating webhook reroutes the pod to HAMi’s scheduler, the scheduler extender picks a node and a slice, and an in-container library enforces that slice at runtime.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1btvht4korsnswcecpr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1btvht4korsnswcecpr.png" alt=" " width="800" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On each node, the &lt;code&gt;device-plugin&lt;/code&gt; (which runs as a DaemonSet) polls the local devices every 30 seconds via the vendor's management library (e.g., NVML for NVIDIA, which powers &lt;code&gt;nvidia-smi&lt;/code&gt;). It then publishes this telemetry data by patching the node with a &lt;code&gt;hami.io/node-&amp;lt;vendor&amp;gt;-register&lt;/code&gt; annotation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;kubectl get nodes gtrekter -o yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hami.io/node-handshake&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Requesting_2026-07-09 09:03:57&lt;/span&gt;
    &lt;span class="na"&gt;hami.io/node-nvidia-register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[{"id":"GPU-a2fd58d2-edbe-4cfd-4dbd-d4197b35431e","count":10,"devmem":6141,"devcore":100,"type":"NVIDIA&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GeForce&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;RTX&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;4050&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Laptop&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GPU","mode":"hami-core","health":true,"devicepairscore":{}}]'&lt;/span&gt;
    &lt;span class="na"&gt;nvidia.com/gpu-driver-upgrade-enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a pod is created, the API server calls HAMi's mutating webhook, which checks the pod's manifest against its supported device drivers, including NVIDIA, Ascend, AWS Neuron, and others. Each driver checks the container's &lt;code&gt;resources.limits&lt;/code&gt; for recognized resource keys. For example, the NVIDIA driver looks for &lt;code&gt;nvidia.com/gpu&lt;/code&gt;, &lt;code&gt;nvidia.com/gpumem&lt;/code&gt;, and &lt;code&gt;nvidia.com/gpucores&lt;/code&gt;, while the Cambricon MLU driver matches &lt;code&gt;cambricon.com/vmlu&lt;/code&gt;. As soon as a compatible request is detected, HAMi updates the pod's &lt;code&gt;schedulerName&lt;/code&gt; to &lt;code&gt;hami-scheduler&lt;/code&gt;, ensuring the pod is handled by HAMi's device-aware scheduling logic rather than the default Kubernetes scheduler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Under HAMi, requesting &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt; no longer means "one whole card," but rather "one shared physical card," with the memory and core limits dictating the exact slice. However, a pod that omits &lt;code&gt;nvidia.com/gpumem&lt;/code&gt; falls back to the configured default (100% of the card's memory).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; hami-system deploy/hami-scheduler &lt;span class="nt"&gt;-c&lt;/span&gt; vgpu-scheduler-extender
I0710 13:51:38.552275  config.go:111] Initializing NVIDIA device
I0710 13:51:38.552355  config.go:248] All devices initialized successfully
...
I0710 14:02:14.161116  devices.go:647] &lt;span class="s2"&gt;"Resource requirements collected"&lt;/span&gt; &lt;span class="nv"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"default/chat-qwen-64c4bd66f9-8qccs"&lt;/span&gt; &lt;span class="nv"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;=[{&lt;/span&gt;&lt;span class="s2"&gt;"NVIDIA"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Nums"&lt;/span&gt;:1,&lt;span class="s2"&gt;"Type"&lt;/span&gt;:&lt;span class="s2"&gt;"NVIDIA"&lt;/span&gt;,&lt;span class="s2"&gt;"Memreq"&lt;/span&gt;:4000,&lt;span class="s2"&gt;"MemPercentagereq"&lt;/span&gt;:101,&lt;span class="s2"&gt;"Coresreq"&lt;/span&gt;:60&lt;span class="o"&gt;}}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;vgpu-scheduler-extender&lt;/code&gt; builds a live usage map for every physical GPU in the cluster. It reads device metadata from each node's &lt;code&gt;hami.io/node-nvidia-register&lt;/code&gt; annotation, then loops through the pods already assigned to that node to calculate the consumed GPU memory and compute capacity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; hami-system deploy/hami-scheduler &lt;span class="nt"&gt;-c&lt;/span&gt; vgpu-scheduler-extender
...
I0710 14:02:14.161182 node_policy.go:82] node node1 used 0, usedCore 0, usedMem 0,
I0710 14:02:14.161191 gpu_policy.go:104] device GPU-a2fd58d2-edbe-4cfd-4dbd-d4197b35431e user 0, userCore 0, userMem 0,
...
I0710 16:54:54.475656 node_policy.go:82] node node1 used 1, usedCore 60, usedMem 4000,
I0710 16:54:54.475667 gpu_policy.go:104] device GPU-a2fd58d2-edbe-4cfd-4dbd-d4197b35431e user 1, userCore 60, userMem 4000,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scheduler then filters out any nodes lacking sufficient capacity and scores the remaining nodes based on the configured HAMi scheduling policy (&lt;code&gt;nodeSchedulerPolicy&lt;/code&gt; and &lt;code&gt;gpuSchedulerPolicy&lt;/code&gt;; the chart defaults are &lt;code&gt;binpack&lt;/code&gt; at the node level and &lt;code&gt;spread&lt;/code&gt; at the GPU level). The selected node and chosen GPU slice are recorded in the pod's annotations (&lt;code&gt;hami.io/vgpu-devices-allocated&lt;/code&gt;) as a comma-separated list of UUID,Type,memMB,cores records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;$ kubectl describe pod -n default embed-bge-f84696cc9-7587j&lt;/span&gt;
&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;         &lt;span class="s"&gt;embed-bge-f84696cc9-7587j&lt;/span&gt;
&lt;span class="na"&gt;Labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;hami.io/vgpu-node=node1&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;Annotations:  hami.io/vgpu-devices-allocated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GPU-a2fd58d2-edbe-4cfd-4dbd-d4197b35431e,NVIDIA,2000,30:;&lt;/span&gt;
              &lt;span class="s"&gt;hami.io/vgpu-devices-to-allocate&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;;;&lt;/span&gt;
              &lt;span class="s"&gt;hami.io/bind-phase&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success&lt;/span&gt;
              &lt;span class="s"&gt;hami.io/bind-time&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1783702494&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the pod is bound to a node, the Kubelet calls &lt;code&gt;Allocate&lt;/code&gt; on that node's HAMi &lt;code&gt;device-plugin&lt;/code&gt;. The plugin reads the pod's &lt;code&gt;hami.io/vgpu-devices-to-allocate&lt;/code&gt; annotation (cleared once the plugin has consumed it, which is why the describe output above shows it empty) to decode the requested slice, identifying the target physical device and its exact compute and memory limits. It then returns a response detailing what the container needs to run against that specific slice: environment variables, host-path mounts (including the enforcement library), and device handles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; hami-system ds/hami-device-plugin &lt;span class="nt"&gt;-c&lt;/span&gt; device-plugin | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'Allocate Response'&lt;/span&gt;
...
I0710 16:54:54.499747  232069 server.go:719] Allocate Response &lt;span class="o"&gt;[&lt;/span&gt;envs:&lt;span class="o"&gt;{&lt;/span&gt;key:&lt;span class="s2"&gt;"CUDA_DEVICE_MEMORY_LIMIT_0"&lt;/span&gt; value:&lt;span class="s2"&gt;"2000m"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; envs:&lt;span class="o"&gt;{&lt;/span&gt;key:&lt;span class="s2"&gt;"CUDA_DEVICE_MEMORY_SHARED_CACHE"&lt;/span&gt; value:&lt;span class="s2"&gt;"/usr/local/vgpu/584ed76a-0856-40b3-8113-1ad696daa252.cache"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; envs:&lt;span class="o"&gt;{&lt;/span&gt;key:&lt;span class="s2"&gt;"CUDA_DEVICE_SM_LIMIT"&lt;/span&gt; value:&lt;span class="s2"&gt;"30"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; envs:&lt;span class="o"&gt;{&lt;/span&gt;key:&lt;span class="s2"&gt;"LIBCUDA_LOG_LEVEL"&lt;/span&gt; value:&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; envs:&lt;span class="o"&gt;{&lt;/span&gt;key:&lt;span class="s2"&gt;"NVIDIA_VISIBLE_DEVICES"&lt;/span&gt; value:&lt;span class="s2"&gt;"GPU-a2fd58d2-edbe-4cfd-4dbd-d4197b35431e"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; mounts:&lt;span class="o"&gt;{&lt;/span&gt;container_path:&lt;span class="s2"&gt;"/usr/local/vgpu/libvgpu.so"&lt;/span&gt; host_path:&lt;span class="s2"&gt;"/usr/local/vgpu/libvgpu.so.v2.9.0"&lt;/span&gt; read_only:true&lt;span class="o"&gt;}&lt;/span&gt; mounts:&lt;span class="o"&gt;{&lt;/span&gt;container_path:&lt;span class="s2"&gt;"/usr/local/vgpu"&lt;/span&gt; host_path:&lt;span class="s2"&gt;"/usr/local/vgpu/containers/1a5bac44-7888-4ea5-9382-3ef49ae1f1ba_tei"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; mounts:&lt;span class="o"&gt;{&lt;/span&gt;container_path:&lt;span class="s2"&gt;"/tmp/vgpulock"&lt;/span&gt; host_path:&lt;span class="s2"&gt;"/tmp/vgpulock"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; mounts:&lt;span class="o"&gt;{&lt;/span&gt;container_path:&lt;span class="s2"&gt;"/etc/ld.so.preload"&lt;/span&gt; host_path:&lt;span class="s2"&gt;"/usr/local/vgpu/ld.so.preload"&lt;/span&gt; read_only:true&lt;span class="o"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Kubelet applies this response directly to the container during creation. From that point, HAMi's preloaded control library sits between the application and the vendor driver, enforcing the slice in-process. It intercepts the driver's memory-allocation calls, checks each request against the slice's budget, and returns an OOM error if the workload attempts to exceed its cap. It also intercepts and rewrites driver management queries (like &lt;code&gt;nvidia-smi&lt;/code&gt;), ensuring the reported total capacity reflects the assigned limit, and the free capacity reflects that limit minus current usage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; default chat-qwen-64c4bd66f9-8qccs &lt;span class="nt"&gt;-c&lt;/span&gt; vllm &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;env
&lt;/span&gt;&lt;span class="nv"&gt;CUDA_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;13.0.2
&lt;span class="nv"&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;GPU-a2fd58d2-edbe-4cfd-4dbd-d4197b35431e
&lt;span class="nv"&gt;CUDA_DEVICE_MEMORY_LIMIT_0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4000m
&lt;span class="nv"&gt;CUDA_DEVICE_SM_LIMIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60
&lt;span class="nv"&gt;CUDA_DEVICE_MEMORY_SHARED_CACHE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/vgpu/5e999bc3-2dbf-46b0-ba81-cc479a1c11dd.cache
...

kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; default chat-qwen-64c4bd66f9-8qccs &lt;span class="nt"&gt;-c&lt;/span&gt; vllm &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/ld.so.preload
/usr/local/vgpu/libvgpu.so

kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; default chat-qwen-64c4bd66f9-8qccs &lt;span class="nt"&gt;-c&lt;/span&gt; vllm &lt;span class="nt"&gt;--&lt;/span&gt; nvidia-smi &lt;span class="nt"&gt;--query-gpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;memory.total &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;csv,noheader
4000 MiB
&lt;span class="o"&gt;[&lt;/span&gt;HAMI-core Msg&lt;span class="o"&gt;(&lt;/span&gt;272:133498069993280:multiprocess_memory_limit.c:703&lt;span class="o"&gt;)]&lt;/span&gt;: Cleanup on &lt;span class="nb"&gt;exit &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;PID 272
&lt;span class="o"&gt;[&lt;/span&gt;HAMI-core Msg&lt;span class="o"&gt;(&lt;/span&gt;272:133498069993280:multiprocess_memory_limit.c:739&lt;span class="o"&gt;)]&lt;/span&gt;: Exit cleanup &lt;span class="nb"&gt;complete &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;PID 272
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scheduling policies that move the bill
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, the scheduler first filters out nodes lacking sufficient capacity. For the remaining candidates, HAMi determines the optimal placement using two distinct scheduling tiers: the node level and the GPU level. Currently, HAMi supports two primary strategies for each: &lt;code&gt;binpack&lt;/code&gt; (pack tasks as densely as possible) and &lt;code&gt;spread&lt;/code&gt; (distribute tasks as widely as possible).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hami.io/node-scheduler-policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binpack"&lt;/span&gt;
    &lt;span class="na"&gt;hami.io/gpu-scheduler-policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;binpack"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both policies come with distinct operational and financial trade-offs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node-Level Strategies
&lt;/h3&gt;

&lt;p&gt;At the node level, the &lt;code&gt;binpack&lt;/code&gt; policy packs workloads densely onto the fewest possible machines. This approach enables cluster autoscalers to quickly drain and spin down empty nodes, directly cutting cloud infrastructure bills. However, this density concentrates tenants, meaning a single node or driver failure has a much larger blast radius, and leads to increased contention with less bandwidth headroom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5lmdv6xqodxnrzykdq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5lmdv6xqodxnrzykdq4.png" alt=" " width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conversely, the &lt;code&gt;spread&lt;/code&gt; policy distributes workloads evenly across all available nodes. While this successfully lowers per-node contention to provide headroom for unexpected traffic spikes and securely distributes fault domains, it keeps every node "warm." As a result, the autoscaler cannot scale down the cluster, leaving you paying for idle capacity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fauowm28ks660szd1h9zu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fauowm28ks660szd1h9zu.png" alt=" " width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GPU-Level Strategies
&lt;/h3&gt;

&lt;p&gt;At the GPU level, the &lt;code&gt;binpack&lt;/code&gt; policy completely fills one physical card before scheduling workloads on the next. This preserves entirely free GPUs for large models that require undivided resources and maximizes the number of small slices sharing a single card. The inherent trade-off is that it creates the densest possible cards, maximizing "noisy-neighbor" pressure and exposing a high number of tenants to single-card XID faults.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzko2153fgs4kwt57naxj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzko2153fgs4kwt57naxj.png" alt=" " width="799" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, the &lt;code&gt;spread&lt;/code&gt; policy balances workloads across all available cards. This minimizes compute and memory bandwidth contention, making it the superior choice for latency-sensitive inference workloads. The downside is that it fragments available memory across the cluster, meaning a subsequent large job requiring massive, continuous memory might fail to schedule even if the total free memory across the cluster is technically sufficient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsc8m3uacpz9wt8320hk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsc8m3uacpz9wt8320hk7.png" alt=" " width="799" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are placement-time policies only: HAMi scores new pods as they arrive; it does not actively migrate running workloads. Financial savings therefore materialize as pods churn, meaning &lt;code&gt;binpack&lt;/code&gt; pays off aggressively on highly elastic inference fleets, but much less so on long-lived, pinned pods.&lt;/p&gt;

&lt;h2&gt;
  
  
  HAMi and MIG: complementary layers
&lt;/h2&gt;

&lt;p&gt;The fence and the wall operate at different layers, and you do not have to pick one per cluster: HAMi can manage both from a single pool. With dynamic MIG enabled, HAMi drives nvidia-mig-parted to carve and re-carve MIG geometry to fit incoming jobs, removing manual &lt;code&gt;nvidia-smi mig&lt;/code&gt; work and pre-committed slice layouts. Pods keep requesting &lt;code&gt;nvidia.com/gpu&lt;/code&gt; and &lt;code&gt;nvidia.com/gpumem&lt;/code&gt; exactly as before; by default, the scheduler may satisfy that with either a hami-core slice or a MIG instance, and a workload that needs hard isolation can pin itself to the wall with the &lt;code&gt;nvidia.com/vgpu-mode: "mig"&lt;/code&gt; annotation. The trade-off is granularity: MIG placements round up to the nearest allowed geometry (an 8 GB request on an A100-40GB lands on a &lt;code&gt;2g.10gb&lt;/code&gt; instance), where hami-core would have fenced off exactly what you asked for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operational reality
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HAMi replaces your device plugin.&lt;/strong&gt; The HAMi device plugin and the standard &lt;code&gt;nvidia-device-plugin&lt;/code&gt; both want to own &lt;code&gt;nvidia.com/gpu&lt;/code&gt;; running both on the same node causes them to fight over resource registration, leading to capacity gaps between real and virtualized counts, and GPU allocation is served by whichever plugin registered last, silently bypassing HAMi’s isolation. If you run the GPU Operator, keep it for the driver, container toolkit, DCGM, and disable its device plugin on HAMi-managed nodes. Scope HAMi with the gpu=on node label and roll it pool by pool, not cluster-wide on day one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The scheduler image tracks your control plane.&lt;/strong&gt; &lt;code&gt;hami-scheduler&lt;/code&gt; wraps a stock &lt;code&gt;kube-scheduler&lt;/code&gt; image, and current charts resolve its tag from the API server’s version at install time, which means a Kubernetes upgrade quietly leaves the old scheduler running until your next Helm upgrade. Add &lt;code&gt;scheduler.kubeScheduler.image.tag&lt;/code&gt; to your Kubernetes upgrade runbook, or it will bite you six months in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;gpucores&lt;/code&gt; throttles; it does not reserve.&lt;/strong&gt; The scheduler books your share at placement time, but at runtime that share is a ceiling, never a floor. The limiter is a token bucket checked at kernel launch, not a hardware partition: expect oscillation around the target, bursting above the share while the card is idle, and a few seconds of overlap before limits re-arm when a neighbor arrives mid-burst (set &lt;code&gt;GPU_CORE_UTILIZATION_POLICY=force&lt;/code&gt; to pin the limiter on at all times). Benchmark p99 under a noisy neighbor before you commit to an SLO.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A practical recommendation
&lt;/h2&gt;

&lt;p&gt;If your GPU fleet is A100/H100-class, shared by multiple teams, and your utilization dashboards would embarrass you in the finance review, pilot HAMi on one inference node pool this week. The install fits in an afternoon: label two nodes gpu=on, helm install, convert one over-provisioned inference Deployment to gpumem/gpucores slices, and let it run for a week while you watch allocation against DCGM utilization. The arithmetic you’re testing is blunt: an 8-GPU H100 node runs roughly $290,000 to $480,000 a year on-demand depending on cloud and region, so every node that bin-packing drains is real money back. On owned hardware, at roughly $25–30k per H100, every ten points of sustained utilization on a thousand-GPU fleet is $2.5–3M of capex doing work instead of nothing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>kubernetes</category>
      <category>gpu</category>
    </item>
    <item>
      <title>AWS Summit Seoul 2026: Korean Enterprises And Agentic AI</title>
      <dc:creator>Ivan Porta</dc:creator>
      <pubDate>Thu, 21 May 2026 02:32:09 +0000</pubDate>
      <link>https://dev.to/todea/aws-summit-seoul-2026-korean-enterprises-and-agentic-ai-2nm</link>
      <guid>https://dev.to/todea/aws-summit-seoul-2026-korean-enterprises-and-agentic-ai-2nm</guid>
      <description>&lt;p&gt;Over the last few years, people have been asking the same question about AI: with so much money going into models, GPUs, and data centers, when will it pay off? Earnings calls and analyst reports have often mentioned a possible bubble, and companies that tried generative-AI pilots in 2024 have been waiting to see real production results.&lt;/p&gt;

&lt;p&gt;At AWS Summit Seoul 2026, Samsung Electronics, Yogiyo, and Yanolja presented production-oriented agentic-AI/AIOps cases, while KB Kookmin Bank presented a production-scale KBaaS API-infrastructure modernization case. Together, the sessions showed how Korean enterprises are applying AI-era cloud architecture to operations, development, and embedded finance. Here's a summary of how the event was organized, what the enterprise sessions showed, which AWS tools were most common, and the key patterns you can apply to your own plans.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shift the day was framed around
&lt;/h2&gt;

&lt;p&gt;AWS Korea CEO Ham Ki-ho opened the event by outlining three stages: Generative AI, Agentic AI, and Physical AI. He described Agentic AI as the active phase, where large language models act as reasoning engines that plan, use tools, and take action, instead of just answering prompts. Physical AI was presented as the next step, with a new Physical AI Frontier Program for Korean robotics, AI-chip, and manufacturing companies. This program will support everything from data collection to edge inference and help with global expansion.&lt;/p&gt;

&lt;p&gt;AWS CFO Jon Felton announced a cumulative ₩12.6 trillion investment plan in Korea by 2031, described publicly as the largest-ever investment in Korea by a global cloud provider, with an estimated ₩15.06 trillion contribution to Korea's GDP between 2023 and 2027. The Industry Day talks that followed showed how this commitment will play out in practice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlmtt4wy742kwfa819cf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlmtt4wy742kwfa819cf.png" alt="Amazon's internal AI evolution presented by AWS — from an LLM-powered search assistant in 2023 to a planning-engine architecture and MCP-driven tooling in 2025" width="799" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The keynote also highlighted the main agentic tools AWS featured at the event, with Vice President Jason Bennett explaining each one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kiro:&lt;/strong&gt; a new agentic IDE for software development, described on stage as a peer to Claude Code and Copilot-style coding assistants&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Quick Suite:&lt;/strong&gt; an agentic AI workspace for finding insights, conducting research, automating tasks, visualizing data, and taking actions across apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Transform and AWS Transform Custom:&lt;/strong&gt; agentic modernization tools for mainframe, VMware, Windows, and legacy-code modernization, including version upgrades, runtime migrations, language translations, and architecture changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the enterprise talks actually showed
&lt;/h2&gt;

&lt;p&gt;Across the agentic-AI sessions, a pattern emerged, but it was not universal. Samsung and Yanolja both used a supervisor or core-agent structure that delegates work to specialist agents. Yogiyo showed a Bedrock AgentCore-based AIOps workflow connected to operational data and tool functions. KBaaS was different: an EKS-based API platform and gateway modernization for embedded finance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyehzfoez1i3xi2m2lx6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyehzfoez1i3xi2m2lx6g.png" alt="Samsung Electronics' AgentCore-based AIOps architecture: a Supervisor Agent orchestrates Domain Agents (DR, Incident, Change, Database, FinOps), each composed of Task Agents that call AWS resources directly" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The numbers made it clear these were real deployments, not just experiments. Samsung Electronics used Samsung Account, which supports 2.1 billion users, over 50 services, more than 2.7 million requests per second, and 200,000 transactions per second across four regions on EKS with over 70 namespaces. Samsung set Day-1 AIOps goals including 90%+ MTTR reduction, 99% incident detection within 10 minutes, and reducing human-in-the-loop operational work below 20%, as part of a roadmap toward 'Toil 0% / Human First.' KB Kookmin Bank's KBaaS platform now handles about 1,800 APIs and 200 million calls per day after switching from a third-party API gateway to their own on AWS EKS. Yogiyo showed how they moved from checking multiple consoles and logs during incidents to using an AgentCore-based AIOps loop, which brings metric observation, correlation analysis, change-history comparison, and RCA grounding into one workflow. Yanolja shared the most technical details, describing how their domain-specialist agents for DevOps and SRE are managed by a Core Agent on Bedrock AgentCore Runtime, using Strands Agent as the SDK and end-to-end authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyfs61jcf7w82z7wm8n9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyfs61jcf7w82z7wm8n9.png" alt="Yanolja's three Strands Agents multi-agent patterns: " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Samsung, Yogiyo, and Yanolja all centered their agentic-AI cases on AIOps or infrastructure operations rather than customer-facing copilots. KB Kookmin Bank's case showed a different but related production pattern: modernizing a high-volume API platform on EKS for embedded finance.&lt;/p&gt;

&lt;p&gt;On the development side, the counterpart is AI-DLC (AI-Driven Development Lifecycle), which is AWS's approach to AI-led development with humans checking at validation and final approval. Samsung saw a 70% reduction in lead time using this method, and LG Electronics' MS division reported double the productivity. The main idea is to separate intent from execution: humans decide what should happen and check the results, while agents handle the steps in between.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AWS-native stack that recurred
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2caprwhhcri1ymtk5u2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2caprwhhcri1ymtk5u2c.png" alt="AWS AI Factories — the full agentic stack as presented in the AWS Summit Seoul 2026 keynote: Applications and Agents (Kiro, Amazon Quick Suite, AWS Transform), Agent Builders (Amazon Nova Act, Strands Agents), Amazon Bedrock (Models, Capabilities, AgentCore with Runtime / Identity / Memory / Observability / Policy), and the infrastructure layer beneath" width="799" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few key components showed up again and again in the enterprise sessions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Bedrock AgentCore&lt;/strong&gt; appeared across Samsung, Yogiyo, and Yanolja. Yanolja explicitly presented Bedrock AgentCore Runtime with Strands Agent and authentication. Yogiyo showed an AIOps architecture using Amazon Bedrock AgentCore with runtime, memory, gateway, and MCP tool functions. Samsung showed an AgentCore-based AIOps architecture with Supervisor, Domain, and Task agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kiro&lt;/strong&gt; was used as the agentic IDE, and Samsung included it in their toolset along with Amazon Quick Suite and Bedrock AgentCore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon EKS&lt;/strong&gt; was the hosting platform for both Samsung Account and KBaaS, the two cases where the host was clearly specified.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The themes worth taking home
&lt;/h2&gt;

&lt;p&gt;Several patterns stood out during the day. First, the supervisor pattern appeared twice independently. Samsung and Yanolja reaching the same structure without coordination is a strong signal. Second, in three of the four cases (Samsung, Yogiyo, Yanolja), the entry point was AIOps or infrastructure operations rather than customer-facing copilots. KB Kookmin Bank instead modernized its API platform on EKS for embedded finance. Third, humans are intentionally kept in the loop. Datadog's session made this clear, stating that sovereignty and judgment remain with people, while agents handle execution via the Datadog AI Agent Builder. Samsung's AI-DLC approach on the development side followed the same principle. Fourth, infrastructure needs to catch up. GS Neotek's session highlighted that the real GPU issue in agent workloads is not a shortage but poor utilization, excessive idle time, and over-allocation. They suggested using Dynamic Resource Allocation (DRA) on EKS as a next-generation operations model that considers workload needs, sharing policies, and topology.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ac4icinyvo4vok65qyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ac4icinyvo4vok65qyq.png" alt="GS Neotek's DRA (Dynamic Resource Allocation) core structure: a three-stage flow of Advertise (ResourceSlice) → Define &amp;amp; Request (DeviceClass + Claim) → Match (Attribute-aware Matching), letting workloads request GPUs by capability rather than by count" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>aiops</category>
      <category>sre</category>
    </item>
    <item>
      <title>Kubecost Explained: Kubernetes FinOps That Moves the Bill</title>
      <dc:creator>Ivan Porta</dc:creator>
      <pubDate>Tue, 19 May 2026 01:38:37 +0000</pubDate>
      <link>https://dev.to/todea/kubecost-explained-kubernetes-finops-that-moves-the-bill-45gp</link>
      <guid>https://dev.to/todea/kubecost-explained-kubernetes-finops-that-moves-the-bill-45gp</guid>
      <description>&lt;p&gt;Most platform teams are familiar with Kubernetes costs. The monthly cloud bill arrives, finance asks why it’s higher, and engineering can only respond with “more workloads.” This gap between what the bill shows and what platform teams can explain is exactly what FinOps aims to address to help optimize operational costs. The real question is whether you need an enterprise platform for this. For most teams, the answer is no. &lt;a href="https://www.opencost.io/" rel="noopener noreferrer"&gt;OpenCost&lt;/a&gt; and &lt;a href="https://www.kubecost.com/" rel="noopener noreferrer"&gt;Kubecost&lt;/a&gt; can give platform teams the visibility they need, as long as the tool is paired with an operating cadence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pressure is real
&lt;/h2&gt;

&lt;p&gt;Kubernetes accounting is no longer just about a single cluster or a single cloud. Most teams now manage fleets of clusters, often across multiple cloud providers, and sometimes combine on-premises control planes with managed services. Containers move between nodes, nodes move between zones, and the same workload might run in several regions to meet latency or compliance needs, making the cost attribution even harder.&lt;/p&gt;

&lt;p&gt;Industry data has shown the same problem for years. Back in 2021, a CNCF FinOps survey found that most teams couldn’t reliably measure their Kubernetes spending, with over-provisioning and lack of accountability as the main issues. The same story happened in 2025, with a fleet-telemetry benchmark using real cluster data from over 2,100 organizations on AWS, GCP, and Azure, showing average CPU utilization at &lt;strong&gt;10%&lt;/strong&gt; and memory utilization at &lt;strong&gt;23%&lt;/strong&gt;. These numbers come from production telemetry, not just survey responses. The problem hasn’t changed in four years; if anything, it’s become clearer as fleets have grown.&lt;/p&gt;

&lt;p&gt;The real issue isn’t that Kubernetes is too expensive. It’s that most teams don’t have enough visibility into what they’re spending.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Kubecost actually is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sjxzc0mrjclepugpjl9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sjxzc0mrjclepugpjl9.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kubecost is a Kubernetes platform for cost allocation, optimization, and governance. After IBM acquired it in 2024, Kubecost now offers both open-source and enterprise versions. At its core, it sits on top of &lt;strong&gt;OpenCost&lt;/strong&gt;, and runs as an in-cluster agent stack with several microservices: data collectors, a cloud-cost ingestor, a forecasting service, a per-node network-costs DaemonSet, and a fast ClickHouse-backed aggregator. By combining Kubernetes telemetry with cloud-provider billing data, Kubecost provides detailed cost allocation views, and accuracy improves when cloud billing integrations are configured and reconciled.&lt;/p&gt;

&lt;p&gt;The platform is built around three primary pillars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost allocation&lt;/strong&gt; rolls spend up by namespace, label, service, workload, or &lt;em&gt;Collection&lt;/em&gt;. Kubecost v3 adds a grouping concept that bundles Kubernetes and external cloud-side costs into a single deduplicated unit. Costs are tracked across CPU, memory, persistent volumes, GPUs, and network traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimization recommendations&lt;/strong&gt; suggest right-sized requests based on real usage, propose cheaper node types, and let teams configure quantile-based controls instead of accepting a one-size default. Recommendations can be archived for historical reference and exported as CSV or PDF.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alerts and governance&lt;/strong&gt; ship as configurable budget actions, scheduled reports, and Slack/email notifications. Alerts live next to the budget they belong to rather than as a separate alerting subsystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How a Kubecost install flows
&lt;/h2&gt;

&lt;p&gt;Cost data collection begins inside your clusters. When it starts, the &lt;strong&gt;FinOps agent&lt;/strong&gt; sets up a watch on the Kubernetes API for the pricing ConfigMap, so any custom pricing rules can be applied without a restart. It also resolves node pricing per node (falling back to a computed value when the cloud provider's price is unavailable). It then collects metrics from each &lt;strong&gt;Network Costs&lt;/strong&gt; DaemonSet pod, creates a new binary snapshot, and, if configured, writes it to external storage such as Azure Blob Storage or AWS S3.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Network Costs&lt;/strong&gt; DaemonSet subscribes to the kernel's conntrack table via a netlink socket, parsing each flow per-direction byte and packet counters, and maintains an in-memory map of pod, node, service, and endpoint state via Kubernetes API watches. It uses this map to link observed connections to specific workloads.&lt;/p&gt;

&lt;p&gt;While these agents send internal snapshots to shared storage, the &lt;strong&gt;Cloud Cost Ingestor&lt;/strong&gt; manages external financial data. It runs on a schedule, connects to cloud provider billing exports, pulls daily CSVs, and backfills historical data. Because cloud providers release billing data with a several-hour delay, Kubecost reconciles cluster data with cloud billing after a short wait. This means the most recent day or two of cost data is only an estimate, while older data is fully reconciled (assuming a working cloud-billing integration).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Aggregator&lt;/strong&gt; is the main engine and uses an embedded ClickHouse database. In a multi-cluster deployment, it fans in snapshots from several agent clusters. It checks multiple ConfigMaps for configuration and falls back to defaults when none are present. It ingests agent snapshots and, when configured, external billing CSVs, then drives them through a multi-stage SQL pipeline that reconciles and de-duplicates overlapping costs and produces the final cost tables that other microservices consume. The Aggregator also manages data retention by setting per-table, per-resolution TTLs in ClickHouse, so fine-grained windows expire within days while rollups are kept for weeks or months.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;strong&gt;Forecasting Service&lt;/strong&gt; serves as a predictive cost-monitoring tool, using this data to generate cost forecasts. At the same time, the &lt;strong&gt;Cluster Controller&lt;/strong&gt; uses the Aggregator’s optimization insights to take actions, such as applying right-sizing recommendations directly in the cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcw5ylekk55qq5gabgsj7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcw5ylekk55qq5gabgsj7.png" alt=" " width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Allocate to a real owner first
&lt;/h2&gt;

&lt;p&gt;Kubecost spreads node costs across the pods running on each node, typically weighted by resource requests, and rolls the result up by namespace, label, service, workload, or Collection, covering CPU, memory, PV, GPU, and network.&lt;/p&gt;

&lt;p&gt;What makes this approach effective is good organization, not just technical setup. Each namespace should match a real owner, like a team, product, or department. When this mapping is in place, the allocation view shows which team is responsible for each cost, without needing a spreadsheet. Teams that already use labels like &lt;code&gt;team&lt;/code&gt;, &lt;code&gt;cost-center&lt;/code&gt;, or &lt;code&gt;product&lt;/code&gt; can use these for the same purpose, and Collections help make label-based views easy to use.&lt;/p&gt;

&lt;p&gt;Labels can change over time, namespaces can increase, and someone will eventually deploy into &lt;code&gt;default&lt;/code&gt;. Reviewing the unlabeled bucket each week helps keep the data accurate and useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Right-size requests against actual usage
&lt;/h2&gt;

&lt;p&gt;This is the lever that moves the bill the most. Often, developers set CPU and memory requests defensively, never revisit them, and the gap between request and use shows up directly on the invoice. The 10%-CPU / 23%-memory benchmark cited above is a useful authority anchor when finance asks for a number.&lt;/p&gt;

&lt;p&gt;A pattern that reliably finds savings: plot &lt;em&gt;requested vs. actual&lt;/em&gt; CPU and memory per workload over a few weeks, then walk each workload's request down to what it actually uses. One practical case from a service mesh deployment had proxy sidecars set to 100 millicores each. The node could host roughly 200 pods on paper, but the scheduler exhausted allocatable CPU at around 90 pods because every pod carried a 100 millicores sidecar request on top of its own. After the request-rightsizing pass, pod density per node tripled with no application change and no node fleet change.&lt;/p&gt;

&lt;p&gt;Kubecost 3.0 makes this loop tighter. Container Request Sizing Insights show usage visualizations directly in the UI, recommendations can be archived, CSV/PDF exports include labels, and quantile-based controls let you set tighter recommendation percentiles for predictable services and looser ones for bursty workloads. The enterprise tier adds an Automated Container Request Sizing UI that operates across clusters with custom profiles, suspension controls, audit history, and a comparison between recommended and realized savings; the open-source tier gets a free allowance up to 250 cores on EKS primary clusters.&lt;/p&gt;

&lt;p&gt;Using a percentile-based recommendation policy is usually the most effective approach in production.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set the CPU request to the 90th percentile of actual CPU usage from the past week or month, and then add a safety margin. The Kubernetes VPA default is about 15% for CPU. Because CPU is time-shared, the kernel lets bursty workloads use extra capacity when it is available. Adding more padding for rare spikes usually just increases requests without much benefit.&lt;/li&gt;
&lt;li&gt;Set the memory request to a high percentile of peak usage, and then add a safety margin. Memory is not time-shared, so going over the limit can cause OOM kills instead of graceful degradation. Aim for about the 90th percentile of peaks, then add a margin. The VPA default is about 20% for memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These settings decide the QoS class. A pod is considered Guaranteed only if every container has CPU and memory requests set equal to their limits. If this is not the case for any container, the whole pod is treated as Burstable, or as BestEffort if no container sets any requests or limits. This setup works well for most workloads. Reserve the fully Guaranteed class for critical workloads with strict latency SLAs, where CPU and memory requests match their limits. In those cases, you might waste some headroom, but you get the best eviction protection and, if needed, exclusive CPU pinning.&lt;/p&gt;

&lt;p&gt;If you want an additional feedback before automating any of this, you can run &lt;a href="https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler" rel="noopener noreferrer"&gt;VPA&lt;/a&gt; in recommendation-only mode for several weeks, or use &lt;a href="https://github.com/robusta-dev/krr" rel="noopener noreferrer"&gt;KRR&lt;/a&gt; open-source. Comparing recommendations across KRR, VPA-recommendation-mode, and Kubecost is more reliable than trusting any single tool's number.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6z8upg0xj4ii285vnukh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6z8upg0xj4ii285vnukh.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Capacity-versus-request as the North Star metric
&lt;/h2&gt;

&lt;p&gt;The ratio that tells you most about cluster efficiency is  &lt;strong&gt;total pod requests ÷ total node allocatable capacity&lt;/strong&gt;, across CPU and memory: how much of what you pay for is even claimed by a pod. It is also what Kubecost's request right-sizing is built on. Kubecost ships with several targets against which recommendations are computed: Production 0.65, Development 0.80, High Availability 0.50 (Cluster Right-Sizing API). Below it you carry capacity nothing asks for; above it you've spent the headroom that cluster class should keep. Kubecost also picks the utilization it sizes against by context; development the trending 85th-percentile, production the 98th, HA the 99.9th; and only on a one-day window; longer windows use maximum usage. The often-quoted "85th percentile" is just the development one-day default, not a universal setting.&lt;/p&gt;

&lt;p&gt;The ratio is what you watch; an autoscaler (Karpenter, Cluster Autoscaler) moves it — but only if requests are honest, which is why Kubecost's request right-sizing sits upstream of any autoscaling story. The autoscaler reacts to requests; Kubecost tells you whether they reflect reality.&lt;/p&gt;

&lt;p&gt;Recent days are directional by design: reconciliation needs a full day of billing data, so for a roughly 48-hour window costs stay at public on-demand pricing unless a node is provably not on-demand; Spot is accurate sooner only through a separately configured AWS Spot data feed (Cloud Billing Integrations). Read efficiency — independent of reconciled pricing — separately from cost.&lt;br&gt;
Node Group Sizing — formerly Cluster Right-Sizing, rebuilt in v3.0 — turns this into an action: it analyzes in-cluster CPU, RAM, and GPU utilization against node capacity over a configurable window and recommends, per node group, changing the node count or switching the instance type. It runs from a preset profile or a custom metric — usage.max/p95/p85/avg or request.max/avg — with a target-utilization threshold per resource, never below average requested resources. It detects node groups by each provider's standard label, so it works across EKS, AKS, and GKE without setup (v3.x docs).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f6mnshfx3kwb60f84gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f6mnshfx3kwb60f84gk.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the always-on workloads that don't need to be
&lt;/h2&gt;

&lt;p&gt;Once you’ve handled allocation and right-sizing, look at workloads that run all day, every day, even when they don’t have to. In one platform team’s review, 31% of workloads used less than 25% CPU for almost the entire day, yet Kubernetes costs still went up by about 18% over the year. This happened because engineers spent a lot of time tuning capacity and dealing with alerts, and because each team set up its own autoscaling rules differently.&lt;/p&gt;

&lt;p&gt;The triage falls into three buckets. Production services that are genuinely over-spec’d belong in the right-sizing loop above. Non-production environments — dev, integration, demo — rarely need to run on weekends or overnight; a scheduled scale-to-zero is the highest-ROI change in this category. Batch and stateless workloads with retry tolerance are candidates for Spot instances, which trade roughly a 90% discount for a two-minute interruption notice.&lt;/p&gt;

&lt;p&gt;Kubecost helps you find underused workloads. With Kubecost 3.0’s Advanced Filters, you can quickly sort workloads by namespace, label, or service using AND/OR conditions right in the UI, instead of having to do it elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Track commitment coverage and utilization separately
&lt;/h2&gt;

&lt;p&gt;Reserved capacity and savings commitments are common sources of unnecessary cloud costs. Teams often either ignore them and pay full on-demand prices, or buy them and forget to check if they are being used, leaving discounts unused on resources that are no longer needed. There are two important metrics to watch, and they are easy to mix up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage&lt;/strong&gt; means the portion of your regular usage that is protected by a commitment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Utilization&lt;/strong&gt; is how much of your commitment you actually use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each cloud provider has different tools, but they all fit into three main types, and the calculations work the same way everywhere:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Typical max discount vs on-demand&lt;/th&gt;
&lt;th&gt;Commitment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flexible spend commitment&lt;/td&gt;
&lt;td&gt;~60–66%&lt;/td&gt;
&lt;td&gt;1 or 3 yr; hourly $ commitment; applies across families/regions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instance-specific reservation&lt;/td&gt;
&lt;td&gt;~55–72%&lt;/td&gt;
&lt;td&gt;1 or 3 yr; locked to a region + instance family/SKU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spot / preemptible&lt;/td&gt;
&lt;td&gt;up to ~90%&lt;/td&gt;
&lt;td&gt;none; interruption notice from ~30 sec to ~2 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A good approach is to aim for commitment utilization between 80% and 95%, instead of trying to reach 100%. Going for 100% leaves no room for normal changes, like removing unused instances, changing instance types, or handling a drop in traffic. It may look efficient in a quarterly review, but it can cause problems day-to-day. For coverage, aiming for 60% to 75% is reasonable. This range is high enough to get a good discount, but low enough to allow for changes each quarter. These ranges are based on practical experience, not rules set by the cloud provider.&lt;/p&gt;

&lt;p&gt;With Kubecost, costs are first estimated using public on-demand cloud provider prices until the actual cloud bill is ready. When the bill becomes available, usually within about 48 hours, Kubecost updates its estimates with the real costs. This update includes Reserved Instances, Savings Plans, committed-use discounts, and Spot pricing, along with any special rates you might have, such as Enterprise Discount Programs.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use a commercial FinOps platform instead
&lt;/h2&gt;

&lt;p&gt;Most teams should start with the open-source chart. You can look at the commercial tiers later, once your needs grow.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability / Feature&lt;/th&gt;
&lt;th&gt;Open-source Kubecost&lt;/th&gt;
&lt;th&gt;Commercial FinOps platform&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost allocation (namespace, label, workload)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimization recommendations (right-sizing)&lt;/td&gt;
&lt;td&gt;✓ (manual application)&lt;/td&gt;
&lt;td&gt;✓ + automated application across clusters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud-billing reconciliation&lt;/td&gt;
&lt;td&gt;✓ (basic)&lt;/td&gt;
&lt;td&gt;✓ + EDP / RI / custom-discount aware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-cluster aggregation&lt;/td&gt;
&lt;td&gt;Manual / federation&lt;/td&gt;
&lt;td&gt;✓ (built-in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSO, RBAC, audit log&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;History retention&lt;/td&gt;
&lt;td&gt;Limited by your storage layer&lt;/td&gt;
&lt;td&gt;Long-term, vendor-managed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collections (cloud + K8s dedup)&lt;/td&gt;
&lt;td&gt;✓ (3.x)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated Container Request Sizing UI&lt;/td&gt;
&lt;td&gt;✕ (free tier limited)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quantile-based recommendation controls&lt;/td&gt;
&lt;td&gt;✓ (3.x)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advanced filters (AND/OR)&lt;/td&gt;
&lt;td&gt;✓ (3.x)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support / SLA&lt;/td&gt;
&lt;td&gt;Community&lt;/td&gt;
&lt;td&gt;Vendor SLA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you just need per-namespace allocation, basic recommendations, and Slack alerts for a few clusters, the open-source version is enough. But if you manage many clusters across different clouds, need automated fixes, want vendor-managed history, or need to give your finance team detailed, reconciled discount numbers, then a commercial platform is worth it. The decision should be based on these needs, not just on how the dashboard looks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operational reality
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ClickHouse and a unified agent replace the old stack.&lt;/strong&gt; In v3, the 2.x DuckDB store is replaced with a ClickHouse database. This change makes allocation and cloud-cost API queries much faster and more reliable at scale. It also removes the need for Prometheus, which cuts down on memory use and makes deployment easier, while still providing OpenCost-standard metrics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;History is a deliberate choice, not a default.&lt;/strong&gt; Whatever the storage backend, the retention window is the upper bound on the period-over-period reporting you can produce. Monthly reporting requires at least 30 days; year-over-year requires a year. Tier cold data to object storage if on-cluster retention gets expensive faster than the engineering time to set up the tiered pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reconciliation lag is structural.&lt;/strong&gt; The 24–48 hour billing-reconciliation delay is a property of cloud-provider billing exports, not of Kubecost. Build the operating model around it: argue about last week, not yesterday.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-cluster needs a story.&lt;/strong&gt; Open-source Kubecost can federate across clusters, but the experience is rougher than the commercial multi-cluster aggregator. Beyond five or six clusters, decide early whether to run per-cluster Kubecost and aggregate externally — into your own warehouse, for example — or pay for the commercial multi-cluster path. Either is defensible; drifting between the two is not.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The EKS add-on offers a quick way to get started.&lt;/strong&gt; The Kubecost v3 free tier has a $100k USD spend limit over 30 days, while the Amazon EKS optimized Kubecost bundle is listed by AWS as exempt from that spend limit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The operating model is the deliverable.&lt;/strong&gt; If a team installs Kubecost but does not set up regular reviews, they will drift just like a team without any FinOps tools. The standard approach is to have a small FinOps group, such as a platform engineer, a finance analyst, and an SRE on rotation, meet each week to review the capacity-versus-request ratio, identify the most over-provisioned workloads, and check any namespace with a significant change in monthly cost. For smaller teams, a 30-minute review every two weeks with the platform engineer and CTO can achieve the same results.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A practical recommendation
&lt;/h2&gt;

&lt;p&gt;If you are considering a FinOps approach for a Kubernetes platform and do not have a contractual obligation to choose a commercial product, start by piloting open-source Kubecost 3.x. Installation can be completed in an afternoon. Assign at least one namespace to a designated owner, provide a request-versus-usage dashboard to one team for two weeks, and share the capacity-versus-request ratio in a channel visible to the platform team. If regular reviews of these metrics become routine, you have achieved FinOps. If not, adopting a commercial platform will not resolve the underlying issues.&lt;/p&gt;

</description>
      <category>kubecost</category>
      <category>finops</category>
      <category>kubernetes</category>
      <category>sre</category>
    </item>
    <item>
      <title>What Platform Teams Can Expect From Crossplane v2.2</title>
      <dc:creator>Ivan Porta</dc:creator>
      <pubDate>Tue, 05 May 2026 05:21:20 +0000</pubDate>
      <link>https://dev.to/todea/what-platform-teams-can-expect-from-crossplane-v22-1pm1</link>
      <guid>https://dev.to/todea/what-platform-teams-can-expect-from-crossplane-v22-1pm1</guid>
      <description>&lt;p&gt;A developer submits a ticket to request a database. Three days later, the platform team responds, but the configuration isn’t quite right. The developer files another ticket and waits again. By the third week, the database might finally be ready. This cycle repeats across every team and environment, creating a daily reality that most platform teams recognize: developers lose significant time waiting for infrastructure, while platform teams struggle to keep up with the constant flow of requests.&lt;/p&gt;

&lt;p&gt;There are plenty of good tools for provisioning. Terraform is platform-agnostic and widely used. CloudFormation is the go-to option on AWS, and every cloud provider offers its own console and CLI. Each tool does its job well. This article isn’t about choosing the best one. Instead, it looks at the problem from a different perspective.&lt;/p&gt;

&lt;p&gt;Crossplane offers a Kubernetes-native approach to managing cloud resources. Instead of setting up infrastructure outside the cluster and then linking it back, Crossplane brings that infrastructure under the same control loop as your applications. This fits naturally with how many teams already work. Paired with GitOps, a pull request becomes the primary way to manage changes, and the cluster continuously reconciles toward the desired state.&lt;/p&gt;

&lt;p&gt;The project has moved quickly over the past year. In August 2025, Crossplane v2 introduced big changes, like removing Claims and adding namespaced composite and managed resources. The latest release, v2.2, adds an alpha Pipeline Inspector for troubleshooting, broader CEL validation, and more improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Crossplane actually is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgzdje5rbtnflngwxm1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgzdje5rbtnflngwxm1d.png" alt=" " width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Crossplane is a control plane framework for platform engineering. You install it into a Kubernetes cluster, known as the management cluster, and that cluster becomes the control plane for everything outside it: cloud accounts, SaaS APIs, internal tools, and even other Kubernetes clusters. All of these are managed through the same Kubernetes API your applications already use. The management cluster itself must be set up separately; Crossplane does not create it for you. Once Crossplane is running, there is no state file and no separate workflow. Drift is fixed by the same reconciliation loop that keeps your &lt;code&gt;Deployments&lt;/code&gt; healthy.&lt;/p&gt;

&lt;p&gt;Crossplane has four major components. You can use all four or only the ones you need.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Managed resources (MRs)&lt;/strong&gt; map directly to external cloud resources in Kubernetes. For example, an S3 from AWS or a ResourceGroup from Azure is considered an MR. Crossplane uses spec.forProvider as the main reference and keeps the actual cloud resource in sync with it. You create MRs using kubectl, and the provider handles provisioning and reconciliation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Composition&lt;/strong&gt; lets you create custom APIs using a function pipeline. There are three main parts to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;CompositeResourceDefinition&lt;/code&gt; (XRD) defines a schema. It tells Kubernetes, “here’s a new custom API kind I’m creating, and these are its fields.” You can think of it as a CRD with added features for Crossplane.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Composition&lt;/code&gt; acts as a recipe. It says, “when someone creates an XR of kind Foo, run this set of functions to create these MRs or other Kubernetes resources.” In version 2, this always uses a function pipeline.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Composite Resource&lt;/code&gt; (XR) is an instance of the API you defined with an XRD. When a user creates an XR, Crossplane uses the matching Composition’s pipeline to generate the needed resources. You can write functions in YAML, KCL, Python, or Go.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Operations&lt;/strong&gt; run function pipelines to completion, similar to a Kubernetes Job. There are three modes: Operation (one-time), CronOperation (scheduled), and WatchOperation (event-driven). Operations are currently in alpha.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The &lt;strong&gt;package manager&lt;/strong&gt; handles installing and updating providers, configurations, and functions.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  How a Crossplane request flows
&lt;/h2&gt;

&lt;p&gt;There are two entry points into this flow, depending on what you're applying.&lt;/p&gt;

&lt;p&gt;When a developer or a pipeline creates an XR in a namespace, the composition engine watches it, runs the configured function pipeline, and creates the needed resources. These resources can be other Kubernetes resources, managed resources, or both.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpia0zafyozau7bitjvd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpia0zafyozau7bitjvd.png" alt=" " width="563" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a user applies an MR directly, either by itself or as part of a &lt;code&gt;Composition&lt;/code&gt;, the provider takes over. It monitors the MR through the Kubernetes API, calls the external system to create or update the real resource, and updates the status. After that, it keeps checking: if the real resource changes from &lt;code&gt;spec.forProvider&lt;/code&gt;, the provider fixes it. All state is stored in etcd, so there is no separate state file.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use traditional IaC instead
&lt;/h2&gt;

&lt;p&gt;Crossplane and tools like Terraform or CloudFormation overlap in scope (both can provision a cloud database) and differ in how. The right choice depends on where your platform already lives.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability / Feature&lt;/th&gt;
&lt;th&gt;Terraform&lt;/th&gt;
&lt;th&gt;CloudFormation&lt;/th&gt;
&lt;th&gt;Crossplane&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control loop&lt;/td&gt;
&lt;td&gt;Manual &lt;code&gt;apply&lt;/code&gt; (or pipeline)&lt;/td&gt;
&lt;td&gt;Manual stack create/update&lt;/td&gt;
&lt;td&gt;Continuous reconciliation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drift handling&lt;/td&gt;
&lt;td&gt;Detect with &lt;code&gt;plan&lt;/code&gt;; correct manually&lt;/td&gt;
&lt;td&gt;Detect drift action; correct via stack update&lt;/td&gt;
&lt;td&gt;Detected and corrected automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tfstate&lt;/code&gt; in a remote backend you secure (e.g., S3 with versioning, HCP Terraform)&lt;/td&gt;
&lt;td&gt;AWS-managed (server-side)&lt;/td&gt;
&lt;td&gt;Kubernetes API objects in the management cluster's etcd&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow&lt;/td&gt;
&lt;td&gt;Separate from app deployment&lt;/td&gt;
&lt;td&gt;Separate from app deployment&lt;/td&gt;
&lt;td&gt;Same as &lt;code&gt;kubectl apply&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composition&lt;/td&gt;
&lt;td&gt;Modules&lt;/td&gt;
&lt;td&gt;Nested stacks, Modules&lt;/td&gt;
&lt;td&gt;XRDs + Compositions + functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Languages&lt;/td&gt;
&lt;td&gt;HCL, JSON&lt;/td&gt;
&lt;td&gt;YAML, JSON&lt;/td&gt;
&lt;td&gt;YAML, Go, Python, KCL, CUE, HCL (via composition functions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in policy&lt;/td&gt;
&lt;td&gt;Variable validation and pre/postconditions (OSS); Sentinel and OPA integration in HCP Terraform / Enterprise&lt;/td&gt;
&lt;td&gt;cfn-guard, Hooks&lt;/td&gt;
&lt;td&gt;XRD CEL validations (incl. metadata in v2.2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-cloud&lt;/td&gt;
&lt;td&gt;Provider per cloud, separate state&lt;/td&gt;
&lt;td&gt;AWS-first (third-party types via the CloudFormation registry)&lt;/td&gt;
&lt;td&gt;One control plane, one API surface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Footprint&lt;/td&gt;
&lt;td&gt;A binary&lt;/td&gt;
&lt;td&gt;AWS-managed service (CLI/SDK only)&lt;/td&gt;
&lt;td&gt;A Kubernetes control plane (Crossplane core, providers, functions) backed by etcd&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operates outside Kubernetes&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✕ — requires a management cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your team does not use Kubernetes, Crossplane is not the best place to start. Terraform is simpler and does not need a control plane. But if you are on Kubernetes, especially if you already use Argo CD or Flux, it is easy to manage your infrastructure in the same way. Crossplane is the closest option for writing infrastructure as code and handling it like the rest of your declarative cluster state.&lt;/p&gt;

&lt;h2&gt;
  
  
  What new with v2.2
&lt;/h2&gt;

&lt;p&gt;v2.2 adds five things you'll notice in practice and one that quietly improves reliability. Each one closes a specific gap that platform teams have been hitting in production.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline inspector (alpha)&lt;/strong&gt;: &lt;code&gt;Composition&lt;/code&gt; functions are powerful, but they have always been hard to debug. If a pipeline acts up on a running control plane, you could only see what each function got and returned by writing tests, running &lt;code&gt;crossplane render&lt;/code&gt; locally, or adding your own instrumentation. v2.2 adds the pipeline inspector. When you turn on the feature flag, the Crossplane controller intercepts every &lt;code&gt;RunFunctionRequest&lt;/code&gt; and &lt;code&gt;RunFunctionResponse&lt;/code&gt; and forwards them over gRPC to a Unix socket you set up. A sidecar read from this socket and handle the data however you need: stream it to stdout during development or send it to an audit pipeline in production. To use it, add &lt;code&gt;--enable-pipeline-inspector&lt;/code&gt; to Crossplane. The default socket path is &lt;code&gt;/var/run/pipeline-inspector/socket&lt;/code&gt;, but you can change it with &lt;code&gt;--pipeline-inspector-socket&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# Enable the pipeline inspector feature flag&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--enable-pipeline-inspector&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--pipeline-inspector-socket=/var/run/pipeline-inspector/socket&lt;/span&gt;

  &lt;span class="c1"&gt;# Inject the pipeline inspector sidecar&lt;/span&gt;
  &lt;span class="na"&gt;sidecarsCrossplane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipeline-inspector&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xpkg.crossplane.io/crossplane/inspector-sidecar:v0.0.3&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--socket-path=/var/run/pipeline-inspector/socket&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--max-recv-msg-size=8388608&lt;/span&gt;  &lt;span class="c1"&gt;# 8MB&lt;/span&gt;
      &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipeline-inspector-socket&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/run/pipeline-inspector&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;10m&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;64Mi&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;100m&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;128Mi&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Add the shared volume for Unix socket communication&lt;/span&gt;
  &lt;span class="na"&gt;extraVolumesCrossplane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipeline-inspector-socket&lt;/span&gt;
      &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;

  &lt;span class="na"&gt;extraVolumeMountsCrossplane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipeline-inspector-socket&lt;/span&gt;
      &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/run/pipeline-inspector&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;XRD validation outside &lt;code&gt;spec&lt;/code&gt;&lt;/strong&gt;: XRD validation outside &lt;code&gt;x-kubernetes-validations&lt;/code&gt;, (which are Kubernetes' CEL-based validation rules) used to only work on fields under an XR's &lt;code&gt;spec&lt;/code&gt;. If you wanted to enforce rules like "all Database names must start with db-", you had to use an external admission controller such as Kyverno, OPA/Gatekeeper, or a custom webhook. With v2.2, that restriction is gone. Now, you can write CEL rules outside of &lt;code&gt;spec&lt;/code&gt;, and the API server enforces them at admission time.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apiextensions.crossplane.io/v1&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CompositeResourceDefinition&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;databases.platform.example.org&lt;/span&gt;
  &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform.example.org&lt;/span&gt;
    &lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Database&lt;/span&gt;
      &lt;span class="na"&gt;plural&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;databases&lt;/span&gt;
    &lt;span class="na"&gt;versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1alpha1&lt;/span&gt;
        &lt;span class="na"&gt;served&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;referenceable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;openAPIV3Schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
            &lt;span class="na"&gt;x-kubernetes-validations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self.metadata.name.startsWith('db-')"&lt;/span&gt;
                &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Database&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;names&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;must&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'db-'"&lt;/span&gt;
            &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
                &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ImageConfig&lt;/code&gt; runtime for dependencies&lt;/strong&gt;: A Crossplane package, including Providers, runs as a Deployment. To customize the Deployment, such as by adding service account annotations, pod labels, or container arguments, use a &lt;code&gt;DeploymentRuntimeConfig&lt;/code&gt; and reference it from the package.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Provider&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xpkg.crossplane.io/crossplane-contrib/provider-azure-network:v1.0.0&lt;/span&gt;
  &lt;span class="na"&gt;runtimeConfigRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure-workload-identity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works well when you install the package directly. However, Crossplane can also install packages as dependencies. In that case, you could not get Workload Identity or any other runtime customization onto providers installed as dependencies.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ImageConfig&lt;/code&gt; is a cluster-scoped resource that matches packages based on their image prefix, not on which Provider or Configuration object created them. In v2.2, a new field was added: &lt;code&gt;spec.runtime.configRef&lt;/code&gt;. With this change, Crossplane applies the &lt;code&gt;DeploymentRuntimeConfig&lt;/code&gt; to any package whose image is matched, regardless of how it was installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pkg.crossplane.io/v1beta1&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ImageConfig&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure-workload-identity&lt;/span&gt;
  &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchImages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xpkg.crossplane.io/crossplane-contrib/provider-azure-&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xpkg.crossplane.io/crossplane-contrib/provider-family-azure&lt;/span&gt;
    &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;configRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure-workload-identity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every Azure family provider, whether installed directly or added as a dependency, receives the runtime config.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;RequiredSchemas&lt;/code&gt; for functions&lt;/strong&gt;: Composition and functions sometimes need the OpenAPI schema of a resource to validate inputs, make schema-aware decisions, or generate resources dynamically. Before v2.2 you could ask Crossplane for the corresponding CRD as a &lt;code&gt;RequiredResource&lt;/code&gt;, parse it, and extract the schema yourself, but only for custom resources, since built-in kinds like Deployment don't have a CRD. v2.2 introduces &lt;code&gt;RequiredSchemas&lt;/code&gt; on the &lt;code&gt;RunFunctionResponse&lt;/code&gt; thich returns the schema for any kind, built-in or custom. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;crossplane beta trace&lt;/code&gt; improvements&lt;/strong&gt;: You can now pass a kind (and optionally a namespace) instead of a single resource and get the dependency tree for every instance. And &lt;code&gt;--watch&lt;/code&gt; (alias &lt;code&gt;-w&lt;/code&gt;) keeps the output live, the way &lt;code&gt;kubectl get -w&lt;/code&gt; does. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Function packages no longer install bundled CRDs&lt;/strong&gt;: CRDs included in a function package are not applied to the cluster anymore. Also, packages with unknown or disallowed kinds now install successfully and simply skip those objects. Previously, the install would fail in these cases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The package cache layout has changed&lt;/strong&gt;: Cache filenames now come from the package’s OCI source and digest instead of the PackageRevision’s Kubernetes name. This change affects side-loading used by some provider e2e suites.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Operational reality
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The management cluster is your state.&lt;/strong&gt; Crossplane does not use an external state file. All XRDs, Compositions, XRs, and managed resources are stored in the management cluster’s etcd. If you lose that cluster without backups, your cloud resources keep running, but Crossplane loses track of them and stops reconciling. Silent drift can build up. Treat the management cluster like any production-critical Kubernetes cluster: use a highly available control plane, back up etcd, and avoid running it on your laptop. Local k3s or kind clusters are fine for learning, demos, or the Get Started guide, but not for important state. This is the trade-off for not having a Terraform state file: you solve one operational problem but gain another that is easier to overlook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Upgrade through v2.1, not directly.&lt;/strong&gt; Crossplane performs CRD migrations with each minor version upgrade, so skipping versions can cause you to miss important migrations. If you are on v1.x, use the Crossplane v2 upgrade guide. If you are on v2.1, upgrade directly to v2.2.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;v1.20 is not yet end-of-life.&lt;/strong&gt; v1.20 is still supported and has not reached end-of-life yet. However, since you are on a maintenance-only branch, it’s a good time to start planning your upgrade to v2.x.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pipeline inspector is alpha.&lt;/strong&gt; The flag is off by default and the contract may still change. Sidecar image versioning is also not stable yet. Try it in development, since function pipelines are much easier to understand when you can see them, but do not add it to your incident-response runbook yet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Namespaced MRs are not yet universal.&lt;/strong&gt; AWS managed resources are fully namespaced. The Upbound Azure provider, which is widely used, and GCP are currently rolling out this feature.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;v2 removed several things.&lt;/strong&gt; Native patch-and-transform composition, the &lt;code&gt;ControllerConfig&lt;/code&gt; type, external secret stores, composite resource connection details, and the default registry for packages are no longer available. Most users can upgrade without breaking changes, but if you use these features, you will need to do some cleanup. Before upgrading, run &lt;code&gt;kubectl get pkg&lt;/code&gt; and make sure every package uses a fully qualified image, such as &lt;code&gt;registry.example.com/repo/package:tag&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A practical recommendation
&lt;/h2&gt;

&lt;p&gt;If you are considering a control plane for your Kubernetes platform and do not have a strong reason to stick with Terraform, try Crossplane v2.2 first. The Get Started guide can be completed in an afternoon on any Kubernetes cluster. If Crossplane meets your needs, you can manage both application and infrastructure workflows with one declarative model. If not, you will have a clear, documented reason to keep your current tools.&lt;/p&gt;

&lt;p&gt;If you are already using Crossplane v2.1, upgrade to v2.2. Features like server-side apply on the MRD controller, dependency-aware runtime config, schema access for functions, and better trace output are valuable even if you do not use the pipeline inspector. If you are still on v1.x, pin to v1.20, migrate any deprecated features, then upgrade to v2.x and continue from there. v2 offers good backward compatibility, but the deprecations are real.&lt;/p&gt;

</description>
      <category>crossplane</category>
      <category>kubernetes</category>
      <category>gitops</category>
    </item>
  </channel>
</rss>
