<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kubernetes Blog</title><link>https://kubernetes.io/</link><description>The Kubernetes blog is used by the project to communicate new features, community reports, and any news that might be relevant to the Kubernetes community.</description><generator>Hugo -- gohugo.io</generator><language>en</language><image><url>https://raw.githubusercontent.com/kubernetes/kubernetes/master/logo/logo.png</url><title>The Kubernetes project logo</title><link>https://kubernetes.io/</link></image><atom:link href="https://kubernetes.io/feed.xml" rel="self" type="application/rss+xml"/><item><title>Kubernetes Multicontainer Pods: An Overview</title><link>https://kubernetes.io/blog/2025/04/22/multi-container-pods-overview/</link><pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/04/22/multi-container-pods-overview/</guid><description>
&lt;p>As cloud-native architectures continue to evolve, Kubernetes has become the go-to platform for deploying complex, distributed systems. One of the most powerful yet nuanced design patterns in this ecosystem is the sidecar pattern—a technique that allows developers to extend application functionality without diving deep into source code.&lt;/p>
&lt;h2 id="the-origins-of-the-sidecar-pattern">The origins of the sidecar pattern&lt;/h2>
&lt;p>Think of a sidecar like a trusty companion motorcycle attachment. Historically, IT infrastructures have always used auxiliary services to handle critical tasks. Before containers, we relied on background processes and helper daemons to manage logging, monitoring, and networking. The microservices revolution transformed this approach, making sidecars a structured and intentional architectural choice.
With the rise of microservices, the sidecar pattern became more clearly defined, allowing developers to offload specific responsibilities from the main service without altering its code. Service meshes like Istio and Linkerd have popularized sidecar proxies, demonstrating how these companion containers can elegantly handle observability, security, and traffic management in distributed systems.&lt;/p>
&lt;h2 id="kubernetes-implementation">Kubernetes implementation&lt;/h2>
&lt;p>In Kubernetes, &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/">sidecar containers&lt;/a> operate within
the same Pod as the main application, enabling communication and resource sharing.
Does this sound just like defining multiple containers along each other inside the Pod? It actually does, and
this is how sidecar containers had to be implemented before Kubernetes v1.29.0, which introduced
native support for sidecars.
Sidecar containers can now be defined within a Pod manifest using the &lt;code>spec.initContainers&lt;/code> field. What makes
it a sidecar container is that you specify it with &lt;code>restartPolicy: Always&lt;/code>. You can see an example of this below, which is a partial snippet of the full Kubernetes manifest:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">initContainers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>logshipper&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>alpine:latest&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">restartPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Always&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">command&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#b44">&amp;#39;sh&amp;#39;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;-c&amp;#39;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;tail -F /opt/logs.txt&amp;#39;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeMounts&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>data&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">mountPath&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/opt&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That field name, &lt;code>spec.initContainers&lt;/code> may sound confusing. How come when you want to define a sidecar container, you have to put an entry in the &lt;code>spec.initContainers&lt;/code> array? &lt;code>spec.initContainers&lt;/code> are run to completion just before main application starts, so they’re one-off, whereas sidecars often run in parallel to the main app container. It’s the &lt;code>spec.initContainers&lt;/code> with &lt;code>restartPolicy:Always&lt;/code> which differs classic &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/">init containers&lt;/a> from Kubernetes-native sidecar containers and ensures they are always up.&lt;/p>
&lt;h2 id="when-to-embrace-or-avoid-sidecars">When to embrace (or avoid) sidecars&lt;/h2>
&lt;p>While the sidecar pattern can be useful in many cases, it is generally not the preferred approach unless the use case justifies it. Adding a sidecar increases complexity, resource consumption, and potential network latency. Instead, simpler alternatives such as built-in libraries or shared infrastructure should be considered first.&lt;/p>
&lt;p>&lt;strong>Deploy a sidecar when:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>You need to extend application functionality without touching the original code&lt;/li>
&lt;li>Implementing cross-cutting concerns like logging, monitoring or security&lt;/li>
&lt;li>Working with legacy applications requiring modern networking capabilities&lt;/li>
&lt;li>Designing microservices that demand independent scaling and updates&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Proceed with caution if:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Resource efficiency is your primary concern&lt;/li>
&lt;li>Minimal network latency is critical&lt;/li>
&lt;li>Simpler alternatives exist&lt;/li>
&lt;li>You want to minimize troubleshooting complexity&lt;/li>
&lt;/ol>
&lt;h2 id="four-essential-multi-container-patterns">Four essential multi-container patterns&lt;/h2>
&lt;h3 id="init-container-pattern">Init container pattern&lt;/h3>
&lt;p>The &lt;strong>Init container&lt;/strong> pattern is used to execute (often critical) setup tasks before the main application container starts. Unlike regular containers, init containers run to completion and then terminate, ensuring that preconditions for the main application are met.&lt;/p>
&lt;p>&lt;strong>Ideal for:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Preparing configurations&lt;/li>
&lt;li>Loading secrets&lt;/li>
&lt;li>Verifying dependency availability&lt;/li>
&lt;li>Running database migrations&lt;/li>
&lt;/ol>
&lt;p>The init container ensures your application starts in a predictable, controlled environment without code modifications.&lt;/p>
&lt;h3 id="ambassador-pattern">Ambassador pattern&lt;/h3>
&lt;p>An ambassador container provides Pod-local helper services that expose a simple way to access a network service. Commonly, ambassador containers send network requests on behalf of a an application container and
take care of challenges such as service discovery, peer identity verification, or encryption in transit.&lt;/p>
&lt;p>&lt;strong>Perfect when you need to:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Offload client connectivity concerns&lt;/li>
&lt;li>Implement language-agnostic networking features&lt;/li>
&lt;li>Add security layers like TLS&lt;/li>
&lt;li>Create robust circuit breakers and retry mechanisms&lt;/li>
&lt;/ol>
&lt;h3 id="configuration-helper">Configuration helper&lt;/h3>
&lt;p>A &lt;em>configuration helper&lt;/em> sidecar provides configuration updates to an application dynamically, ensuring it always has access to the latest settings without disrupting the service. Often the helper needs to provide an initial
configuration before the application would be able to start successfully.&lt;/p>
&lt;p>&lt;strong>Use cases:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Fetching environment variables and secrets&lt;/li>
&lt;li>Polling configuration changes&lt;/li>
&lt;li>Decoupling configuration management from application logic&lt;/li>
&lt;/ol>
&lt;h3 id="adapter-pattern">Adapter pattern&lt;/h3>
&lt;p>An &lt;em>adapter&lt;/em> (or sometimes &lt;em>façade&lt;/em>) container enables interoperability between the main application container and external services. It does this by translating data formats, protocols, or APIs.&lt;/p>
&lt;p>&lt;strong>Strengths:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Transforming legacy data formats&lt;/li>
&lt;li>Bridging communication protocols&lt;/li>
&lt;li>Facilitating integration between mismatched services&lt;/li>
&lt;/ol>
&lt;h2 id="wrap-up">Wrap-up&lt;/h2>
&lt;p>While sidecar patterns offer tremendous flexibility, they're not a silver bullet. Each added sidecar introduces complexity, consumes resources, and potentially increases operational overhead. Always evaluate simpler alternatives first.
The key is strategic implementation: use sidecars as precision tools to solve specific architectural challenges, not as a default approach. When used correctly, they can improve security, networking, and configuration management in containerized environments.
Choose wisely, implement carefully, and let your sidecars elevate your container ecosystem.&lt;/p></description></item><item><title>Introducing kube-scheduler-simulator</title><link>https://kubernetes.io/blog/2025/04/07/introducing-kube-scheduler-simulator/</link><pubDate>Mon, 07 Apr 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/04/07/introducing-kube-scheduler-simulator/</guid><description>
&lt;p>The Kubernetes Scheduler is a crucial control plane component that determines which node a Pod will run on.
Thus, anyone utilizing Kubernetes relies on a scheduler.&lt;/p>
&lt;p>&lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-simulator">kube-scheduler-simulator&lt;/a> is a &lt;em>simulator&lt;/em> for the Kubernetes scheduler, that started as a &lt;a href="https://summerofcode.withgoogle.com/">Google Summer of Code 2021&lt;/a> project developed by me (Kensei Nakada) and later received a lot of contributions.
This tool allows users to closely examine the scheduler’s behavior and decisions.&lt;/p>
&lt;p>It is useful for casual users who employ scheduling constraints (for example, &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity/#affinity-and-anti-affinity">inter-Pod affinity&lt;/a>)
and experts who extend the scheduler with custom plugins.&lt;/p>
&lt;h2 id="motivation">Motivation&lt;/h2>
&lt;p>The scheduler often appears as a black box,
composed of many plugins that each contribute to the scheduling decision-making process from their unique perspectives.
Understanding its behavior can be challenging due to the multitude of factors it considers.&lt;/p>
&lt;p>Even if a Pod appears to be scheduled correctly in a simple test cluster, it might have been scheduled based on different calculations than expected. This discrepancy could lead to unexpected scheduling outcomes when deployed in a large production environment.&lt;/p>
&lt;p>Also, testing a scheduler is a complex challenge.
There are countless patterns of operations executed within a real cluster, making it unfeasible to anticipate every scenario with a finite number of tests.
More often than not, bugs are discovered only when the scheduler is deployed in an actual cluster.
Actually, many bugs are found by users after shipping the release,
even in the upstream kube-scheduler.&lt;/p>
&lt;p>Having a development or sandbox environment for testing the scheduler — or, indeed, any Kubernetes controllers — is a common practice.
However, this approach falls short of capturing all the potential scenarios that might arise in a production cluster
because a development cluster is often much smaller with notable differences in workload sizes and scaling dynamics.
It never sees the exact same use or exhibits the same behavior as its production counterpart.&lt;/p>
&lt;p>The kube-scheduler-simulator aims to solve those problems.
It enables users to test their scheduling constraints, scheduler configurations,
and custom plugins while checking every detailed part of scheduling decisions.
It also allows users to create a simulated cluster environment, where they can test their scheduler
with the same resources as their production cluster without affecting actual workloads.&lt;/p>
&lt;h2 id="features-of-the-kube-scheduler-simulator">Features of the kube-scheduler-simulator&lt;/h2>
&lt;p>The kube-scheduler-simulator’s core feature is its ability to expose the scheduler's internal decisions.
The scheduler operates based on the &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">scheduling framework&lt;/a>,
using various plugins at different extension points,
filter nodes (Filter phase), score nodes (Score phase), and ultimately determine the best node for the Pod.&lt;/p>
&lt;p>The simulator allows users to create Kubernetes resources and observe how each plugin influences the scheduling decisions for Pods.
This visibility helps users understand the scheduler’s workings and define appropriate scheduling constraints.&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/images/blog/2025-04-07-kube-scheduler-simulator/simulator.png"
alt="Screenshot of the simulator web frontend that shows the detailed scheduling results per node and per extension point"/> &lt;figcaption>
&lt;h4>The simulator web frontend&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;p>Inside the simulator, a debuggable scheduler runs instead of the vanilla scheduler.
This debuggable scheduler outputs the results of each scheduler plugin at every extension point to the Pod’s annotations like the following manifest shows
and the web front end formats/visualizes the scheduling results based on these annotations.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># The JSONs within these annotations are manually formatted for clarity in the blog post. &lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">annotations&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/bind-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;{&amp;#34;DefaultBinder&amp;#34;:&amp;#34;success&amp;#34;}&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/filter-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;gt;-&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;node-jjfg5&amp;#34;:{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeName&amp;#34;:&amp;#34;passed&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;passed&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeUnschedulable&amp;#34;:&amp;#34;passed&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;TaintToleration&amp;#34;:&amp;#34;passed&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> },
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;node-mtb5x&amp;#34;:{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeName&amp;#34;:&amp;#34;passed&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;passed&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeUnschedulable&amp;#34;:&amp;#34;passed&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;TaintToleration&amp;#34;:&amp;#34;passed&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/finalscore-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;gt;-&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;node-jjfg5&amp;#34;:{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;ImageLocality&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeAffinity&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesBalancedAllocation&amp;#34;:&amp;#34;52&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;47&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;TaintToleration&amp;#34;:&amp;#34;300&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;VolumeBinding&amp;#34;:&amp;#34;0&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> },
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;node-mtb5x&amp;#34;:{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;ImageLocality&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeAffinity&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesBalancedAllocation&amp;#34;:&amp;#34;76&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;73&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;TaintToleration&amp;#34;:&amp;#34;300&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;VolumeBinding&amp;#34;:&amp;#34;0&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> } &lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/permit-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;{}&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/permit-result-timeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;{}&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/postfilter-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;{}&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/prebind-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;{&amp;#34;VolumeBinding&amp;#34;:&amp;#34;success&amp;#34;}&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/prefilter-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;{}&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/prefilter-result-status&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;gt;-&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;AzureDiskLimits&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;EBSLimits&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;GCEPDLimits&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;InterPodAffinity&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeAffinity&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodePorts&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;success&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeVolumeLimits&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;PodTopologySpread&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;VolumeBinding&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;VolumeRestrictions&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;VolumeZone&amp;#34;:&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/prescore-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;gt;-&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;InterPodAffinity&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeAffinity&amp;#34;:&amp;#34;success&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesBalancedAllocation&amp;#34;:&amp;#34;success&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;success&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;PodTopologySpread&amp;#34;:&amp;#34;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;TaintToleration&amp;#34;:&amp;#34;success&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/reserve-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;{&amp;#34;VolumeBinding&amp;#34;:&amp;#34;success&amp;#34;}&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/result-history&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;gt;-&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> [
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/bind-result&amp;#34;:&amp;#34;{\&amp;#34;DefaultBinder\&amp;#34;:\&amp;#34;success\&amp;#34;}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/filter-result&amp;#34;:&amp;#34;{\&amp;#34;node-jjfg5\&amp;#34;:{\&amp;#34;NodeName\&amp;#34;:\&amp;#34;passed\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;passed\&amp;#34;,\&amp;#34;NodeUnschedulable\&amp;#34;:\&amp;#34;passed\&amp;#34;,\&amp;#34;TaintToleration\&amp;#34;:\&amp;#34;passed\&amp;#34;},\&amp;#34;node-mtb5x\&amp;#34;:{\&amp;#34;NodeName\&amp;#34;:\&amp;#34;passed\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;passed\&amp;#34;,\&amp;#34;NodeUnschedulable\&amp;#34;:\&amp;#34;passed\&amp;#34;,\&amp;#34;TaintToleration\&amp;#34;:\&amp;#34;passed\&amp;#34;}}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/finalscore-result&amp;#34;:&amp;#34;{\&amp;#34;node-jjfg5\&amp;#34;:{\&amp;#34;ImageLocality\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeAffinity\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeResourcesBalancedAllocation\&amp;#34;:\&amp;#34;52\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;47\&amp;#34;,\&amp;#34;TaintToleration\&amp;#34;:\&amp;#34;300\&amp;#34;,\&amp;#34;VolumeBinding\&amp;#34;:\&amp;#34;0\&amp;#34;},\&amp;#34;node-mtb5x\&amp;#34;:{\&amp;#34;ImageLocality\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeAffinity\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeResourcesBalancedAllocation\&amp;#34;:\&amp;#34;76\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;73\&amp;#34;,\&amp;#34;TaintToleration\&amp;#34;:\&amp;#34;300\&amp;#34;,\&amp;#34;VolumeBinding\&amp;#34;:\&amp;#34;0\&amp;#34;}}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/permit-result&amp;#34;:&amp;#34;{}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/permit-result-timeout&amp;#34;:&amp;#34;{}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/postfilter-result&amp;#34;:&amp;#34;{}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/prebind-result&amp;#34;:&amp;#34;{\&amp;#34;VolumeBinding\&amp;#34;:\&amp;#34;success\&amp;#34;}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/prefilter-result&amp;#34;:&amp;#34;{}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/prefilter-result-status&amp;#34;:&amp;#34;{\&amp;#34;AzureDiskLimits\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;EBSLimits\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;GCEPDLimits\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;InterPodAffinity\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;NodeAffinity\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;NodePorts\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;success\&amp;#34;,\&amp;#34;NodeVolumeLimits\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;PodTopologySpread\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;VolumeBinding\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;VolumeRestrictions\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;VolumeZone\&amp;#34;:\&amp;#34;\&amp;#34;}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/prescore-result&amp;#34;:&amp;#34;{\&amp;#34;InterPodAffinity\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;NodeAffinity\&amp;#34;:\&amp;#34;success\&amp;#34;,\&amp;#34;NodeResourcesBalancedAllocation\&amp;#34;:\&amp;#34;success\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;success\&amp;#34;,\&amp;#34;PodTopologySpread\&amp;#34;:\&amp;#34;\&amp;#34;,\&amp;#34;TaintToleration\&amp;#34;:\&amp;#34;success\&amp;#34;}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/reserve-result&amp;#34;:&amp;#34;{\&amp;#34;VolumeBinding\&amp;#34;:\&amp;#34;success\&amp;#34;}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/score-result&amp;#34;:&amp;#34;{\&amp;#34;node-jjfg5\&amp;#34;:{\&amp;#34;ImageLocality\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeAffinity\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeResourcesBalancedAllocation\&amp;#34;:\&amp;#34;52\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;47\&amp;#34;,\&amp;#34;TaintToleration\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;VolumeBinding\&amp;#34;:\&amp;#34;0\&amp;#34;},\&amp;#34;node-mtb5x\&amp;#34;:{\&amp;#34;ImageLocality\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeAffinity\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;NodeResourcesBalancedAllocation\&amp;#34;:\&amp;#34;76\&amp;#34;,\&amp;#34;NodeResourcesFit\&amp;#34;:\&amp;#34;73\&amp;#34;,\&amp;#34;TaintToleration\&amp;#34;:\&amp;#34;0\&amp;#34;,\&amp;#34;VolumeBinding\&amp;#34;:\&amp;#34;0\&amp;#34;}}&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;kube-scheduler-simulator.sigs.k8s.io/selected-node&amp;#34;:&amp;#34;node-mtb5x&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> ]&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/score-result&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;gt;-&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;node-jjfg5&amp;#34;:{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;ImageLocality&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeAffinity&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesBalancedAllocation&amp;#34;:&amp;#34;52&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;47&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;TaintToleration&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;VolumeBinding&amp;#34;:&amp;#34;0&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> },
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;node-mtb5x&amp;#34;:{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;ImageLocality&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeAffinity&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesBalancedAllocation&amp;#34;:&amp;#34;76&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;NodeResourcesFit&amp;#34;:&amp;#34;73&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;TaintToleration&amp;#34;:&amp;#34;0&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> &amp;#34;VolumeBinding&amp;#34;:&amp;#34;0&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> }&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kube-scheduler-simulator.sigs.k8s.io/selected-node&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>node-mtb5x&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Users can also integrate &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">their custom plugins&lt;/a> or &lt;a href="https://github.com/kubernetes/design-proposals-archive/blob/main/scheduling/scheduler_extender.md">extenders&lt;/a>, into the debuggable scheduler and visualize their results.&lt;/p>
&lt;p>This debuggable scheduler can also run standalone, for example, on any Kubernetes cluster or in integration tests.
This would be useful to custom plugin developers who want to test their plugins or examine their custom scheduler in a real cluster with better debuggability.&lt;/p>
&lt;h2 id="the-simulator-as-a-better-dev-cluster">The simulator as a better dev cluster&lt;/h2>
&lt;p>As mentioned earlier, with a limited set of tests, it is impossible to predict every possible scenario in a real-world cluster.
Typically, users will test the scheduler in a small, development cluster before deploying it to production, hoping that no issues arise.&lt;/p>
&lt;p>&lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-simulator/blob/master/simulator/docs/import-cluster-resources.md">The simulator’s importing feature&lt;/a>
provides a solution by allowing users to simulate deploying a new scheduler version in a production-like environment without impacting their live workloads.&lt;/p>
&lt;p>By continuously syncing between a production cluster and the simulator, users can safely test a new scheduler version with the same resources their production cluster handles.
Once confident in its performance, they can proceed with the production deployment, reducing the risk of unexpected issues.&lt;/p>
&lt;h2 id="what-are-the-use-cases">What are the use cases?&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Cluster users&lt;/strong>: Examine if scheduling constraints (for example, PodAffinity, PodTopologySpread) work as intended.&lt;/li>
&lt;li>&lt;strong>Cluster admins&lt;/strong>: Assess how a cluster would behave with changes to the scheduler configuration.&lt;/li>
&lt;li>&lt;strong>Scheduler plugin developers&lt;/strong>: Test a custom scheduler plugins or extenders, use the debuggable scheduler in integration tests or development clusters, or use the &lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-simulator/blob/simulator/v0.3.0/simulator/docs/import-cluster-resources.md">syncing&lt;/a> feature for testing within a production-like environment.&lt;/li>
&lt;/ol>
&lt;h2 id="getting-started">Getting started&lt;/h2>
&lt;p>The simulator only requires Docker to be installed on a machine; a Kubernetes cluster is not necessary.&lt;/p>
&lt;pre tabindex="0">&lt;code>git clone git@github.com:kubernetes-sigs/kube-scheduler-simulator.git
cd kube-scheduler-simulator
make docker_up
&lt;/code>&lt;/pre>&lt;p>You can then access the simulator's web UI at &lt;code>http://localhost:3000&lt;/code>.&lt;/p>
&lt;p>Visit the &lt;a href="https://sigs.k8s.io/kube-scheduler-simulator">kube-scheduler-simulator repository&lt;/a> for more details!&lt;/p>
&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>The scheduler simulator is developed by &lt;a href="https://github.com/kubernetes/community/blob/master/sig-scheduling/README.md#kube-scheduler-simulator">Kubernetes SIG Scheduling&lt;/a>. Your feedback and contributions are welcome!&lt;/p>
&lt;p>Open issues or PRs at the &lt;a href="https://sigs.k8s.io/kube-scheduler-simulator">kube-scheduler-simulator repository&lt;/a>.
Join the conversation on the &lt;a href="https://kubernetes.slack.com/messages/sig-scheduling">#sig-scheduling&lt;/a> slack channel.&lt;/p>
&lt;h2 id="acknowledgments">Acknowledgments&lt;/h2>
&lt;p>The simulator has been maintained by dedicated volunteer engineers, overcoming many challenges to reach its current form.&lt;/p>
&lt;p>A big shout out to all &lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-simulator/graphs/contributors">the awesome contributors&lt;/a>!&lt;/p></description></item><item><title>Kubernetes v1.33 sneak peek</title><link>https://kubernetes.io/blog/2025/03/26/kubernetes-v1-33-upcoming-changes/</link><pubDate>Wed, 26 Mar 2025 10:30:00 -0800</pubDate><guid>https://kubernetes.io/blog/2025/03/26/kubernetes-v1-33-upcoming-changes/</guid><description>
&lt;p>As the release of Kubernetes v1.33 approaches, the Kubernetes project continues to evolve. Features may be deprecated, removed, or replaced to improve the overall health of the project. This blog post outlines some planned changes for the v1.33 release, which the release team believes you should be aware of to ensure the continued smooth operation of your Kubernetes environment and to keep you up-to-date with the latest developments. The information below is based on the current status of the v1.33 release and is subject to change before the final release date.&lt;/p>
&lt;h2 id="the-kubernetes-api-removal-and-deprecation-process">The Kubernetes API removal and deprecation process&lt;/h2>
&lt;p>The Kubernetes project has a well-documented &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-policy/">deprecation policy&lt;/a> for features. This policy states that stable APIs may only be deprecated when a newer, stable version of that same API is available and that APIs have a minimum lifetime for each stability level. A deprecated API has been marked for removal in a future Kubernetes release. It will continue to function until removal (at least one year from the deprecation), but usage will result in a warning being displayed. Removed APIs are no longer available in the current version, at which point you must migrate to using the replacement.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Generally available (GA) or stable API versions may be marked as deprecated but must not be removed within a major version of Kubernetes.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Beta or pre-release API versions must be supported for 3 releases after the deprecation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Alpha or experimental API versions may be removed in any release without prior deprecation notice; this process can become a withdrawal in cases where a different implementation for the same feature is already in place.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Whether an API is removed as a result of a feature graduating from beta to stable, or because that API simply did not succeed, all removals comply with this deprecation policy. Whenever an API is removed, migration options are communicated in the &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/">deprecation guide&lt;/a>.&lt;/p>
&lt;h2 id="deprecations-and-removals-for-kubernetes-v1-33">Deprecations and removals for Kubernetes v1.33&lt;/h2>
&lt;h3 id="deprecation-of-the-stable-endpoints-api">Deprecation of the stable Endpoints API&lt;/h3>
&lt;p>The &lt;a href="https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/">EndpointSlices&lt;/a> API has been stable since v1.21, which effectively replaced the original Endpoints API. While the original Endpoints API was simple and straightforward, it also posed some challenges when scaling to large numbers of network endpoints. The EndpointSlices API has introduced new features such as dual-stack networking, making the original Endpoints API ready for deprecation.&lt;/p>
&lt;p>This deprecation only impacts those who use the Endpoints API directly from workloads or scripts; these users should migrate to use EndpointSlices instead. There will be a dedicated blog post with more details on the deprecation implications and migration plans in the coming weeks.&lt;/p>
&lt;p>You can find more in &lt;a href="https://kep.k8s.io/4974">KEP-4974: Deprecate v1.Endpoints&lt;/a>.&lt;/p>
&lt;h3 id="removal-of-kube-proxy-version-information-in-node-status">Removal of kube-proxy version information in node status&lt;/h3>
&lt;p>Following its deprecation in v1.31, as highlighted in the &lt;a href="https://kubernetes.io/blog/2024/07/19/kubernetes-1-31-upcoming-changes/#deprecation-of-status-nodeinfo-kubeproxyversion-field-for-nodes-kep-4004-https-github-com-kubernetes-enhancements-issues-4004">release announcement&lt;/a>, the &lt;code>status.nodeInfo.kubeProxyVersion&lt;/code> field will be removed in v1.33. This field was set by kubelet, but its value was not consistently accurate. As it has been disabled by default since v1.31, the v1.33 release will remove this field entirely.&lt;/p>
&lt;p>You can find more in &lt;a href="https://kep.k8s.io/4004">KEP-4004: Deprecate status.nodeInfo.kubeProxyVersion field&lt;/a>.&lt;/p>
&lt;h3 id="removal-of-host-network-support-for-windows-pods">Removal of host network support for Windows pods&lt;/h3>
&lt;p>Windows Pod networking aimed to achieve feature parity with Linux and provide better cluster density by allowing containers to use the Node’s networking namespace.
The original implementation landed as alpha with v1.26, but as it faced unexpected containerd behaviours,
and alternative solutions were available, the Kubernetes project has decided to withdraw the associated
KEP. We're expecting to see support fully removed in v1.33.&lt;/p>
&lt;p>You can find more in &lt;a href="https://kep.k8s.io/3503">KEP-3503: Host network support for Windows pods&lt;/a>.&lt;/p>
&lt;h2 id="featured-improvement-of-kubernetes-v1-33">Featured improvement of Kubernetes v1.33&lt;/h2>
&lt;p>As authors of this article, we picked one improvement as the most significant change to call out!&lt;/p>
&lt;h3 id="support-for-user-namespaces-within-linux-pods">Support for user namespaces within Linux Pods&lt;/h3>
&lt;p>One of the oldest open KEPs today is &lt;a href="https://kep.k8s.io/127">KEP-127&lt;/a>, Pod security improvement by using Linux &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/">User namespaces&lt;/a> for Pods. This KEP was first opened in late 2016, and after multiple iterations, had its alpha release in v1.25, initial beta in v1.30 (where it was disabled by default), and now is set to be a part of v1.33, where the feature is available by default.&lt;/p>
&lt;p>This support will not impact existing Pods unless you manually specify &lt;code>pod.spec.hostUsers&lt;/code> to opt in. As highlighted in the &lt;a href="https://kubernetes.io/blog/2024/03/12/kubernetes-1-30-upcoming-changes/">v1.30 sneak peek blog&lt;/a>, this is an important milestone for mitigating vulnerabilities.&lt;/p>
&lt;p>You can find more in &lt;a href="https://kep.k8s.io/127">KEP-127: Support User Namespaces in pods&lt;/a>.&lt;/p>
&lt;h2 id="selected-other-kubernetes-v1-33-improvements">Selected other Kubernetes v1.33 improvements&lt;/h2>
&lt;p>The following list of enhancements is likely to be included in the upcoming v1.33 release. This is not a commitment and the release content is subject to change.&lt;/p>
&lt;h3 id="in-place-resource-resize-for-vertical-scaling-of-pods">In-place resource resize for vertical scaling of Pods&lt;/h3>
&lt;p>When provisioning a Pod, you can use various resources such as Deployment, StatefulSet, etc. Scalability requirements may need horizontal scaling by updating the Pod replica count, or vertical scaling by updating resources allocated to Pod’s container(s). Before this enhancement, container resources defined in a Pod's &lt;code>spec&lt;/code> were immutable, and updating any of these details within a Pod template would trigger Pod replacement.&lt;/p>
&lt;p>But what if you could dynamically update the resource configuration for your existing Pods without restarting them?&lt;/p>
&lt;p>The &lt;a href="https://kep.k8s.io/1287">KEP-1287&lt;/a> is precisely to allow such in-place Pod updates. It opens up various possibilities of vertical scale-up for stateful processes without any downtime, seamless scale-down when the traffic is low, and even allocating larger resources during startup that is eventually reduced once the initial setup is complete. This was released as alpha in v1.27, and is expected to land as beta in v1.33.&lt;/p>
&lt;p>You can find more in &lt;a href="https://kep.k8s.io/1287">KEP-1287: In-Place Update of Pod Resources&lt;/a>.&lt;/p>
&lt;h3 id="dra-s-resourceclaim-device-status-graduates-to-beta">DRA’s ResourceClaim Device Status graduates to beta&lt;/h3>
&lt;p>The &lt;code>devices&lt;/code> field in ResourceClaim &lt;code>status&lt;/code>, originally introduced in the v1.32 release, is likely to graduate to beta in v1.33. This field allows drivers to report device status data, improving both observability and troubleshooting capabilities.&lt;/p>
&lt;p>For example, reporting the interface name, MAC address, and IP addresses of network interfaces in the status of a ResourceClaim can significantly help in configuring and managing network services, as well as in debugging network related issues. You can read more about ResourceClaim Device Status in &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/dynamic-resource-allocation/#resourceclaim-device-status">Dynamic Resource Allocation: ResourceClaim Device Status&lt;/a> document.&lt;/p>
&lt;p>Also, you can find more about the planned enhancement in &lt;a href="https://kep.k8s.io/4817">KEP-4817: DRA: Resource Claim Status with possible standardized network interface data&lt;/a>.&lt;/p>
&lt;h3 id="ordered-namespace-deletion">Ordered namespace deletion&lt;/h3>
&lt;p>This KEP introduces a more structured deletion process for Kubernetes namespaces to ensure secure and deterministic resource removal. The current semi-random deletion order can create security gaps or unintended behaviour, such as Pods persisting after their associated NetworkPolicies are deleted. By enforcing a structured deletion sequence that respects logical and security dependencies, this approach ensures Pods are removed before other resources. The design improves Kubernetes’s security and reliability by mitigating risks associated with non-deterministic deletions.&lt;/p>
&lt;p>You can find more in &lt;a href="https://kep.k8s.io/5080">KEP-5080: Ordered namespace deletion&lt;/a>.&lt;/p>
&lt;h3 id="enhancements-for-indexed-job-management">Enhancements for indexed job management&lt;/h3>
&lt;p>These two KEPs are both set to graduate to GA to provide better reliability for job handling, specifically for indexed jobs. &lt;a href="https://kep.k8s.io/3850">KEP-3850&lt;/a> provides per-index backoff limits for indexed jobs, which allows each index to be fully independent of other indexes. Also, &lt;a href="https://kep.k8s.io/3998">KEP-3998&lt;/a> extends Job API to define conditions for making an indexed job as successfully completed when not all indexes are succeeded.&lt;/p>
&lt;p>You can find more in &lt;a href="https://kep.k8s.io/3850">KEP-3850: Backoff Limit Per Index For Indexed Jobs&lt;/a> and &lt;a href="https://kep.k8s.io/3998">KEP-3998: Job success/completion policy&lt;/a>.&lt;/p>
&lt;h2 id="want-to-know-more">Want to know more?&lt;/h2>
&lt;p>New features and deprecations are also announced in the Kubernetes release notes. We will formally announce what's new in &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.33.md">Kubernetes v1.33&lt;/a> as part of the CHANGELOG for that release.&lt;/p>
&lt;p>Kubernetes v1.33 release is planned for &lt;strong>Wednesday, 23rd April, 2025&lt;/strong>. Stay tuned for updates!&lt;/p>
&lt;p>You can also see the announcements of changes in the release notes for:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.32.md">Kubernetes v1.32&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md">Kubernetes v1.31&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md">Kubernetes v1.30&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="get-involved">Get involved&lt;/h2>
&lt;p>The simplest way to get involved with Kubernetes is by joining one of the many &lt;a href="https://github.com/kubernetes/community/blob/master/sig-list.md">Special Interest Groups&lt;/a> (SIGs) that align with your interests. Have something you’d like to broadcast to the Kubernetes community? Share your voice at our weekly &lt;a href="https://github.com/kubernetes/community/tree/master/communication">community meeting&lt;/a>, and through the channels below. Thank you for your continued feedback and support.&lt;/p>
&lt;ul>
&lt;li>Follow us on Bluesky &lt;a href="https://bsky.app/profile/kubernetes.io">@kubernetes.io&lt;/a> for the latest updates&lt;/li>
&lt;li>Join the community discussion on &lt;a href="https://discuss.kubernetes.io/">Discuss&lt;/a>&lt;/li>
&lt;li>Join the community on &lt;a href="http://slack.k8s.io/">Slack&lt;/a>&lt;/li>
&lt;li>Post questions (or answer questions) on &lt;a href="https://serverfault.com/questions/tagged/kubernetes">Server Fault&lt;/a> or &lt;a href="http://stackoverflow.com/questions/tagged/kubernetes">Stack Overflow&lt;/a>&lt;/li>
&lt;li>Share your Kubernetes &lt;a href="https://docs.google.com/a/linuxfoundation.org/forms/d/e/1FAIpQLScuI7Ye3VQHQTwBASrgkjQDSS5TP0g3AXfFhwSM9YpHgxRKFA/viewform">story&lt;/a>&lt;/li>
&lt;li>Read more about what’s happening with Kubernetes on the &lt;a href="https://kubernetes.io/blog/">blog&lt;/a>&lt;/li>
&lt;li>Learn more about the &lt;a href="https://github.com/kubernetes/sig-release/tree/master/release-team">Kubernetes Release Team&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Fresh Swap Features for Linux Users in Kubernetes 1.32</title><link>https://kubernetes.io/blog/2025/03/25/swap-linux-improvements/</link><pubDate>Tue, 25 Mar 2025 10:00:00 -0800</pubDate><guid>https://kubernetes.io/blog/2025/03/25/swap-linux-improvements/</guid><description>
&lt;p>Swap is a fundamental and an invaluable Linux feature.
It offers numerous benefits, such as effectively increasing a node’s memory by
swapping out unused data,
shielding nodes from system-level memory spikes,
preventing Pods from crashing when they hit their memory limits,
and &lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/2400-node-swap/README.md#user-stories">much more&lt;/a>.
As a result, the node special interest group within the Kubernetes project
has invested significant effort into supporting swap on Linux nodes.&lt;/p>
&lt;p>The 1.22 release &lt;a href="https://kubernetes.io/blog/2021/08/09/run-nodes-with-swap-alpha/">introduced&lt;/a> Alpha support
for configuring swap memory usage for Kubernetes workloads running on Linux on a per-node basis.
Later, in release 1.28, support for swap on Linux nodes has graduated to Beta, along with many
new improvements.
In the following Kubernetes releases more improvements were made, paving the way
to GA in the near future.&lt;/p>
&lt;p>Prior to version 1.22, Kubernetes did not provide support for swap memory on Linux systems.
This was due to the inherent difficulty in guaranteeing and accounting for pod memory utilization
when swap memory was involved. As a result, swap support was deemed out of scope in the initial
design of Kubernetes, and the default behavior of a kubelet was to fail to start if swap memory
was detected on a node.&lt;/p>
&lt;p>In version 1.22, the swap feature for Linux was initially introduced in its Alpha stage.
This provided Linux users the opportunity to experiment with the swap feature for the first time.
However, as an Alpha version, it was not fully developed and only partially worked on limited environments.&lt;/p>
&lt;p>In version 1.28 swap support on Linux nodes was promoted to Beta.
The Beta version was a drastic leap forward.
Not only did it fix a large amount of bugs and made swap work in a stable way,
but it also brought cgroup v2 support, introduced a wide variety of tests
which include complex scenarios such as node-level pressure, and more.
It also brought many exciting new capabilities such as the &lt;code>LimitedSwap&lt;/code> behavior
which sets an auto-calculated swap limit to containers, OpenMetrics instrumentation
support (through the &lt;code>/metrics/resource&lt;/code> endpoint) and Summary API for
VerticalPodAutoscalers (through the &lt;code>/stats/summary&lt;/code> endpoint), and more.&lt;/p>
&lt;p>Today we are working on more improvements, paving the way for GA.
Currently, the focus is especially towards ensuring node stability,
enhanced debug abilities, addressing user feedback,
polishing the feature and making it stable.
For example, in order to increase stability, containers in high-priority pods
cannot access swap which ensures the memory they need is ready to use.
In addition, the &lt;code>UnlimitedSwap&lt;/code> behavior was removed since it might compromise
the node's health.
Secret content protection against swapping has also been introduced
(see relevant &lt;a href="#memory-backed-volumes">security-risk section&lt;/a> for more info).&lt;/p>
&lt;p>To conclude, compared to previous releases, the kubelet's support for running with swap enabled
is more stable and robust, more user-friendly, and addresses many known shortcomings.
That said, the NodeSwap feature introduces basic swap support, and this is just the beginning.
In the near future, additional features are planned to enhance swap functionality in various ways,
such as improving evictions, extending the API, increasing customizability, and more!&lt;/p>
&lt;h2 id="how-do-i-use-it">How do I use it?&lt;/h2>
&lt;p>In order for the kubelet to initialize on a swap-enabled node, the &lt;code>failSwapOn&lt;/code>
field must be set to &lt;code>false&lt;/code> on kubelet's configuration setting, or the deprecated
&lt;code>--fail-swap-on&lt;/code> command line flag must be deactivated.&lt;/p>
&lt;p>It is possible to configure the &lt;code>memorySwap.swapBehavior&lt;/code> option to define the
manner in which a node utilizes swap memory.
For instance,&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># this fragment goes into the kubelet&amp;#39;s configuration file&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">memorySwap&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">swapBehavior&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>LimitedSwap&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The currently available configuration options for &lt;code>swapBehavior&lt;/code> are:&lt;/p>
&lt;ul>
&lt;li>&lt;code>NoSwap&lt;/code> (default): Kubernetes workloads cannot use swap. However, processes
outside of Kubernetes' scope, like system daemons (such as kubelet itself!) can utilize swap.
This behavior is beneficial for protecting the node from system-level memory spikes,
but it does not safeguard the workloads themselves from such spikes.&lt;/li>
&lt;li>&lt;code>LimitedSwap&lt;/code>: Kubernetes workloads can utilize swap memory, but with certain limitations.
The amount of swap available to a Pod is determined automatically,
based on the proportion of the memory requested relative to the node's total memory.
Only non-high-priority Pods under the &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#burstable">Burstable&lt;/a>
Quality of Service (QoS) tier are permitted to use swap.
For more details, see the &lt;a href="#how-is-the-swap-limit-being-determined-with-limitedswap">section below&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>If configuration for &lt;code>memorySwap&lt;/code> is not specified,
by default the kubelet will apply the same behaviour as the &lt;code>NoSwap&lt;/code> setting.&lt;/p>
&lt;p>On Linux nodes, Kubernetes only supports running with swap enabled for hosts that use cgroup v2.
On cgroup v1 systems, all Kubernetes workloads are not allowed to use swap memory.&lt;/p>
&lt;h2 id="install-a-swap-enabled-cluster-with-kubeadm">Install a swap-enabled cluster with kubeadm&lt;/h2>
&lt;h3 id="before-you-begin">Before you begin&lt;/h3>
&lt;p>It is required for this demo that the kubeadm tool be installed, following the steps outlined in the
&lt;a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/">kubeadm installation guide&lt;/a>.
If swap is already enabled on the node, cluster creation may proceed.
If swap is not enabled, please refer to the provided instructions for enabling swap.&lt;/p>
&lt;h3 id="create-a-swap-file-and-turn-swap-on">Create a swap file and turn swap on&lt;/h3>
&lt;p>I'll demonstrate creating 4GiB of swap, both in the encrypted and unencrypted case.&lt;/p>
&lt;h4 id="setting-up-unencrypted-swap">Setting up unencrypted swap&lt;/h4>
&lt;p>An unencrypted swap file can be set up as follows.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Allocate storage and restrict access&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fallocate --length 4GiB /swapfile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod &lt;span style="color:#666">600&lt;/span> /swapfile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Format the swap space&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mkswap /swapfile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Activate the swap space for paging&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>swapon /swapfile
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="setting-up-encrypted-swap">Setting up encrypted swap&lt;/h4>
&lt;p>An encrypted swap file can be set up as follows.
Bear in mind that this example uses the &lt;code>cryptsetup&lt;/code> binary (which is available
on most Linux distributions).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Allocate storage and restrict access&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fallocate --length 4GiB /swapfile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod &lt;span style="color:#666">600&lt;/span> /swapfile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Create an encrypted device backed by the allocated storage&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cryptsetup --type plain --cipher aes-xts-plain64 --key-size &lt;span style="color:#666">256&lt;/span> -d /dev/urandom open /swapfile cryptswap
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Format the swap space&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mkswap /dev/mapper/cryptswap
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Activate the swap space for paging&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>swapon /dev/mapper/cryptswap
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="verify-that-swap-is-enabled">Verify that swap is enabled&lt;/h4>
&lt;p>Swap can be verified to be enabled with both &lt;code>swapon -s&lt;/code> command or the &lt;code>free&lt;/code> command&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; swapon -s
Filename Type Size Used Priority
/dev/dm-0 partition 4194300 0 -2
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>&amp;gt; free -h
total used free shared buff/cache available
Mem: 3.8Gi 1.3Gi 249Mi 25Mi 2.5Gi 2.5Gi
Swap: 4.0Gi 0B 4.0Gi
&lt;/code>&lt;/pre>&lt;h4 id="enable-swap-on-boot">Enable swap on boot&lt;/h4>
&lt;p>After setting up swap, to start the swap file at boot time,
you either set up a systemd unit to activate (encrypted) swap, or you
add a line similar to &lt;code>/swapfile swap swap defaults 0 0&lt;/code> into &lt;code>/etc/fstab&lt;/code>.&lt;/p>
&lt;h3 id="set-up-a-kubernetes-cluster-that-uses-swap-enabled-nodes">Set up a Kubernetes cluster that uses swap-enabled nodes&lt;/h3>
&lt;p>To make things clearer, here is an example kubeadm configuration file &lt;code>kubeadm-config.yaml&lt;/code> for the swap enabled cluster.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00f;font-weight:bold">---&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;kubeadm.k8s.io/v1beta3&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>InitConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">---&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>kubelet.config.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>KubeletConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">failSwapOn&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">false&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">memorySwap&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">swapBehavior&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>LimitedSwap&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then create a single-node cluster using &lt;code>kubeadm init --config kubeadm-config.yaml&lt;/code>.
During init, there is a warning that swap is enabled on the node and in case the kubelet
&lt;code>failSwapOn&lt;/code> is set to true. We plan to remove this warning in a future release.&lt;/p>
&lt;h2 id="how-is-the-swap-limit-being-determined-with-limitedswap">How is the swap limit being determined with LimitedSwap?&lt;/h2>
&lt;p>The configuration of swap memory, including its limitations, presents a significant
challenge. Not only is it prone to misconfiguration, but as a system-level property, any
misconfiguration could potentially compromise the entire node rather than just a specific
workload. To mitigate this risk and ensure the health of the node, we have implemented
Swap with automatic configuration of limitations.&lt;/p>
&lt;p>With &lt;code>LimitedSwap&lt;/code>, Pods that do not fall under the Burstable QoS classification (i.e.
&lt;code>BestEffort&lt;/code>/&lt;code>Guaranteed&lt;/code> QoS Pods) are prohibited from utilizing swap memory.
&lt;code>BestEffort&lt;/code> QoS Pods exhibit unpredictable memory consumption patterns and lack
information regarding their memory usage, making it difficult to determine a safe
allocation of swap memory.
Conversely, &lt;code>Guaranteed&lt;/code> QoS Pods are typically employed for applications that rely on the
precise allocation of resources specified by the workload, with memory being immediately available.
To maintain the aforementioned security and node health guarantees,
these Pods are not permitted to use swap memory when &lt;code>LimitedSwap&lt;/code> is in effect.
In addition, high-priority pods are not permitted to use swap in order to ensure the memory
they consume always residents on disk, hence ready to use.&lt;/p>
&lt;p>Prior to detailing the calculation of the swap limit, it is necessary to define the following terms:&lt;/p>
&lt;ul>
&lt;li>&lt;code>nodeTotalMemory&lt;/code>: The total amount of physical memory available on the node.&lt;/li>
&lt;li>&lt;code>totalPodsSwapAvailable&lt;/code>: The total amount of swap memory on the node that is available for use by Pods (some swap memory may be reserved for system use).&lt;/li>
&lt;li>&lt;code>containerMemoryRequest&lt;/code>: The container's memory request.&lt;/li>
&lt;/ul>
&lt;p>Swap limitation is configured as:
&lt;code>(containerMemoryRequest / nodeTotalMemory) × totalPodsSwapAvailable&lt;/code>&lt;/p>
&lt;p>In other words, the amount of swap that a container is able to use is proportionate to its
memory request, the node's total physical memory and the total amount of swap memory on
the node that is available for use by Pods.&lt;/p>
&lt;p>It is important to note that, for containers within Burstable QoS Pods, it is possible to
opt-out of swap usage by specifying memory requests that are equal to memory limits.
Containers configured in this manner will not have access to swap memory.&lt;/p>
&lt;h2 id="how-does-it-work">How does it work?&lt;/h2>
&lt;p>There are a number of possible ways that one could envision swap use on a node.
When swap is already provisioned and available on a node,
the kubelet is able to be configured so that:&lt;/p>
&lt;ul>
&lt;li>It can start with swap on.&lt;/li>
&lt;li>It will direct the Container Runtime Interface to allocate zero swap memory
to Kubernetes workloads by default.&lt;/li>
&lt;/ul>
&lt;p>Swap configuration on a node is exposed to a cluster admin via the
&lt;a href="https://kubernetes.io/docs/reference/config-api/kubelet-config.v1/">&lt;code>memorySwap&lt;/code> in the KubeletConfiguration&lt;/a>.
As a cluster administrator, you can specify the node's behaviour in the
presence of swap memory by setting &lt;code>memorySwap.swapBehavior&lt;/code>.&lt;/p>
&lt;p>The kubelet employs the &lt;a href="https://kubernetes.io/docs/concepts/architecture/cri/">CRI&lt;/a>
(container runtime interface) API, and directs the container runtime to
configure specific cgroup v2 parameters (such as &lt;code>memory.swap.max&lt;/code>) in a manner that will
enable the desired swap configuration for a container. For runtimes that use control groups,
the container runtime is then responsible for writing these settings to the container-level cgroup.&lt;/p>
&lt;h2 id="how-can-i-monitor-swap">How can I monitor swap?&lt;/h2>
&lt;h3 id="node-and-container-level-metric-statistics">Node and container level metric statistics&lt;/h3>
&lt;p>Kubelet now collects node and container level metric statistics,
which can be accessed at the &lt;code>/metrics/resource&lt;/code> (which is used mainly by monitoring
tools like Prometheus) and &lt;code>/stats/summary&lt;/code> (which is used mainly by Autoscalers) kubelet HTTP endpoints.
This allows clients who can directly interrogate the kubelet to
monitor swap usage and remaining swap memory when using &lt;code>LimitedSwap&lt;/code>.
Additionally, a &lt;code>machine_swap_bytes&lt;/code> metric has been added to cadvisor to show
the total physical swap capacity of the machine.
See &lt;a href="https://kubernetes.io/docs/reference/instrumentation/node-metrics/">this page&lt;/a> for more info.&lt;/p>
&lt;h3 id="node-feature-discovery">Node Feature Discovery (NFD)&lt;/h3>
&lt;p>&lt;a href="https://github.com/kubernetes-sigs/node-feature-discovery">Node Feature Discovery&lt;/a>
is a Kubernetes addon for detecting hardware features and configuration.
It can be utilized to discover which nodes are provisioned with swap.&lt;/p>
&lt;p>As an example, to figure out which nodes are provisioned with swap,
use the following command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl get nodes -o &lt;span style="color:#b8860b">jsonpath&lt;/span>&lt;span style="color:#666">=&lt;/span>&lt;span style="color:#b44">&amp;#39;{range .items[?(@.metadata.labels.feature\.node\.kubernetes\.io/memory-swap)]}{.metadata.name}{&amp;#34;\t&amp;#34;}{.metadata.labels.feature\.node\.kubernetes\.io/memory-swap}{&amp;#34;\n&amp;#34;}{end}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will result in an output similar to:&lt;/p>
&lt;pre tabindex="0">&lt;code>k8s-worker1: true
k8s-worker2: true
k8s-worker3: false
&lt;/code>&lt;/pre>&lt;p>In this example, swap is provisioned on nodes &lt;code>k8s-worker1&lt;/code> and &lt;code>k8s-worker2&lt;/code>, but not on &lt;code>k8s-worker3&lt;/code>.&lt;/p>
&lt;h2 id="caveats">Caveats&lt;/h2>
&lt;p>Having swap available on a system reduces predictability.
While swap can enhance performance by making more RAM available, swapping data
back to memory is a heavy operation, sometimes slower by many orders of magnitude,
which can cause unexpected performance regressions.
Furthermore, swap changes a system's behaviour under memory pressure.
Enabling swap increases the risk of noisy neighbors,
where Pods that frequently use their RAM may cause other Pods to swap.
In addition, since swap allows for greater memory usage for workloads in Kubernetes that cannot be predictably accounted for,
and due to unexpected packing configurations,
the scheduler currently does not account for swap memory usage.
This heightens the risk of noisy neighbors.&lt;/p>
&lt;p>The performance of a node with swap memory enabled depends on the underlying physical storage.
When swap memory is in use, performance will be significantly worse in an I/O
operations per second (IOPS) constrained environment, such as a cloud VM with
I/O throttling, when compared to faster storage mediums like solid-state drives
or NVMe.
As swap might cause IO pressure, it is recommended to give a higher IO latency
priority to system critical daemons. See the relevant section in the
&lt;a href="#good-practice-for-using-swap-in-a-kubernetes-cluster">recommended practices&lt;/a> section below.&lt;/p>
&lt;h3 id="memory-backed-volumes">Memory-backed volumes&lt;/h3>
&lt;p>On Linux nodes, memory-backed volumes (such as &lt;a href="https://kubernetes.io/docs/concepts/configuration/secret/">&lt;code>secret&lt;/code>&lt;/a>
volume mounts, or &lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/#emptydir">&lt;code>emptyDir&lt;/code>&lt;/a> with &lt;code>medium: Memory&lt;/code>)
are implemented with a &lt;code>tmpfs&lt;/code> filesystem.
The contents of such volumes should remain in memory at all times, hence should
not be swapped to disk.
To ensure the contents of such volumes remain in memory, the &lt;code>noswap&lt;/code> tmpfs option
is being used.&lt;/p>
&lt;p>The Linux kernel officially supports the &lt;code>noswap&lt;/code> option from version 6.3 (more info
can be found in &lt;a href="https://kubernetes.io/docs/reference/node/kernel-version-requirements/#requirements-other">Linux Kernel Version Requirements&lt;/a>).
However, the different distributions often choose to backport this mount option to older
Linux versions as well.&lt;/p>
&lt;p>In order to verify whether the node supports the &lt;code>noswap&lt;/code> option, the kubelet will do the following:&lt;/p>
&lt;ul>
&lt;li>If the kernel's version is above 6.3 then the &lt;code>noswap&lt;/code> option will be assumed to be supported.&lt;/li>
&lt;li>Otherwise, kubelet would try to mount a dummy tmpfs with the &lt;code>noswap&lt;/code> option at startup.
If kubelet fails with an error indicating of an unknown option, &lt;code>noswap&lt;/code> will be assumed
to not be supported, hence will not be used.
A kubelet log entry will be emitted to warn the user about memory-backed volumes might swap to disk.
If kubelet succeeds, the dummy tmpfs will be deleted and the &lt;code>noswap&lt;/code> option will be used.
&lt;ul>
&lt;li>If the &lt;code>noswap&lt;/code> option is not supported, kubelet will emit a warning log entry,
then continue its execution.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>It is deeply encouraged to encrypt the swap space.
See the &lt;a href="#setting-up-encrypted-swap">section above&lt;/a> with an example for setting unencrypted swap.
However, handling encrypted swap is not within the scope of kubelet;
rather, it is a general OS configuration concern and should be addressed at that level.
It is the administrator's responsibility to provision encrypted swap to mitigate this risk.&lt;/p>
&lt;h2 id="good-practice-for-using-swap-in-a-kubernetes-cluster">Good practice for using swap in a Kubernetes cluster&lt;/h2>
&lt;h3 id="disable-swap-for-system-critical-daemons">Disable swap for system-critical daemons&lt;/h3>
&lt;p>During the testing phase and based on user feedback, it was observed that the performance
of system-critical daemons and services might degrade.
This implies that system daemons, including the kubelet, could operate slower than usual.
If this issue is encountered, it is advisable to configure the cgroup of the system slice
to prevent swapping (i.e., set &lt;code>memory.swap.max=0&lt;/code>).&lt;/p>
&lt;h3 id="protect-system-critical-daemons-for-i-o-latency">Protect system-critical daemons for I/O latency&lt;/h3>
&lt;p>Swap can increase the I/O load on a node.
When memory pressure causes the kernel to rapidly swap pages in and out,
system-critical daemons and services that rely on I/O operations may
experience performance degradation.&lt;/p>
&lt;p>To mitigate this, it is recommended for systemd users to prioritize the system slice in terms of I/O latency.
For non-systemd users,
setting up a dedicated cgroup for system daemons and processes and prioritizing I/O latency in the same way is advised.
This can be achieved by setting &lt;code>io.latency&lt;/code> for the system slice,
thereby granting it higher I/O priority.
See &lt;a href="https://www.kernel.org/doc/Documentation/admin-guide/cgroup-v2.rst">cgroup's documentation&lt;/a> for more info.&lt;/p>
&lt;h3 id="swap-and-control-plane-nodes">Swap and control plane nodes&lt;/h3>
&lt;p>The Kubernetes project recommends running control plane nodes without any swap space configured.
The control plane primarily hosts Guaranteed QoS Pods, so swap can generally be disabled.
The main concern is that swapping critical services on the control plane could negatively impact performance.&lt;/p>
&lt;h3 id="use-of-a-dedicated-disk-for-swap">Use of a dedicated disk for swap&lt;/h3>
&lt;p>It is recommended to use a separate, encrypted disk for the swap partition.
If swap resides on a partition or the root filesystem, workloads may interfere
with system processes that need to write to disk.
When they share the same disk, processes can overwhelm swap,
disrupting the I/O of kubelet, container runtime, and systemd, which would impact other workloads.
Since swap space is located on a disk, it is crucial to ensure the disk is fast enough for the intended use cases.
Alternatively, one can configure I/O priorities between different mapped areas of a single backing device.&lt;/p>
&lt;h2 id="looking-ahead">Looking ahead&lt;/h2>
&lt;p>As you can see, the swap feature was dramatically improved lately,
paving the way for a feature GA.
However, this is just the beginning.
It's a foundational implementation marking the beginning of enhanced swap functionality.&lt;/p>
&lt;p>In the near future, additional features are planned to further improve swap capabilities,
including better eviction mechanisms, extended API support, increased customizability,
better debug abilities and more!&lt;/p>
&lt;h2 id="how-can-i-learn-more">How can I learn more?&lt;/h2>
&lt;p>You can review the current &lt;a href="https://kubernetes.io/docs/concepts/architecture/nodes/#swap-memory">documentation&lt;/a>
for using swap with Kubernetes.&lt;/p>
&lt;p>For more information, please see &lt;a href="https://github.com/kubernetes/enhancements/issues/4128">KEP-2400&lt;/a> and its
&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/2400-node-swap/README.md">design proposal&lt;/a>.&lt;/p>
&lt;h2 id="how-do-i-get-involved">How do I get involved?&lt;/h2>
&lt;p>Your feedback is always welcome! SIG Node &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node#meetings">meets regularly&lt;/a>
and &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node#contact">can be reached&lt;/a>
via &lt;a href="https://slack.k8s.io/">Slack&lt;/a> (channel &lt;strong>#sig-node&lt;/strong>), or the SIG's
&lt;a href="https://groups.google.com/forum/#!forum/kubernetes-sig-node">mailing list&lt;/a>. A Slack
channel dedicated to swap is also available at &lt;strong>#sig-node-swap&lt;/strong>.&lt;/p>
&lt;p>Feel free to reach out to me, Itamar Holder (&lt;strong>@iholder101&lt;/strong> on Slack and GitHub)
if you'd like to help or ask further questions.&lt;/p></description></item><item><title>Ingress-nginx CVE-2025-1974: What You Need to Know</title><link>https://kubernetes.io/blog/2025/03/24/ingress-nginx-cve-2025-1974/</link><pubDate>Mon, 24 Mar 2025 12:00:00 -0800</pubDate><guid>https://kubernetes.io/blog/2025/03/24/ingress-nginx-cve-2025-1974/</guid><description>
&lt;p>Today, the ingress-nginx maintainers have &lt;a href="https://github.com/kubernetes/ingress-nginx/releases">released patches for a batch of critical vulnerabilities&lt;/a> that could make it easy for attackers to take over your Kubernetes cluster. If you are among the over 40% of Kubernetes administrators using &lt;a href="https://github.com/kubernetes/ingress-nginx/">ingress-nginx&lt;/a>, you should take action immediately to protect your users and data.&lt;/p>
&lt;h2 id="background">Background&lt;/h2>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/">Ingress&lt;/a> is the traditional Kubernetes feature for exposing your workload Pods to the world so that they can be useful. In an implementation-agnostic way, Kubernetes users can define how their applications should be made available on the network. Then, an &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/">ingress controller&lt;/a> uses that definition to set up local or cloud resources as required for the user’s particular situation and needs.&lt;/p>
&lt;p>Many different ingress controllers are available, to suit users of different cloud providers or brands of load balancers. Ingress-nginx is a software-only ingress controller provided by the Kubernetes project. Because of its versatility and ease of use, ingress-nginx is quite popular: it is deployed in over 40% of Kubernetes clusters!&lt;/p>
&lt;p>Ingress-nginx translates the requirements from Ingress objects into configuration for nginx, a powerful open source webserver daemon. Then, nginx uses that configuration to accept and route requests to the various applications running within a Kubernetes cluster. Proper handling of these nginx configuration parameters is crucial, because ingress-nginx needs to allow users significant flexibility while preventing them from accidentally or intentionally tricking nginx into doing things it shouldn’t.&lt;/p>
&lt;h2 id="vulnerabilities-patched-today">Vulnerabilities Patched Today&lt;/h2>
&lt;p>Four of today’s ingress-nginx vulnerabilities are improvements to how ingress-nginx handles particular bits of nginx config. Without these fixes, a specially-crafted Ingress object can cause nginx to misbehave in various ways, including revealing the values of &lt;a href="https://kubernetes.io/docs/concepts/configuration/secret/">Secrets&lt;/a> that are accessible to ingress-nginx. By default, ingress-nginx has access to all Secrets cluster-wide, so this can often lead to complete cluster takeover by any user or entity that has permission to create an Ingress.&lt;/p>
&lt;p>The most serious of today’s vulnerabilities, &lt;a href="https://github.com/kubernetes/kubernetes/issues/131009">CVE-2025-1974&lt;/a>, rated &lt;a href="https://www.first.org/cvss/calculator/3-1#CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H">9.8 CVSS&lt;/a>, allows anything on the Pod network to exploit configuration injection vulnerabilities via the Validating Admission Controller feature of ingress-nginx. This makes such vulnerabilities far more dangerous: ordinarily one would need to be able to create an Ingress object in the cluster, which is a fairly privileged action. When combined with today’s other vulnerabilities, &lt;strong>CVE-2025-1974 means that anything on the Pod network has a good chance of taking over your Kubernetes cluster, with no credentials or administrative access required&lt;/strong>. In many common scenarios, the Pod network is accessible to all workloads in your cloud VPC, or even anyone connected to your corporate network! This is a very serious situation.&lt;/p>
&lt;p>Today, we have &lt;a href="https://github.com/kubernetes/ingress-nginx/releases">released ingress-nginx v1.12.1 and v1.11.5&lt;/a>, which have fixes for all five of these vulnerabilities.&lt;/p>
&lt;h2 id="your-next-steps">Your next steps&lt;/h2>
&lt;p>First, determine if your clusters are using ingress-nginx. In most cases, you can check this by running &lt;code>kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginx&lt;/code> with cluster administrator permissions.&lt;/p>
&lt;p>&lt;strong>If you are using ingress-nginx, make a plan to remediate these vulnerabilities immediately.&lt;/strong>&lt;/p>
&lt;p>&lt;strong>The best and easiest remedy is to &lt;a href="https://kubernetes.github.io/ingress-nginx/deploy/upgrade/">upgrade to the new patch release of ingress-nginx&lt;/a>.&lt;/strong> All five of today’s vulnerabilities are fixed by installing today’s patches.&lt;/p>
&lt;p>If you can’t upgrade right away, you can significantly reduce your risk by turning off the Validating Admission Controller feature of ingress-nginx.&lt;/p>
&lt;ul>
&lt;li>If you have installed ingress-nginx using Helm
&lt;ul>
&lt;li>Reinstall, setting the Helm value &lt;code>controller.admissionWebhooks.enabled=false&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>If you have installed ingress-nginx manually
&lt;ul>
&lt;li>delete the ValidatingWebhookconfiguration called &lt;code>ingress-nginx-admission&lt;/code>&lt;/li>
&lt;li>edit the &lt;code>ingress-nginx-controller&lt;/code> Deployment or Daemonset, removing &lt;code>--validating-webhook&lt;/code> from the controller container’s argument list&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>If you turn off the Validating Admission Controller feature as a mitigation for CVE-2025-1974, remember to turn it back on after you upgrade. This feature provides important quality of life improvements for your users, warning them about incorrect Ingress configurations before they can take effect.&lt;/p>
&lt;h2 id="conclusion-thanks-and-further-reading">Conclusion, thanks, and further reading&lt;/h2>
&lt;p>The ingress-nginx vulnerabilities announced today, including CVE-2025-1974, present a serious risk to many Kubernetes users and their data. If you use ingress-nginx, you should take action immediately to keep yourself safe.&lt;/p>
&lt;p>Thanks go out to Nir Ohfeld, Sagi Tzadik, Ronen Shustin, and Hillai Ben-Sasson from Wiz for responsibly disclosing these vulnerabilities, and for working with the Kubernetes SRC members and ingress-nginx maintainers (Marco Ebert and James Strong) to ensure we fixed them effectively.&lt;/p>
&lt;p>For further information about the maintenance and future of ingress-nginx, please see this &lt;a href="https://github.com/kubernetes/ingress-nginx/issues/13002">GitHub issue&lt;/a> and/or attend &lt;a href="https://kccnceu2025.sched.com/event/1tcyc/">James and Marco’s KubeCon/CloudNativeCon EU 2025 presentation&lt;/a>.&lt;/p>
&lt;p>For further information about the specific vulnerabilities discussed in this article, please see the appropriate GitHub issue: &lt;a href="https://github.com/kubernetes/kubernetes/issues/131005">CVE-2025-24513&lt;/a>, &lt;a href="https://github.com/kubernetes/kubernetes/issues/131006">CVE-2025-24514&lt;/a>, &lt;a href="https://github.com/kubernetes/kubernetes/issues/131007">CVE-2025-1097&lt;/a>, &lt;a href="https://github.com/kubernetes/kubernetes/issues/131008">CVE-2025-1098&lt;/a>, or &lt;a href="https://github.com/kubernetes/kubernetes/issues/131009">CVE-2025-1974&lt;/a>&lt;/p></description></item><item><title>Introducing JobSet</title><link>https://kubernetes.io/blog/2025/03/23/introducing-jobset/</link><pubDate>Sun, 23 Mar 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/03/23/introducing-jobset/</guid><description>
&lt;p>&lt;strong>Authors&lt;/strong>: Daniel Vega-Myhre (Google), Abdullah Gharaibeh (Google), Kevin Hannon (Red Hat)&lt;/p>
&lt;p>In this article, we introduce &lt;a href="https://jobset.sigs.k8s.io/">JobSet&lt;/a>, an open source API for
representing distributed jobs. The goal of JobSet is to provide a unified API for distributed ML
training and HPC workloads on Kubernetes.&lt;/p>
&lt;h2 id="why-jobset">Why JobSet?&lt;/h2>
&lt;p>The Kubernetes community’s recent enhancements to the batch ecosystem on Kubernetes has attracted ML
engineers who have found it to be a natural fit for the requirements of running distributed training
workloads.&lt;/p>
&lt;p>Large ML models (particularly LLMs) which cannot fit into the memory of the GPU or TPU chips on a
single host are often distributed across tens of thousands of accelerator chips, which in turn may
span thousands of hosts.&lt;/p>
&lt;p>As such, the model training code is often containerized and executed simultaneously on all these
hosts, performing distributed computations which often shard both the model parameters and/or the
training dataset across the target accelerator chips, using communication collective primitives like
all-gather and all-reduce to perform distributed computations and synchronize gradients between
hosts.&lt;/p>
&lt;p>These workload characteristics make Kubernetes a great fit for this type of workload, as efficiently
scheduling and managing the lifecycle of containerized applications across a cluster of compute
resources is an area where it shines.&lt;/p>
&lt;p>It is also very extensible, allowing developers to define their own Kubernetes APIs, objects, and
controllers which manage the behavior and life cycle of these objects, allowing engineers to develop
custom distributed training orchestration solutions to fit their needs.&lt;/p>
&lt;p>However, as distributed ML training techniques continue to evolve, existing Kubernetes primitives do
not adequately model them alone anymore.&lt;/p>
&lt;p>Furthermore, the landscape of Kubernetes distributed training orchestration APIs has become
fragmented, and each of the existing solutions in this fragmented landscape has certain limitations
that make it non-optimal for distributed ML training.&lt;/p>
&lt;p>For example, the KubeFlow training operator defines custom APIs for different frameworks (e.g.
PyTorchJob, TFJob, MPIJob, etc.); however, each of these job types are in fact a solution fit
specifically to the target framework, each with different semantics and behavior.&lt;/p>
&lt;p>On the other hand, the Job API fixed many gaps for running batch workloads, including Indexed
completion mode, higher scalability, Pod failure policies and Pod backoff policy to mention a few of
the most recent enhancements. However, running ML training and HPC workloads using the upstream Job
API requires extra orchestration to fill the following gaps:&lt;/p>
&lt;p>Multi-template Pods : Most HPC or ML training jobs include more than one type of Pods. The different
Pods are part of the same workload, but they need to run a different container, request different
resources or have different failure policies. A common example is the driver-worker pattern.&lt;/p>
&lt;p>Job groups : Large scale training workloads span multiple network topologies, running across
multiple racks for example. Such workloads are network latency sensitive, and aim to localize
communication and minimize traffic crossing the higher-latency network links. To facilitate this,
the workload needs to be split into groups of Pods each assigned to a network topology.&lt;/p>
&lt;p>Inter-Pod communication : Create and manage the resources (e.g. &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#headless-services">headless
Services&lt;/a>) necessary to establish
communication between the Pods of a job.&lt;/p>
&lt;p>Startup sequencing : Some jobs require a specific start sequence of pods; sometimes the driver is
expected to start first (like Ray or Spark), in other cases the workers are expected to be ready
before starting the driver (like MPI).&lt;/p>
&lt;p>JobSet aims to address those gaps using the Job API as a building block to build a richer API for
large-scale distributed HPC and ML use cases.&lt;/p>
&lt;h2 id="how-jobset-works">How JobSet Works&lt;/h2>
&lt;p>JobSet models a distributed batch workload as a group of Kubernetes Jobs. This allows a user to
easily specify different pod templates for different distinct groups of pods (e.g. a leader,
workers, parameter servers, etc.).&lt;/p>
&lt;p>It uses the abstraction of a ReplicatedJob to manage child Jobs, where a ReplicatedJob is
essentially a Job Template with some desired number of Job replicas specified. This provides a
declarative way to easily create identical child-jobs to run on different islands of accelerators,
without resorting to scripting or Helm charts to generate many versions of the same job but with
different names.&lt;/p>
&lt;figure class="diagram-large clickable-zoom">
&lt;img src="https://kubernetes.io/blog/2025/03/23/introducing-jobset/jobset_diagram.svg"
alt="JobSet Architecture"/>
&lt;/figure>
&lt;p>Some other key JobSet features which address the problems described above include:&lt;/p>
&lt;p>Replicated Jobs : In modern data centers, hardware accelerators like GPUs and TPUs allocated in
islands of homogenous accelerators connected via a specialized, high bandwidth network links. For
example, a user might provision nodes containing a group of hosts co-located on a rack, each with
H100 GPUs, where GPU chips within each host are connected via NVLink, with a NVLink Switch
connecting the multiple NVLinks. TPU Pods are another example of this: TPU ViperLitePods consist of
64 hosts, each with 4 TPU v5e chips attached, all connected via ICI mesh. When running a distributed
training job across multiple of these islands, we often want to partition the workload into a group
of smaller identical jobs, 1 per island, where each pod primarily communicates with the pods within
the same island to do segments of distributed computation, and keeping the gradient synchronization
over DCN (data center network, which is lower bandwidth than ICI) to a bare minimum.&lt;/p>
&lt;p>Automatic headless service creation, configuration, and lifecycle management : Pod-to-pod
communication via pod hostname is enabled by default, with automatic configuration and lifecycle
management of the headless service enabling this.&lt;/p>
&lt;p>Configurable success policies : JobSet has configurable success policies which target specific
ReplicatedJobs, with operators to target “Any” or “All” of their child jobs. For example, you can
configure the JobSet to be marked complete if and only if all pods that are part of the “worker”
ReplicatedJob are completed.&lt;/p>
&lt;p>Configurable failure policies : JobSet has configurable failure policies which allow the user to
specify a maximum number of times the JobSet should be restarted in the event of a failure. If any
job is marked failed, the entire JobSet will be recreated, allowing the workload to resume from the
last checkpoint. When no failure policy is specified, if any job fails, the JobSet simply fails.&lt;/p>
&lt;p>Exclusive placement per topology domain : JobSet allows users to express that child jobs have 1:1
exclusive assignment to a topology domain, typically an accelerator island like a rack. For example,
if the JobSet creates two child jobs, then this feature will enforce that the pods of each child job
will be co-located on the same island, and that only one child job is allowed to schedule per
island. This is useful for scenarios where we want to use a distributed data parallel (DDP) training
strategy to train a model using multiple islands of compute resources (GPU racks or TPU slices),
running 1 model replica in each accelerator island, ensuring the forward and backward passes
themselves occur within a single model replica occurs over the high bandwidth interconnect linking
the accelerators chips within the island, and only the gradient synchronization between model
replicas occurs across accelerator islands over the lower bandwidth data center network.&lt;/p>
&lt;p>Integration with Kueue : Users can submit JobSets via &lt;a href="https://kueue.sigs.k8s.io/">Kueue&lt;/a> to
oversubscribe their clusters, queue workloads to run as capacity becomes available, prevent partial
scheduling and deadlocks, enable multi-tenancy, and more.&lt;/p>
&lt;h2 id="example-use-case">Example use case&lt;/h2>
&lt;h3 id="distributed-ml-training-on-multiple-tpu-slices-with-jax">Distributed ML training on multiple TPU slices with Jax&lt;/h3>
&lt;p>The following example is a JobSet spec for running a TPU Multislice workload on 4 TPU v5e
&lt;a href="https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#slices">slices&lt;/a>. To learn more about
TPU concepts and terminology, please refer to these
&lt;a href="https://cloud.google.com/tpu/docs/system-architecture-tpu-vm">docs&lt;/a>.&lt;/p>
&lt;p>This example uses &lt;a href="https://jax.readthedocs.io/en/latest/quickstart.html">Jax&lt;/a>, an ML framework with
native support for Just-In-Time (JIT) compilation targeting TPU chips via
&lt;a href="https://github.com/openxla">OpenXLA&lt;/a>. However, you can also use
&lt;a href="https://pytorch.org/xla/release/2.3/index.html">PyTorch/XLA&lt;/a> to do ML training on TPUs.&lt;/p>
&lt;p>This example makes use of several JobSet features (both explicitly and implicitly) to support the
unique scheduling requirements of TPU multislice training out-of-the-box with very little
configuration required by the user.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># Run a simple Jax workload on &lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>jobset.x-k8s.io/v1alpha2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>JobSet&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>multislice&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">annotations&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Give each child Job exclusive usage of a TPU slice &lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">alpha.jobset.sigs.k8s.io/exclusive-topology&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>cloud.google.com/gke-nodepool&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">failurePolicy&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">maxRestarts&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">3&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">replicatedJobs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>workers&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">replicas&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">4&lt;/span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Set to number of TPU slices&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">template&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">parallelism&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">2&lt;/span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Set to number of VMs per TPU slice&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">completions&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">2&lt;/span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Set to number of VMs per TPU slice&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backoffLimit&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">0&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">template&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">hostNetwork&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">true&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">dnsPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ClusterFirstWithHostNet&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">nodeSelector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">cloud.google.com/gke-tpu-accelerator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>tpu-v5-lite-podslice&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">cloud.google.com/gke-tpu-topology&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>2x4&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>jax-tpu&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>python:3.8&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">ports&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">containerPort&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">8471&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">containerPort&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">8080&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">securityContext&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">privileged&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">true&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">command&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- bash&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- -c&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- |&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> pip install &amp;#34;jax[tpu]&amp;#34; -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> python -c &amp;#39;import jax; print(&amp;#34;Global device count:&amp;#34;, jax.device_count())&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> sleep 60&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">resources&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">limits&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">google.com/tpu&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">4&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="future-work-and-getting-involved">Future work and getting involved&lt;/h2>
&lt;p>We have a number of features on the JobSet roadmap planned for development this year, which can be
found in the &lt;a href="https://github.com/kubernetes-sigs/jobset?tab=readme-ov-file#roadmap">JobSet roadmap&lt;/a>.&lt;/p>
&lt;p>Please feel free to reach out with feedback of any kind. We’re also open to additional contributors,
whether it is to fix or report bugs, or help add new features or write documentation.&lt;/p>
&lt;p>You can get in touch with us via our &lt;a href="http://sigs.k8s.io/jobset">repo&lt;/a>, &lt;a href="https://groups.google.com/a/kubernetes.io/g/wg-batch">mailing
list&lt;/a> or on
&lt;a href="https://kubernetes.slack.com/messages/wg-batch">Slack&lt;/a>.&lt;/p>
&lt;p>Last but not least, thanks to all &lt;a href="https://github.com/kubernetes-sigs/jobset/graphs/contributors">our
contributors&lt;/a> who made this project
possible!&lt;/p></description></item><item><title>Spotlight on SIG Apps</title><link>https://kubernetes.io/blog/2025/03/12/sig-apps-spotlight-2025/</link><pubDate>Wed, 12 Mar 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/03/12/sig-apps-spotlight-2025/</guid><description>
&lt;p>In our ongoing SIG Spotlight series, we dive into the heart of the Kubernetes project by talking to
the leaders of its various Special Interest Groups (SIGs). This time, we focus on
&lt;strong>&lt;a href="https://github.com/kubernetes/community/tree/master/sig-apps#apps-special-interest-group">SIG Apps&lt;/a>&lt;/strong>,
the group responsible for everything related to developing, deploying, and operating applications on
Kubernetes. &lt;a href="https://www.linkedin.com/in/sandipanpanda">Sandipan Panda&lt;/a>
(&lt;a href="https://www.devzero.io/">DevZero&lt;/a>) had the opportunity to interview &lt;a href="https://github.com/soltysh">Maciej
Szulik&lt;/a> (&lt;a href="https://defenseunicorns.com/">Defense Unicorns&lt;/a>) and &lt;a href="https://github.com/janetkuo">Janet
Kuo&lt;/a> (&lt;a href="https://about.google/">Google&lt;/a>), the chairs and tech leads of
SIG Apps. They shared their experiences, challenges, and visions for the future of application
management within the Kubernetes ecosystem.&lt;/p>
&lt;h2 id="introductions">Introductions&lt;/h2>
&lt;p>&lt;strong>Sandipan: Hello, could you start by telling us a bit about yourself, your role, and your journey
within the Kubernetes community that led to your current roles in SIG Apps?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Maciej&lt;/strong>: Hey, my name is Maciej, and I’m one of the leads for SIG Apps. Aside from this role, you
can also find me helping
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-cli#readme">SIG CLI&lt;/a> and also being one of
the Steering Committee members. I’ve been contributing to Kubernetes since late 2014 in various
areas, including controllers, apiserver, and kubectl.&lt;/p>
&lt;p>&lt;strong>Janet&lt;/strong>: Certainly! I'm Janet, a Staff Software Engineer at Google, and I've been deeply involved
with the Kubernetes project since its early days, even before the 1.0 launch in 2015. It's been an
amazing journey!&lt;/p>
&lt;p>My current role within the Kubernetes community is one of the chairs and tech leads of SIG Apps. My
journey with SIG Apps started organically. I started with building the Deployment API and adding
rolling update functionalities. I naturally gravitated towards SIG Apps and became increasingly
involved. Over time, I took on more responsibilities, culminating in my current leadership roles.&lt;/p>
&lt;h2 id="about-sig-apps">About SIG Apps&lt;/h2>
&lt;p>&lt;em>All following answers were jointly provided by Maciej and Janet.&lt;/em>&lt;/p>
&lt;p>&lt;strong>Sandipan: For those unfamiliar, could you provide an overview of SIG Apps' mission and objectives?
What key problems does it aim to solve within the Kubernetes ecosystem?&lt;/strong>&lt;/p>
&lt;p>As described in our
&lt;a href="https://github.com/kubernetes/community/blob/master/sig-apps/charter.md#scope">charter&lt;/a>, we cover a
broad area related to developing, deploying, and operating applications on Kubernetes. That, in
short, means we’re open to each and everyone showing up at our bi-weekly meetings and discussing the
ups and downs of writing and deploying various applications on Kubernetes.&lt;/p>
&lt;p>&lt;strong>Sandipan: What are some of the most significant projects or initiatives currently being undertaken
by SIG Apps?&lt;/strong>&lt;/p>
&lt;p>At this point in time, the main factors driving the development of our controllers are the
challenges coming from running various AI-related workloads. It’s worth giving credit here to two
working groups we’ve sponsored over the past years:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://github.com/kubernetes/community/tree/master/wg-batch">The Batch Working Group&lt;/a>, which is
looking at running HPC, AI/ML, and data analytics jobs on top of Kubernetes.&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/community/tree/master/wg-serving">The Serving Working Group&lt;/a>, which
is focusing on hardware-accelerated AI/ML inference.&lt;/li>
&lt;/ol>
&lt;h2 id="best-practices-and-challenges">Best practices and challenges&lt;/h2>
&lt;p>&lt;strong>Sandipan: SIG Apps plays a crucial role in developing application management best practices for
Kubernetes. Can you share some of these best practices and how they help improve application
lifecycle management?&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Implementing &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/">health checks and readiness probes&lt;/a>
ensures that your applications are healthy and ready to serve traffic, leading to improved
reliability and uptime. The above, combined with comprehensive logging, monitoring, and tracing
solutions, will provide insights into your application's behavior, enabling you to identify and
resolve issues quickly.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/workloads/autoscaling/">Auto-scale your application&lt;/a> based
on resource utilization or custom metrics, optimizing resource usage and ensuring your
application can handle varying loads.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Use Deployment for stateless applications, StatefulSet for stateful applications, Job
and CronJob for batch workloads, and DaemonSet for running a daemon on each node. Use
Operators and CRDs to extend the Kubernetes API to automate the deployment, management, and
lifecycle of complex applications, making them easier to operate and reducing manual
intervention.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Sandipan: What are some of the common challenges SIG Apps faces, and how do you address them?&lt;/strong>&lt;/p>
&lt;p>The biggest challenge we’re facing all the time is the need to reject a lot of features, ideas, and
improvements. This requires a lot of discipline and patience to be able to explain the reasons
behind those decisions.&lt;/p>
&lt;p>&lt;strong>Sandipan: How has the evolution of Kubernetes influenced the work of SIG Apps? Are there any
recent changes or upcoming features in Kubernetes that you find particularly relevant or beneficial
for SIG Apps?&lt;/strong>&lt;/p>
&lt;p>The main benefit for both us and the whole community around SIG Apps is the ability to extend
kubernetes with &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">Custom Resource Definitions&lt;/a>
and the fact that users can build their own custom controllers leveraging the built-in ones to
achieve whatever sophisticated use cases they might have and we, as the core maintainers, haven’t
considered or weren’t able to efficiently resolve inside Kubernetes.&lt;/p>
&lt;h2 id="contributing-to-sig-apps">Contributing to SIG Apps&lt;/h2>
&lt;p>&lt;strong>Sandipan: What opportunities are available for new contributors who want to get involved with SIG
Apps, and what advice would you give them?&lt;/strong>&lt;/p>
&lt;p>We get the question, &amp;quot;What good first issue might you recommend we start with?&amp;quot; a lot :-) But
unfortunately, there’s no easy answer to it. We always tell everyone that the best option to start
contributing to core controllers is to find one you are willing to spend some time with. Read
through the code, then try running unit tests and integration tests focusing on that
controller. Once you grasp the general idea, try breaking it and the tests again to verify your
breakage. Once you start feeling confident you understand that particular controller, you may want
to search through open issues affecting that controller and either provide suggestions, explaining
the problem users have, or maybe attempt your first fix.&lt;/p>
&lt;p>Like we said, there are no shortcuts on that road; you need to spend the time with the codebase to
understand all the edge cases we’ve slowly built up to get to the point where we are. Once you’re
successful with one controller, you’ll need to repeat that same process with others all over again.&lt;/p>
&lt;p>&lt;strong>Sandipan: How does SIG Apps gather feedback from the community, and how is this feedback
integrated into your work?&lt;/strong>&lt;/p>
&lt;p>We always encourage everyone to show up and present their problems and solutions during our
bi-weekly &lt;a href="https://github.com/kubernetes/community/tree/master/sig-apps#meetings">meetings&lt;/a>. As long
as you’re solving an interesting problem on top of Kubernetes and you can provide valuable feedback
about any of the core controllers, we’re always happy to hear from everyone.&lt;/p>
&lt;h2 id="looking-ahead">Looking ahead&lt;/h2>
&lt;p>&lt;strong>Sandipan: Looking ahead, what are the key focus areas or upcoming trends in application management
within Kubernetes that SIG Apps is excited about? How is the SIG adapting to these trends?&lt;/strong>&lt;/p>
&lt;p>Definitely the current AI hype is the major driving factor; as mentioned above, we have two working
groups, each covering a different aspect of it.&lt;/p>
&lt;p>&lt;strong>Sandipan: What are some of your favorite things about this SIG?&lt;/strong>&lt;/p>
&lt;p>Without a doubt, the people that participate in our meetings and on
&lt;a href="https://kubernetes.slack.com/messages/sig-apps">Slack&lt;/a>, who tirelessly help triage issues, pull
requests and invest a lot of their time (very frequently their private time) into making kubernetes
great!&lt;/p>
&lt;hr>
&lt;p>SIG Apps is an essential part of the Kubernetes community, helping to shape how applications are
deployed and managed at scale. From its work on improving Kubernetes' workload APIs to driving
innovation in AI/ML application management, SIG Apps is continually adapting to meet the needs of
modern application developers and operators. Whether you’re a new contributor or an experienced
developer, there’s always an opportunity to get involved and make an impact.&lt;/p>
&lt;p>If you’re interested in learning more or contributing to SIG Apps, be sure to check out their &lt;a href="https://github.com/kubernetes/community/tree/master/sig-apps">SIG
README&lt;/a> and join their bi-weekly &lt;a href="https://github.com/kubernetes/community/tree/master/sig-apps#meetings">meetings&lt;/a>.&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://groups.google.com/a/kubernetes.io/g/sig-apps">SIG Apps Mailing List&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kubernetes.slack.com/messages/sig-apps">SIG Apps on Slack&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Spotlight on SIG etcd</title><link>https://kubernetes.io/blog/2025/03/04/sig-etcd-spotlight/</link><pubDate>Tue, 04 Mar 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/03/04/sig-etcd-spotlight/</guid><description>
&lt;p>In this SIG etcd spotlight we talked with &lt;a href="https://github.com/jmhbnz">James Blair&lt;/a>, &lt;a href="https://github.com/serathius">Marek
Siarkowicz&lt;/a>, &lt;a href="https://github.com/wenjiaswe">Wenjia Zhang&lt;/a>, and
&lt;a href="https://github.com/ahrtr">Benjamin Wang&lt;/a> to learn a bit more about this Kubernetes Special Interest
Group.&lt;/p>
&lt;h2 id="introducing-sig-etcd">Introducing SIG etcd&lt;/h2>
&lt;p>&lt;strong>Frederico: Hello, thank you for the time! Let’s start with some introductions, could you tell us a
bit about yourself, your role and how you got involved in Kubernetes.&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Benjamin:&lt;/strong> Hello, I am Benjamin. I am a SIG etcd Tech Lead and one of the etcd maintainers. I
work for VMware, which is part of the Broadcom group. I got involved in Kubernetes &amp;amp; etcd &amp;amp; CSI
(&lt;a href="https://github.com/container-storage-interface/spec/blob/master/spec.md">Container Storage Interface&lt;/a>)
because of work and also a big passion for open source. I have been working on Kubernetes &amp;amp; etcd
(and also CSI) since 2020.&lt;/p>
&lt;p>&lt;strong>James:&lt;/strong> Hey team, I’m James, a co-chair for SIG etcd and etcd maintainer. I work at Red Hat as a
Specialist Architect helping people adopt cloud native technology. I got involved with the
Kubernetes ecosystem in 2019. Around the end of 2022 I noticed how the etcd community and project
needed help so started contributing as often as I could. There is a saying in our community that
&amp;quot;you come for the technology, and stay for the people&amp;quot;: for me this is absolutely real, it’s been a
wonderful journey so far and I’m excited to support our community moving forward.&lt;/p>
&lt;p>&lt;strong>Marek:&lt;/strong> Hey everyone, I'm Marek, the SIG etcd lead. At Google, I lead the GKE etcd team, ensuring
a stable and reliable experience for all GKE users. My Kubernetes journey began with &lt;a href="https://github.com/kubernetes/community/tree/master/sig-instrumentation">SIG
Instrumentation&lt;/a>, where I
created and led the &lt;a href="https://kubernetes.io/blog/2020/09/04/kubernetes-1-19-introducing-structured-logs/">Kubernetes Structured Logging effort&lt;/a>.&lt;br>
I'm still the main project lead for &lt;a href="https://kubernetes-sigs.github.io/metrics-server/">Kubernetes Metrics Server&lt;/a>,
providing crucial signals for autoscaling in Kubernetes. I started working on etcd 3 years ago,
right around the 3.5 release. We faced some challenges, but I'm thrilled to see etcd now the most
scalable and reliable it's ever been, with the highest contribution numbers in the project's
history. I'm passionate about distributed systems, extreme programming, and testing.&lt;/p>
&lt;p>&lt;strong>Wenjia:&lt;/strong> Hi there, my name is Wenjia, I am the co-chair of SIG etcd and one of the etcd
maintainers. I work at Google as an Engineering Manager, working on GKE (Google Kubernetes Engine)
and GDC (Google Distributed Cloud). I have been working in the area of open source Kubernetes and
etcd since the Kubernetes v1.10 and etcd v3.1 releases. I got involved in Kubernetes because of my
job, but what keeps me in the space is the charm of the container orchestration technology, and more
importantly, the awesome open source community.&lt;/p>
&lt;h2 id="becoming-a-kubernetes-special-interest-group-sig">Becoming a Kubernetes Special Interest Group (SIG)&lt;/h2>
&lt;p>&lt;strong>Frederico: Excellent, thank you. I'd like to start with the origin of the SIG itself: SIG etcd is
a very recent SIG, could you quickly go through the history and reasons behind its creation?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: Absolutely! SIG etcd was formed because etcd is a critical component of Kubernetes,
serving as its data store. However, etcd was facing challenges like maintainer turnover and
reliability issues. &lt;a href="https://etcd.io/blog/2023/introducing-sig-etcd/">Creating a dedicated SIG&lt;/a>
allowed us to focus on addressing these problems, improving development and maintenance processes,
and ensuring etcd evolves in sync with the cloud-native landscape.&lt;/p>
&lt;p>&lt;strong>Frederico: And has becoming a SIG worked out as expected? Better yet, are the motivations you just
described being addressed, and to what extent?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: It's been a positive change overall. Becoming a SIG has brought more structure and
transparency to etcd's development. We've adopted Kubernetes processes like KEPs
(&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/README.md">Kubernetes Enhancement Proposals&lt;/a>
and PRRs (&lt;a href="https://github.com/kubernetes/community/blob/master/sig-architecture/production-readiness.md">Production Readiness Reviews&lt;/a>,
which has improved our feature development and release cycle.&lt;/p>
&lt;p>&lt;strong>Frederico: On top of those, what would you single out as the major benefit that has resulted from
becoming a SIG?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: The biggest benefits for me was adopting Kubernetes testing infrastructure, tools like
&lt;a href="https://docs.prow.k8s.io/">Prow&lt;/a> and &lt;a href="https://testgrid.k8s.io/">TestGrid&lt;/a>. For large projects like
etcd there is just no comparison to the default GitHub tooling. Having known, easy to use, clear
tools is a major boost to the etcd as it makes it much easier for Kubernetes contributors to also
help etcd.&lt;/p>
&lt;p>&lt;strong>Wenjia&lt;/strong>: Totally agree, while challenges remain, the SIG structure provides a solid foundation
for addressing them and ensuring etcd's continued success as a critical component of the Kubernetes
ecosystem.&lt;/p>
&lt;p>The positive impact on the community is another crucial aspect of SIG etcd's success that I’d like
to highlight. The Kubernetes SIG structure has created a welcoming environment for etcd
contributors, leading to increased participation from the broader Kubernetes community. We have had
greater collaboration with other SIGs like &lt;a href="https://github.com/kubernetes/community/blob/master/sig-api-machinery/README.md">SIG API
Machinery&lt;/a>,
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-scalability">SIG Scalability&lt;/a>,
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-scalability">SIG Testing&lt;/a>,
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-cluster-lifecycle">SIG Cluster Lifecycle&lt;/a>, etc.&lt;/p>
&lt;p>This collaboration helps ensure etcd's development aligns with the needs of the wider Kubernetes
ecosystem. The formation of the &lt;a href="https://github.com/kubernetes/community/blob/master/wg-etcd-operator/README.md">etcd Operator Working Group&lt;/a>
under the joint effort between SIG etcd and SIG Cluster Lifecycle exemplifies this successful
collaboration, demonstrating a shared commitment to improving etcd's operational aspects within
Kubernetes.&lt;/p>
&lt;p>&lt;strong>Frederico: Since you mentioned collaboration, have you seen changes in terms of contributors and
community involvement in recent months?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>James&lt;/strong>: Yes -- as showing in our
&lt;a href="https://etcd.devstats.cncf.io/d/23/prs-authors-repository-groups?orgId=1&amp;var-period=m&amp;var-repogroup_name=All&amp;from=1422748800000&amp;to=1738454399000">unique PR author data&lt;/a>
we recently hit an all time high in March and are trending in a positive direction:&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2025/03/04/sig-etcd-spotlight/stats.png"
alt="Unique PR author data stats"/>
&lt;/figure>
&lt;p>Additionally, looking at our
&lt;a href="https://etcd.devstats.cncf.io/d/74/contributions-chart?orgId=1&amp;from=1422748800000&amp;to=1738454399000&amp;var-period=m&amp;var-metric=contributions&amp;var-repogroup_name=All&amp;var-country_name=All&amp;var-company_name=All&amp;var-company=all">overall contributions across all etcd project repositories&lt;/a>
we are also observing a positive trend showing a resurgence in etcd project activity:&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2025/03/04/sig-etcd-spotlight/stats2.png"
alt="Overall contributions stats"/>
&lt;/figure>
&lt;h2 id="the-road-ahead">The road ahead&lt;/h2>
&lt;p>&lt;strong>Frederico: That's quite telling, thank you. In terms of the near future, what are the current
priorities for SIG etcd?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: Reliability is always top of mind -– we need to make sure etcd is rock-solid. We're also
working on making etcd easier to use and manage for operators. And we have our sights set on making
etcd a viable standalone solution for infrastructure management, not just for Kubernetes. Oh, and of
course, scaling -– we need to ensure etcd can handle the growing demands of the cloud-native world.&lt;/p>
&lt;p>&lt;strong>Benjamin&lt;/strong>: I agree that reliability should always be our top guiding principle. We need to ensure
not only correctness but also compatibility. Additionally, we should continuously strive to improve
the understandability and maintainability of etcd. Our focus should be on addressing the pain points
that the community cares about the most.&lt;/p>
&lt;p>&lt;strong>Frederico: Are there any specific SIGs that you work closely with?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: SIG API Machinery, for sure – they own the structure of the data etcd stores, so we're
constantly working together. And SIG Cluster Lifecycle – etcd is a key part of Kubernetes clusters,
so we collaborate on the newly created etcd operator Working group.&lt;/p>
&lt;p>&lt;strong>Wenjia&lt;/strong>: Other than SIG API Machinery and SIG Cluster Lifecycle that Marek mentioned above, SIG
Scalability and SIG Testing is another group that we work closely with.&lt;/p>
&lt;p>&lt;strong>Frederico: In a more general sense, how would you list the key challenges for SIG etcd in the
evolving cloud native landscape?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: Well, reliability is always a challenge when you're dealing with critical data. The
cloud-native world is evolving so fast that scaling to meet those demands is a constant effort.&lt;/p>
&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>&lt;strong>Frederico: We're almost at the end of our conversation, but for those interested in in etcd, how
can they get involved?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: We'd love to have them! The best way to start is to join our
&lt;a href="https://github.com/kubernetes/community/blob/master/sig-etcd/README.md#meetings">SIG etcd meetings&lt;/a>,
follow discussions on the &lt;a href="https://groups.google.com/g/etcd-dev">etcd-dev mailing list&lt;/a>, and check
out our &lt;a href="https://github.com/etcd-io/etcd/issues">GitHub issues&lt;/a>. We're always looking for people to
review proposals, test code, and contribute to documentation.&lt;/p>
&lt;p>&lt;strong>Wenjia&lt;/strong>: I love this question 😀 . There are numerous ways for people interested in contributing
to SIG etcd to get involved and make a difference. Here are some key areas where you can help:&lt;/p>
&lt;p>&lt;strong>Code Contributions&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;em>Bug Fixes&lt;/em>: Tackle existing issues in the etcd codebase. Start with issues labeled &amp;quot;good first
issue&amp;quot; or &amp;quot;help wanted&amp;quot; to find tasks that are suitable for newcomers.&lt;/li>
&lt;li>&lt;em>Feature Development&lt;/em>: Contribute to the development of new features and enhancements. Check the
etcd roadmap and discussions to see what's being planned and where your skills might fit in.&lt;/li>
&lt;li>&lt;em>Testing and Code Reviews&lt;/em>: Help ensure the quality of etcd by writing tests, reviewing code
changes, and providing feedback.&lt;/li>
&lt;li>&lt;em>Documentation&lt;/em>: Improve &lt;a href="https://etcd.io/docs/">etcd's documentation&lt;/a> by adding new content,
clarifying existing information, or fixing errors. Clear and comprehensive documentation is
essential for users and contributors.&lt;/li>
&lt;li>&lt;em>Community Support&lt;/em>: Answer questions on forums, mailing lists, or &lt;a href="https://kubernetes.slack.com/archives/C3HD8ARJ5">Slack channels&lt;/a>.
Helping others understand and use etcd is a valuable contribution.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Getting Started&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;em>Join the community&lt;/em>: Start by joining the etcd community on Slack,
attending SIG meetings, and following the mailing lists. This will
help you get familiar with the project, its processes, and the
people involved.&lt;/li>
&lt;li>&lt;em>Find a mentor&lt;/em>: If you're new to open source or etcd, consider
finding a mentor who can guide you and provide support. Stay tuned!
Our first cohort of mentorship program was very successful. We will
have a new round of mentorship program coming up.&lt;/li>
&lt;li>&lt;em>Start small&lt;/em>: Don't be afraid to start with small contributions. Even
fixing a typo in the documentation or submitting a simple bug fix
can be a great way to get involved.&lt;/li>
&lt;/ul>
&lt;p>By contributing to etcd, you'll not only be helping to improve a
critical piece of the cloud-native ecosystem but also gaining valuable
experience and skills. So, jump in and start contributing!&lt;/p>
&lt;p>&lt;strong>Frederico: Excellent, thank you. Lastly, one piece of advice that
you'd like to give to other newly formed SIGs?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Marek&lt;/strong>: Absolutely! My advice would be to embrace the established
processes of the larger community, prioritize collaboration with other
SIGs, and focus on building a strong community.&lt;/p>
&lt;p>&lt;strong>Wenjia&lt;/strong>: Here are some tips I myself found very helpful in my OSS
journey:&lt;/p>
&lt;ul>
&lt;li>&lt;em>Be patient&lt;/em>: Open source development can take time. Don't get
discouraged if your contributions aren't accepted immediately or if
you encounter challenges.&lt;/li>
&lt;li>&lt;em>Be respectful&lt;/em>: The etcd community values collaboration and
respect. Be mindful of others' opinions and work together to achieve
common goals.&lt;/li>
&lt;li>&lt;em>Have fun&lt;/em>: Contributing to open source should be
enjoyable. Find areas that interest you and contribute in ways that
you find fulfilling.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Frederico: A great way to end this spotlight, thank you all!&lt;/strong>&lt;/p>
&lt;hr>
&lt;p>For more information and resources, please take a look at :&lt;/p>
&lt;ol>
&lt;li>etcd website: &lt;a href="https://etcd.io/">https://etcd.io/&lt;/a>&lt;/li>
&lt;li>etcd GitHub repository: &lt;a href="https://github.com/etcd-io/etcd">https://github.com/etcd-io/etcd&lt;/a>&lt;/li>
&lt;li>etcd community: &lt;a href="https://etcd.io/community/">https://etcd.io/community/&lt;/a>&lt;/li>
&lt;/ol></description></item><item><title>NFTables mode for kube-proxy</title><link>https://kubernetes.io/blog/2025/02/28/nftables-kube-proxy/</link><pubDate>Fri, 28 Feb 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/02/28/nftables-kube-proxy/</guid><description>
&lt;p>A new nftables mode for kube-proxy was introduced as an alpha feature
in Kubernetes 1.29. Currently in beta, it is expected to be GA as of
1.33. The new mode fixes long-standing performance problems with the
iptables mode and all users running on systems with reasonably-recent
kernels are encouraged to try it out. (For compatibility reasons, even
once nftables becomes GA, iptables will still be the &lt;em>default&lt;/em>.)&lt;/p>
&lt;h2 id="why-nftables-part-1-data-plane-latency">Why nftables? Part 1: data plane latency&lt;/h2>
&lt;p>The iptables API was designed for implementing simple firewalls, and
has problems scaling up to support Service proxying in a large
Kubernetes cluster with tens of thousands of Services.&lt;/p>
&lt;p>In general, the ruleset generated by kube-proxy in iptables mode has a
number of iptables rules proportional to the sum of the number of
Services and the total number of endpoints. In particular, at the top
level of the ruleset, there is one rule to test each possible Service
IP (and port) that a packet might be addressed to:&lt;/p>
&lt;pre tabindex="0">&lt;code># If the packet is addressed to 172.30.0.41:80, then jump to the chain
# KUBE-SVC-XPGD46QRK7WJZT7O for further processing
-A KUBE-SERVICES -m comment --comment &amp;#34;namespace1/service1:p80 cluster IP&amp;#34; -m tcp -p tcp -d 172.30.0.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O
# If the packet is addressed to 172.30.0.42:443, then...
-A KUBE-SERVICES -m comment --comment &amp;#34;namespace2/service2:p443 cluster IP&amp;#34; -m tcp -p tcp -d 172.30.0.42 --dport 443 -j KUBE-SVC-GNZBNJ2PO5MGZ6GT
# etc...
-A KUBE-SERVICES -m comment --comment &amp;#34;namespace3/service3:p80 cluster IP&amp;#34; -m tcp -p tcp -d 172.30.0.43 --dport 80 -j KUBE-SVC-X27LE4BHSL4DOUIK
&lt;/code>&lt;/pre>&lt;p>This means that when a packet comes in, the time it takes the kernel
to check it against all of the Service rules is &lt;strong>O(n)&lt;/strong> in the number
of Services. As the number of Services increases, both the average and
the worst-case latency for the first packet of a new connection
increases (with the difference between best-case, average, and
worst-case being mostly determined by whether a given Service IP
address appears earlier or later in the &lt;code>KUBE-SERVICES&lt;/code> chain).&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2025/02/28/nftables-kube-proxy/iptables-only.svg"
alt="kube-proxy iptables first packet latency, at various percentiles, in clusters of various sizes"/>
&lt;/figure>
&lt;p>By contrast, with nftables, the normal way to write a ruleset like
this is to have a &lt;em>single&lt;/em> rule, using a &amp;quot;verdict map&amp;quot; to do the
dispatch:&lt;/p>
&lt;pre tabindex="0">&lt;code>table ip kube-proxy {
# The service-ips verdict map indicates the action to take for each matching packet.
map service-ips {
type ipv4_addr . inet_proto . inet_service : verdict
comment &amp;#34;ClusterIP, ExternalIP and LoadBalancer IP traffic&amp;#34;
elements = { 172.30.0.41 . tcp . 80 : goto service-ULMVA6XW-namespace1/service1/tcp/p80,
172.30.0.42 . tcp . 443 : goto service-42NFTM6N-namespace2/service2/tcp/p443,
172.30.0.43 . tcp . 80 : goto service-4AT6LBPK-namespace3/service3/tcp/p80,
... }
}
# Now we just need a single rule to process all packets matching an
# element in the map. (This rule says, &amp;#34;construct a tuple from the
# destination IP address, layer 4 protocol, and destination port; look
# that tuple up in &amp;#34;service-ips&amp;#34;; and if there&amp;#39;s a match, execute the
# associated verdict.)
chain services {
ip daddr . meta l4proto . th dport vmap @service-ips
}
...
}
&lt;/code>&lt;/pre>&lt;p>Since there's only a single rule, with a roughly &lt;strong>O(1)&lt;/strong> map lookup,
packet processing time is more or less constant regardless of cluster
size, and the best/average/worst cases are very similar:&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2025/02/28/nftables-kube-proxy/nftables-only.svg"
alt="kube-proxy nftables first packet latency, at various percentiles, in clusters of various sizes"/>
&lt;/figure>
&lt;p>But note the huge difference in the vertical scale between the
iptables and nftables graphs! In the clusters with 5000 and 10,000
Services, the p50 (average) latency for nftables is about the same as
the p01 (approximately best-case) latency for iptables. In the 30,000
Service cluster, the p99 (approximately worst-case) latency for
nftables manages to beat out the p01 latency for iptables by a few
microseconds! Here's both sets of data together, but you may have to
squint to see the nftables results!:&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2025/02/28/nftables-kube-proxy/iptables-vs-nftables.svg"
alt="kube-proxy iptables-vs-nftables first packet latency, at various percentiles, in clusters of various sizes"/>
&lt;/figure>
&lt;h2 id="why-nftables-part-2-control-plane-latency">Why nftables? Part 2: control plane latency&lt;/h2>
&lt;p>While the improvements to data plane latency in large clusters are
great, there's another problem with iptables kube-proxy that often
keeps users from even being able to grow their clusters to that size:
the time it takes kube-proxy to program new iptables rules when
Services and their endpoints change.&lt;/p>
&lt;p>With both iptables and nftables, the total size of the ruleset as a
whole (actual rules, plus associated data) is &lt;strong>O(n)&lt;/strong> in the combined
number of Services and their endpoints. Originally, the iptables
backend would rewrite every rule on every update, and with tens of
thousands of Services, this could grow to be hundreds of thousands of
iptables rules. Starting in Kubernetes 1.26, we began improving
kube-proxy so that it could skip updating &lt;em>most&lt;/em> of the unchanged
rules in each update, but the limitations of &lt;code>iptables-restore&lt;/code> as an
API meant that it was still always necessary to send an update that's
&lt;strong>O(n)&lt;/strong> in the number of Services (though with a noticeably smaller
constant than it used to be). Even with those optimizations, it can
still be necessary to make use of kube-proxy's &lt;code>minSyncPeriod&lt;/code> config
option to ensure that it doesn't spend every waking second trying to
push iptables updates.&lt;/p>
&lt;p>The nftables APIs allow for doing much more incremental updates, and
when kube-proxy in nftables mode does an update, the size of the
update is only &lt;strong>O(n)&lt;/strong> in the number of Services and endpoints that
have changed since the last sync, regardless of the total number of
Services and endpoints. The fact that the nftables API allows each
nftables-using component to have its own private table also means that
there is no global lock contention between components like with
iptables. As a result, kube-proxy's nftables updates can be done much
more efficiently than with iptables.&lt;/p>
&lt;p>(Unfortunately I don't have cool graphs for this part.)&lt;/p>
&lt;h2 id="why-not-nftables">Why &lt;em>not&lt;/em> nftables?&lt;/h2>
&lt;p>All that said, there are a few reasons why you might not want to jump
right into using the nftables backend for now.&lt;/p>
&lt;p>First, the code is still fairly new. While it has plenty of unit
tests, performs correctly in our CI system, and has now been used in
the real world by multiple users, it has not seen anything close to as
much real-world usage as the iptables backend has, so we can't promise
that it is as stable and bug-free.&lt;/p>
&lt;p>Second, the nftables mode will not work on older Linux distributions;
currently it requires a 5.13 or newer kernel. Additionally, because of
bugs in early versions of the &lt;code>nft&lt;/code> command line tool, you should not
run kube-proxy in nftables mode on nodes that have an old (earlier
than 1.0.0) version of &lt;code>nft&lt;/code> in the host filesystem (or else
kube-proxy's use of nftables may interfere with other uses of nftables
on the system).&lt;/p>
&lt;p>Third, you may have other networking components in your cluster, such
as the pod network or NetworkPolicy implementation, that do not yet
support kube-proxy in nftables mode. You should consult the
documentation (or forums, bug tracker, etc.) for any such components
to see if they have problems with nftables mode. (In many cases they
will not; as long as they don't try to directly interact with or
override kube-proxy's iptables rules, they shouldn't care whether
kube-proxy is using iptables or nftables.) Additionally, observability
and monitoring tools that have not been updated may report less data
for kube-proxy in nftables mode than they do for kube-proxy in
iptables mode.&lt;/p>
&lt;p>Finally, kube-proxy in nftables mode is intentionally not 100%
compatible with kube-proxy in iptables mode. There are a few old
kube-proxy features whose default behaviors are less secure, less
performant, or less intuitive than we'd like, but where we felt that
changing the default would be a compatibility break. Since the
nftables mode is opt-in, this gave us a chance to fix those bad
defaults without breaking users who weren't expecting changes. (In
particular, with nftables mode, NodePort Services are now only
reachable on their nodes' default IPs, as opposed to being reachable
on all IPs, including &lt;code>127.0.0.1&lt;/code>, with iptables mode.) The
&lt;a href="https://kubernetes.io/docs/reference/networking/virtual-ips/#migrating-from-iptables-mode-to-nftables">kube-proxy documentation&lt;/a> has more information about this, including
information about metrics you can look at to determine if you are
relying on any of the changed functionality, and what configuration
options are available to get more backward-compatible behavior.&lt;/p>
&lt;h2 id="trying-out-nftables-mode">Trying out nftables mode&lt;/h2>
&lt;p>Ready to try it out? In Kubernetes 1.31 and later, you just need to
pass &lt;code>--proxy-mode nftables&lt;/code> to kube-proxy (or set &lt;code>mode: nftables&lt;/code> in
your kube-proxy config file).&lt;/p>
&lt;p>If you are using kubeadm to set up your cluster, the kubeadm
documentation explains &lt;a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/control-plane-flags/#customizing-kube-proxy">how to pass a &lt;code>KubeProxyConfiguration&lt;/code> to
&lt;code>kubeadm init&lt;/code>&lt;/a>. You can also &lt;a href="https://kind.sigs.k8s.io/docs/user/configuration/#kube-proxy-mode">deploy nftables-based clusters with
&lt;code>kind&lt;/code>&lt;/a>.&lt;/p>
&lt;p>You can also convert existing clusters from iptables (or ipvs) mode to
nftables by updating the kube-proxy configuration and restarting the
kube-proxy pods. (You do not need to reboot the nodes: when restarting
in nftables mode, kube-proxy will delete any existing iptables or ipvs
rules, and likewise, if you later revert back to iptables or ipvs
mode, it will delete any existing nftables rules.)&lt;/p>
&lt;h2 id="future-plans">Future plans&lt;/h2>
&lt;p>As mentioned above, while nftables is now the &lt;em>best&lt;/em> kube-proxy mode,
it is not the &lt;em>default&lt;/em>, and we do not yet have a plan for changing
that. We will continue to support the iptables mode for a long time.&lt;/p>
&lt;p>The future of the IPVS mode of kube-proxy is less certain: its main
advantage over iptables was that it was faster, but certain aspects of
the IPVS architecture and APIs were awkward for kube-proxy's purposes
(for example, the fact that the &lt;code>kube-ipvs0&lt;/code> device needs to have
&lt;em>every&lt;/em> Service IP address assigned to it), and some parts of
Kubernetes Service proxying semantics were difficult to implement
using IPVS (particularly the fact that some Services had to have
different endpoints depending on whether you connected to them from a
local or remote client). And now, the nftables mode has the same
performance as IPVS mode (actually, slightly better), without any of
the downsides:&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2025/02/28/nftables-kube-proxy/ipvs-vs-nftables.svg"
alt="kube-proxy ipvs-vs-nftables first packet latency, at various percentiles, in clusters of various sizes"/>
&lt;/figure>
&lt;p>(In theory the IPVS mode also has the advantage of being able to use
various other IPVS functionality, like alternative &amp;quot;schedulers&amp;quot; for
balancing endpoints. In practice, this ended up not being very useful,
because kube-proxy runs independently on every node, and the IPVS
schedulers on each node had no way of sharing their state with the
proxies on other nodes, thus thwarting the effort to balance traffic
more cleverly.)&lt;/p>
&lt;p>While the Kubernetes project does not have an immediate plan to drop
the IPVS backend, it is probably doomed in the long run, and people
who are currently using IPVS mode should try out the nftables mode
instead (and file bugs if you think there is missing functionality in
nftables mode that you can't work around).&lt;/p>
&lt;h2 id="learn-more">Learn more&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&amp;quot;&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-network/3866-nftables-proxy/README.md">KEP-3866: Add an nftables-based kube-proxy backend&lt;/a>&amp;quot; has the
history of the new feature.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&amp;quot;&lt;a href="https://youtu.be/yOGHb2HjslY?si=6O4PVJu7fGpReo1U">How the Tables Have Turned: Kubernetes Says Goodbye to IPTables&lt;/a>&amp;quot;,
from KubeCon/CloudNativeCon North America 2024, talks about porting
kube-proxy and Calico from iptables to nftables.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&amp;quot;&lt;a href="https://youtu.be/uYo2O3jbJLk?si=py2AXzMJZ4PuhxNg">From Observability to Performance&lt;/a>&amp;quot;, from KubeCon/CloudNativeCon
North America 2024. (This is where the kube-proxy latency data came
from; the &lt;a href="https://docs.google.com/spreadsheets/d/1-ryDNc6gZocnMHEXC7mNtqknKSOv5uhXFKDx8Hu3AYA/edit">raw data for the charts&lt;/a> is also available.)&lt;/p>
&lt;/li>
&lt;/ul></description></item><item><title>The Cloud Controller Manager Chicken and Egg Problem</title><link>https://kubernetes.io/blog/2025/02/14/cloud-controller-manager-chicken-egg-problem/</link><pubDate>Fri, 14 Feb 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/02/14/cloud-controller-manager-chicken-egg-problem/</guid><description>
&lt;p>Kubernetes 1.31
&lt;a href="https://kubernetes.io/blog/2024/05/20/completing-cloud-provider-migration/">completed the largest migration in Kubernetes history&lt;/a>, removing the in-tree
cloud provider. While the component migration is now done, this leaves some additional
complexity for users and installer projects (for example, kOps or Cluster API) . We will go
over those additional steps and failure points and make recommendations for cluster owners.
This migration was complex and some logic had to be extracted from the core components,
building four new subsystems.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Cloud controller manager&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-cloud-provider/2392-cloud-controller-manager/README.md">KEP-2392&lt;/a>)&lt;/li>
&lt;li>&lt;strong>API server network proxy&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/1281-network-proxy">KEP-1281&lt;/a>)&lt;/li>
&lt;li>&lt;strong>kubelet credential provider plugins&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2133-kubelet-credential-providers">KEP-2133&lt;/a>)&lt;/li>
&lt;li>&lt;strong>Storage migration to use &lt;a href="https://github.com/container-storage-interface/spec?tab=readme-ov-file#container-storage-interface-csi-specification-">CSI&lt;/a>&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/625-csi-migration/README.md">KEP-625&lt;/a>)&lt;/li>
&lt;/ol>
&lt;p>The &lt;a href="https://kubernetes.io/docs/concepts/architecture/cloud-controller/">cloud controller manager is part of the control plane&lt;/a>. It is a critical component
that replaces some functionality that existed previously in the kube-controller-manager and the
kubelet.&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/images/docs/components-of-kubernetes.svg"
alt="Components of Kubernetes"/> &lt;figcaption>
&lt;p>Components of Kubernetes&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>One of the most critical functionalities of the cloud controller manager is the node controller,
which is responsible for the initialization of the nodes.&lt;/p>
&lt;p>As you can see in the following diagram, when the &lt;strong>kubelet&lt;/strong> starts, it registers the Node
object with the apiserver, Tainting the node so it can be processed first by the
cloud-controller-manager. The initial Node is missing the cloud-provider specific information,
like the Node Addresses and the Labels with the cloud provider specific information like the
Node, Region and Instance type information.&lt;/p>
&lt;figure class="diagram-medium ">
&lt;img src="https://kubernetes.io/blog/2025/02/14/cloud-controller-manager-chicken-egg-problem/ccm-chicken-egg-problem-sequence-diagram.svg"
alt="Chicken and egg problem sequence diagram"/> &lt;figcaption>
&lt;p>Chicken and egg problem sequence diagram&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>This new initialization process adds some latency to the node readiness. Previously, the kubelet
was able to initialize the node at the same time it created the node. Since the logic has moved
to the cloud-controller-manager, this can cause a &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/#chicken-and-egg">chicken and egg problem&lt;/a>
during the cluster bootstrapping for those Kubernetes architectures that do not deploy the
controller manager as the other components of the control plane, commonly as static pods,
standalone binaries or daemonsets/deployments with tolerations to the taints and using
&lt;code>hostNetwork&lt;/code> (more on this below)&lt;/p>
&lt;h2 id="examples-of-the-dependency-problem">Examples of the dependency problem&lt;/h2>
&lt;p>As noted above, it is possible during bootstrapping for the cloud-controller-manager to be
unschedulable and as such the cluster will not initialize properly. The following are a few
concrete examples of how this problem can be expressed and the root causes for why they might
occur.&lt;/p>
&lt;p>These examples assume you are running your cloud-controller-manager using a Kubernetes resource
(e.g. Deployment, DaemonSet, or similar) to control its lifecycle. Because these methods
rely on Kubernetes to schedule the cloud-controller-manager, care must be taken to ensure it
will schedule properly.&lt;/p>
&lt;h3 id="example-cloud-controller-manager-not-scheduling-due-to-uninitialized-taint">Example: Cloud controller manager not scheduling due to uninitialized taint&lt;/h3>
&lt;p>As &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/#running-cloud-controller-manager">noted in the Kubernetes documentation&lt;/a>, when the kubelet is started with the command line
flag &lt;code>--cloud-provider=external&lt;/code>, its corresponding &lt;code>Node&lt;/code> object will have a no schedule taint
named &lt;code>node.cloudprovider.kubernetes.io/uninitialized&lt;/code> added. Because the cloud-controller-manager
is responsible for removing the no schedule taint, this can create a situation where a
cloud-controller-manager that is being managed by a Kubernetes resource, such as a &lt;code>Deployment&lt;/code>
or &lt;code>DaemonSet&lt;/code>, may not be able to schedule.&lt;/p>
&lt;p>If the cloud-controller-manager is not able to be scheduled during the initialization of the
control plane, then the resulting &lt;code>Node&lt;/code> objects will all have the
&lt;code>node.cloudprovider.kubernetes.io/uninitialized&lt;/code> no schedule taint. It also means that this taint
will not be removed as the cloud-controller-manager is responsible for its removal. If the no
schedule taint is not removed, then critical workloads, such as the container network interface
controllers, will not be able to schedule, and the cluster will be left in an unhealthy state.&lt;/p>
&lt;h3 id="example-cloud-controller-manager-not-scheduling-due-to-not-ready-taint">Example: Cloud controller manager not scheduling due to not-ready taint&lt;/h3>
&lt;p>The next example would be possible in situations where the container network interface (CNI) is
waiting for IP address information from the cloud-controller-manager (CCM), and the CCM has not
tolerated the taint which would be removed by the CNI.&lt;/p>
&lt;p>The &lt;a href="https://kubernetes.io/docs/reference/labels-annotations-taints/#node-kubernetes-io-not-ready">Kubernetes documentation describes&lt;/a> the &lt;code>node.kubernetes.io/not-ready&lt;/code> taint as follows:&lt;/p>
&lt;blockquote>
&lt;p>&amp;quot;The Node controller detects whether a Node is ready by monitoring its health and adds or removes this taint accordingly.&amp;quot;&lt;/p>
&lt;/blockquote>
&lt;p>One of the conditions that can lead to a Node resource having this taint is when the container
network has not yet been initialized on that node. As the cloud-controller-manager is responsible
for adding the IP addresses to a Node resource, and the IP addresses are needed by the container
network controllers to properly configure the container network, it is possible in some
circumstances for a node to become stuck as not ready and uninitialized permanently.&lt;/p>
&lt;p>This situation occurs for a similar reason as the first example, although in this case, the
&lt;code>node.kubernetes.io/not-ready&lt;/code> taint is used with the no execute effect and thus will cause the
cloud-controller-manager not to run on the node with the taint. If the cloud-controller-manager is
not able to execute, then it will not initialize the node. It will cascade into the container
network controllers not being able to run properly, and the node will end up carrying both the
&lt;code>node.cloudprovider.kubernetes.io/uninitialized&lt;/code> and &lt;code>node.kubernetes.io/not-ready&lt;/code> taints,
leaving the cluster in an unhealthy state.&lt;/p>
&lt;h2 id="our-recommendations">Our Recommendations&lt;/h2>
&lt;p>There is no one “correct way” to run a cloud-controller-manager. The details will depend on the
specific needs of the cluster administrators and users. When planning your clusters and the
lifecycle of the cloud-controller-managers please consider the following guidance:&lt;/p>
&lt;p>For cloud-controller-managers running in the same cluster, they are managing.&lt;/p>
&lt;ol>
&lt;li>Use host network mode, rather than the pod network: in most cases, a cloud controller manager
will need to communicate with an API service endpoint associated with the infrastructure.
Setting “hostNetwork” to true will ensure that the cloud controller is using the host
networking instead of the container network and, as such, will have the same network access as
the host operating system. It will also remove the dependency on the networking plugin. This
will ensure that the cloud controller has access to the infrastructure endpoint (always check
your networking configuration against your infrastructure provider’s instructions).&lt;/li>
&lt;li>Use a scalable resource type. &lt;code>Deployments&lt;/code> and &lt;code>DaemonSets&lt;/code> are useful for controlling the
lifecycle of a cloud controller. They allow easy access to running multiple copies for redundancy
as well as using the Kubernetes scheduling to ensure proper placement in the cluster. When using
these primitives to control the lifecycle of your cloud controllers and running multiple
replicas, you must remember to enable leader election, or else your controllers will collide
with each other which could lead to nodes not being initialized in the cluster.&lt;/li>
&lt;li>Target the controller manager containers to the control plane. There might exist other
controllers which need to run outside the control plane (for example, Azure’s node manager
controller). Still, the controller managers themselves should be deployed to the control plane.
Use a node selector or affinity stanza to direct the scheduling of cloud controllers to the
control plane to ensure that they are running in a protected space. Cloud controllers are vital
to adding and removing nodes to a cluster as they form a link between Kubernetes and the
physical infrastructure. Running them on the control plane will help to ensure that they run
with a similar priority as other core cluster controllers and that they have some separation
from non-privileged user workloads.
&lt;ol>
&lt;li>It is worth noting that an anti-affinity stanza to prevent cloud controllers from running
on the same host is also very useful to ensure that a single node failure will not degrade
the cloud controller performance.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Ensure that the tolerations allow operation. Use tolerations on the manifest for the cloud
controller container to ensure that it will schedule to the correct nodes and that it can run
in situations where a node is initializing. This means that cloud controllers should tolerate
the &lt;code>node.cloudprovider.kubernetes.io/uninitialized&lt;/code> taint, and it should also tolerate any
taints associated with the control plane (for example, &lt;code>node-role.kubernetes.io/control-plane&lt;/code>
or &lt;code>node-role.kubernetes.io/master&lt;/code>). It can also be useful to tolerate the
&lt;code>node.kubernetes.io/not-ready&lt;/code> taint to ensure that the cloud controller can run even when the
node is not yet available for health monitoring.&lt;/li>
&lt;/ol>
&lt;p>For cloud-controller-managers that will not be running on the cluster they manage (for example,
in a hosted control plane on a separate cluster), then the rules are much more constrained by the
dependencies of the environment of the cluster running the cloud-controller-manager. The advice
for running on a self-managed cluster may not be appropriate as the types of conflicts and network
constraints will be different. Please consult the architecture and requirements of your topology
for these scenarios.&lt;/p>
&lt;h3 id="example">Example&lt;/h3>
&lt;p>This is an example of a Kubernetes Deployment highlighting the guidance shown above. It is
important to note that this is for demonstration purposes only, for production uses please
consult your cloud provider’s documentation.&lt;/p>
&lt;pre tabindex="0">&lt;code>apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: cloud-controller-manager
name: cloud-controller-manager
namespace: kube-system
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: cloud-controller-manager
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: cloud-controller-manager
annotations:
kubernetes.io/description: Cloud controller manager for my infrastructure
spec:
containers: # the container details will depend on your specific cloud controller manager
- name: cloud-controller-manager
command:
- /bin/my-infrastructure-cloud-controller-manager
- --leader-elect=true
- -v=1
image: registry/my-infrastructure-cloud-controller-manager@latest
resources:
requests:
cpu: 200m
memory: 50Mi
hostNetwork: true # these Pods are part of the control plane
nodeSelector:
node-role.kubernetes.io/control-plane: &amp;#34;&amp;#34;
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: &amp;#34;kubernetes.io/hostname&amp;#34;
labelSelector:
matchLabels:
app.kubernetes.io/name: cloud-controller-manager
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
operator: Exists
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 120
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 120
- effect: NoSchedule
key: node.cloudprovider.kubernetes.io/uninitialized
operator: Exists
- effect: NoSchedule
key: node.kubernetes.io/not-ready
operator: Exists
&lt;/code>&lt;/pre>&lt;p>When deciding how to deploy your cloud controller manager it is worth noting that
cluster-proportional, or resource-based, pod autoscaling is not recommended. Running multiple
replicas of a cloud controller manager is good practice for ensuring high-availability and
redundancy, but does not contribute to better performance. In general, only a single instance
of a cloud controller manager will be reconciling a cluster at any given time.&lt;/p></description></item><item><title>Spotlight on SIG Architecture: Enhancements</title><link>https://kubernetes.io/blog/2025/01/21/sig-architecture-enhancements/</link><pubDate>Tue, 21 Jan 2025 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2025/01/21/sig-architecture-enhancements/</guid><description>
&lt;p>&lt;em>This is the fourth interview of a SIG Architecture Spotlight series that will cover the different
subprojects, and we will be covering &lt;a href="https://github.com/kubernetes/community/blob/master/sig-architecture/README.md#enhancements">SIG Architecture:
Enhancements&lt;/a>.&lt;/em>&lt;/p>
&lt;p>In this SIG Architecture spotlight we talked with &lt;a href="https://github.com/kikisdeliveryservice">Kirsten
Garrison&lt;/a>, lead of the Enhancements subproject.&lt;/p>
&lt;h2 id="the-enhancements-subproject">The Enhancements subproject&lt;/h2>
&lt;p>&lt;strong>Frederico (FSM): Hi Kirsten, very happy to have the opportunity to talk about the Enhancements
subproject. Let's start with some quick information about yourself and your role.&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Kirsten Garrison (KG)&lt;/strong>: I’m a lead of the Enhancements subproject of SIG-Architecture and
currently work at Google. I first got involved by contributing to the service-catalog project with
the help of &lt;a href="https://github.com/carolynvs">Carolyn Van Slyck&lt;/a>. With time, &lt;a href="https://github.com/kubernetes/sig-release/blob/master/releases/release-1.17/release_team.md">I joined the Release
team&lt;/a>,
eventually becoming the Enhancements Lead and a Release Lead shadow. While on the release team, I
worked on some ideas to make the process better for the SIGs and Enhancements team (the opt-in
process) based on my team’s experiences. Eventually, I started attending Subproject meetings and
contributing to the Subproject’s work.&lt;/p>
&lt;p>&lt;strong>FSM: You mentioned the Enhancements subproject: how would you describe its main goals and areas of
intervention?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: The &lt;a href="https://github.com/kubernetes/community/blob/master/sig-architecture/README.md#enhancements">Enhancements
Subproject&lt;/a>
primarily concerns itself with the &lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-architecture/0000-kep-process/README.md">Kubernetes Enhancement
Proposal&lt;/a>
(&lt;em>KEP&lt;/em> for short)—the &amp;quot;design&amp;quot; documents required for all features and significant changes
to the Kubernetes project.&lt;/p>
&lt;h2 id="the-kep-and-its-impact">The KEP and its impact&lt;/h2>
&lt;p>&lt;strong>FSM: The improvement of the KEP process was (and is) one in which SIG Architecture was heavily
involved. Could you explain the process to those that aren’t aware of it?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: &lt;a href="https://kubernetes.io/releases/release/#the-release-cycle">Every release&lt;/a>, the SIGs let the
Release Team know which features they intend to work on to be put into the release. As mentioned
above, the prerequisite for these changes is a KEP - a standardized design document that all authors
must fill out and approve in the first weeks of the release cycle. Most features &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/#feature-stages">will move
through 3
phases&lt;/a>:
alpha, beta and finally GA so approving a feature represents a significant commitment for the SIG.&lt;/p>
&lt;p>The KEP serves as the full source of truth of a feature. The &lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/NNNN-kep-template/README.md">KEP
template&lt;/a>
has different requirements based on what stage a feature is in, but it generally requires a detailed
discussion of the design and the impact as well as providing artifacts of stability and
performance. The KEP takes quite a bit of iterative work between authors, SIG reviewers, api review
team and the Production Readiness Review team&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> before it is approved. Each set of reviewers is
looking to make sure that the proposal meets their standards in order to have a stable and
performant Kubernetes release. Only after all approvals are secured, can an author go forth and
merge their feature in the Kubernetes code base.&lt;/p>
&lt;p>&lt;strong>FSM: I see, quite a bit of additional structure was added. Looking back, what were the most
significant improvements of that approach?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: In general, I think that the improvements with the most impact had to do with focusing on
the core intent of the KEP. KEPs exist not just to memorialize designs, but provide a structured way
to discuss and come to an agreement about different facets of the change. At the core of the KEP
process is communication and consideration.&lt;/p>
&lt;p>To that end, some of the significant changes revolve around a more detailed and accessible KEP
template. A significant amount of work was put in over time to get the
&lt;a href="https://github.com/kubernetes/enhancements">k/enhancements&lt;/a> repo into its current form -- a
directory structure organized by SIG with the contours of the modern KEP template (with
Proposal/Motivation/Design Details subsections). We might take that basic structure for granted
today, but it really represents the work of many people trying to get the foundation of this process
in place over time.&lt;/p>
&lt;p>As Kubernetes matures, we’ve needed to think about more than just the end goal of getting a single
feature merged. We need to think about things like: stability, performance, setting and meeting user
expectations. And as we’ve thought about those things the template has grown more detailed. The
addition of the Production Readiness Review was major as well as the enhanced testing requirements
(varying at different stages of a KEP’s lifecycle).&lt;/p>
&lt;h2 id="current-areas-of-focus">Current areas of focus&lt;/h2>
&lt;p>&lt;strong>FSM: Speaking of maturing, we’ve &lt;a href="https://kubernetes.io/blog/2024/08/13/kubernetes-v1-31-release/">recently released Kubernetes
v1.31&lt;/a>, and work on v1.32 &lt;a href="https://github.com/fsmunoz/sig-release/tree/release-1.32/releases/release-1.32">has
started&lt;/a>. Are there
any areas that the Enhancements sub-project is currently addressing that might change the way things
are done?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: We’re currently working on two things:&lt;/p>
&lt;ol>
&lt;li>&lt;em>Creating a Process KEP template.&lt;/em> Sometimes people want to harness the KEP process for
significant changes that are more process oriented rather than feature oriented. We want to
support this because memorializing changes is important and giving people a better tool to do so
will only encourage more discussion and transparency.&lt;/li>
&lt;li>&lt;em>KEP versioning.&lt;/em> While our template changes aim to be as non-disruptive as possible, we
believe that it will be easier to track and communicate those changes to the community better with
a versioned KEP template and the policies that go alongside such versioning.&lt;/li>
&lt;/ol>
&lt;p>Both features will take some time to get right and fully roll out (just like a KEP feature) but we
believe that they will both provide improvements that will benefit the community at large.&lt;/p>
&lt;p>&lt;strong>FSM: You mentioned improvements: I remember when project boards for Enhancement tracking were
introduced in recent releases, to great effect and unanimous applause from release team members. Was
this a particular area of focus for the subproject?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: The Subproject provided support to the Release Team’s Enhancement team in the migration away
from using the spreadsheet to a project board. The collection and tracking of enhancements has
always been a logistical challenge. During my time on the Release Team, I helped with the transition
to an opt-in system of enhancements, whereby the SIG leads &amp;quot;opt-in&amp;quot; KEPs for release tracking. This
helped to enhance communication between authors and SIGs before any significant work was undertaken
on a KEP and removed toil from the Enhancements team. This change used the existing tools to avoid
introducing too many changes at once to the community. Later, the Release Team approached the
Subproject with an idea of leveraging GitHub Project Boards to further improve the collection
process. This was to be a move away from the use of complicated spreadsheets to using repo-native
labels on &lt;a href="https://github.com/kubernetes/enhancements">k/enhancement&lt;/a> issues and project boards.&lt;/p>
&lt;p>&lt;strong>FSM: That surely adds an impact on simplifying the workflow...&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: Removing sources of friction and promoting clear communication is very important to the
Enhancements Subproject. At the same time, it’s important to give careful consideration to
decisions that impact the community as a whole. We want to make sure that changes are balanced to
give an upside and while not causing any regressions and pain in the rollout. We supported the
Release Team in ideation as well as through the actual migration to the project boards. It was a
great success and exciting to see the team make high impact changes that helped everyone involved in
the KEP process!&lt;/p>
&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>&lt;strong>FSM: For those reading that might be curious and interested in helping, how would you describe the
required skills for participating in the sub-project?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: Familiarity with KEPs either via experience or taking time to look through the
kubernetes/enhancements repo is helpful. All are welcome to participate if interested - we can take
it from there.&lt;/p>
&lt;p>&lt;strong>FSM: Excellent! Many thanks for your time and insight -- any final comments you would like to
share with our readers?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KG&lt;/strong>: The Enhancements process is one of the most important parts of Kubernetes and requires
enormous amounts of coordination and collaboration of people and teams across the project to make it
successful. I’m thankful and inspired by everyone’s continued hard work and dedication to making the
project great. This is truly a wonderful community.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>For more information, check the &lt;a href="https://kubernetes.io/blog/2023/11/02/sig-architecture-production-readiness-spotlight-2023/">Production Readiness Review spotlight
interview&lt;/a>
in this series.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Kubernetes 1.32: Moving Volume Group Snapshots to Beta</title><link>https://kubernetes.io/blog/2024/12/18/kubernetes-1-32-volume-group-snapshot-beta/</link><pubDate>Wed, 18 Dec 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/12/18/kubernetes-1-32-volume-group-snapshot-beta/</guid><description>
&lt;p>Volume group snapshots were &lt;a href="https://kubernetes.io/blog/2023/05/08/kubernetes-1-27-volume-group-snapshot-alpha/">introduced&lt;/a>
as an Alpha feature with the Kubernetes 1.27 release.
The recent release of Kubernetes v1.32 moved that support to &lt;strong>beta&lt;/strong>.
The support for volume group snapshots relies on a set of
&lt;a href="https://kubernetes-csi.github.io/docs/group-snapshot-restore-feature.html#volume-group-snapshot-apis">extension APIs for group snapshots&lt;/a>.
These APIs allow users to take crash consistent snapshots for a set of volumes.
Behind the scenes, Kubernetes uses a label selector to group multiple PersistentVolumeClaims
for snapshotting.
A key aim is to allow you restore that set of snapshots to new volumes and
recover your workload based on a crash consistent recovery point.&lt;/p>
&lt;p>This new feature is only supported for &lt;a href="https://kubernetes-csi.github.io/docs/">CSI&lt;/a> volume drivers.&lt;/p>
&lt;h2 id="an-overview-of-volume-group-snapshots">An overview of volume group snapshots&lt;/h2>
&lt;p>Some storage systems provide the ability to create a crash consistent snapshot of
multiple volumes. A group snapshot represents &lt;em>copies&lt;/em> made from multiple volumes, that
are taken at the same point-in-time. A group snapshot can be used either to rehydrate
new volumes (pre-populated with the snapshot data) or to restore existing volumes to
a previous state (represented by the snapshots).&lt;/p>
&lt;h2 id="why-add-volume-group-snapshots-to-kubernetes">Why add volume group snapshots to Kubernetes?&lt;/h2>
&lt;p>The Kubernetes volume plugin system already provides a powerful abstraction that
automates the provisioning, attaching, mounting, resizing, and snapshotting of block
and file storage.&lt;/p>
&lt;p>Underpinning all these features is the Kubernetes goal of workload portability:
Kubernetes aims to create an abstraction layer between distributed applications and
underlying clusters so that applications can be agnostic to the specifics of the
cluster they run on and application deployment requires no cluster specific knowledge.&lt;/p>
&lt;p>There was already a &lt;a href="https://kubernetes.io/docs/concepts/storage/volume-snapshots/">VolumeSnapshot&lt;/a> API
that provides the ability to take a snapshot of a persistent volume to protect against
data loss or data corruption. However, there are other snapshotting functionalities
not covered by the VolumeSnapshot API.&lt;/p>
&lt;p>Some storage systems support consistent group snapshots that allow a snapshot to be
taken from multiple volumes at the same point-in-time to achieve write order consistency.
This can be useful for applications that contain multiple volumes. For example,
an application may have data stored in one volume and logs stored in another volume.
If snapshots for the data volume and the logs volume are taken at different times,
the application will not be consistent and will not function properly if it is restored
from those snapshots when a disaster strikes.&lt;/p>
&lt;p>It is true that you can quiesce the application first, take an individual snapshot from
each volume that is part of the application one after the other, and then unquiesce the
application after all the individual snapshots are taken. This way, you would get
application consistent snapshots.&lt;/p>
&lt;p>However, sometimes the application quiesce can be so time consuming that you want to do it less frequently,
or it may not be possible to quiesce an application at all.
For example, a user may want to run weekly backups with application quiesce
and nightly backups without application quiesce but with consistent group support which
provides crash consistency across all volumes in the group.&lt;/p>
&lt;h2 id="kubernetes-apis-for-volume-group-snapshots">Kubernetes APIs for volume group snapshots&lt;/h2>
&lt;p>Kubernetes' support for &lt;em>volume group snapshots&lt;/em> relies on three API kinds that
are used
for managing snapshots:&lt;/p>
&lt;dl>
&lt;dt>VolumeGroupSnapshot&lt;/dt>
&lt;dd>Created by a Kubernetes user (or perhaps by your own automation) to request
creation of a volume group snapshot for multiple persistent volume claims.
It contains information about the volume group snapshot operation such as the
timestamp when the volume group snapshot was taken and whether it is ready to use.
The creation and deletion of this object represents a desire to create or delete a
cluster resource (a group snapshot).&lt;/dd>
&lt;dt>VolumeGroupSnapshotContent&lt;/dt>
&lt;dd>Created by the snapshot controller for a dynamically created VolumeGroupSnapshot.
It contains information about the volume group snapshot including the volume group
snapshot ID.
This object represents a provisioned resource on the cluster (a group snapshot).
The VolumeGroupSnapshotContent object binds to the VolumeGroupSnapshot for which it
was created with a one-to-one mapping.&lt;/dd>
&lt;dt>VolumeGroupSnapshotClass&lt;/dt>
&lt;dd>Created by cluster administrators to describe how volume group snapshots should be
created, including the driver information, the deletion policy, etc.&lt;/dd>
&lt;/dl>
&lt;p>These three API kinds are defined as
&lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">CustomResourceDefinitions&lt;/a>
(CRDs).
These CRDs must be installed in a Kubernetes cluster for a CSI Driver to support
volume group snapshots.&lt;/p>
&lt;h2 id="what-components-are-needed-to-support-volume-group-snapshots">What components are needed to support volume group snapshots&lt;/h2>
&lt;p>Volume group snapshots are implemented in the
&lt;a href="https://github.com/kubernetes-csi/external-snapshotter">external-snapshotter&lt;/a> repository.
Implementing volume group snapshots meant adding or changing several components:&lt;/p>
&lt;ul>
&lt;li>Added new CustomResourceDefinitions for VolumeGroupSnapshot and two supporting APIs.&lt;/li>
&lt;li>Volume group snapshot controller logic is added to the common snapshot controller.&lt;/li>
&lt;li>Adding logic to make CSI calls into the snapshotter sidecar controller.&lt;/li>
&lt;/ul>
&lt;p>The volume snapshot controller and CRDs are deployed once per
cluster, while the sidecar is bundled with each CSI driver.&lt;/p>
&lt;p>Therefore, it makes sense to deploy the volume snapshot controller and CRDs as a cluster addon.&lt;/p>
&lt;p>The Kubernetes project recommends that Kubernetes distributors
bundle and deploy the volume snapshot controller and CRDs as part
of their Kubernetes cluster management process (independent of any CSI Driver).&lt;/p>
&lt;h2 id="what-s-new-in-beta">What's new in Beta?&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>The VolumeGroupSnapshot feature in CSI spec moved to GA in the &lt;a href="https://github.com/container-storage-interface/spec/releases/tag/v1.11.0">v1.11.0 release&lt;/a>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The snapshot validation webhook was deprecated in external-snapshotter v8.0.0 and it is now removed.
Most of the validation webhook logic was added as validation rules into the CRDs.
Minimum required Kubernetes version is 1.25 for these validation rules.
One thing in the validation webhook not moved to CRDs is the prevention of creating
multiple default volume snapshot classes and multiple default volume group snapshot classes
for the same CSI driver.
With the removal of the validation webhook, an error will still be raised when dynamically
provisioning a VolumeSnapshot or VolumeGroupSnapshot when multiple default volume snapshot
classes or multiple default volume group snapshot classes for the same CSI driver exist.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The &lt;code>enable-volumegroup-snapshot&lt;/code> flag in the snapshot-controller and the CSI snapshotter
sidecar has been replaced by a feature gate.
Since VolumeGroupSnapshot is a new API, the feature moves to Beta but the feature gate is
disabled by default.
To use this feature, enable the feature gate by adding the flag &lt;code>--feature-gates=CSIVolumeGroupSnapshot=true&lt;/code>
when starting the snapshot-controller and the CSI snapshotter sidecar.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The logic to dynamically create the VolumeGroupSnapshot and its corresponding individual
VolumeSnapshot and VolumeSnapshotContent objects are moved from the CSI snapshotter to the common
snapshot-controller.
New RBAC rules are added to the common snapshot-controller and some RBAC rules are removed from
the CSI snapshotter sidecar accordingly.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="how-do-i-use-kubernetes-volume-group-snapshots">How do I use Kubernetes volume group snapshots&lt;/h2>
&lt;h3 id="creating-a-new-group-snapshot-with-kubernetes">Creating a new group snapshot with Kubernetes&lt;/h3>
&lt;p>Once a VolumeGroupSnapshotClass object is defined and you have volumes you want to
snapshot together, you may request a new group snapshot by creating a VolumeGroupSnapshot
object.&lt;/p>
&lt;p>The source of the group snapshot specifies whether the underlying group snapshot
should be dynamically created or if a pre-existing VolumeGroupSnapshotContent
should be used.&lt;/p>
&lt;p>A pre-existing VolumeGroupSnapshotContent is created by a cluster administrator.
It contains the details of the real volume group snapshot on the storage system which
is available for use by cluster users.&lt;/p>
&lt;p>One of the following members in the source of the group snapshot must be set.&lt;/p>
&lt;ul>
&lt;li>&lt;code>selector&lt;/code> - a label query over PersistentVolumeClaims that are to be grouped
together for snapshotting. This selector will be used to match the label
added to a PVC.&lt;/li>
&lt;li>&lt;code>volumeGroupSnapshotContentName&lt;/code> - specifies the name of a pre-existing
VolumeGroupSnapshotContent object representing an existing volume group snapshot.&lt;/li>
&lt;/ul>
&lt;h4 id="dynamically-provision-a-group-snapshot">Dynamically provision a group snapshot&lt;/h4>
&lt;p>In the following example, there are two PVCs.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">pvc-0 Bound pvc-6e1f7d34-a5c5-4548-b104-01e72c72b9f2 100Mi RWO csi-hostpath-sc &amp;lt;unset&amp;gt; 2m15s
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">pvc-1 Bound pvc-abc640b3-2cc1-4c56-ad0c-4f0f0e636efa 100Mi RWO csi-hostpath-sc &amp;lt;unset&amp;gt; 2m7s
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Label the PVCs.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">%&lt;/span> kubectl label pvc pvc-0 &lt;span style="color:#b8860b">group&lt;/span>&lt;span style="color:#666">=&lt;/span>myGroup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">persistentvolumeclaim/pvc-0 labeled
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">&lt;/span>&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>&lt;span style="color:#000080;font-weight:bold">%&lt;/span> kubectl label pvc pvc-1 &lt;span style="color:#b8860b">group&lt;/span>&lt;span style="color:#666">=&lt;/span>myGroup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">persistentvolumeclaim/pvc-1 labeled
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For dynamic provisioning, a selector must be set so that the snapshot controller can find PVCs
with the matching labels to be snapshotted together.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>groupsnapshot.storage.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeGroupSnapshot&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>snapshot-daily-20241217&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>demo-namespace&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeGroupSnapshotClassName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>csi-groupSnapclass&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">source&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">selector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchLabels&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>myGroup&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In the VolumeGroupSnapshot spec, a user can specify the VolumeGroupSnapshotClass which
has the information about which CSI driver should be used for creating the group snapshot.
A VolumGroupSnapshotClass is required for dynamic provisioning.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>groupsnapshot.storage.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeGroupSnapshotClass&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>csi-groupSnapclass&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">annotations&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kubernetes.io/description&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;Example group snapshot class&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">driver&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>example.csi.k8s.io&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">deletionPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Delete&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As a result of the volume group snapshot creation, a corresponding VolumeGroupSnapshotContent
object will be created with a volumeGroupSnapshotHandle pointing to a resource on the storage
system.&lt;/p>
&lt;p>Two individual volume snapshots will be created as part of the volume group snapshot creation.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME READYTOUSE SOURCEPVC RESTORESIZE SNAPSHOTCONTENT AGE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">snapshot-0962a745b2bf930bb385b7b50c9b08af471f1a16780726de19429dd9c94eaca0 true pvc-0 100Mi snapcontent-0962a745b2bf930bb385b7b50c9b08af471f1a16780726de19429dd9c94eaca0 16m
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">snapshot-da577d76bd2106c410616b346b2e72440f6ec7b12a75156263b989192b78caff true pvc-1 100Mi snapcontent-da577d76bd2106c410616b346b2e72440f6ec7b12a75156263b989192b78caff 16m
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="importing-an-existing-group-snapshot-with-kubernetes">Importing an existing group snapshot with Kubernetes&lt;/h4>
&lt;p>To import a pre-existing volume group snapshot into Kubernetes, you must also import
the corresponding individual volume snapshots.&lt;/p>
&lt;p>Identify the individual volume snapshot handles, manually construct a
VolumeSnapshotContent object first, then create a VolumeSnapshot object pointing to
the VolumeSnapshotContent object. Repeat this for every individual volume snapshot.&lt;/p>
&lt;p>Then manually create a VolumeGroupSnapshotContent object, specifying the
volumeGroupSnapshotHandle and individual volumeSnapshotHandles already existing
on the storage system.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>groupsnapshot.storage.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeGroupSnapshotContent&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>static-group-content&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">deletionPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Delete&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">driver&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>hostpath.csi.k8s.io&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">source&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">groupSnapshotHandles&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeGroupSnapshotHandle&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>e8779136-a93e-11ef-9549-66940726f2fd&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeSnapshotHandles&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- e8779147-a93e-11ef-9549-66940726f2fd&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- e8783cd0-a93e-11ef-9549-66940726f2fd&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeGroupSnapshotRef&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>static-group-snapshot&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>demo-namespace&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After that create a VolumeGroupSnapshot object pointing to the VolumeGroupSnapshotContent
object.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>groupsnapshot.storage.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeGroupSnapshot&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>static-group-snapshot&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>demo-namespace&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">source&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeGroupSnapshotContentName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>static-group-content&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="how-to-use-group-snapshot-for-restore-in-kubernetes">How to use group snapshot for restore in Kubernetes&lt;/h3>
&lt;p>At restore time, the user can request a new PersistentVolumeClaim to be created from
a VolumeSnapshot object that is part of a VolumeGroupSnapshot. This will trigger
provisioning of a new volume that is pre-populated with data from the specified
snapshot. The user should repeat this until all volumes are created from all the
snapshots that are part of a group snapshot.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PersistentVolumeClaim&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>examplepvc-restored-2024-12-17&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>demo-namespace&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">storageClassName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>example-foo-nearline&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">dataSource&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>snapshot-0962a745b2bf930bb385b7b50c9b08af471f1a16780726de19429dd9c94eaca0&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeSnapshot&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">apiGroup&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>snapshot.storage.k8s.io&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">accessModes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- ReadWriteOncePod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">resources&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requests&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">storage&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>100Mi&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># must be enough storage to fit the existing snapshot&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="as-a-storage-vendor-how-do-i-add-support-for-group-snapshots-to-my-csi-driver">As a storage vendor, how do I add support for group snapshots to my CSI driver?&lt;/h2>
&lt;p>To implement the volume group snapshot feature, a CSI driver &lt;strong>must&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Implement a new group controller service.&lt;/li>
&lt;li>Implement group controller RPCs: &lt;code>CreateVolumeGroupSnapshot&lt;/code>, &lt;code>DeleteVolumeGroupSnapshot&lt;/code>, and &lt;code>GetVolumeGroupSnapshot&lt;/code>.&lt;/li>
&lt;li>Add group controller capability &lt;code>CREATE_DELETE_GET_VOLUME_GROUP_SNAPSHOT&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>See the &lt;a href="https://github.com/container-storage-interface/spec/blob/master/spec.md">CSI spec&lt;/a>
and the &lt;a href="https://kubernetes-csi.github.io/docs/">Kubernetes-CSI Driver Developer Guide&lt;/a>
for more details.&lt;/p>
&lt;p>As mentioned earlier, it is strongly recommended that Kubernetes distributors
bundle and deploy the volume snapshot controller and CRDs as part
of their Kubernetes cluster management process (independent of any CSI Driver).&lt;/p>
&lt;p>As part of this recommended deployment process, the Kubernetes team provides a number of
sidecar (helper) containers, including the
&lt;a href="https://kubernetes-csi.github.io/docs/external-snapshotter.html">external-snapshotter sidecar container&lt;/a>
which has been updated to support volume group snapshot.&lt;/p>
&lt;p>The external-snapshotter watches the Kubernetes API server for
VolumeGroupSnapshotContent objects, and triggers &lt;code>CreateVolumeGroupSnapshot&lt;/code> and
&lt;code>DeleteVolumeGroupSnapshot&lt;/code> operations against a CSI endpoint.&lt;/p>
&lt;h2 id="what-are-the-limitations">What are the limitations?&lt;/h2>
&lt;p>The beta implementation of volume group snapshots for Kubernetes has the following limitations:&lt;/p>
&lt;ul>
&lt;li>Does not support reverting an existing PVC to an earlier state represented by
a snapshot (only supports provisioning a new volume from a snapshot).&lt;/li>
&lt;li>No application consistency guarantees beyond any guarantees provided by the storage system
(e.g. crash consistency). See this &lt;a href="https://github.com/kubernetes/community/blob/30d06f49fba22273f31b3c616b74cf8745c19b3d/wg-data-protection/data-protection-workflows-white-paper.md#quiesce-and-unquiesce-hooks">doc&lt;/a>
for more discussions on application consistency.&lt;/li>
&lt;/ul>
&lt;h2 id="what-s-next">What’s next?&lt;/h2>
&lt;p>Depending on feedback and adoption, the Kubernetes project plans to push the volume
group snapshot implementation to general availability (GA) in a future release.&lt;/p>
&lt;h2 id="how-can-i-learn-more">How can I learn more?&lt;/h2>
&lt;ul>
&lt;li>The &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/3476-volume-group-snapshot">design spec&lt;/a>
for the volume group snapshot feature.&lt;/li>
&lt;li>The &lt;a href="https://github.com/kubernetes-csi/external-snapshotter">code repository&lt;/a> for volume group
snapshot APIs and controller.&lt;/li>
&lt;li>CSI &lt;a href="https://kubernetes-csi.github.io/docs/">documentation&lt;/a> on the group snapshot feature.&lt;/li>
&lt;/ul>
&lt;h2 id="how-do-i-get-involved">How do I get involved?&lt;/h2>
&lt;p>This project, like all of Kubernetes, is the result of hard work by many contributors
from diverse backgrounds working together. On behalf of SIG Storage, I would like to
offer a huge thank you to the contributors who stepped up these last few quarters
to help the project reach beta:&lt;/p>
&lt;ul>
&lt;li>Ben Swartzlander (&lt;a href="https://github.com/bswartz">bswartz&lt;/a>)&lt;/li>
&lt;li>Cici Huang (&lt;a href="https://github.com/cici37">cici37&lt;/a>)&lt;/li>
&lt;li>Hemant Kumar (&lt;a href="https://github.com/gnufied">gnufied&lt;/a>)&lt;/li>
&lt;li>James Defelice (&lt;a href="https://github.com/jdef">jdef&lt;/a>)&lt;/li>
&lt;li>Jan Šafránek (&lt;a href="https://github.com/jsafrane">jsafrane&lt;/a>)&lt;/li>
&lt;li>Madhu Rajanna (&lt;a href="https://github.com/Madhu-1">Madhu-1&lt;/a>)&lt;/li>
&lt;li>Manish M Yathnalli (&lt;a href="https://github.com/manishym">manishym&lt;/a>)&lt;/li>
&lt;li>Michelle Au (&lt;a href="https://github.com/msau42">msau42&lt;/a>)&lt;/li>
&lt;li>Niels de Vos (&lt;a href="https://github.com/nixpanic">nixpanic&lt;/a>)&lt;/li>
&lt;li>Leonardo Cecchi (&lt;a href="https://github.com/leonardoce">leonardoce&lt;/a>)&lt;/li>
&lt;li>Rakshith R (&lt;a href="https://github.com/Rakshith-R">Rakshith-R&lt;/a>)&lt;/li>
&lt;li>Raunak Shah (&lt;a href="https://github.com/RaunakShah">RaunakShah&lt;/a>)&lt;/li>
&lt;li>Saad Ali (&lt;a href="https://github.com/saad-ali">saad-ali&lt;/a>)&lt;/li>
&lt;li>Xing Yang (&lt;a href="https://github.com/xing-yang">xing-yang&lt;/a>)&lt;/li>
&lt;li>Yati Padia (&lt;a href="https://github.com/yati1998">yati1998&lt;/a>)&lt;/li>
&lt;/ul>
&lt;p>For those interested in getting involved with the design and development of CSI or
any part of the Kubernetes Storage system, join the
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">Kubernetes Storage Special Interest Group&lt;/a> (SIG).
We always welcome new contributors.&lt;/p>
&lt;p>We also hold regular &lt;a href="https://github.com/kubernetes/community/tree/master/wg-data-protection">Data Protection Working Group meetings&lt;/a>.
New attendees are welcome to join our discussions.&lt;/p></description></item><item><title>Enhancing Kubernetes API Server Efficiency with API Streaming</title><link>https://kubernetes.io/blog/2024/12/17/kube-apiserver-api-streaming/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/12/17/kube-apiserver-api-streaming/</guid><description>
&lt;p>Managing Kubernetes clusters efficiently is critical, especially as their size is growing.
A significant challenge with large clusters is the memory overhead caused by &lt;strong>list&lt;/strong> requests.&lt;/p>
&lt;p>In the existing implementation, the kube-apiserver processes &lt;strong>list&lt;/strong> requests by assembling the entire response in-memory before transmitting any data to the client.
But what if the response body is substantial, say hundreds of megabytes? Additionally, imagine a scenario where multiple &lt;strong>list&lt;/strong> requests flood in simultaneously, perhaps after a brief network outage.
While &lt;a href="https://kubernetes.io/docs/concepts/cluster-administration/flow-control/">API Priority and Fairness&lt;/a> has proven to reasonably protect kube-apiserver from CPU overload, its impact is visibly smaller for memory protection.
This can be explained by the differing nature of resource consumption by a single API request - the CPU usage at any given time is capped by a constant, whereas memory, being uncompressible, can grow proportionally with the number of processed objects and is unbounded.
This situation poses a genuine risk, potentially overwhelming and crashing any kube-apiserver within seconds due to out-of-memory (OOM) conditions. To better visualize the issue, let's consider the below graph.&lt;/p>
&lt;figure class="diagram-large clickable-zoom">
&lt;img src="https://kubernetes.io/blog/2024/12/17/kube-apiserver-api-streaming/kube-apiserver-memory_usage.png"
alt="Monitoring graph showing kube-apiserver memory usage"/>
&lt;/figure>
&lt;p>The graph shows the memory usage of a kube-apiserver during a synthetic test.
(see the &lt;a href="#the-synthetic-test">synthetic test&lt;/a> section for more details).
The results clearly show that increasing the number of informers significantly boosts the server's memory consumption.
Notably, at approximately 16:40, the server crashed when serving only 16 informers.&lt;/p>
&lt;h2 id="why-does-kube-apiserver-allocate-so-much-memory-for-list-requests">Why does kube-apiserver allocate so much memory for list requests?&lt;/h2>
&lt;p>Our investigation revealed that this substantial memory allocation occurs because the server before sending the first byte to the client must:&lt;/p>
&lt;ul>
&lt;li>fetch data from the database,&lt;/li>
&lt;li>deserialize the data from its stored format,&lt;/li>
&lt;li>and finally construct the final response by converting and serializing the data into a client requested format&lt;/li>
&lt;/ul>
&lt;p>This sequence results in significant temporary memory consumption.
The actual usage depends on many factors like the page size, applied filters (e.g. label selectors), query parameters, and sizes of individual objects.&lt;/p>
&lt;p>Unfortunately, neither &lt;a href="https://kubernetes.io/docs/concepts/cluster-administration/flow-control/">API Priority and Fairness&lt;/a> nor Golang's garbage collection or Golang memory limits can prevent the system from exhausting memory under these conditions.
The memory is allocated suddenly and rapidly, and just a few requests can quickly deplete the available memory, leading to resource exhaustion.&lt;/p>
&lt;p>Depending on how the API server is run on the node, it might either be killed through OOM by the kernel when exceeding the configured memory limits during these uncontrolled spikes, or if limits are not configured it might have even worse impact on the control plane node.
And worst, after the first API server failure, the same requests will likely hit another control plane node in an HA setup with probably the same impact.
Potentially a situation that is hard to diagnose and hard to recover from.&lt;/p>
&lt;h2 id="streaming-list-requests">Streaming list requests&lt;/h2>
&lt;p>Today, we're excited to announce a major improvement.
With the graduation of the &lt;em>watch list&lt;/em> feature to beta in Kubernetes 1.32, client-go users can opt-in (after explicitly enabling &lt;code>WatchListClient&lt;/code> feature gate)
to streaming lists by switching from &lt;strong>list&lt;/strong> to (a special kind of) &lt;strong>watch&lt;/strong> requests.&lt;/p>
&lt;p>&lt;strong>Watch&lt;/strong> requests are served from the &lt;em>watch cache&lt;/em>, an in-memory cache designed to improve scalability of read operations.
By streaming each item individually instead of returning the entire collection, the new method maintains constant memory overhead.
The API server is bound by the maximum allowed size of an object in etcd plus a few additional allocations.
This approach drastically reduces the temporary memory usage compared to traditional &lt;strong>list&lt;/strong> requests, ensuring a more efficient and stable system,
especially in clusters with a large number of objects of a given type or large average object sizes where despite paging memory consumption used to be high.&lt;/p>
&lt;p>Building on the insight gained from the synthetic test (see the &lt;a href="#the-synthetic-test">synthetic test&lt;/a>, we developed an automated performance test to systematically evaluate the impact of the &lt;em>watch list&lt;/em> feature.
This test replicates the same scenario, generating a large number of Secrets with a large payload, and scaling the number of informers to simulate heavy &lt;strong>list&lt;/strong> request patterns.
The automated test is executed periodically to monitor memory usage of the server with the feature enabled and disabled.&lt;/p>
&lt;p>The results showed significant improvements with the &lt;em>watch list&lt;/em> feature enabled.
With the feature turned on, the kube-apiserver’s memory consumption stabilized at approximately &lt;strong>2 GB&lt;/strong>.
By contrast, with the feature disabled, memory usage increased to approximately &lt;strong>20GB&lt;/strong>, a &lt;strong>10x&lt;/strong> increase!
These results confirm the effectiveness of the new streaming API, which reduces the temporary memory footprint.&lt;/p>
&lt;h2 id="enabling-api-streaming-for-your-component">Enabling API Streaming for your component&lt;/h2>
&lt;p>Upgrade to Kubernetes 1.32. Make sure your cluster uses etcd in version 3.4.31+ or 3.5.13+.
Change your client software to use watch lists. If your client code is written in Golang, you'll want to enable &lt;code>WatchListClient&lt;/code> for client-go.
For details on enabling that feature, read &lt;a href="https://kubernetes.io/blog/2024/08/12/feature-gates-in-client-go">Introducing Feature Gates to Client-Go: Enhancing Flexibility and Control&lt;/a>.&lt;/p>
&lt;h2 id="what-s-next">What's next?&lt;/h2>
&lt;p>In Kubernetes 1.32, the feature is enabled in kube-controller-manager by default despite its beta state.
This will eventually be expanded to other core components like kube-scheduler or kubelet; once the feature becomes generally available, if not earlier.
Other 3rd-party components are encouraged to opt-in to the feature during the beta phase, especially when they are at risk of accessing a large number of resources or kinds with potentially large object sizes.&lt;/p>
&lt;p>For the time being, &lt;a href="https://kubernetes.io/docs/concepts/cluster-administration/flow-control/">API Priority and Fairness&lt;/a> assigns a reasonable small cost to &lt;strong>list&lt;/strong> requests.
This is necessary to allow enough parallelism for the average case where &lt;strong>list&lt;/strong> requests are cheap enough.
But it does not match the spiky exceptional situation of many and large objects.
Once the majority of the Kubernetes ecosystem has switched to &lt;em>watch list&lt;/em>, the &lt;strong>list&lt;/strong> cost estimation can be changed to larger values without risking degraded performance in the average case,
and with that increasing the protection against this kind of requests that can still hit the API server in the future.&lt;/p>
&lt;h2 id="the-synthetic-test">The synthetic test&lt;/h2>
&lt;p>In order to reproduce the issue, we conducted a manual test to understand the impact of &lt;strong>list&lt;/strong> requests on kube-apiserver memory usage.
In the test, we created 400 Secrets, each containing 1 MB of data, and used informers to retrieve all Secrets.&lt;/p>
&lt;p>The results were alarming, only 16 informers were needed to cause the test server to run out of memory and crash, demonstrating how quickly memory consumption can grow under such conditions.&lt;/p>
&lt;p>Special shout out to &lt;a href="https://github.com/deads2k">@deads2k&lt;/a> for his help in shaping this feature.&lt;/p></description></item><item><title>Kubernetes v1.32 Adds A New CPU Manager Static Policy Option For Strict CPU Reservation</title><link>https://kubernetes.io/blog/2024/12/16/cpumanager-strict-cpu-reservation/</link><pubDate>Mon, 16 Dec 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/12/16/cpumanager-strict-cpu-reservation/</guid><description>
&lt;p>In Kubernetes v1.32, after years of community discussion, we are excited to introduce a
&lt;code>strict-cpu-reservation&lt;/code> option for the &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/#static-policy-options">CPU Manager static policy&lt;/a>.
This feature is currently in alpha, with the associated policy hidden by default. You can only use the
policy if you explicitly enable the alpha behavior in your cluster.&lt;/p>
&lt;h2 id="understanding-the-feature">Understanding the feature&lt;/h2>
&lt;p>The CPU Manager static policy is used to reduce latency or improve performance. The &lt;code>reservedSystemCPUs&lt;/code> defines an explicit CPU set for OS system daemons and kubernetes system daemons. This option is designed for Telco/NFV type use cases where uncontrolled interrupts/timers may impact the workload performance. you can use this option to define the explicit cpuset for the system/kubernetes daemons as well as the interrupts/timers, so the rest CPUs on the system can be used exclusively for workloads, with less impact from uncontrolled interrupts/timers. More details of this parameter can be found on the &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/#explicitly-reserved-cpu-list">Explicitly Reserved CPU List&lt;/a> page.&lt;/p>
&lt;p>If you want to protect your system daemons and interrupt processing, the obvious way is to use the &lt;code>reservedSystemCPUs&lt;/code> option.&lt;/p>
&lt;p>However, until the Kubernetes v1.32 release, this isolation was only implemented for guaranteed
pods that made requests for a whole number of CPUs. At pod admission time, the kubelet only
compares the CPU &lt;em>requests&lt;/em> against the allocatable CPUs. In Kubernetes, limits can be higher than
the requests; the previous implementation allowed burstable and best-effort pods to use up
the capacity of &lt;code>reservedSystemCPUs&lt;/code>, which could then starve host OS services of CPU - and we
know that people saw this in real life deployments.
The existing behavior also made benchmarking (for both infrastructure and workloads) results inaccurate.&lt;/p>
&lt;p>When this new &lt;code>strict-cpu-reservation&lt;/code> policy option is enabled, the CPU Manager static policy will not allow any workload to use the reserved system CPU cores.&lt;/p>
&lt;h2 id="enabling-the-feature">Enabling the feature&lt;/h2>
&lt;p>To enable this feature, you need to turn on both the &lt;code>CPUManagerPolicyAlphaOptions&lt;/code> feature gate and the &lt;code>strict-cpu-reservation&lt;/code> policy option. And you need to remove the &lt;code>/var/lib/kubelet/cpu_manager_state&lt;/code> file if it exists and restart kubelet.&lt;/p>
&lt;p>With the following kubelet configuration:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>KubeletConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>kubelet.config.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">featureGates&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>...&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">CPUManagerPolicyOptions&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">true&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">CPUManagerPolicyAlphaOptions&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">true&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">cpuManagerPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>static&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">cpuManagerPolicyOptions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">strict-cpu-reservation&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">reservedSystemCPUs&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;0,32,1,33,16,48&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">...&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>When &lt;code>strict-cpu-reservation&lt;/code> is not set or set to false:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> cat /var/lib/kubelet/cpu_manager_state
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">{&amp;#34;policyName&amp;#34;:&amp;#34;static&amp;#34;,&amp;#34;defaultCpuSet&amp;#34;:&amp;#34;0-63&amp;#34;,&amp;#34;checksum&amp;#34;:1058907510}
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>When &lt;code>strict-cpu-reservation&lt;/code> is set to true:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> cat /var/lib/kubelet/cpu_manager_state
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">{&amp;#34;policyName&amp;#34;:&amp;#34;static&amp;#34;,&amp;#34;defaultCpuSet&amp;#34;:&amp;#34;2-15,17-31,34-47,49-63&amp;#34;,&amp;#34;checksum&amp;#34;:4141502832}
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="monitoring-the-feature">Monitoring the feature&lt;/h2>
&lt;p>You can monitor the feature impact by checking the following CPU Manager counters:&lt;/p>
&lt;ul>
&lt;li>&lt;code>cpu_manager_shared_pool_size_millicores&lt;/code>: report shared pool size, in millicores (e.g. 13500m)&lt;/li>
&lt;li>&lt;code>cpu_manager_exclusive_cpu_allocation_count&lt;/code>: report exclusively allocated cores, counting full cores (e.g. 16)&lt;/li>
&lt;/ul>
&lt;p>Your best-effort workloads may starve if the &lt;code>cpu_manager_shared_pool_size_millicores&lt;/code> count is zero for prolonged time.&lt;/p>
&lt;p>We believe any pod that is required for operational purpose like a log forwarder should not run as best-effort, but you can review and adjust the amount of CPU cores reserved as needed.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Strict CPU reservation is critical for Telco/NFV use cases. It is also a prerequisite for enabling the all-in-one type of deployments where workloads are placed on nodes serving combined control+worker+storage roles.&lt;/p>
&lt;p>We want you to start using the feature and looking forward to your feedback.&lt;/p>
&lt;h2 id="further-reading">Further reading&lt;/h2>
&lt;p>Please check out the &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/">Control CPU Management Policies on the Node&lt;/a>
task page to learn more about the CPU Manager, and how it fits in relation to the other node-level resource managers.&lt;/p>
&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>This feature is driven by the &lt;a href="https://github.com/Kubernetes/community/blob/master/sig-node/README.md">SIG Node&lt;/a>. If you are interested in helping develop this feature, sharing feedback, or participating in any other ongoing SIG Node projects, please attend the SIG Node meeting for more details.&lt;/p></description></item><item><title>Kubernetes v1.32: Memory Manager Goes GA</title><link>https://kubernetes.io/blog/2024/12/13/memory-manager-goes-ga/</link><pubDate>Fri, 13 Dec 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/12/13/memory-manager-goes-ga/</guid><description>
&lt;p>With Kubernetes 1.32, the memory manager has officially graduated to General Availability (GA),
marking a significant milestone in the journey toward efficient and predictable memory allocation for containerized applications.
Since Kubernetes v1.22, where it graduated to beta, the memory manager has proved itself reliable, stable and a good complementary feature for the
&lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/">CPU Manager&lt;/a>.&lt;/p>
&lt;p>As part of kubelet's workload admission process,
the memory manager provides topology hints
to optimize memory allocation and alignment.
This enables users to allocate exclusive
memory for Pods in the &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#guaranteed">Guaranteed&lt;/a> QoS class.
More details about the process can be found in the memory manager goes to beta &lt;a href="https://kubernetes.io/blog/2021/08/11/kubernetes-1-22-feature-memory-manager-moves-to-beta/">blog&lt;/a>.&lt;/p>
&lt;p>Most of the changes introduced since the Beta are bug fixes, internal refactoring and
observability improvements, such as metrics and better logging.&lt;/p>
&lt;h2 id="observability-improvements">Observability improvements&lt;/h2>
&lt;p>As part of the effort
to increase the observability of memory manager, new metrics have been added
to provide some statistics on memory allocation patterns.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>memory_manager_pinning_requests_total&lt;/strong> -
tracks the number of times the pod spec required the memory manager to pin memory pages.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>memory_manager_pinning_errors_total&lt;/strong> -
tracks the number of times the pod spec required the memory manager
to pin memory pages, but the allocation failed.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="improving-memory-manager-reliability-and-consistency">Improving memory manager reliability and consistency&lt;/h2>
&lt;p>The kubelet does not guarantee pod ordering
when admitting pods after a restart or reboot.&lt;/p>
&lt;p>In certain edge cases, this behavior could cause
the memory manager to reject some pods,
and in more extreme cases, it may cause kubelet to fail upon restart.&lt;/p>
&lt;p>Previously, the beta implementation lacked certain checks and logic to prevent
these issues.&lt;/p>
&lt;p>To stabilize the memory manager for general availability (GA) readiness,
small but critical refinements have been
made to the algorithm, improving its robustness and handling of edge cases.&lt;/p>
&lt;h2 id="future-development">Future development&lt;/h2>
&lt;p>There is more to come for the future of Topology Manager in general,
and memory manager in particular.
Notably, ongoing efforts are underway
to extend &lt;a href="https://github.com/kubernetes/kubernetes/pull/128560">memory manager support to Windows&lt;/a>,
enabling CPU and memory affinity on a Windows operating system.&lt;/p>
&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>This feature is driven by the &lt;a href="https://github.com/Kubernetes/community/blob/master/sig-node/README.md">SIG Node&lt;/a> community.
Please join us to connect with the community
and share your ideas and feedback around the above feature and
beyond.
We look forward to hearing from you!&lt;/p></description></item><item><title>Kubernetes v1.32: QueueingHint Brings a New Possibility to Optimize Pod Scheduling</title><link>https://kubernetes.io/blog/2024/12/12/scheduler-queueinghint/</link><pubDate>Thu, 12 Dec 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/12/12/scheduler-queueinghint/</guid><description>
&lt;p>The Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/">scheduler&lt;/a> is the core
component that selects the nodes on which new Pods run. The scheduler processes
these new Pods &lt;strong>one by one&lt;/strong>. Therefore, the larger your clusters, the more important
the throughput of the scheduler becomes.&lt;/p>
&lt;p>Over the years, Kubernetes SIG Scheduling has improved the throughput
of the scheduler in multiple enhancements. This blog post describes a major improvement to the
scheduler in Kubernetes v1.32: a
&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/#extension-points">scheduling context element&lt;/a>
named &lt;em>QueueingHint&lt;/em>. This page provides background knowledge of the scheduler and explains how
QueueingHint improves scheduling throughput.&lt;/p>
&lt;h2 id="scheduling-queue">Scheduling queue&lt;/h2>
&lt;p>The scheduler stores all unscheduled Pods in an internal component called the &lt;em>scheduling queue&lt;/em>.&lt;/p>
&lt;p>The scheduling queue consists of the following data structures:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>ActiveQ&lt;/strong>: holds newly created Pods or Pods that are ready to be retried for scheduling.&lt;/li>
&lt;li>&lt;strong>BackoffQ&lt;/strong>: holds Pods that are ready to be retried but are waiting for a backoff period to end. The
backoff period depends on the number of unsuccessful scheduling attempts performed by the scheduler on that Pod.&lt;/li>
&lt;li>&lt;strong>Unschedulable Pod Pool&lt;/strong>: holds Pods that the scheduler won't attempt to schedule for one of the
following reasons:
&lt;ul>
&lt;li>The scheduler previously attempted and was unable to schedule the Pods. Since that attempt, the cluster
hasn't changed in a way that could make those Pods schedulable.&lt;/li>
&lt;li>The Pods are blocked from entering the scheduling cycles by PreEnqueue Plugins,
for example, they have a &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/pod-scheduling-readiness/#configuring-pod-schedulinggates">scheduling gate&lt;/a>,
and get blocked by the scheduling gate plugin.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="scheduling-framework-and-plugins">Scheduling framework and plugins&lt;/h2>
&lt;p>The Kubernetes scheduler is implemented following the Kubernetes
&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">scheduling framework&lt;/a>.&lt;/p>
&lt;p>And, all scheduling features are implemented as plugins
(e.g., &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity">Pod affinity&lt;/a>
is implemented in the &lt;code>InterPodAffinity&lt;/code> plugin.)&lt;/p>
&lt;p>The scheduler processes pending Pods in phases called &lt;em>cycles&lt;/em> as follows:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Scheduling cycle&lt;/strong>: the scheduler takes pending Pods from the activeQ component of the scheduling
queue &lt;em>one by one&lt;/em>. For each Pod, the scheduler runs the filtering/scoring logic from every scheduling plugin. The
scheduler then decides on the best node for the Pod, or decides that the Pod can't be scheduled at that time.&lt;/p>
&lt;p>If the scheduler decides that a Pod can't be scheduled, that Pod enters the Unschedulable Pod Pool
component of the scheduling queue. However, if the scheduler decides to place the Pod on a node,
the Pod goes to the binding cycle.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Binding cycle&lt;/strong>: the scheduler communicates the node placement decision to the Kubernetes API
server. This operation bounds the Pod to the selected node.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Aside from some exceptions, most unscheduled Pods enter the unschedulable pod pool after each scheduling
cycle. The Unschedulable Pod Pool component is crucial because of how the scheduling cycle processes Pods one by one. If the scheduler had to constantly retry placing unschedulable Pods, instead of offloading those
Pods to the Unschedulable Pod Pool, multiple scheduling cycles would be wasted on those Pods.&lt;/p>
&lt;h2 id="improvements-to-retrying-pod-scheduling-with-queuinghint">Improvements to retrying Pod scheduling with QueuingHint&lt;/h2>
&lt;p>Unschedulable Pods only move back into the ActiveQ or BackoffQ components of the scheduling
queue if changes in the cluster might allow the scheduler to place those Pods on nodes.&lt;/p>
&lt;p>Prior to v1.32, each plugin registered which cluster changes could solve their failures, an object creation, update, or deletion in the cluster (called &lt;em>cluster events&lt;/em>),
with &lt;code>EnqueueExtensions&lt;/code> (&lt;code>EventsToRegister&lt;/code>),
and the scheduling queue retries a pod with an event that is registered by a plugin that rejected the pod in a previous scheduling cycle.&lt;/p>
&lt;p>Additionally, we had an internal feature called &lt;code>preCheck&lt;/code>, which helped further filtering of events for efficiency, based on Kubernetes core scheduling constraints;
For example, &lt;code>preCheck&lt;/code> could filter out node-related events when the node status is &lt;code>NotReady&lt;/code>.&lt;/p>
&lt;p>However, we had two issues for those approaches:&lt;/p>
&lt;ul>
&lt;li>Requeueing with events was too broad, could lead to scheduling retries for no reason.
&lt;ul>
&lt;li>A new scheduled Pod &lt;em>might&lt;/em> solve the &lt;code>InterPodAffinity&lt;/code>'s failure, but not all of them do.
For example, if a new Pod is created, but without a label matching &lt;code>InterPodAffinity&lt;/code> of the unschedulable pod, the pod wouldn't be schedulable.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>preCheck&lt;/code> relied on the logic of in-tree plugins and was not extensible to custom plugins,
like in issue &lt;a href="https://github.com/kubernetes/kubernetes/issues/110175">#110175&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Here QueueingHints come into play;
a QueueingHint subscribes to a particular kind of cluster event, and make a decision about whether each incoming event could make the Pod schedulable.&lt;/p>
&lt;p>For example, consider a Pod named &lt;code>pod-a&lt;/code> that has a required Pod affinity. &lt;code>pod-a&lt;/code> was rejected in
the scheduling cycle by the &lt;code>InterPodAffinity&lt;/code> plugin because no node had an existing Pod that matched
the Pod affinity specification for &lt;code>pod-a&lt;/code>.&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2024/12/12/scheduler-queueinghint/queueinghint1.svg"
alt="A diagram showing the scheduling queue and pod-a rejected by InterPodAffinity plugin"/> &lt;figcaption>
&lt;p>A diagram showing the scheduling queue and pod-a rejected by InterPodAffinity plugin&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>&lt;code>pod-a&lt;/code> moves into the Unschedulable Pod Pool. The scheduling queue records which plugin caused
the scheduling failure for the Pod. For &lt;code>pod-a&lt;/code>, the scheduling queue records that the &lt;code>InterPodAffinity&lt;/code>
plugin rejected the Pod.&lt;/p>
&lt;p>&lt;code>pod-a&lt;/code> will never be schedulable until the InterPodAffinity failure is resolved.
There're some scenarios that the failure could be resolved, one example is an existing running pod gets a label update and becomes matching a Pod affinity.
For this scenario, the &lt;code>InterPodAffinity&lt;/code> plugin's &lt;code>QueuingHint&lt;/code> callback function checks every Pod label update that occurs in the cluster.
Then, if a Pod gets a label update that matches the Pod affinity requirement of &lt;code>pod-a&lt;/code>, the &lt;code>InterPodAffinity&lt;/code>,
plugin's &lt;code>QueuingHint&lt;/code> prompts the scheduling queue to move &lt;code>pod-a&lt;/code> back into the ActiveQ or
the BackoffQ component.&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2024/12/12/scheduler-queueinghint/queueinghint2.svg"
alt="A diagram showing the scheduling queue and pod-a being moved by InterPodAffinity QueueingHint"/> &lt;figcaption>
&lt;p>A diagram showing the scheduling queue and pod-a being moved by InterPodAffinity QueueingHint&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;h2 id="queueinghint-s-history-and-what-s-new-in-v1-32">QueueingHint's history and what's new in v1.32&lt;/h2>
&lt;p>At SIG Scheduling, we have been working on the development of QueueingHint since
Kubernetes v1.28.&lt;/p>
&lt;p>While QueuingHint isn't user-facing, we implemented the &lt;code>SchedulerQueueingHints&lt;/code> feature gate as a
safety measure when we originally added this feature. In v1.28, we implemented QueueingHints with a
few in-tree plugins experimentally, and made the feature gate enabled by default.&lt;/p>
&lt;p>However, users reported a memory leak, and consequently we disabled the feature gate in a
patch release of v1.28. From v1.28 until v1.31, we kept working on the QueueingHint implementation
within the rest of the in-tree plugins and fixing bugs.&lt;/p>
&lt;p>In v1.32, we made this feature enabled by default again. We finished implementing QueueingHints
in all plugins and also identified the cause of the memory leak!&lt;/p>
&lt;p>We thank all the contributors who participated in the development of this feature and those who reported and investigated the earlier issues.&lt;/p>
&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>These features are managed by Kubernetes &lt;a href="https://github.com/kubernetes/community/tree/master/sig-scheduling">SIG Scheduling&lt;/a>.&lt;/p>
&lt;p>Please join us and share your feedback.&lt;/p>
&lt;h2 id="how-can-i-learn-more">How can I learn more?&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/4247-queueinghint/README.md">KEP-4247: Per-plugin callback functions for efficient requeueing in the scheduling queue&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes v1.32: Penelope</title><link>https://kubernetes.io/blog/2024/12/11/kubernetes-v1-32-release/</link><pubDate>Wed, 11 Dec 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/12/11/kubernetes-v1-32-release/</guid><description>
&lt;p>&lt;strong>Editors:&lt;/strong> Matteo Bianchi, Edith Puclla, William Rizzo, Ryota Sawada, Rashan Smith&lt;/p>
&lt;p>Announcing the release of Kubernetes v1.32: Penelope!&lt;/p>
&lt;p>In line with previous releases, the release of Kubernetes v1.32 introduces new stable, beta, and alpha features.
The consistent delivery of high-quality releases underscores the strength of our development cycle and the vibrant
support from our community.
This release consists of 44 enhancements in total.
Of those enhancements, 13 have graduated to Stable, 12 are entering Beta, and 19 have entered in Alpha.&lt;/p>
&lt;h2 id="release-theme-and-logo">Release theme and logo&lt;/h2>
&lt;figure class="release-logo ">
&lt;img src="https://kubernetes.io/blog/2024/12/11/kubernetes-v1-32-release/k8s-1.32.png"
alt="Kubernetes v1.32 logo: Penelope from the Odyssey, a helm and a purple geometric background"/>
&lt;/figure>
&lt;p>The Kubernetes v1.32 Release Theme is &amp;quot;Penelope&amp;quot;.&lt;/p>
&lt;p>If Kubernetes is Ancient Greek for &amp;quot;pilot&amp;quot;, in this release we start from that origin
and reflect on the last 10 years of Kubernetes and our accomplishments:
each release cycle is a journey, and just like Penelope, in &amp;quot;The Odyssey&amp;quot;,&lt;br>
weaved for 10 years -- each night removing parts of what she had done during the day --
so does each release add new features and removes others, albeit here with a much
clearer purpose of constantly improving Kubernetes.
With v1.32 being the last release in the year Kubernetes marks its first decade anniversary,
we wanted to honour all of those that have been part of the global Kubernetes crew
that roams the cloud-native seas through perils and challanges:
may we continue to weave the future of Kubernetes together.&lt;/p>
&lt;h2 id="updates-to-recent-key-features">Updates to recent key features&lt;/h2>
&lt;h3 id="a-note-on-dra-enhancements">A note on DRA enhancements&lt;/h3>
&lt;p>In this release, like the previous one, the Kubernetes project continues proposing a number of enhancements to the
Dynamic Resource Allocation (DRA), a key component of the Kubernetes resource management system. These enhancements aim
to improve the flexibility and efficiency of resource allocation for workloads that require specialized hardware, such
as GPUs, FPGAs and network adapters.
These features are particularly useful for use-cases such as machine learning or high-performance computing
applications. The core part enabling DRA Structured parameter support &lt;a href="#structured-parameter-support">got promoted to beta&lt;/a>.&lt;/p>
&lt;h3 id="quality-of-life-improvements-on-nodes-and-sidecar-containers-update">Quality of life improvements on nodes and sidecar containers update&lt;/h3>
&lt;p>&lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a> has the following highlights that go beyond
KEPs:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The systemd watchdog capability is now used to restart the kubelet when its health check fails, while also limiting
the maximum number of restarts within a given time period. This enhances the reliability of the kubelet. For more
details, see pull request &lt;a href="https://github.com/kubernetes/kubernetes/pull/127566">#127566&lt;/a>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>In cases when an image pull back-off error is encountered, the message displayed in the Pod status has been improved
to be more human-friendly and to indicate details about why the Pod is in this condition.
When an image pull back-off occurs, the error is appended to the &lt;code>status.containerStatuses[*].state.waiting.message&lt;/code>
field in the Pod specification with an &lt;code>ImagePullBackOff&lt;/code> value in the &lt;code>reason&lt;/code> field. This change provides you with
more context and helps you to identify the root cause of the issue. For more details, see pull request
&lt;a href="https://github.com/kubernetes/kubernetes/pull/127918">#127918&lt;/a>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The sidecar containers feature is targeting graduation to Stable in v1.33. To view the remaining work items and
feedback from users, see comments in the issue
&lt;a href="https://github.com/kubernetes/enhancements/issues/753#issuecomment-2350136594">#753&lt;/a>.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="highlights-of-features-graduating-to-stable">Highlights of features graduating to Stable&lt;/h2>
&lt;p>&lt;em>This is a selection of some of the improvements that are now stable following the v1.32 release.&lt;/em>&lt;/p>
&lt;h3 id="custom-resource-field-selectors">Custom Resource field selectors&lt;/h3>
&lt;p>Custom resource field selector allows developers to add field selectors to custom resources, mirroring the functionality
available for built-in Kubernetes objects. This allows for more efficient and precise filtering of custom resources,
promoting better API design practices.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4358">KEP #4358&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-api-machinery">SIG API
Machinery&lt;/a>.&lt;/p>
&lt;h3 id="support-to-size-memory-backed-volumes">Support to size memory backed volumes&lt;/h3>
&lt;p>This feature makes it possible to dynamically size memory-backed volumes based on Pod resource limits, improving the
workload's portability and overall node resource utilization.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/1967">KEP #1967&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG
Node&lt;/a>.&lt;/p>
&lt;h3 id="bound-service-account-token-improvement">Bound service account token improvement&lt;/h3>
&lt;p>The inclusion of the node name in the service account token claims allows users to use such information during
authorization and admission (ValidatingAdmissionPolicy).
Furthermore this improvement keeps service account credentials from being a privilege escalation path for nodes.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4193">KEP #4193&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-auth">SIG
Auth&lt;/a>.&lt;/p>
&lt;h3 id="structured-authorization-configuration">Structured authorization configuration&lt;/h3>
&lt;p>Multiple authorizers can be configured in the API server to allow for structured authorization decisions,
with support for CEL match conditions in webhooks.
This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3221">KEP #3221&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-auth">SIG
Auth&lt;/a>.&lt;/p>
&lt;h3 id="auto-remove-pvcs-created-by-statefulset">Auto remove PVCs created by StatefulSet&lt;/h3>
&lt;p>PersistentVolumeClaims (PVCs) created by StatefulSets get automatically deleted when no longer needed,
while ensuring data persistence during StatefulSet updates and node maintenance.
This feature simplifies storage management for StatefulSets and reduces the risk of orphaned PVCs.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/1847">KEP #1847&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-apps">SIG
Apps&lt;/a>.&lt;/p>
&lt;h2 id="highlights-of-features-graduating-to-beta">Highlights of features graduating to Beta&lt;/h2>
&lt;p>&lt;em>This is a selection of some of the improvements that are now beta following the v1.32 release.&lt;/em>&lt;/p>
&lt;h3 id="job-api-managed-by-mechanism">Job API managed-by mechanism&lt;/h3>
&lt;p>The &lt;code>managedBy&lt;/code> field for Jobs was promoted to beta in the v1.32 release. This feature enables external controllers
(like &lt;a href="https://kueue.sigs.k8s.io/">Kueue&lt;/a>) to manage Job synchronization, offering greater flexibility and integration
with advanced workload management systems.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4368">KEP #4368&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-apps">SIG
Apps&lt;/a>.&lt;/p>
&lt;h3 id="only-allow-anonymous-auth-for-configured-endpoints">Only allow anonymous auth for configured endpoints&lt;/h3>
&lt;p>This feature lets admins specify which endpoints are allowed for anonymous requests. For example, the admin
can choose to only allow anonymous access to health endpoints like &lt;code>/healthz&lt;/code>, &lt;code>/livez&lt;/code>, and &lt;code>/readyz&lt;/code> while
making sure preventing anonymous access to other cluster endpoints or resources even if a user
misconfigures RBAC.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4633">KEP #4633&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-auth">SIG
Auth&lt;/a>.&lt;/p>
&lt;h3 id="per-plugin-callback-functions-for-accurate-requeueing-in-kube-scheduler-enhancements">Per-plugin callback functions for accurate requeueing in kube-scheduler enhancements&lt;/h3>
&lt;p>This feature enhances scheduling throughput with more efficient scheduling retry decisions by
per-plugin callback functions (QueueingHint). All plugins now have QueueingHints.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4247">KEP #4247&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-scheduling">SIG
Scheduling&lt;/a>.&lt;/p>
&lt;h3 id="recover-from-volume-expansion-failure">Recover from volume expansion failure&lt;/h3>
&lt;p>This feature lets users recover from volume expansion failure by retrying with a smaller size. This enhancement ensures
that volume expansion is more resilient and reliable, reducing the risk of data loss or corruption during the process.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/1790">KEP #1790&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">SIG
Storage&lt;/a>.&lt;/p>
&lt;h3 id="volume-group-snapshot">Volume group snapshot&lt;/h3>
&lt;p>This feature introduces a VolumeGroupSnapshot API, which lets users take a snapshot of multiple volumes together, ensuring data consistency across the volumes.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3476">KEP #3476&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">SIG
Storage&lt;/a>.&lt;/p>
&lt;h3 id="structured-parameter-support">Structured parameter support&lt;/h3>
&lt;p>The core part of Dynamic Resource Allocation (DRA), the structured parameter support, got promoted to beta.
This allows the kube-scheduler and Cluster Autoscaler to simulate claim allocation directly, without needing a
third-party driver.
These components can now predict whether resource requests can be fulfilled based on the cluster's current state without actually
committing to the allocation. By eliminating the need for a third-party driver to validate or test allocations, this
feature improves planning and decision-making for resource distribution, making the scheduling and scaling processes
more efficient.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4381">KEP #4381&lt;/a>, by WG Device
Management (a cross functional team containing &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a>,
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-scheduling">SIG Scheduling&lt;/a> and &lt;a href="https://github.com/kubernetes/community/tree/master/sig-autoscaling">SIG
Autoscaling&lt;/a>).&lt;/p>
&lt;h3 id="label-and-field-selector-authorization">Label and field selector authorization&lt;/h3>
&lt;p>Label and field selectors can be used in authorization decisions. The node authorizer
automatically takes advantage of this to limit nodes to list or watch their pods only.
Webhook authorizers can be updated to limit requests based on the label or field selector used.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4601">KEP #4601&lt;/a>
by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-auth">SIG Auth&lt;/a>.&lt;/p>
&lt;h2 id="highlights-of-new-features-in-alpha">Highlights of new features in Alpha&lt;/h2>
&lt;p>&lt;em>This is a selection of key improvements introduced as alpha features in the v1.32 release.&lt;/em>&lt;/p>
&lt;h3 id="asynchronous-preemption-in-the-kubernetes-scheduler">Asynchronous preemption in the Kubernetes Scheduler&lt;/h3>
&lt;p>The Kubernetes scheduler has been enhanced with Asynchronous Preemption, a feature that improves scheduling throughput
by handling preemption operations asynchronously. Preemption ensures higher-priority pods get the resources they need by
evicting lower-priority ones, but this process previously involved heavy operations like API calls to delete pods,
slowing down the scheduler. With this enhancement, such tasks are now processed in parallel, allowing the scheduler to
continue scheduling other pods without delays.
This improvement is particularly beneficial in clusters with high Pod churn or frequent scheduling failures, ensuring a
more efficient and resilient scheduling process.&lt;/p>
&lt;p>This work was done as a part of KEP &lt;a href="https://github.com/kubernetes/enhancements/issues/4832">#4832&lt;/a>
by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-scheduling">SIG Scheduling&lt;/a>.&lt;/p>
&lt;h3 id="mutating-admission-policies-using-cel-expressions">Mutating admission policies using CEL expressions&lt;/h3>
&lt;p>This feature leverages CEL's object instantiation and JSON Patch strategies, combined with Server Side Apply’s merge
algorithms. It simplifies policy definition, reduces mutation conflicts, and enhances admission control performance
while laying a foundation for more robust, extensible policy frameworks in Kubernetes.&lt;/p>
&lt;p>The Kubernetes API server now supports Common Expression Language (CEL)-based Mutating Admission Policies, providing a
lightweight, efficient alternative to mutating admission webhooks. With this enhancement, administrators can use CEL to
declare mutations like setting labels, defaulting fields, or injecting sidecars with simple, declarative expressions.
This approach reduces operational complexity, eliminates the need for webhooks, and integrates directly with the
kube-apiserver, offering faster and more reliable in-process mutation handling.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3962">KEP #3962&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-api-machinery">SIG API
Machinery&lt;/a>.&lt;/p>
&lt;h3 id="pod-level-resource-specifications">Pod-level resource specifications&lt;/h3>
&lt;p>This enhancement simplifies resource management in Kubernetes by introducing the ability to set resource requests and
limits at the Pod level, creating a shared pool that all containers in the Pod can dynamically use. This is particularly
valuable for workloads with containers that have fluctuating or bursty resource needs, as it minimizes over-provisioning
and improves overall resource efficiency.&lt;/p>
&lt;p>By leveraging Linux cgroup settings at the Pod level, Kubernetes ensures that these resource limits are enforced while
enabling tightly coupled containers to collaborate more effectively without hitting artificial constraints. Importantly,
this feature maintains backward compatibility with existing container-level resource settings, allowing users to adopt
it incrementally without disrupting current workflows or existing configurations.&lt;/p>
&lt;p>This marks a significant improvement for multi-container pods, as it reduces the operational complexity of managing
resource allocations across containers. It also provides a performance boost for tightly integrated applications, such
as sidecar architectures, where containers share workloads or depend on each other’s availability to perform optimally.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/2837">KEP #2837&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG
Node&lt;/a>.&lt;/p>
&lt;h3 id="allow-zero-value-for-sleep-action-of-prestop-hook">Allow zero value for sleep action of PreStop hook&lt;/h3>
&lt;p>This enhancement introduces the ability to set a zero-second sleep duration for the PreStop lifecycle hook in
Kubernetes, offering a more flexible and no-op option for resource validation and customization. Previously, attempting
to define a zero value for the sleep action resulted in validation errors, restricting its use. With this update, users
can configure a zero-second duration as a valid sleep setting, enabling immediate execution and termination behaviors
where needed.&lt;/p>
&lt;p>The enhancement is backward-compatible, introduced as an opt-in feature controlled by the
&lt;code>PodLifecycleSleepActionAllowZero&lt;/code> feature gate. This change is particularly beneficial for scenarios requiring PreStop
hooks for validation or admission webhook processing without requiring an actual sleep duration. By aligning with the
capabilities of the &lt;code>time.After&lt;/code> Go function, this update simplifies configuration and expands usability for Kubernetes
workloads.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4818">KEP #4818&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG
Node&lt;/a>.&lt;/p>
&lt;h3 id="dra-standardized-network-interface-data-for-resource-claim-status">DRA: Standardized network interface data for resource claim status&lt;/h3>
&lt;p>This enhancement adds a new field that allows drivers to report specific device status data for each allocated object
in a ResourceClaim. It also establishes a standardized way to represent networking devices information.&lt;/p>
&lt;p>This work was done as a part of
&lt;a href="https://github.com/kubernetes/enhancements/issues/4817">KEP #4817&lt;/a>, by
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-network">SIG Network&lt;/a>.&lt;/p>
&lt;h3 id="new-statusz-and-flagz-endpoints-for-core-components">New statusz and flagz endpoints for core components&lt;/h3>
&lt;p>You can enable two new HTTP endpoints, &lt;code>/statusz&lt;/code> and &lt;code>/flagz&lt;/code>, for core components.
These enhance cluster debuggability by gaining insight into what versions (e.g. Golang version) that component is
running as, along with details about its uptime, and which command line flags that component was executed with;
making it easier to diagnose both runtime and configuration issues.&lt;/p>
&lt;p>This work was done as part of
&lt;a href="https://github.com/kubernetes/enhancements/issues/4827">KEP #4827&lt;/a>
and &lt;a href="https://github.com/kubernetes/enhancements/issues/4828">KEP #4828&lt;/a> by
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-instrumentation">SIG Instrumentation&lt;/a>.&lt;/p>
&lt;h3 id="windows-strikes-back">Windows strikes back!&lt;/h3>
&lt;p>Support for graceful shutdowns of Windows nodes in Kubernetes clusters has been added.
Before this release, Kubernetes provided graceful node shutdown functionality for Linux nodes
but lacked equivalent support for Windows. This enhancement enables the kubelet on Windows nodes to handle system
shutdown events properly. Doing so, it ensures that Pods running on Windows nodes are gracefully terminated,
allowing workloads to be rescheduled without disruption. This improvement enhances the reliability and stability
of clusters that include Windows nodes, especially during a planned maintenance or any system updates.&lt;/p>
&lt;p>Moreover CPU and memory affinity support has been added for Windows nodes with nodes, with improvements
to the CPU manager, memory manager and topology manager.&lt;/p>
&lt;p>This work was done respectively as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4802">KEP #4802&lt;/a>
and &lt;a href="https://github.com/kubernetes/enhancements/issues/4885">KEP #4885&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-windows">SIG
Windows&lt;/a>.&lt;/p>
&lt;h2 id="graduations-deprecations-and-removals-in-1-32">Graduations, deprecations, and removals in 1.32&lt;/h2>
&lt;h3 id="graduations-to-stable">Graduations to Stable&lt;/h3>
&lt;p>This lists all the features that graduated to stable (also known as &lt;em>general availability&lt;/em>). For a full list of updates
including new features and graduations from alpha to beta, see the release notes.&lt;/p>
&lt;p>This release includes a total of 13 enhancements promoted to Stable:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3221">Structured Authorization Configuration&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4193">Bound service account token improvements&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4358">Custom Resource Field Selectors&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4420">Retry Generate Name&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/1860">Make Kubernetes aware of the LoadBalancer behaviour&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/2681">Field &lt;code>status.hostIPs&lt;/code> added for Pod&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4292">Custom profile in kubectl debug&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/1769">Memory Manager&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/1967">Support to size memory backed volumes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3545">Improved multi-numa alignment in Topology Manager&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4026">Add job creation timestamp to job annotations&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4017">Add Pod Index Label for StatefulSets and Indexed Jobs&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/1847">Auto remove PVCs created by StatefulSet&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="deprecations-and-removals">Deprecations and removals&lt;/h3>
&lt;p>As Kubernetes develops and matures, features may be deprecated, removed, or replaced with better ones for the project's
overall health.
See the Kubernetes &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-policy/">deprecation and removal policy&lt;/a> for more details on
this process.&lt;/p>
&lt;h4 id="withdrawal-of-the-old-dra-implementation">Withdrawal of the old DRA implementation&lt;/h4>
&lt;p>The enhancement &lt;a href="https://github.com/kubernetes/enhancements/issues/3063">#3063&lt;/a> introduced Dynamic Resource Allocation
(DRA) in Kubernetes 1.26.&lt;/p>
&lt;p>However, in Kubernetes v1.32, this approach to DRA will be significantly changed. Code related to the original
implementation will be removed, leaving KEP &lt;a href="https://github.com/kubernetes/enhancements/issues/4381">#4381&lt;/a> as the &amp;quot;new&amp;quot;
base functionality.&lt;/p>
&lt;p>The decision to change the existing approach originated from its incompatibility with cluster autoscaling as resource
availability was non-transparent, complicating decision-making for both Cluster Autoscaler and controllers.
The newly added Structured Parameter model substitutes the functionality.&lt;/p>
&lt;p>This removal will allow Kubernetes to handle new hardware requirements and resource claims more predictably, bypassing
the complexities of back and forth API calls to the kube-apiserver.&lt;/p>
&lt;p>See the enhancement issue &lt;a href="https://github.com/kubernetes/enhancements/issues/3063">#3063&lt;/a> to find out more.&lt;/p>
&lt;h4 id="api-removals">API removals&lt;/h4>
&lt;p>There is one API removal in &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-32">Kubernetes v1.32&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>The &lt;code>flowcontrol.apiserver.k8s.io/v1beta3&lt;/code> API version of FlowSchema and PriorityLevelConfiguration has been removed.
To prepare for this, you can edit your existing manifests and rewrite client software to use the
&lt;code>flowcontrol.apiserver.k8s.io/v1 API&lt;/code> version, available since v1.29.
All existing persisted objects are accessible via the new API. Notable changes in flowcontrol.apiserver.k8s.io/v1beta3
include that the PriorityLevelConfiguration &lt;code>spec.limited.nominalConcurrencyShares&lt;/code> field only defaults to 30 when
unspecified, and an explicit value of 0 is not changed to 30.&lt;/li>
&lt;/ul>
&lt;p>For more information, refer to the &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-32">API deprecation guide&lt;/a>.&lt;/p>
&lt;h3 id="release-notes-and-upgrade-actions-required">Release notes and upgrade actions required&lt;/h3>
&lt;p>Check out the full details of the Kubernetes v1.32 release in our &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.32.md">release
notes&lt;/a>.&lt;/p>
&lt;h2 id="availability">Availability&lt;/h2>
&lt;p>Kubernetes v1.32 is available for download on &lt;a href="https://github.com/kubernetes/kubernetes/releases/tag/v1.32.0">GitHub&lt;/a> or
on the &lt;a href="https://kubernetes.io/releases/download/">Kubernetes download page&lt;/a>.&lt;/p>
&lt;p>To get started with Kubernetes, check out these &lt;a href="https://kubernetes.io/docs/tutorials/">interactive tutorials&lt;/a> or run local Kubernetes
clusters using &lt;a href="https://minikube.sigs.k8s.io/">minikube&lt;/a>. You can also easily install v1.32 using
&lt;a href="https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/">kubeadm&lt;/a>.&lt;/p>
&lt;h2 id="release-team">Release team&lt;/h2>
&lt;p>Kubernetes is only possible with the support, commitment, and hard work of its community.
Each release team is made up of dedicated community volunteers who work together to build the many pieces that make up
the Kubernetes releases you rely on.
This requires the specialized skills of people from all corners of our community, from the code itself to its
documentation and project management.&lt;/p>
&lt;p>We would like to thank the entire &lt;a href="https://github.com/kubernetes/sig-release/blob/master/releases/release-1.32/release-team.md">release
team&lt;/a> for the hours spent
hard at work to deliver the Kubernetes v1.32 release to our community.
The Release Team's membership ranges from first-time shadows to returning team leads with experience forged over several
release cycles.
A very special thanks goes out our release lead, Frederico Muñoz, for leading the release team so gracefully and handle
any matter with the uttermost care, making sure this release was executed smoothly and efficiently.
Last but not least a big thanks goes to all the release members - leads and shadows alike - and to the following SIGs
for the terrific work and outcome achieved during these 14 weeks of release work:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/kubernetes/community/tree/master/sig-docs">SIG Docs&lt;/a> - for the fundamental support in docs and
blog reviews and continous collaboration with release Comms and Docs;&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/community/tree/master/sig-k8s-infra">SIG k8s Infra&lt;/a> and &lt;a href="https://github.com/kubernetes/community/tree/master/sig-testing">SIG
Testing&lt;/a> - for the outstanding work in keeping the
testing framework in check, along with all the infra components necessary;&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/community/tree/master/sig-release">SIG Release&lt;/a> and
all the release managers - for the incredible support provided throughout the orchestration of the entire release,
addressing even the most challenging issues in a graceful and timely manner.&lt;/li>
&lt;/ul>
&lt;h2 id="project-velocity">Project velocity&lt;/h2>
&lt;p>The CNCF K8s &lt;a href="https://k8s.devstats.cncf.io/d/11/companies-contributing-in-repository-groups?orgId=1&amp;var-period=m&amp;var-repogroup_name=All">DevStats
project&lt;/a>
aggregates a number of interesting data points related to the velocity of Kubernetes and various sub-projects. This
includes everything from individual contributions to the number of companies that are contributing and is an
illustration of the depth and breadth of effort that goes into evolving this ecosystem.&lt;/p>
&lt;p>In the v1.32 release cycle, which ran for 14 weeks (September 9th to December 11th), we saw contributions to Kubernetes
from as many as 125 different companies and 559 individuals as of writing.&lt;/p>
&lt;p>In the whole Cloud Native ecosystem, the figure goes up to 433 companies counting 2441 total contributors. This sees an
increase of 7% more overall contributions compared to the &lt;a href="https://kubernetes.io/blog/2024/08/13/kubernetes-v1-31-release/#project-velocity">previous
release&lt;/a> cycle, along with 14%
increase in the number of companies involved, showcasing strong interest and community behind the Cloud Native projects.&lt;/p>
&lt;p>Source for this data:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://k8s.devstats.cncf.io/d/11/companies-contributing-in-repository-groups?orgId=1&amp;from=1725832800000&amp;to=1733961599000&amp;var-period=d28&amp;var-repogroup_name=Kubernetes&amp;var-repo_name=kubernetes%2Fkubernetes">Companies contributing to
Kubernetes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://k8s.devstats.cncf.io/d/11/companies-contributing-in-repository-groups?orgId=1&amp;from=1725832800000&amp;to=1733961599000&amp;var-period=d28&amp;var-repogroup_name=All&amp;var-repo_name=kubernetes%2Fkubernetes">Overall ecosystem
contributions&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>By contribution we mean when someone makes a commit, code review, comment, creates an issue or PR, reviews a PR
(including blogs and documentation) or comments on issues and PRs.&lt;/p>
&lt;p>If you are interested in contributing visit &lt;a href="https://www.kubernetes.dev/docs/guide/#getting-started">Getting Started&lt;/a> on
our contributor website.&lt;/p>
&lt;p>&lt;a href="https://k8s.devstats.cncf.io/d/11/companies-contributing-in-repository-groups?orgId=1&amp;var-period=m&amp;var-repogroup_name=All">Check out
DevStats&lt;/a>
to learn more about the overall velocity of the Kubernetes project and community.&lt;/p>
&lt;h2 id="event-updates">Event updates&lt;/h2>
&lt;p>Explore the upcoming Kubernetes and cloud-native events from March to June 2025, featuring KubeCon and KCD Stay informed
and engage with the Kubernetes community.&lt;/p>
&lt;p>&lt;strong>March 2025&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Beijing, China&lt;/strong>&lt;/a>: In March | Beijing, China&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Guadalajara, Mexico&lt;/strong>&lt;/a>: March 16, 2025 | Guadalajara,
Mexico&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Rio de Janeiro, Brazil&lt;/strong>&lt;/a>: March 22, 2025 | Rio de
Janeiro, Brazil&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>April 2025&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-europe">&lt;strong>KubeCon + CloudNativeCon Europe 2025&lt;/strong>&lt;/a>: April
1-4, 2025 | London, United Kingdom&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Budapest, Hungary&lt;/strong>&lt;/a>: April 23, 2025 | Budapest,
Hungary&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Chennai, India&lt;/strong>&lt;/a>: April 26, 2025 | Chennai, India&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Auckland, New Zealand&lt;/strong>&lt;/a>: April 28, 2025 | Auckland,
New Zealand&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>May 2025&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Helsinki, Finland&lt;/strong>&lt;/a>: May 6, 2025 | Helsinki, Finland&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: San Francisco, USA&lt;/strong>&lt;/a>: May 8, 2025 | San Francisco, USA&lt;/li>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-kcd-texas-presents-kcd-texas-austin-2025/">&lt;strong>KCD - Kubernetes Community Days: Austin,
USA&lt;/strong>&lt;/a>: May 15, 2025 | Austin,
USA&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Seoul, South Korea&lt;/strong>&lt;/a>: May 22, 2025 | Seoul, South
Korea&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Istanbul, Turkey&lt;/strong>&lt;/a>: May 23, 2025 | Istanbul, Turkey&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Heredia, Costa Rica&lt;/strong>&lt;/a>: May 31, 2025 | Heredia, Costa
Rica&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: New York, USA&lt;/strong>&lt;/a>: In May | New York, USA&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>June 2025&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Bratislava, Slovakia&lt;/strong>&lt;/a>: June 5, 2025 | Bratislava,
Slovakia&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Bangalore, India&lt;/strong>&lt;/a>: June 6, 2025 | Bangalore, India&lt;/li>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-china/">&lt;strong>KubeCon + CloudNativeCon China 2025&lt;/strong>&lt;/a>: June
10-11, 2025 | Hong Kong&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Antigua Guatemala, Guatemala&lt;/strong>&lt;/a>: June 14, 2025 |
Antigua Guatemala, Guatemala&lt;/li>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-japan">&lt;strong>KubeCon + CloudNativeCon Japan 2025&lt;/strong>&lt;/a>: June
16-17, 2025 | Tokyo, Japan&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/kcds/">&lt;strong>KCD - Kubernetes Community Days: Nigeria, Africa&lt;/strong>&lt;/a>: June 19, 2025 | Nigeria, Africa&lt;/li>
&lt;/ul>
&lt;h2 id="upcoming-release-webinar">Upcoming release webinar&lt;/h2>
&lt;p>Join members of the Kubernetes v1.32 release team on &lt;strong>Thursday, January 9th 2025 at 5:00 PM (UTC)&lt;/strong>, to learn about the
release highlights of this release, as well as deprecations and removals to help plan for upgrades.
For more information and registration, visit the &lt;a href="https://community.cncf.io/events/details/cncf-cncf-online-programs-presents-cncf-live-webinar-kubernetes-132-release/">event
page&lt;/a>
on the CNCF Online Programs site.&lt;/p>
&lt;h2 id="get-involved">Get involved&lt;/h2>
&lt;p>The simplest way to get involved with Kubernetes is by joining one of the many &lt;a href="https://www.kubernetes.dev/community/community-groups/#special-interest-groups">Special Interest
Groups&lt;/a> (SIGs) that align with your
interests.
Have something you’d like to broadcast to the Kubernetes community?
Share your voice at our weekly &lt;a href="https://github.com/kubernetes/community/tree/master/communication">community meeting&lt;/a>,
and through the channels below.
Thank you for your continued feedback and support.&lt;/p>
&lt;ul>
&lt;li>Follow us on Bluesky &lt;a href="https://bsky.app/profile/did:plc:kyg4uikmq7lzpb76ugvxa6ul">@Kubernetes.io&lt;/a> for latest updates&lt;/li>
&lt;li>Join the community discussion on &lt;a href="https://discuss.kubernetes.io/">Discuss&lt;/a>&lt;/li>
&lt;li>Join the community on &lt;a href="http://slack.k8s.io/">Slack&lt;/a>&lt;/li>
&lt;li>Post questions (or answer questions) on &lt;a href="http://stackoverflow.com/questions/tagged/kubernetes">Stack Overflow&lt;/a>&lt;/li>
&lt;li>Share your Kubernetes
&lt;a href="https://docs.google.com/a/linuxfoundation.org/forms/d/e/1FAIpQLScuI7Ye3VQHQTwBASrgkjQDSS5TP0g3AXfFhwSM9YpHgxRKFA/viewform">story&lt;/a>&lt;/li>
&lt;li>Read more about what’s happening with Kubernetes on the &lt;a href="https://kubernetes.io/blog/">blog&lt;/a>&lt;/li>
&lt;li>Learn more about the &lt;a href="https://github.com/kubernetes/sig-release/tree/master/release-team">Kubernetes Release Team&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Gateway API v1.2: WebSockets, Timeouts, Retries, and More</title><link>https://kubernetes.io/blog/2024/11/21/gateway-api-v1-2/</link><pubDate>Thu, 21 Nov 2024 09:00:00 -0800</pubDate><guid>https://kubernetes.io/blog/2024/11/21/gateway-api-v1-2/</guid><description>
&lt;p>&lt;img alt="Gateway API logo" src="https://kubernetes.io/blog/2024/11/21/gateway-api-v1-2/gateway-api-logo.svg">&lt;/p>
&lt;p>Kubernetes SIG Network is delighted to announce the general availability of
&lt;a href="https://gateway-api.sigs.k8s.io/">Gateway API&lt;/a> v1.2! This version of the API
was released on October 3, and we're delighted to report that we now have a
number of conformant implementations of it for you to try out.&lt;/p>
&lt;p>Gateway API v1.2 brings a number of new features to the &lt;em>Standard channel&lt;/em>
(Gateway API's GA release channel), introduces some new experimental features,
and inaugurates our new release process — but it also brings two breaking
changes that you'll want to be careful of.&lt;/p>
&lt;h2 id="breaking-changes">Breaking changes&lt;/h2>
&lt;h3 id="grpcroute-and-referencegrant-v1alpha2-removal">GRPCRoute and ReferenceGrant &lt;code>v1alpha2&lt;/code> removal&lt;/h3>
&lt;p>Now that the &lt;code>v1&lt;/code> versions of GRPCRoute and ReferenceGrant have graduated to
Standard, the old &lt;code>v1alpha2&lt;/code> versions have been removed from both the Standard
and Experimental channels, in order to ease the maintenance burden that
perpetually supporting the old versions would place on the Gateway API
community.&lt;/p>
&lt;p>Before upgrading to Gateway API v1.2, you'll want to confirm that any
implementations of Gateway API have been upgraded to support the v1 API
version of these resources instead of the v1alpha2 API version. Note that even
if you've been using v1 in your YAML manifests, a controller may still be
using v1alpha2 which would cause it to fail during this upgrade. Additionally,
Kubernetes itself goes to some effort to stop you from removing a CRD version
that it thinks you're using: check out the &lt;a href="https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.2.0">release notes&lt;/a> for more
information about what you need to do to safely upgrade.&lt;/p>
&lt;h3 id="status-supported-features">Change to &lt;code>.status.supportedFeatures&lt;/code> (experimental)&lt;/h3>
&lt;p>A much smaller breaking change: &lt;code>.status.supportedFeatures&lt;/code> in a Gateway is
now a list of objects instead of a list of strings. The objects have a single
&lt;code>name&lt;/code> field, so the translation from the strings is straightforward, but
moving to objects permits a lot more flexibility for the future. This stanza
is not yet present in the Standard channel.&lt;/p>
&lt;h2 id="graduations-to-the-standard-channel">Graduations to the standard channel&lt;/h2>
&lt;p>Gateway API 1.2.0 graduates four features to the Standard channel, meaning
that they can now be considered generally available. Inclusion in the Standard
release channel denotes a high level of confidence in the API surface and
provides guarantees of backward compatibility. Of course, as with any other
Kubernetes API, Standard channel features can continue to evolve with
backward-compatible additions over time, and we certainly expect further
refinements and improvements to these new features in the future. For more
information on how all of this works, refer to the &lt;a href="https://gateway-api.sigs.k8s.io/concepts/versioning/">Gateway API Versioning
Policy&lt;/a>.&lt;/p>
&lt;h3 id="httproute-timeouts">HTTPRoute timeouts&lt;/h3>
&lt;p>&lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-1742/">GEP-1742&lt;/a> introduced the
&lt;code>timeouts&lt;/code> stanza into HTTPRoute, permitting configuring basic timeouts for
HTTP traffic. This is a simple but important feature for proper resilience
when handling HTTP traffic, and it is now Standard.&lt;/p>
&lt;p>For example, this HTTPRoute configuration sets a timeout of 300ms for traffic
to the &lt;code>/face&lt;/code> path:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gateway.networking.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>HTTPRoute&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>face-with-timeouts&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>faces&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">parentRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>my-gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">rules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">matches&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">path&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PathPrefix&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">value&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/face&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backendRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>face&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">timeouts&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">request&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>300ms&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For more information, check out the &lt;a href="https://gateway-api.sigs.k8s.io/guides/http-routing/">HTTP routing&lt;/a> documentation. (Note that
this applies only to HTTPRoute timeouts. GRPCRoute timeouts are not yet part
of Gateway API.)&lt;/p>
&lt;h3 id="gateway-infrastructure-labels-and-annotations">Gateway infrastructure labels and annotations&lt;/h3>
&lt;p>Gateway API implementations are responsible for creating the backing
infrastructure needed to make each Gateway work. For example, implementations
running in a Kubernetes cluster often create Services and Deployments, while
cloud-based implementations may be creating cloud load balancer resources. In
many cases, it can be helpful to be able to propagate labels or annotations to
these generated resources.&lt;/p>
&lt;p>In v1.2.0, the Gateway &lt;code>infrastructure&lt;/code> stanza moves to the Standard channel,
allowing you to specify labels and annotations for the infrastructure created
by the Gateway API controller. For example, if your Gateway infrastructure is
running in-cluster, you can specify both Linkerd and Istio injection using the
following Gateway configuration, making it simpler for the infrastructure to
be incorporated into whichever service mesh you've installed:&lt;/p>
&lt;pre tabindex="0">&lt;code>apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: meshed-gateway
namespace: incoming
spec:
gatewayClassName: meshed-gateway-class
listeners:
- name: http-listener
protocol: HTTP
port: 80
infrastructure:
labels:
istio-injection: enabled
annotations:
linkerd.io/inject: enabled
&lt;/code>&lt;/pre>&lt;p>For more information, check out the
&lt;a href="https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure">&lt;code>infrastructure&lt;/code> API reference&lt;/a>.&lt;/p>
&lt;h3 id="backend-protocol-support">Backend protocol support&lt;/h3>
&lt;p>Since Kubernetes v1.20, the Service and EndpointSlice resources have supported
a stable &lt;code>appProtocol&lt;/code> field to allow users to specify the L7 protocol that
Service supports. With the adoption of
&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/3726-standard-application-protocols">KEP 3726&lt;/a>,
Kubernetes now supports three new &lt;code>appProtocol&lt;/code> values:&lt;/p>
&lt;dl>
&lt;dt>&lt;code>kubernetes.io/h2c&lt;/code>&lt;/dt>
&lt;dd>HTTP/2 over cleartext as described in &lt;a href="https://www.rfc-editor.org/rfc/rfc7540">RFC7540&lt;/a>&lt;/dd>
&lt;dt>&lt;code>kubernetes.io/ws&lt;/code>&lt;/dt>
&lt;dd>WebSocket over cleartext as described in &lt;a href="https://www.rfc-editor.org/rfc/rfc6445">RFC6445&lt;/a>&lt;/dd>
&lt;dt>&lt;code>kubernetes.io/wss&lt;/code>&lt;/dt>
&lt;dd>WebSocket over TLS as described in &lt;a href="https://www.rfc-editor.org/rfc/rfc6445">RFC6445&lt;/a>&lt;/dd>
&lt;/dl>
&lt;p>With Gateway API 1.2.0, support for honoring &lt;code>appProtocol&lt;/code> is now Standard.
For example, given the following Service:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Service&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>websocket-service&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>my-namespace&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">selector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">app.kubernetes.io/name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>websocket-app&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">ports&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>http&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">targetPort&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">9376&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">protocol&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>TCP&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">appProtocol&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>kubernetes.io/ws&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>then an HTTPRoute that includes this Service as a &lt;code>backendRef&lt;/code> will
automatically upgrade the connection to use WebSockets rather than assuming
that the connection is pure HTTP.&lt;/p>
&lt;p>For more information, check out
&lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-1911/">GEP-1911&lt;/a>.&lt;/p>
&lt;h2 id="new-additions-to-experimental-channel">New additions to experimental channel&lt;/h2>
&lt;h3 id="named-rules-for-route-resources">Named rules for *Route resources&lt;/h3>
&lt;p>The &lt;code>rules&lt;/code> field in HTTPRoute and GRPCRoute resources can now be named, in
order to make it easier to reference the specific rule, for example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gateway.networking.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>HTTPRoute&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>multi-color-route&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>faces&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">parentRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>my-gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">rules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>center-rule&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matches&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">path&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PathPrefix&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">value&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/color/center&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backendRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color-center&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>edge-rule&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matches&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">path&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PathPrefix&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">value&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/color/edge&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backendRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color-edge&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Logging or status messages can now refer to these two rules as &lt;code>center-rule&lt;/code>
or &lt;code>edge-rule&lt;/code> instead of being forced to refer to them by index. For more
information, see &lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-995/">GEP-995&lt;/a>.&lt;/p>
&lt;h3 id="httproute-retry-support">HTTPRoute retry support&lt;/h3>
&lt;p>Gateway API 1.2.0 introduces experimental support for counted HTTPRoute
retries. For example, the following HTTPRoute configuration retries requests
to the &lt;code>/face&lt;/code> path up to 3 times with a 500ms delay between retries:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gateway.networking.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>HTTPRoute&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>face-with-retries&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>faces&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">parentRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>my-gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">rules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">matches&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">path&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PathPrefix&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">value&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/face&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backendRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>face&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">retry&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">codes&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">500&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">502&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">503&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">504&lt;/span>&lt;span style="color:#bbb"> &lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">attempts&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">3&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backoff&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>500ms&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For more information, check out &lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-1731">GEP
1731&lt;/a>.&lt;/p>
&lt;h3 id="httproute-percentage-based-mirroring">HTTPRoute percentage-based mirroring&lt;/h3>
&lt;p>Gateway API has long supported the
&lt;a href="https://gateway-api.sigs.k8s.io/guides/http-request-mirroring/">Request Mirroring&lt;/a>
feature, which allows sending the same request to multiple backends. In
Gateway API 1.2.0, we're introducing percentage-based mirroring, which allows
you to specify a percentage of requests to mirror to a different backend. For
example, the following HTTPRoute configuration mirrors 42% of requests to the
&lt;code>color-mirror&lt;/code> backend:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gateway.networking.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>HTTPRoute&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color-mirror-route&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>faces&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">parentRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>mirror-gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">hostnames&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- mirror.example&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">rules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">backendRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">filters&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>RequestMirror&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requestMirror&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backendRef&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color-mirror&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">percent&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">42&lt;/span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># This value must be an integer.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There's also a &lt;code>fraction&lt;/code> stanza which can be used in place of &lt;code>percent&lt;/code>, to
allow for more precise control over exactly what amount of traffic is
mirrored, for example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>...&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">filters&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>RequestMirror&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requestMirror&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">backendRef&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color-mirror&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">fraction&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">numerator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">1&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">denominator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">10000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This configuration mirrors 1 in 10,000 requests to the &lt;code>color-mirror&lt;/code> backend,
which may be relevant with very high request rates. For more details, see
&lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-3171">GEP-1731&lt;/a>.&lt;/p>
&lt;h3 id="additional-backend-tls-configuration">Additional backend TLS configuration&lt;/h3>
&lt;p>This release includes three additions related to TLS configuration for
communications between a Gateway and a workload (a &lt;em>backend&lt;/em>):&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>A new &lt;code>backendTLS&lt;/code> field on Gateway&lt;/strong>&lt;/p>
&lt;p>This new field allows you to specify the client certificate that a Gateway
should use when connecting to backends.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>A new &lt;code>subjectAltNames&lt;/code> field on BackendTLSPolicy&lt;/strong>&lt;/p>
&lt;p>Previously, the &lt;code>hostname&lt;/code> field was used to configure both the SNI that a
Gateway should send to a backend &lt;em>and&lt;/em> the identity that should be provided
by a certificate. When the new &lt;code>subjectAltNames&lt;/code> field is specified, any
certificate matching at least one of the specified SANs will be considered
valid. This is particularly critical for SPIFFE where URI-based SANs may
not be valid SNIs.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>A new &lt;code>options&lt;/code> field on BackendTLSPolicy&lt;/strong>&lt;/p>
&lt;p>Similar to the TLS options field on Gateway Listeners, we believe the same
concept will be broadly useful for TLS-specific configuration for Backend
TLS.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>For more information, check out
&lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-3155">GEP-3135&lt;/a>.&lt;/p>
&lt;h2 id="more-changes">More changes&lt;/h2>
&lt;p>For a full list of the changes included in this release, please refer to the
&lt;a href="https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.2.0">v1.2.0 release notes&lt;/a>.&lt;/p>
&lt;h2 id="project-updates">Project updates&lt;/h2>
&lt;p>Beyond the technical, the v1.2 release also marks a few milestones in the life
of the Gateway API project itself.&lt;/p>
&lt;h3 id="release-process-improvements">Release process improvements&lt;/h3>
&lt;p>Gateway API has never been intended to be a static API, and as more projects
use it as a component to build on, it's become clear that we need to bring
some more predictability to Gateway API releases. To that end, we're pleased -
and a little nervous! - to announce that we've formalized a new release
process:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Scoping&lt;/strong> (4-6 weeks): maintainers and community determine the set of
features we want to include in the release. A particular emphasis here is
getting features &lt;em>out&lt;/em> of the Experimental channel — ideally this involves
moving them to Standard, but it can also mean removing them.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>GEP Iteration and Review&lt;/strong> (5-7 weeks): contributors write or update
Gateway Enhancement Proposals (GEPs) for features accepted into the release,
with emphasis on getting consensus around the design and graduation criteria
of the feature.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>API Refinement and Documentation&lt;/strong> (3-5 weeks): contributors implement the
features in the Gateway API controllers and write the necessary
documentation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>SIG Network Review and Release Candidates&lt;/strong> (2-4 weeks): maintainers get
the required upstream review, build release candidates, and release the new
version.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Gateway API 1.2.0 was the first release to use the new process, and although
there are the usual rough edges of anything new, we believe that it went well.
We've already completed the Scoping phase for Gateway API 1.3, with the
release expected around the end of January 2025.&lt;/p>
&lt;h3 id="gwctl-moves-out">&lt;code>gwctl&lt;/code> moves out&lt;/h3>
&lt;p>The &lt;code>gwctl&lt;/code> CLI tool has moved into its very own repository,
&lt;a href="https://github.com/kubernetes-sigs/gwctl">https://github.com/kubernetes-sigs/gwctl&lt;/a>. &lt;code>gwctl&lt;/code> has proven a valuable tool
for the Gateway API community; moving it into its own repository will, we
believe, make it easier to maintain and develop. As always, we welcome
contributions; while still experimental, &lt;code>gwctl&lt;/code> already helps make working
with Gateway API a bit easier — especially for newcomers to the project!&lt;/p>
&lt;h3 id="maintainer-changes">Maintainer changes&lt;/h3>
&lt;p>Rounding out our changes to the project itself, we're pleased to announce that
&lt;a href="https://github.com/mlavacca">Mattia Lavacca&lt;/a> has joined the ranks of Gateway API Maintainers! We're also
sad to announce that &lt;a href="https://github.com/keithmattix">Keith Mattix&lt;/a> has stepped down as a GAMMA lead —
happily, &lt;a href="https://github.com/mikemorris">Mike Morris&lt;/a> has returned to the role. We're grateful for everything
Keith has done, and excited to have Mattia and Mike on board.&lt;/p>
&lt;h2 id="try-it-out">Try it out&lt;/h2>
&lt;p>Unlike other Kubernetes APIs, you don't need to upgrade to the latest version of
Kubernetes to get the latest version of Gateway API. As long as you're running
Kubernetes 1.26 or later, you'll be able to get up and running with this
version of Gateway API.&lt;/p>
&lt;p>To try out the API, follow our &lt;a href="https://gateway-api.sigs.k8s.io/guides/">Getting Started
Guide&lt;/a>. As of this writing, five
implementations are already conformant with Gateway API v1.2. In alphabetical
order:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/cilium/cilium">Cilium v1.17.0-pre.1&lt;/a>, Experimental channel&lt;/li>
&lt;li>&lt;a href="https://github.com/envoyproxy/gateway">Envoy Gateway v1.2.0-rc.1&lt;/a>, Experimental channel&lt;/li>
&lt;li>&lt;a href="https://istio.io">Istio v1.24.0-alpha.0&lt;/a>, Experimental channel&lt;/li>
&lt;li>&lt;a href="https://github.com/kong/kubernetes-ingress-controller">Kong v3.2.0-244-gea4944bb0&lt;/a>, Experimental channel&lt;/li>
&lt;li>&lt;a href="https://traefik.io">Traefik v3.2&lt;/a>, Experimental channel&lt;/li>
&lt;/ul>
&lt;h2 id="get-involved">Get involved&lt;/h2>
&lt;p>There are lots of opportunities to get involved and help define the future of
Kubernetes routing APIs for both ingress and service mesh.&lt;/p>
&lt;ul>
&lt;li>Check out the &lt;a href="https://gateway-api.sigs.k8s.io/guides">user guides&lt;/a> to see what use-cases can be addressed.&lt;/li>
&lt;li>Try out one of the &lt;a href="https://gateway-api.sigs.k8s.io/implementations/">existing Gateway controllers&lt;/a>.&lt;/li>
&lt;li>Or &lt;a href="https://gateway-api.sigs.k8s.io/contributing/">join us in the community&lt;/a>
and help us build the future of Gateway API together!&lt;/li>
&lt;/ul>
&lt;p>The maintainers would like to thank &lt;em>everyone&lt;/em> who's contributed to Gateway
API, whether in the form of commits to the repo, discussion, ideas, or general
support. We could never have gotten this far without the support of this
dedicated and active community.&lt;/p>
&lt;h2 id="related-kubernetes-blog-articles">Related Kubernetes blog articles&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://kubernetes.io/blog/2024/05/09/gateway-api-v1-1/">Gateway API v1.1: Service mesh, GRPCRoute, and a whole lot more&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/11/28/gateway-api-ga/">New Experimental Features in Gateway API v1.0&lt;/a>
11/2023&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/10/31/gateway-api-ga/">Gateway API v1.0: GA Release&lt;/a>
10/2023&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/10/25/introducing-ingress2gateway/">Introducing ingress2gateway; Simplifying Upgrades to Gateway API&lt;/a>
10/2023&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/08/29/gateway-api-v0-8/">Gateway API v0.8.0: Introducing Service Mesh Support&lt;/a>
08/2023&lt;/li>
&lt;/ul></description></item><item><title>How we built a dynamic Kubernetes API Server for the API Aggregation Layer in Cozystack</title><link>https://kubernetes.io/blog/2024/11/21/dynamic-kubernetes-api-server-for-cozystack/</link><pubDate>Thu, 21 Nov 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/11/21/dynamic-kubernetes-api-server-for-cozystack/</guid><description>
&lt;p>Hi there! I'm Andrei Kvapil, but you might know me as &lt;a href="https://github.com/kvaps">@kvaps&lt;/a> in communities dedicated to Kubernetes
and cloud-native tools. In this article, I want to share how we implemented our own extension api-server
in the open-source PaaS platform, Cozystack.&lt;/p>
&lt;p>Kubernetes truly amazes me with its powerful extensibility features. You're probably already
familiar with the &lt;a href="https://kubernetes.io/docs/concepts/architecture/controller/">controller&lt;/a> concept
and frameworks like &lt;a href="https://book.kubebuilder.io/">kubebuilder&lt;/a> and
&lt;a href="https://sdk.operatorframework.io/">operator-sdk&lt;/a> that help you implement it. In a nutshell, they
allow you to extend your Kubernetes cluster by defining custom resources (CRDs) and writing additional
controllers that handle your business logic for reconciling and managing these kinds of resources.
This approach is well-documented, with a wealth of information available online on how to develop your
own operators.&lt;/p>
&lt;p>However, this is not the only way to
&lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/#api-extensions">extend the Kubernetes API&lt;/a>.
For more complex scenarios such as implementing imperative logic,
managing subresources, and dynamically generating responses—the Kubernetes API &lt;em>aggregation layer&lt;/em>
provides an effective alternative. Through the aggregation layer, you can develop a custom
extension API server and seamlessly integrate it within the broader Kubernetes API framework.&lt;/p>
&lt;p>In this article, I will explore the API aggregation layer, the types of challenges it is well-suited
to address, cases where it may be less appropriate, and how we utilized this model to implement
our own extension API server in Cozystack.&lt;/p>
&lt;h2 id="what-is-the-api-aggregation-layer">What Is the API Aggregation Layer?&lt;/h2>
&lt;p>First, let's get definitions straight to avoid any confusion down the road.
The &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/">API aggregation layer&lt;/a>
is a feature in Kubernetes, while an extension api-server is a specific implementation of an
API server for the aggregation layer. An extension API server is just like the standard Kubernetes API server, except it runs separately and handles requests for your specific resource types.&lt;/p>
&lt;p>So, the aggregation layer lets you write your own extension API server, integrate it easily into Kubernetes,
and directly process requests for resources in a certain group. Unlike the CRD mechanism, the extension API
is registered in Kubernetes as an APIService, telling Kubernetes to consider this new API server and acknowledge
that it serves certain APIs.&lt;/p>
&lt;p>You can execute this command to list all registered apiservices:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl get apiservices.apiregistration.k8s.io
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Example APIService:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME SERVICE AVAILABLE AGE
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">v1alpha1.apps.cozystack.io cozy-system/cozystack-api True 7h29m
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As soon as the Kubernetes api-server receives requests for resources in the group
&lt;code>v1alpha1.apps.cozystack.io&lt;/code>, it redirects all those requests to our extension api-server,
which can handle them based on the business logic we've built into it.&lt;/p>
&lt;h2 id="when-to-use-the-api-aggregation-layer">When to use the API Aggregation Layer&lt;/h2>
&lt;p>The API Aggregation Layer helps solve several issues where the usual CRD mechanism might
not enough. Let's break them down.&lt;/p>
&lt;h3 id="imperative-logic-and-subresources">Imperative Logic and Subresources&lt;/h3>
&lt;p>Besides regular resources, Kubernetes also has something called subresources.&lt;/p>
&lt;p>In Kubernetes, subresources are additional actions or operations you can perform on primary resources
(like Pods, Deployments, Services) via the Kubernetes API. They provide interfaces to manage
specific aspects of resources without affecting the entire object.&lt;/p>
&lt;p>A simple example is &lt;code>status&lt;/code>, which is traditionally exposed as a separate subresource that you can
access independently from the parent object. The &lt;code>status&lt;/code> field isn't meant to be changed&lt;/p>
&lt;p>But beyond &lt;code>/status&lt;/code>, Pods in Kubernetes also have subresources like &lt;code>/exec&lt;/code>, &lt;code>/portforward&lt;/code>, and
&lt;code>/log&lt;/code>. Interestingly, instead of the usual declarative resources in Kubernetes, these represent
endpoints for imperative operations like viewing logs, proxying connections, executing commands in
a running container, and so on.&lt;/p>
&lt;p>To support such imperative commands on your own API, you need implement an extension API and an
extension API server. Here are some well-known examples:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>KubeVirt&lt;/strong>: An add-on for Kubernetes that extends its API capabilities to run traditional virtual machines.
The extension api-server created as part of KubeVirt handles subresources
like &lt;code>/restart&lt;/code>, &lt;code>/console&lt;/code>, and &lt;code>/vnc&lt;/code> for virtual machines.&lt;/li>
&lt;li>&lt;strong>Knative&lt;/strong>: A Kubernetes add-on that extends its capabilities for serverless computing,
implementing the &lt;code>/scale&lt;/code> subresource to set up autoscaling for its resource types.&lt;/li>
&lt;/ul>
&lt;p>By the way, even though subresource logic in Kubernetes can be &lt;em>imperative&lt;/em>, you can manage access
to them &lt;em>declaratively&lt;/em> using Kubernetes standard RBAC model.&lt;/p>
&lt;p>For example this way you can control access to the &lt;code>/log&lt;/code> and &lt;code>/exec&lt;/code> subresources of the Pod kind:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Role&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>rbac.authorization.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>default&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>pod-and-pod-logs-reader&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">rules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#008000;font-weight:bold">apiGroups&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#b44">&amp;#34;&amp;#34;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">resources&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#b44">&amp;#34;pods&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;pods/log&amp;#34;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">verbs&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#b44">&amp;#34;get&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;list&amp;#34;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#008000;font-weight:bold">apiGroups&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#b44">&amp;#34;&amp;#34;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">resources&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#b44">&amp;#34;pods/exec&amp;#34;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">verbs&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#b44">&amp;#34;create&amp;#34;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="you-re-not-tied-to-use-etcd">You're not tied to use etcd&lt;/h3>
&lt;p>Usually, the Kubernetes API server uses &lt;a href="https://etcd.io/">etcd&lt;/a> for its backend.
However, implementing your own API server doesn't lock you into using only etcd.
If it doesn't make sense to store your server's state in etcd, you can store information in any
other system and generate responses on the fly. Here are a few cases to illustrate:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes-sigs/metrics-server">metrics-server&lt;/a> is a standard extension for Kubernetes
which allows you to view real-time metrics of your nodes and pods. It defines alternative Pod and Node
kinds in its own metrics.k8s.io API. Requests to these resources are translated into metrics
directly from Kubelet. So when you run &lt;code>kubectl top node&lt;/code> or &lt;code>kubectl top pod&lt;/code>, metrics-server fetches
metrics from cAdvisor in real-time. It then returns these metrics to you. Since the information
is generated in real-time and is only relevant at the moment of the request, there is no need
to store it in etcd. This approach saves resources.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>If needed, you can use a backend other than etcd. You can even implement a Kubernetes-compatible API
for it. For example, if you use Postgres, you can create a transparent representation of its entities
in the Kubernetes API. Eg. databases, users, and grants within Postgres would appear as regular
Kubernetes resources, thanks to your extension API server. You could manage them using &lt;code>kubectl&lt;/code> or any
other Kubernetes-compatible tool. Unlike controllers, which implement business logic using custom resources
and reconciliation methods, an extension API server eliminates the need for separate controllers for every kind.
This means you don't have to sync state between the Kubernetes API and your backend.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="one-time-resources">One-Time resources&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>Kubernetes has a special API used to provide users with information about their permissions.
This is implemented using the SelfSubjectAccessReview API. One unusual detail of these
resources is that you can't view them using &lt;strong>get&lt;/strong> or &lt;strong>list&lt;/strong> verbs. You can only create them (using
the &lt;strong>create&lt;/strong> verb) and receive output with information about what you have access to at that
moment.&lt;/p>
&lt;p>If you try to run &lt;code>kubectl get selfsubjectaccessreviews&lt;/code> directly, you'll just get an error
like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">Error from server (MethodNotAllowed): the server does not allow this method on the requested resource
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The reason is that the Kubernetes API server doesn't support any other interaction with this
type of resource (you can only CREATE them).&lt;/p>
&lt;p>The SelfSubjectAccessReview API supports commands such as:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl auth can-i create deployments --namespace dev
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>When you run the command above, &lt;code>kubectl&lt;/code> creates a SelfSubjectAccessReview using the
Kubernetes API. This allows Kubernetes to fetch a list of possible permissions for your user.
Kubernetes then generates a personalized response to your request in real-time. This logic is
different from a scenario where this resource is simply stored in etcd.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Similarly, in KubeVirt's &lt;a href="https://github.com/kubevirt/containerized-data-importer">CDI (Containerized Data Importer)&lt;/a>
extension, which allows file uploads into a PVC from a local machine using the &lt;code>virtctl&lt;/code> tool,
a special token is required before the upload process begins.
This token is generated by creating an UploadTokenRequest resource via the Kubernetes API. Kubernetes
routes (proxies) all UploadTokenRequest resource creation requests to the CDI extension API server,
which generates and returns the token in response.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="full-control-over-conversion-validation-and-output-formatting">Full control over conversion, validation, and output formatting&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>Your own API server can have all the capabilities of the vanilla Kubernetes API server. The resources you create
in your API server can be validated immediately on the server side without additional webhooks.
While CRDs also support server-side validation using &lt;a href="https://kubernetes.io/docs/reference/using-api/cel/">Common Expression Language (CEL)&lt;/a>
for declarative validation and &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/">ValidatingAdmissionPolicies&lt;/a>
without the need for webhooks, a custom API server allows for more complex and tailored validation logic if needed.&lt;/p>
&lt;p>Kubernetes allows you to serve multiple API versions for each resource type, traditionally
&lt;code>v1alpha1&lt;/code>, &lt;code>v1beta1&lt;/code> and &lt;code>v1&lt;/code>. Only one version can be specified as the storage version.
All requests to other versions must be automatically converted to the version specified as storage version.
With CRDs, this mechanism is implemented using conversion webhooks. Whereas in an extension API server,
you can implement your own conversion mechanism, choose to mix up different storage versions (one
object might be serialized as &lt;code>v1&lt;/code>, another as &lt;code>v2&lt;/code>), or rely on an external backing API.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Directly implementing the Kubernetes API lets you format table output however you like and doesn't force you to follow
the &lt;code>additionalPrinterColumns&lt;/code> logic in CRDs. Instead, you can write your own formatter that
formats the table output and custom fields in it. For example, when using &lt;code>additionalPrinterColumns&lt;/code>,
you can display field values only following the JSONPath logic. In your own API server, you can generate
and insert values on the fly, formatting the table output as you wish.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="dynamic-resource-registration">Dynamic resource registration&lt;/h3>
&lt;ul>
&lt;li>The resources served by an extension api-server don't need to be pre-registered as CRDs.
Once your extension API server is registered using an APIService, Kubernetes starts polling it to discover
APIs and resources it can serve. After receiving a discovery response, the Kubernetes API server automatically
registers all available types for this API group.
Although this isn't considered common practice, you can implement logic that dynamically registers
the resource types you need in your Kubernetes cluster.&lt;/li>
&lt;/ul>
&lt;h2 id="when-not-to-use-the-api-aggregation-layer">When not to use the API Aggregation Layer&lt;/h2>
&lt;p>There are some anti-patterns where using the API Aggregation Layer isn't recommended.
Let's go through them.&lt;/p>
&lt;h3 id="unstable-backend">Unstable backend&lt;/h3>
&lt;p>If your API server stops responding for some reason due to an unavailable backend or other issues it
may block some Kubernetes functionality. For example, when deleting namespaces, Kubernetes will wait
for a response from your API server to see if there are any remaining resources.
If the response doesn't come, the namespace deletion will be blocked.&lt;/p>
&lt;p>Also, you might have encountered a &lt;a href="https://github.com/kedacore/keda/issues/4224">situation&lt;/a> where,
when the metrics-server is unavailable, an extra message appears in stderr after every API request
(even unrelated to metrics) stating that &lt;code>metrics.k8s.io&lt;/code> is unavailable. This is another example
of how using the API Aggregation Layer can lead to problems when the api-server handling requests
is unavailable.&lt;/p>
&lt;h3 id="slow-requests">Slow requests&lt;/h3>
&lt;p>If you can't guarantee an instant response for user requests, it's better to consider using a
CustomResourceDefinition and controller.
Otherwise, you might make your cluster less stable. Many projects implement an extension
API server only for a limited set of resources, particularly for imperative logic and subresources.
This recommendation is also
&lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/#response-latency">mentioned&lt;/a>
in the official Kubernetes
documentation.&lt;/p>
&lt;h2 id="why-we-needed-it-in-cozystack">Why we needed it in Cozystack&lt;/h2>
&lt;p>As a reminder, we're developing the open-source PaaS platform &lt;a href="https://cozystack.io/">Cozystack&lt;/a>,
which can also be used as a framework for building your own private cloud. Therefore, the ability
to easily extend the platform is crucial for us.&lt;/p>
&lt;p>Cozystack is built on top of &lt;a href="https://fluxcd.io/">FluxCD&lt;/a>. Any application is packaged into its
own Helm chart, ready for deployment in a tenant namespace. Deploying any application on the platform
is done by creating a HelmRelease resource, specifying the chart name and parameters for the application.
All the rest logic is handled by FluxCD. This pattern allows us to easily extend the platform with new
applications and provide the ability to create new applications that just need to be packaged
into the appropriate Helm chart.&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2024/11/21/dynamic-kubernetes-api-server-for-cozystack/cozystack.png"
alt="Interface of the Cozystack platform"/> &lt;figcaption>
&lt;p>Interface of the Cozystack platform&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>So, in our platform, everything is configured as HelmRelease resources. However, we ran into
two problems: limitations of the RBAC model and the need for a public API. Let's delve into these&lt;/p>
&lt;h3 id="limitations-of-the-rbac-model">Limitations of the RBAC model&lt;/h3>
&lt;p>The widely-deployed RBAC system in Kubernetes doesn't allow you to restrict access to a list of resources
of the same kind based on labels or specific fields in the spec. When creating a role, you can limit
access across the resources in the same kind only by specifying specific resource names in &lt;code>resourceNames&lt;/code>.
For verbs like &lt;strong>get&lt;/strong> or &lt;strong>update&lt;/strong> it will work. However, filtering by &lt;code>resourceNames&lt;/code> using &lt;strong>list&lt;/strong>
verb doesn't work like that. Thus you can limit listing certain resources by kind but not by name.&lt;/p>
&lt;ul>
&lt;li>Kubernetes has a special API used to provide users with information about their permissions.
This is implemented using the SelfSubjectAccessReview API. One unusual detail of these
resources is that you can't view them using &lt;strong>get&lt;/strong> or &lt;strong>list&lt;/strong> verbs. You can only create them (using
the &lt;strong>create&lt;/strong> verb) and receive output with information about what you have access to at that
moment.&lt;/li>
&lt;/ul>
&lt;p>So, we decided to introduce new resource types based on the names of the Helm charts they use and
generate the list of available kinds dynamically at runtime in our extension api-server.
This way, we can reuse Kubernetes standard RBAC model to manage access to specific resource types.&lt;/p>
&lt;h3 id="need-for-a-public-api">Need for a public API&lt;/h3>
&lt;p>Since our platform provides capabilities for deploying various managed services, we want to organize
public access to the platform's API. However, we can't allow users to interact directly with resources
like HelmRelease because that would let them specify arbitrary names and parameters for Helm charts to
deploy, potentially compromising our system.&lt;/p>
&lt;p>We wanted to give users the ability to deploy a specific service simply by creating the resource with corresponding
kind in Kubernetes. The type of this resource should be named the same as the chart from
which it's deployed. Here are some examples:&lt;/p>
&lt;ul>
&lt;li>&lt;code>kind: Kubernetes&lt;/code> → &lt;code>chart: kubernetes&lt;/code>&lt;/li>
&lt;li>&lt;code>kind: Postgres&lt;/code> → &lt;code>chart: postgres&lt;/code>&lt;/li>
&lt;li>&lt;code>kind: Redis&lt;/code> → &lt;code>chart: redis&lt;/code>&lt;/li>
&lt;li>&lt;code>kind: VirtualMachine&lt;/code> → &lt;code>chart: virtual-machine&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Moreover, we don't want to have to add a new type to codegen and recompile our extension API server
every time we add a new chart for it to start being served.
The schema update should be done dynamically or provided via a ConfigMap by the administrator.&lt;/p>
&lt;h3 id="two-way-conversion">Two-Way conversion&lt;/h3>
&lt;p>Currently, we already have integrations and a dashboard that continue to use HelmRelease resources.
At this stage, we didn't want to lose the ability to support this API. Considering that we're simply
translating one resource into another, support is maintained and it works both ways.
If you create a HelmRelease, you'll get a custom resource in Kubernetes, and if you create a
custom resource in Kubernetes, it will also be available as a HelmRelease.&lt;/p>
&lt;p>We don't have any additional controllers that synchronize state between these resources.
All requests to resources in our extension API server are transparently proxied to HelmRelease and vice versa.
This eliminates intermediate states and the need to write controllers and synchronization logic.&lt;/p>
&lt;h2 id="implementation">Implementation&lt;/h2>
&lt;p>To implement the Aggregation API, you might consider starting with the following projects:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/kubernetes-sigs/apiserver-builder-alpha">apiserver-builder&lt;/a>:
Currently in alpha and hasn't been updated for two years. It works like kubebuilder,
providing a framework for creating an extension API server, allowing you to sequentially create
a project structure and generate code for your resources.&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/sample-apiserver">sample-apiserver&lt;/a>:
A ready-made example of an implemented API server, based on official Kubernetes libraries,
which you can use as a foundation for your project.&lt;/li>
&lt;/ul>
&lt;p>For practical reasons, we chose the second project. Here's what we needed to do:&lt;/p>
&lt;h3 id="disable-etcd-support">Disable etcd support&lt;/h3>
&lt;p>In our case, we don't need it since all resources are stored directly in the Kubernetes API.&lt;/p>
&lt;p>You can disable etcd options by passing nil to &lt;code>RecommendedOptions.Etcd&lt;/code>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/pkg/cmd/server/start.go#L70">Disabling etcd options&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="generate-a-common-resource-kind">Generate a common resource kind&lt;/h3>
&lt;p>We called it Application, and it looks like this:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/pkg/apis/apps/v1alpha1/types.go">Application type definition&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>This is a generic type used for any application type, and its handling logic is the same for all charts.&lt;/p>
&lt;h3 id="configure-configuration-loading">Configure configuration loading&lt;/h3>
&lt;p>Since we want to configure our extension api-server via a config file, we formed the config structure in Go:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/pkg/config/config.go">Config type definition&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>We also modified the resource registration logic so that the resources we create are registered in scheme with different &lt;code>Kind&lt;/code> values:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/pkg/apis/apps/v1alpha1/register.go#L63-L77">Dynamic resource registration&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>As a result, we got a config where you can pass all possible types and specify what they should map to:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/packages/system/cozystack-api/templates/configmap.yaml">ConfigMap example&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="implement-our-own-registry">Implement our own registry&lt;/h3>
&lt;p>To store state not in etcd but translate it directly into Kubernetes HelmRelease resources (and vice versa),
we wrote conversion functions from Application to HelmRelease and from HelmRelease to Application:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/pkg/registry/apps/application/rest.go#L920-L991">Conversion functions&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>We implemented logic to filter resources by chart name, &lt;code>sourceRef&lt;/code>, and prefix in the HelmRelease name:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/pkg/registry/apps/application/rest.go#L747-L784">Filtering functions&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Then, using this logic, we implemented the methods &lt;code>Get()&lt;/code>, &lt;code>Delete()&lt;/code>, &lt;code>List()&lt;/code>, &lt;code>Create()&lt;/code>.&lt;/p>
&lt;p>You can see the full example here:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/aenix-io/cozystack/blob/003edf8cf0a419bd67cd822d61ff806db49e7026/pkg/registry/apps/application/rest.go">Registry Implementation&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>At the end of each method, we set the correct &lt;code>Kind&lt;/code> and return an &lt;code>unstructured.Unstructured{}&lt;/code> object
so that Kubernetes serializes the object correctly. Otherwise,
it would always serialize them with &lt;code>kind: Application&lt;/code>, which we don't want.&lt;/p>
&lt;h2 id="what-did-we-achieve">What did we achieve?&lt;/h2>
&lt;p>In Cozystack, all our types from the ConfigMap are now available in Kubernetes as-is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl api-resources | grep cozystack
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">buckets apps.cozystack.io/v1alpha1 true Bucket
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">clickhouses apps.cozystack.io/v1alpha1 true ClickHouse
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">etcds apps.cozystack.io/v1alpha1 true Etcd
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">ferretdb apps.cozystack.io/v1alpha1 true FerretDB
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">httpcaches apps.cozystack.io/v1alpha1 true HTTPCache
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">ingresses apps.cozystack.io/v1alpha1 true Ingress
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">kafkas apps.cozystack.io/v1alpha1 true Kafka
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">kuberneteses apps.cozystack.io/v1alpha1 true Kubernetes
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">monitorings apps.cozystack.io/v1alpha1 true Monitoring
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">mysqls apps.cozystack.io/v1alpha1 true MySQL
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">natses apps.cozystack.io/v1alpha1 true NATS
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">postgreses apps.cozystack.io/v1alpha1 true Postgres
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">rabbitmqs apps.cozystack.io/v1alpha1 true RabbitMQ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">redises apps.cozystack.io/v1alpha1 true Redis
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">seaweedfses apps.cozystack.io/v1alpha1 true SeaweedFS
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">tcpbalancers apps.cozystack.io/v1alpha1 true TCPBalancer
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">tenants apps.cozystack.io/v1alpha1 true Tenant
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">virtualmachines apps.cozystack.io/v1alpha1 true VirtualMachine
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vmdisks apps.cozystack.io/v1alpha1 true VMDisk
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vminstances apps.cozystack.io/v1alpha1 true VMInstance
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vpns apps.cozystack.io/v1alpha1 true VPN
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can work with them just like regular Kubernetes resources.&lt;/p>
&lt;p>Listing S3 Buckets:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl get buckets.apps.cozystack.io -n tenant-kvaps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Example output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME READY AGE VERSION
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">foo True 22h 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">testaasd True 27h 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Listing Kubernetes Clusters:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl get kuberneteses.apps.cozystack.io -n tenant-kvaps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Example output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME READY AGE VERSION
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">abc False 19h 0.14.0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">asdte True 22h 0.13.0
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Listing Virtual Machine Disks:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl get vmdisks.apps.cozystack.io -n tenant-kvaps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Example output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME READY AGE VERSION
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">docker True 21d 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">test True 18d 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">win2k25-iso True 21d 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">win2k25-system True 21d 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Listing Virtual Machine Instances:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl get vminstances.apps.cozystack.io -n tenant-kvaps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Example output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME READY AGE VERSION
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">docker True 21d 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">test True 18d 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">win2k25 True 20d 0.1.0
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can create, modify, and delete each of them, and any interaction with them will be translated
into HelmRelease resources, while also applying the resource structure and prefix in the name.&lt;/p>
&lt;p>To see all related Helm releases:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl get helmreleases -n tenant-kvaps -l cozystack.io/ui
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Example output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">NAME AGE READY
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">bucket-foo 22h True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">bucket-testaasd 27h True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">kubernetes-abc 19h False
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">kubernetes-asdte 22h True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">redis-test 18d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">redis-yttt 12d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vm-disk-docker 21d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vm-disk-test 18d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vm-disk-win2k25-iso 21d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vm-disk-win2k25-system 21d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vm-instance-docker 21d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vm-instance-test 18d True
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">vm-instance-win2k25 20d True
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>We don’t intend to stop here with our API. In the future, we plan to add new features:&lt;/p>
&lt;ul>
&lt;li>Add validation based on an OpenAPI spec generated directly from Helm charts.&lt;/li>
&lt;li>Develop a controller that collects release notes from deployed releases and shows users
access information for specific services.&lt;/li>
&lt;li>Revamp our dashboard to work directly with the new API.&lt;/li>
&lt;/ul>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>The API Aggregation Layer allowed us to quickly and efficiently solve our problem by providing
a flexible mechanism for extending the Kubernetes API with dynamically registered resources and
converting them on the fly. Ultimately, this made our platform even more flexible and extensible
without the need to write code for each new resource.&lt;/p>
&lt;p>You can test the API yourself in the open-source PaaS platform Cozystack,
starting from &lt;a href="https://github.com/aenix-io/cozystack/releases/tag/v0.18.0">version v0.18&lt;/a>.&lt;/p></description></item><item><title>Kubernetes v1.32 sneak peek</title><link>https://kubernetes.io/blog/2024/11/08/kubernetes-1-32-upcoming-changes/</link><pubDate>Fri, 08 Nov 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/11/08/kubernetes-1-32-upcoming-changes/</guid><description>
&lt;p>As we get closer to the release date for Kubernetes v1.32, the project develops and matures.
Features may be deprecated, removed, or replaced with better ones for the project's overall health.&lt;/p>
&lt;p>This blog outlines some of the planned changes for the Kubernetes v1.32 release,
that the release team feels you should be aware of, for the continued maintenance
of your Kubernetes environment and keeping up to date with the latest changes.
Information listed below is based on the current status of the v1.32 release
and may change before the actual release date.&lt;/p>
&lt;h2 id="the-kubernetes-api-removal-and-deprecation-process">The Kubernetes API removal and deprecation process&lt;/h2>
&lt;p>The Kubernetes project has a well-documented &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-policy/">deprecation policy&lt;/a>
for features. This policy states that stable APIs may only be deprecated when a newer,
stable version of that API is available and that APIs have a minimum lifetime for each stability level.
A deprecated API has been marked for removal in a future Kubernetes release will continue to function until
removal (at least one year from the deprecation). Its usage will result in a warning being displayed.
Removed APIs are no longer available in the current version, so you must migrate to use the replacement instead.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Generally available (GA) or stable API versions may be marked as deprecated but must not be removed within a major version of Kubernetes.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Beta or pre-release API versions must be supported for 3 releases after the deprecation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Alpha or experimental API versions may be removed in any release without prior deprecation notice;
this process can become a withdrawal in cases where a different implementation for the same feature is already in place.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Whether an API is removed due to a feature graduating from beta to stable or because that API did not succeed,
all removals comply with this deprecation policy. Whenever an API is removed,
migration options are communicated in the &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/">deprecation guide&lt;/a>.&lt;/p>
&lt;h2 id="note-on-the-withdrawal-of-the-old-dra-implementation">Note on the withdrawal of the old DRA implementation&lt;/h2>
&lt;p>The enhancement &lt;a href="https://github.com/kubernetes/enhancements/issues/3063">#3063&lt;/a>
introduced Dynamic Resource Allocation (DRA) in Kubernetes 1.26.&lt;/p>
&lt;p>However, in Kubernetes v1.32, this approach to DRA will be significantly changed.
Code related to the original implementation will be removed, leaving KEP
&lt;a href="https://github.com/kubernetes/enhancements/issues/4381">#4381&lt;/a> as the &amp;quot;new&amp;quot; base functionality.&lt;/p>
&lt;p>The decision to change the existing approach originated from its incompatibility with cluster autoscaling
as resource availability was non-transparent, complicating decision-making for both Cluster Autoscaler and controllers.
The newly added Structured Parameter model substitutes the functionality.&lt;/p>
&lt;p>This removal will allow Kubernetes to handle new hardware requirements and resource claims more predictably,
bypassing the complexities of back and forth API calls to the kube-apiserver.&lt;/p>
&lt;p>Please also see the enhancement issue &lt;a href="https://github.com/kubernetes/enhancements/issues/3063">#3063&lt;/a> to find out more.&lt;/p>
&lt;h2 id="api-removal">API removal&lt;/h2>
&lt;p>There is only a single API removal planned for &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-32">Kubernetes v1.32&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>The &lt;code>flowcontrol.apiserver.k8s.io/v1beta3&lt;/code> API version of FlowSchema and PriorityLevelConfiguration has been removed.
To prepare for this, you can edit your existing manifests and rewrite client software to use the
&lt;code>flowcontrol.apiserver.k8s.io/v1 API&lt;/code> version, available since v1.29.
All existing persisted objects are accessible via the new API. Notable changes in &lt;code>flowcontrol.apiserver.k8s.io/v1beta3&lt;/code>
include that the PriorityLevelConfiguration &lt;code>spec.limited.nominalConcurrencyShares&lt;/code> field only defaults to 30 when unspecified,
and an explicit value of 0 is not changed to 30.&lt;/li>
&lt;/ul>
&lt;p>For more information, please refer to the &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-32">API deprecation guide&lt;/a>.&lt;/p>
&lt;h2 id="sneak-peek-of-kubernetes-v1-32">Sneak peek of Kubernetes v1.32&lt;/h2>
&lt;p>The following list of enhancements is likely to be included in the v1.32 release.
This is not a commitment and the release content is subject to change.&lt;/p>
&lt;h3 id="even-more-dra-enhancements">Even more DRA enhancements!&lt;/h3>
&lt;p>In this release, like the previous one, the Kubernetes project continues proposing a number
of enhancements to the Dynamic Resource Allocation (DRA), a key component of the Kubernetes resource management system.
These enhancements aim to improve the flexibility and efficiency of resource allocation for workloads that require specialized hardware,
such as GPUs, FPGAs and network adapters. This release introduces improvements,
including the addition of resource health status in the Pod status, as outlined in
KEP &lt;a href="https://github.com/kubernetes/enhancements/issues/4680">#4680&lt;/a>.&lt;/p>
&lt;h4 id="add-resource-health-status-to-the-pod-status">Add resource health status to the Pod status&lt;/h4>
&lt;p>It isn't easy to know when a Pod uses a device that has failed or is temporarily unhealthy.
KEP &lt;a href="https://github.com/kubernetes/enhancements/issues/4680">#4680&lt;/a> proposes exposing device
health via Pod &lt;code>status&lt;/code>, making troubleshooting of Pod crashes easier.&lt;/p>
&lt;h3 id="windows-strikes-back">Windows strikes back!&lt;/h3>
&lt;p>KEP &lt;a href="https://github.com/kubernetes/enhancements/issues/4802">#4802&lt;/a> adds support
for graceful shutdowns of Windows nodes in Kubernetes clusters.
Before this release, Kubernetes provided graceful node shutdown functionality for
Linux nodes but lacked equivalent support for Windows.
This enhancement enables the kubelet on Windows nodes to handle system shutdown events properly.
Doing so, it ensures that Pods running on Windows nodes are gracefully terminated,
allowing workloads to be rescheduled without disruption.
This improvement enhances the reliability and stability of clusters that include Windows nodes,
especially during a planned maintenance or any system updates.&lt;/p>
&lt;h3 id="allow-special-characters-in-environment-variables">Allow special characters in environment variables&lt;/h3>
&lt;p>With the graduation of this &lt;a href="https://github.com/kubernetes/enhancements/issues/4369">enhancement&lt;/a> to beta,
Kubernetes now allows almost all printable ASCII characters (excluding &amp;quot;=&amp;quot;) to be used as environment variable names.
This change addresses the limitations previously imposed on variable naming, facilitating a broader adoption of
Kubernetes by accommodating various application needs. The relaxed validation will be enabled by default via the
&lt;code>RelaxedEnvironmentVariableValidation&lt;/code> feature gate, ensuring that users can easily utilize environment
variables without strict constraints, enhancing flexibility for developers working with applications like
.NET Core that require special characters in their configurations.&lt;/p>
&lt;h3 id="make-kubernetes-aware-of-the-loadbalancer-behavior">Make Kubernetes aware of the LoadBalancer behavior&lt;/h3>
&lt;p>KEP &lt;a href="https://github.com/kubernetes/enhancements/issues/1860">#1860&lt;/a> graduates to GA,
introducing the &lt;code>ipMode&lt;/code> field for a Service of &lt;code>type: LoadBalancer&lt;/code>, which can be set to either
&lt;code>&amp;quot;VIP&amp;quot;&lt;/code> or &lt;code>&amp;quot;Proxy&amp;quot;&lt;/code>. This enhancement is aimed at improving how cloud providers load balancers
interact with kube-proxy and it is a change transparent to the end user.
The existing behavior of kube-proxy is preserved when using &lt;code>&amp;quot;VIP&amp;quot;&lt;/code>,
where kube-proxy handles the load balancing. Using &lt;code>&amp;quot;Proxy&amp;quot;&lt;/code> results in traffic sent directly to the load balancer,
providing cloud providers greater control over relying on kube-proxy;
this means that you could see an improvement in the performance of your load balancer for some cloud providers.&lt;/p>
&lt;h3 id="retry-generate-name-for-resources">Retry generate name for resources&lt;/h3>
&lt;p>This &lt;a href="https://github.com/kubernetes/enhancements/issues/4420">enhancement&lt;/a>
improves how name conflicts are handled for Kubernetes resources created with the &lt;code>generateName&lt;/code> field.
Previously, if a name conflict occurred, the API server returned a 409 HTTP Conflict error and clients
had to manually retry the request. With this update, the API server automatically retries generating
a new name up to seven times in case of a conflict. This significantly reduces the chances of collision,
ensuring smooth generation of up to 1 million names with less than a 0.1% probability of a conflict,
providing more resilience for large-scale workloads.&lt;/p>
&lt;h2 id="want-to-know-more">Want to know more?&lt;/h2>
&lt;p>New features and deprecations are also announced in the Kubernetes release notes.
We will formally announce what's new in
&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.32.md">Kubernetes v1.32&lt;/a>
as part of the CHANGELOG for this release.&lt;/p>
&lt;p>You can see the announcements of changes in the release notes for:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md">Kubernetes v1.31&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md">Kubernetes v1.30&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md">Kubernetes v1.29&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.28.md">Kubernetes v1.28&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul></description></item><item><title>Spotlight on Kubernetes Upstream Training in Japan</title><link>https://kubernetes.io/blog/2024/10/28/k8s-upstream-training-japan-spotlight/</link><pubDate>Mon, 28 Oct 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/10/28/k8s-upstream-training-japan-spotlight/</guid><description>
&lt;p>We are organizers of &lt;a href="https://github.com/kubernetes-sigs/contributor-playground/tree/master/japan">Kubernetes Upstream Training in Japan&lt;/a>.
Our team is composed of members who actively contribute to Kubernetes, including individuals who hold roles such as member, reviewer, approver, and chair.&lt;/p>
&lt;p>Our goal is to increase the number of Kubernetes contributors and foster the growth of the community.
While Kubernetes community is friendly and collaborative, newcomers may find the first step of contributing to be a bit challenging.
Our training program aims to lower that barrier and create an environment where even beginners can participate smoothly.&lt;/p>
&lt;h2 id="what-is-kubernetes-upstream-training-in-japan">What is Kubernetes upstream training in Japan?&lt;/h2>
&lt;p>&lt;img alt="Upstream Training in 2022" src="https://kubernetes.io/blog/2024/10/28/k8s-upstream-training-japan-spotlight/ood-2022-01.png">&lt;/p>
&lt;p>Our training started in 2019 and is held 1 to 2 times a year.
Initially, Kubernetes Upstream Training was conducted as a co-located event of KubeCon (Kubernetes Contributor Summit),
but we launched Kubernetes Upstream Training in Japan with the aim of increasing Japanese contributors by hosting a similar event in Japan.&lt;/p>
&lt;p>Before the pandemic, the training was held in person, but since 2020, it has been conducted online.
The training offers the following content for those who have not yet contributed to Kubernetes:&lt;/p>
&lt;ul>
&lt;li>Introduction to Kubernetes community&lt;/li>
&lt;li>Overview of Kubernetes codebase and how to create your first PR&lt;/li>
&lt;li>Tips and encouragement to lower participation barriers, such as language&lt;/li>
&lt;li>How to set up the development environment&lt;/li>
&lt;li>Hands-on session using &lt;a href="https://github.com/kubernetes-sigs/contributor-playground">kubernetes-sigs/contributor-playground&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>At the beginning of the program, we explain why contributing to Kubernetes is important and who can contribute.
We emphasize that contributing to Kubernetes allows you to make a global impact and that Kubernetes community is looking forward to your contributions!&lt;/p>
&lt;p>We also explain Kubernetes community, SIGs, and Working Groups.
Next, we explain the roles and responsibilities of Member, Reviewer, Approver, Tech Lead, and Chair.
Additionally, we introduce the communication tools we primarily use, such as Slack, GitHub, and mailing lists.
Some Japanese speakers may feel that communicating in English is a barrier.
Additionally, those who are new to the community need to understand where and how communication takes place.
We emphasize the importance of taking that first step, which is the most important aspect we focus on in our training!&lt;/p>
&lt;p>We then go over the structure of Kubernetes codebase, the main repositories, how to create a PR, and the CI/CD process using &lt;a href="https://docs.prow.k8s.io/">Prow&lt;/a>.
We explain in detail the process from creating a PR to getting it merged.&lt;/p>
&lt;p>After several lectures, participants get to experience hands-on work using &lt;a href="https://github.com/kubernetes-sigs/contributor-playground">kubernetes-sigs/contributor-playground&lt;/a>, where they can create a simple PR.
The goal is for participants to get a feel for the process of contributing to Kubernetes.&lt;/p>
&lt;p>At the end of the program, we also provide a detailed explanation of setting up the development environment for contributing to the &lt;code>kubernetes/kubernetes&lt;/code> repository,
including building code locally, running tests efficiently, and setting up clusters.&lt;/p>
&lt;h2 id="interview-with-participants">Interview with participants&lt;/h2>
&lt;p>We conducted interviews with those who participated in our training program.
We asked them about their reasons for joining, their impressions, and their future goals.&lt;/p>
&lt;h3 id="keita-mochizuki-https-github-com-mochizuki875-ntt-data-group-corporation-https-www-nttdata-com-global-en-about-us-profile">&lt;a href="https://github.com/mochizuki875">Keita Mochizuki&lt;/a> (&lt;a href="https://www.nttdata.com/global/en/about-us/profile">NTT DATA Group Corporation&lt;/a>)&lt;/h3>
&lt;p>Keita Mochizuki is a contributor who consistently contributes to Kubernetes and related projects.
Keita is also a professional in container security and has recently published a book.
Additionally, he has made available a &lt;a href="https://github.com/mochizuki875/KubernetesFirstContributionRoadMap">Roadmap for New Contributors&lt;/a>, which is highly beneficial for those new to contributing.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> Why did you decide to participate in Kubernetes Upstream Training?&lt;/p>
&lt;p>&lt;strong>Keita:&lt;/strong> Actually, I participated twice, in 2020 and 2022.
In 2020, I had just started learning about Kubernetes and wanted to try getting involved in activities outside of work, so I signed up after seeing the event on Twitter by chance.
However, I didn't have much knowledge at the time, and contributing to OSS felt like something beyond my reach.
As a result, my understanding after the training was shallow, and I left with more of a &amp;quot;hmm, okay&amp;quot; feeling.&lt;/p>
&lt;p>In 2022, I participated again when I was at a stage where I was seriously considering starting contributions.
This time, I did prior research and was able to resolve my questions during the lectures, making it a very productive experience.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> How did you feel after participating?&lt;/p>
&lt;p>&lt;strong>Keita:&lt;/strong> I felt that the significance of this training greatly depends on the participant's mindset.
The training itself consists of general explanations and simple hands-on exercises, but it doesn't mean that attending the training will immediately lead to contributions.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> What is your purpose for contributing?&lt;/p>
&lt;p>&lt;strong>Keita:&lt;/strong> My initial motivation was to &amp;quot;gain a deep understanding of Kubernetes and build a track record,&amp;quot; meaning &amp;quot;contributing itself was the goal.&amp;quot;
Nowadays, I also contribute to address bugs or constraints I discover during my work.
Additionally, through contributing, I've become less hesitant to analyze undocumented features directly from the source code.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> What has been challenging about contributing?&lt;/p>
&lt;p>&lt;strong>Keita:&lt;/strong> The most difficult part was taking the first step. Contributing to OSS requires a certain level of knowledge, and leveraging resources like this training and support from others was essential.
One phrase that stuck with me was, &amp;quot;Once you take the first step, it becomes easier to move forward.&amp;quot;
Also, in terms of continuing contributions as part of my job, the most challenging aspect is presenting the outcomes as achievements.
To keep contributing over time, it's important to align it with business goals and strategies, but upstream contributions don't always lead to immediate results that can be directly tied to performance.
Therefore, it's crucial to ensure mutual understanding with managers and gain their support.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> What are your future goals?&lt;/p>
&lt;p>&lt;strong>Keita:&lt;/strong> My goal is to contribute to areas with a larger impact.
So far, I've mainly contributed by fixing smaller bugs as my primary focus was building a track record,
but moving forward, I'd like to challenge myself with contributions that have a greater impact on Kubernetes users or that address issues related to my work.
Recently, I've also been working on reflecting the changes I've made to the codebase into the official documentation,
and I see this as a step toward achieving my goals.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> Thank you very much!&lt;/p>
&lt;h3 id="yoshiki-fujikane-https-github-com-ffjlabo-cyberagent-inc-https-www-cyberagent-co-jp-en">&lt;a href="https://github.com/ffjlabo">Yoshiki Fujikane&lt;/a> (&lt;a href="https://www.cyberagent.co.jp/en/">CyberAgent, Inc.&lt;/a>)&lt;/h3>
&lt;p>Yoshiki Fujikane is one of the maintainers of &lt;a href="https://pipecd.dev/">PipeCD&lt;/a>, a CNCF Sandbox project.
In addition to developing new features for Kubernetes support in PipeCD,
Yoshiki actively participates in community management and speaks at various technical conferences.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> Why did you decide to participate in the Kubernetes Upstream Training?&lt;/p>
&lt;p>&lt;strong>Yoshiki:&lt;/strong> At the time I participated, I was still a student.
I had only briefly worked with EKS, but I thought Kubernetes seemed complex yet cool, and I was casually interested in it.
Back then, OSS felt like something out of reach, and upstream development for Kubernetes seemed incredibly daunting.
While I had always been interested in OSS, I didn't know where to start.
It was during this time that I learned about the Kubernetes Upstream Training and decided to take the challenge of contributing to Kubernetes.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> What were your impressions after participating?&lt;/p>
&lt;p>&lt;strong>Yoshiki:&lt;/strong> I found it extremely valuable as a way to understand what it's like to be part of an OSS community.
At the time, my English skills weren't very strong, so accessing primary sources of information felt like a big hurdle for me.
Kubernetes is a very large project, and I didn't have a clear understanding of the overall structure, let alone what was necessary for contributing.
The upstream training provided a Japanese explanation of the community structure and allowed me to gain hands-on experience with actual contributions.
Thanks to the guidance I received, I was able to learn how to approach primary sources and use them as entry points for further investigation, which was incredibly helpful.
This experience made me realize the importance of organizing and reviewing primary sources, and now I often dive into GitHub issues and documentation when something piques my interest.
As a result, while I am no longer contributing to Kubernetes itself, the experience has been a great foundation for contributing to other projects.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> What areas are you currently contributing to, and what are the other projects you're involved in?&lt;/p>
&lt;p>&lt;strong>Yoshiki:&lt;/strong> Right now, I'm no longer working with Kubernetes, but instead, I'm a maintainer of PipeCD, a CNCF Sandbox project.
PipeCD is a CD tool that supports GitOps-style deployments for various application platforms.
The tool originally started as an internal project at CyberAgent.
With different teams adopting different platforms, PipeCD was developed to provide a unified CD platform with a consistent user experience.
Currently, it supports Kubernetes, AWS ECS, Lambda, Cloud Run, and Terraform.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> What role do you play within the PipeCD team?&lt;/p>
&lt;p>&lt;strong>Yoshiki:&lt;/strong> I work full-time on improving and developing Kubernetes-related features within the team.
Since we provide PipeCD as a SaaS internally, my main focus is on adding new features and improving existing ones as part of that support.
In addition to code contributions, I also contribute by giving talks at various events and managing community meetings to help grow the PipeCD community.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> Could you explain what kind of improvements or developments you are working on with regards to Kubernetes?&lt;/p>
&lt;p>&lt;strong>Yoshiki:&lt;/strong> PipeCD supports GitOps and Progressive Delivery for Kubernetes, so I'm involved in the development of those features.
Recently, I've been working on features that streamline deployments across multiple clusters.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> Have you encountered any challenges while contributing to OSS?&lt;/p>
&lt;p>&lt;strong>Yoshiki:&lt;/strong> One challenge is developing features that maintain generality while meeting user use cases.
When we receive feature requests while operating the internal SaaS, we first consider adding features to solve those issues.
At the same time, we want PipeCD to be used by a broader audience as an OSS tool.
So, I always think about whether a feature designed for one use case could be applied to another, ensuring the software remains flexible and widely usable.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> What are your goals moving forward?&lt;/p>
&lt;p>&lt;strong>Yoshiki:&lt;/strong> I want to focus on expanding PipeCD's functionality.
Currently, we are developing PipeCD under the slogan &amp;quot;One CD for All.&amp;quot;
As I mentioned earlier, it supports Kubernetes, AWS ECS, Lambda, Cloud Run, and Terraform, but there are many other platforms out there, and new platforms may emerge in the future.
For this reason, we are currently developing a plugin system that will allow users to extend PipeCD on their own, and I want to push this effort forward.
I'm also working on features for multi-cluster deployments in Kubernetes, and I aim to continue making impactful contributions.&lt;/p>
&lt;p>&lt;strong>Junya:&lt;/strong> Thank you very much!&lt;/p>
&lt;h2 id="future-of-kubernetes-upstream-training">Future of Kubernetes upstream training&lt;/h2>
&lt;p>We plan to continue hosting Kubernetes Upstream Training in Japan and look forward to welcoming many new contributors.
Our next session is scheduled to take place at the end of November during &lt;a href="https://event.cloudnativedays.jp/cndw2024">CloudNative Days Winter 2024&lt;/a>.&lt;/p>
&lt;p>Moreover, our goal is to expand these training programs not only in Japan but also around the world.
&lt;a href="https://kubernetes.io/blog/2024/06/06/10-years-of-kubernetes/">Kubernetes celebrated its 10th anniversary&lt;/a> this year, and for the community to become even more active, it's crucial for people across the globe to continue contributing.
While Upstream Training is already held in several regions, we aim to bring it to even more places.&lt;/p>
&lt;p>We hope that as more people join Kubernetes community and contribute, our community will become even more vibrant!&lt;/p></description></item><item><title>Announcing the 2024 Steering Committee Election Results</title><link>https://kubernetes.io/blog/2024/10/02/steering-committee-results-2024/</link><pubDate>Wed, 02 Oct 2024 15:10:00 -0500</pubDate><guid>https://kubernetes.io/blog/2024/10/02/steering-committee-results-2024/</guid><description>
&lt;p>The &lt;a href="https://github.com/kubernetes/community/tree/master/elections/steering/2024">2024 Steering Committee Election&lt;/a> is now complete. The Kubernetes Steering Committee consists of 7 seats, 3 of which were up for election in 2024. Incoming committee members serve a term of 2 years, and all members are elected by the Kubernetes Community.&lt;/p>
&lt;p>This community body is significant since it oversees the governance of the entire Kubernetes project. With that great power comes great responsibility. You can learn more about the steering committee’s role in their &lt;a href="https://github.com/kubernetes/steering/blob/master/charter.md">charter&lt;/a>.&lt;/p>
&lt;p>Thank you to everyone who voted in the election; your participation helps support the community’s continued health and success.&lt;/p>
&lt;h2 id="results">Results&lt;/h2>
&lt;p>Congratulations to the elected committee members whose two year terms begin immediately (listed in alphabetical order by GitHub handle):&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Antonio Ojea (&lt;a href="https://github.com/aojea">@aojea&lt;/a>), Google&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Benjamin Elder (&lt;a href="https://github.com/bentheelder">@BenTheElder&lt;/a>), Google&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Sascha Grunert (&lt;a href="https://github.com/saschagrunert">@saschagrunert&lt;/a>), Red Hat&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>They join continuing members:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Stephen Augustus (&lt;a href="https://github.com/justaugustus">@justaugustus&lt;/a>), Cisco&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Paco Xu 徐俊杰 (&lt;a href="https://github.com/pacoxu">@pacoxu&lt;/a>), DaoCloud&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Patrick Ohly (&lt;a href="https://github.com/pohly">@pohly&lt;/a>), Intel&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Maciej Szulik (&lt;a href="https://github.com/soltysh">@soltysh&lt;/a>), Defense Unicorns&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>Benjamin Elder is a returning Steering Committee Member.&lt;/p>
&lt;h2 id="big-thanks">Big thanks!&lt;/h2>
&lt;p>Thank you and congratulations on a successful election to this round’s election officers:&lt;/p>
&lt;ul>
&lt;li>Bridget Kromhout (&lt;a href="https://github.com/bridgetkromhout">@bridgetkromhout&lt;/a>)&lt;/li>
&lt;li>Christoph Blecker (&lt;a href="https://github.com/cblecker">@cblecker&lt;/a>)&lt;/li>
&lt;li>Priyanka Saggu (&lt;a href="https://github.com/Priyankasaggu11929">@Priyankasaggu11929&lt;/a>)&lt;/li>
&lt;/ul>
&lt;p>Thanks to the Emeritus Steering Committee Members. Your service is appreciated by the community:&lt;/p>
&lt;ul>
&lt;li>Bob Killen (&lt;a href="https://github.com/mrbobbytables">@mrbobbytables&lt;/a>)&lt;/li>
&lt;li>Nabarun Pal (&lt;a href="https://github.com/palnabarun">@palnabarun&lt;/a>)&lt;/li>
&lt;/ul>
&lt;p>And thank you to all the candidates who came forward to run for election.&lt;/p>
&lt;h2 id="get-involved-with-the-steering-committee">Get involved with the Steering Committee&lt;/h2>
&lt;p>This governing body, like all of Kubernetes, is open to all. You can follow along with Steering Committee &lt;a href="https://bit.ly/k8s-steering-wd">meeting notes&lt;/a> and weigh in by filing an issue or creating a PR against their &lt;a href="https://github.com/kubernetes/steering">repo&lt;/a>. They have an open meeting on &lt;a href="https://github.com/kubernetes/steering">the first Monday at 8am PT of every month&lt;/a>. They can also be contacted at their public mailing list &lt;a href="mailto:steering@kubernetes.io">steering@kubernetes.io&lt;/a>.&lt;/p>
&lt;p>You can see what the Steering Committee meetings are all about by watching past meetings on the &lt;a href="https://www.youtube.com/playlist?list=PL69nYSiGNLP1yP1B_nd9-drjoxp0Q14qM">YouTube Playlist&lt;/a>.&lt;/p>
&lt;p>If you want to meet some of the newly elected Steering Committee members, join us for the &lt;a href="https://www.kubernetes.dev/events/2024/kcsna/schedule/#steering-ama">Steering AMA&lt;/a> at the Kubernetes Contributor Summit North America 2024 in Salt Lake City.&lt;/p>
&lt;hr>
&lt;p>&lt;em>This post was adapted from one written by the &lt;a href="https://github.com/kubernetes/community/tree/master/communication/contributor-comms">Contributor Comms Subproject&lt;/a>. If you want to write stories about the Kubernetes community, learn more about us.&lt;/em>&lt;/p></description></item><item><title>Spotlight on CNCF Deaf and Hard-of-hearing Working Group (DHHWG)</title><link>https://kubernetes.io/blog/2024/09/30/cncf-deaf-and-hard-of-hearing-working-group-spotlight/</link><pubDate>Mon, 30 Sep 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/09/30/cncf-deaf-and-hard-of-hearing-working-group-spotlight/</guid><description>
&lt;p>&lt;em>In recognition of Deaf Awareness Month and the importance of inclusivity in the tech community, we are spotlighting &lt;a href="https://www.linkedin.com/in/catherinepaganini/">Catherine Paganini&lt;/a>, facilitator and one of the founding members of &lt;a href="https://contribute.cncf.io/about/deaf-and-hard-of-hearing/">CNCF Deaf and Hard-of-Hearing Working Group&lt;/a> (DHHWG). In this interview, &lt;a href="https://www.linkedin.com/in/sandeepkanabar/">Sandeep Kanabar&lt;/a>, a deaf member of the DHHWG and part of the Kubernetes &lt;a href="https://github.com/kubernetes/community/blob/master/sig-contributor-experience/README.md#contributor-comms">SIG ContribEx Communications team&lt;/a>, sits down with Catherine to explore the impact of the DHHWG on cloud native projects like Kubernetes.&lt;/em>&lt;/p>
&lt;p>&lt;em>Sandeep’s journey is a testament to the power of inclusion. Through his involvement in the DHHWG, he connected with members of the Kubernetes community who encouraged him to join &lt;a href="https://github.com/kubernetes/community/blob/master/sig-contributor-experience/README.md">SIG ContribEx&lt;/a> - the group responsible for sustaining the Kubernetes contributor experience. In an ecosystem where open-source projects are actively seeking contributors and maintainers, this story highlights how important it is to create pathways for underrepresented groups, including those with disabilities, to contribute their unique perspectives and skills.&lt;/em>&lt;/p>
&lt;p>&lt;em>In this interview, we delve into Catherine’s journey, the challenges and triumphs of establishing the DHHWG, and the vision for a more inclusive future in cloud native. We invite Kubernetes contributors, maintainers, and community members to reflect on the &lt;strong>significance of empathy, advocacy, and community&lt;/strong> in fostering a truly inclusive environment for all, and to think about how they can support efforts to increase diversity and accessibility within their own projects.&lt;/em>&lt;/p>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>&lt;strong>Sandeep Kanabar (SK): Hello Catherine, could you please introduce yourself, share your professional background, and explain your connection to the Kubernetes ecosystem?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Catherine Paganini (CP)&lt;/strong>: I'm the Head of Marketing at &lt;a href="https://buoyant.io/">Buoyant&lt;/a>, the creator of &lt;a href="https://linkerd.io/">Linkerd&lt;/a>, the CNCF-graduated service mesh, and 5th CNCF project. Four years ago, I started contributing to open source. The initial motivation was to make cloud native concepts more accessible to newbies and non-technical people. Without a technical background, it was hard for me to understand what Kubernetes, containers, service meshes, etc. mean. All content was targeted at engineers already familiar with foundational concepts. Clearly, I couldn't be the only one struggling with wrapping my head around cloud native.&lt;/p>
&lt;p>My first contribution was the &lt;a href="https://landscape.cncf.io/guide#introduction">CNCF Landscape Guide&lt;/a>, which I co-authored with my former colleague Jason Morgan. Next, we started the &lt;a href="https://glossary.cncf.io/">CNCF Glossary&lt;/a>, which explains cloud native concepts in simple terms. Today, the glossary has been (partially) localised into 14 languages!&lt;/p>
&lt;p>Currently, I'm the co-chair of the &lt;a href="https://contribute.cncf.io/about/">TAG Contributor Strategy&lt;/a> and the Facilitator of the Deaf and Hard of Hearing Working Group (DHHWG) and Blind and Visually Impaired WG (BVIWG), which is still in formation. I'm also working on a new Linux Foundation (LF) initiative called ABIDE (Accessibility and Belonging through Inclusion, Diversity, and Equity), so stay tuned to learn more about it!&lt;/p>
&lt;h2 id="motivation-and-early-milestones">Motivation and early milestones&lt;/h2>
&lt;p>&lt;strong>SK: That's inspiring! Building on your passion for accessibility, what motivated you to facilitate the creation of the DHHWG? Was there a speecifc moment or experience that sparked this initiative?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: Last year at KubeCon Amsterdam, I learned about a great initiative by Jay Tihema that creates &lt;a href="https://contribute.cncf.io/resources/videos/2023/from-maori-to-deaf-engineers/">pathways for Maori youth into cloud native&lt;/a> and open source. While telling my CODA (children of deaf adults) high school friend about it, I thought it'd be great to create something similar for deaf folks. A few months later, I posted about it in a LinkedIn post that the CNCF shared. Deaf people started to reach out, wanting to participate. And the rest is history.&lt;/p>
&lt;p>&lt;strong>SK: Speaking of history, since its launch, how has the DHHWG evolved? Could you highlight some of the key milestones or achievements the group has reached recently?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: Our WG is about a year old. It started with a few deaf engineers and me brainstorming how to make KubeCon more accessible. We published an initial draft of &lt;a href="https://contribute.cncf.io/accessibility/deaf-and-hard-of-hearing/conference-best-practices/">Best practices for an inclusive conference&lt;/a> and shared it with the LF events team. KubeCon Chicago was two months later, and we had a couple of deaf attendees. It was the &lt;strong>first&lt;/strong> KubeCon accessible to deaf signers. &lt;a href="https://www.linkedin.com/in/destiny-o-connor-28b2a5255/">Destiny&lt;/a>, one of our co-chairs, even participated in a &lt;a href="https://youtu.be/3WJ_s4Jvbsk?si=iscthTiCyMxoMUqY&amp;t=347">keynote panel&lt;/a>. It was incredible how quickly everything happened!&lt;/p>
&lt;p>&lt;img alt="DHHWG members at KubeCon Chicago" src="https://kubernetes.io/blog/2024/09/30/cncf-deaf-and-hard-of-hearing-working-group-spotlight/cncf-dhhwg-chicago.jpg">
&lt;em>DHHWG members at KubeCon Chicago&lt;/em>&lt;/p>
&lt;p>The team has grown since then, and we've been able to do much more. With a kiosk in the project pavilion, an open space discussion, a sign language crash course, and a few media interviews, KubeCon Paris had a stronger advocacy and outreach focus. &lt;a href="https://www.youtube.com/watch?v=E8AcyqsgAyQ">Check out this video of our team in Paris&lt;/a> to get a glimpse of all the different KubeCon activities — it was such a great event! The team also launched the first CNCF Community Group in sign language, &lt;a href="https://community.cncf.io/deaf-in-cloud-native/">Deaf in Cloud Native&lt;/a>, a glossary team that creates sign language videos for each technical term to help standardize technical signs across the globe. It's crazy to think that it all happened within one year!&lt;/p>
&lt;h2 id="overcoming-challenges-and-addressing-misconceptions">Overcoming challenges and addressing misconceptions&lt;/h2>
&lt;p>&lt;strong>SK: That's remarkable progress in just a year! Building such momentum must have come with its challenges. What barriers have you encountered in facilitating the DHHWG, and how did you and the group work to overcome them?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: The support from the community, LF, and CNCF has been incredible. The fact that we achieved so much is proof of it. The challenges are more in helping some team members overcome their fear of contributing. Most are new to open source, and it can be intimidating to put your work out there for everyone to see. The fear of being criticized in public is real; however, as they will hopefully realize over time, our community is incredibly supportive. Instead of criticizing, people tend to help improve the work, leading to better outcomes.&lt;/p>
&lt;p>&lt;strong>SK: Are there any misconceptions about the deaf and hard-of-hearing community in tech that you'd like to address?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: Deaf and hard of hearing individuals are very diverse — there is no one-size-fits-all. Some deaf people are oral (speak), others sign, while some lip read or prefer captions. It generally depends on how people grew up. While some people come from deaf families and sign language is their native language, others were born into hearing families who may or may not have learned how to sign. Some deaf people grew up surrounded by hearing people, while others grew up deeply embedded in Deaf culture. Hard-of-hearing individuals, on the other hand, typically can communicate well with hearing peers one-on-one in quiet settings, but loud environments or conversations with multiple people can make it hard to follow the conversation. Most rely heavily on captions. Each background and experience will shape their communication style and preferences. In short, what works for one person, doesn't necessarily work for others. So &lt;strong>never assume&lt;/strong> and &lt;strong>always ask&lt;/strong> about accessibility needs and preferences.&lt;/p>
&lt;h2 id="impact-and-the-role-of-allies">Impact and the role of allies&lt;/h2>
&lt;p>&lt;strong>SK: Can you share some key impacts/outcomes of the conference best practices document?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: Here are the two most important ones: Captions should be on the monitor, not in an app. That's especially important during technical talks with live demos. Deaf and hard of hearing attendees will miss important information switching between captions on their phone and code on the screen.&lt;/p>
&lt;p>Interpreters are most valuable during networking, not in talks (with captions). Most people come to conferences for the hallway track. That is no different for deaf attendees. If they can't network, they are missing out on key professional connections, affecting their career prospects.&lt;/p>
&lt;p>&lt;strong>SK: In your view, how crucial is the role of allies within the DHHWG, and what contributions have they made to the group’s success?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: Deaf and hard of hearing individuals are a minority and can only do so much. &lt;em>&lt;strong>Allies are the key to any diversity and inclusion initiative&lt;/strong>&lt;/em>. As a majority, allies can help spread the word and educate their peers, playing a key role in scaling advocacy efforts. They also have the power to demand change. It's easy for companies to ignore minorities, but if the majority demands that their employers be accessible, environmentally conscious, and good citizens, they will ultimately be pushed to adapt to new societal values.&lt;/p>
&lt;h2 id="expanding-dei-efforts-and-future-vision">Expanding DEI efforts and future vision&lt;/h2>
&lt;p>&lt;strong>SK: The importance of allies in driving change is clear. Beyond the DHHWG, are you involved in any other DEI groups or initiatives within the tech community?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: As mentioned above, I'm working on an initiative called ABIDE, which is still work in progress. I don't want to share too much about it yet, but what I can say is that the DHHWG will be part of it and that we just started a Blind and Visually Impaired WG (BVIWG). ABIDE will start by focusing on accessibility, so if anyone reading this has an idea for another WG, please reach out to me via the CNCF Slack @Catherine Paganini.&lt;/p>
&lt;p>&lt;strong>SK: What does the future hold for the DHHWG? Can you share details about any ongoing or upcoming initiatives?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: I think we've been very successful in terms of visibility and awareness so far. We can't stop, though. Awareness work is ongoing, and most people in our community haven't heard about us or met anyone on our team yet, so a lot of work still lies ahead.&lt;/p>
&lt;p>&lt;img alt="DHHWG members at KubeCon Paris" src="https://kubernetes.io/blog/2024/09/30/cncf-deaf-and-hard-of-hearing-working-group-spotlight/cncf-dhhwg-paris.jpg">
&lt;em>DHHWG members at KubeCon Paris&lt;/em>&lt;/p>
&lt;p>The next step is to refocus on advocacy. The same thing we did with the conference best practices but for other areas. The goal is to help educate the community about what real accessibility looks like, how projects can be more accessible, and why employers should seriously consider deaf candidates while providing them with the tools they need to conduct successful interviews and employee onboarding. We need to capture all that in documents, publish it, and then get the word out. That last part is certainly the most challenging, but it's also where everyone can get involved.&lt;/p>
&lt;h2 id="call-to-action">Call to action&lt;/h2>
&lt;p>&lt;strong>SK: Thank you for sharing your insights, Catherine. As we wrap up, do you have any final thoughts or a call to action for our readers?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>CP&lt;/strong>: As we build our &lt;a href="https://contribute.cncf.io/accessibility/deaf-and-hard-of-hearing/">accessibility page&lt;/a>, check in regularly to see what's new. Share the docs with your team, employer, and network — anyone, really. The more people understand what accessibility really means and why it matters, the more people will recognize when something isn't accessible, and be able to call out marketing-BS, which, unfortunately, is more often the case than not. We need allies to help push for change. &lt;strong>No minority can do this on their own&lt;/strong>. So please learn about accessibility, keep an eye out for it, and call it out when something isn't accessible. We need your help!&lt;/p>
&lt;h2 id="wrapping-up">Wrapping up&lt;/h2>
&lt;p>Catherine and the DHHWG's work exemplify the power of community and advocacy. As we celebrate Deaf Awareness Month, let's reflect on her role as an ally and consider how we can all contribute to building a more inclusive tech community, particularly within open-source projects like Kubernetes.&lt;/p>
&lt;p>&lt;em>Together, we can break down barriers, challenge misconceptions, and ensure that everyone feels welcome and valued. By advocating for accessibility, supporting initiatives like the DHHWG, and fostering a culture of empathy, we can create a truly inclusive and welcoming space for all.&lt;/em>&lt;/p></description></item><item><title>Spotlight on SIG Scheduling</title><link>https://kubernetes.io/blog/2024/09/24/sig-scheduling-spotlight-2024/</link><pubDate>Tue, 24 Sep 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/09/24/sig-scheduling-spotlight-2024/</guid><description>
&lt;p>In this SIG Scheduling spotlight we talked with &lt;a href="https://github.com/sanposhiho/">Kensei Nakada&lt;/a>, an
approver in SIG Scheduling.&lt;/p>
&lt;h2 id="introductions">Introductions&lt;/h2>
&lt;p>&lt;strong>Arvind:&lt;/strong> &lt;strong>Hello, thank you for the opportunity to learn more about SIG Scheduling! Would you
like to introduce yourself and tell us a bit about your role, and how you got involved with
Kubernetes?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Kensei&lt;/strong>: Hi, thanks for the opportunity! I’m Kensei Nakada
(&lt;a href="https://github.com/sanposhiho/">@sanposhiho&lt;/a>), a software engineer at
&lt;a href="https://tetrate.io/">Tetrate.io&lt;/a>. I have been contributing to Kubernetes in my free time for more
than 3 years, and now I’m an approver of SIG Scheduling in Kubernetes. Also, I’m a founder/owner of
two SIG subprojects,
&lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-simulator">kube-scheduler-simulator&lt;/a> and
&lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-wasm-extension">kube-scheduler-wasm-extension&lt;/a>.&lt;/p>
&lt;h2 id="about-sig-scheduling">About SIG Scheduling&lt;/h2>
&lt;p>&lt;strong>AP: That's awesome! You've been involved with the project since a long time. Can you provide a
brief overview of SIG Scheduling and explain its role within the Kubernetes ecosystem?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: As the name implies, our responsibility is to enhance scheduling within
Kubernetes. Specifically, we develop the components that determine which Node is the best place for
each Pod. In Kubernetes, our main focus is on maintaining the
&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/">kube-scheduler&lt;/a>, along
with other scheduling-related components as part of our SIG subprojects.&lt;/p>
&lt;p>&lt;strong>AP: I see, got it! That makes me curious--what recent innovations or developments has SIG
Scheduling introduced to Kubernetes scheduling?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: From a feature perspective, there have been
&lt;a href="https://kubernetes.io/blog/2023/04/17/fine-grained-pod-topology-spread-features-beta/">several enhancements&lt;/a>
to &lt;code>PodTopologySpread&lt;/code> recently. &lt;code>PodTopologySpread&lt;/code> is a relatively new feature in the scheduler,
and we are still in the process of gathering feedback and making improvements.&lt;/p>
&lt;p>Most recently, we have been focusing on a new internal enhancement called
&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/4247-queueinghint/README.md">QueueingHint&lt;/a>
which aims to enhance scheduling throughput. Throughput is one of our crucial metrics in
scheduling. Traditionally, we have primarily focused on optimizing the latency of each scheduling
cycle. QueueingHint takes a different approach, optimizing when to retry scheduling, thereby
reducing the likelihood of wasting scheduling cycles.&lt;/p>
&lt;p>&lt;strong>A: That sounds interesting! Are there any other interesting topics or projects you are currently
working on within SIG Scheduling?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: I’m leading the development of &lt;code>QueueingHint&lt;/code> which I just shared. Given that it’s a big new
challenge for us, we’ve been facing many unexpected challenges, especially around the scalability,
and we’re trying to solve each of them to eventually enable it by default.&lt;/p>
&lt;p>And also, I believe
&lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-wasm-extension">kube-scheduler-wasm-extension&lt;/a>
(a SIG subproject) that I started last year would be interesting to many people. Kubernetes has
various extensions from many components. Traditionally, extensions are provided via webhooks
(&lt;a href="https://github.com/kubernetes/design-proposals-archive/blob/main/scheduling/scheduler_extender.md">extender&lt;/a>
in the scheduler) or Go SDK (&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">Scheduling Framework&lt;/a>
in the scheduler). However, these come with drawbacks - performance issues with webhooks and the need to
rebuild and replace schedulers with Go SDK, posing difficulties for those seeking to extend the
scheduler but lacking familiarity with it. The project is trying to introduce a new solution to
this general challenge - a &lt;a href="https://webassembly.org/">WebAssembly&lt;/a> based extension. Wasm allows
users to build plugins easily, without worrying about recompiling or replacing their scheduler, and
sidestepping performance concerns.&lt;/p>
&lt;p>Through this project, SIG Scheduling has been learning valuable insights about WebAssembly's
interaction with large Kubernetes objects. And I believe the experience that we’re gaining should be
useful broadly within the community, beyond SIG Scheduling.&lt;/p>
&lt;p>&lt;strong>A: Definitely! Now, there are 8 subprojects inside SIG Scheduling. Would you like to
talk about them? Are there some interesting contributions by those teams you want to highlight?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: Let me pick up three subprojects: Kueue, KWOK and descheduler.&lt;/p>
&lt;dl>
&lt;dt>&lt;a href="https://github.com/kubernetes-sigs/kueue">Kueue&lt;/a>&lt;/dt>
&lt;dd>Recently, many people have been trying to manage batch workloads with Kubernetes, and in 2022,
Kubernetes community founded
&lt;a href="https://github.com/kubernetes/community/blob/master/wg-batch/README.md">WG-Batch&lt;/a> for better
support for such batch workloads in Kubernetes. &lt;a href="https://github.com/kubernetes-sigs/kueue">Kueue&lt;/a>
is a project that takes a crucial role for it. It’s a job queueing controller, deciding when a job
should wait, when a job should be admitted to start, and when a job should be preempted. Kueue aims
to be installed on a vanilla Kubernetes cluster while cooperating with existing matured controllers
(scheduler, cluster-autoscaler, kube-controller-manager, etc).&lt;/dd>
&lt;dt>&lt;a href="https://github.com/kubernetes-sigs/kwok">KWOK&lt;/a>&lt;/dt>
&lt;dd>KWOK is a component in which you can create a cluster of thousands of Nodes in seconds. It’s
mostly useful for simulation/testing as a lightweight cluster, and actually another SIG sub
project &lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-simulator">kube-scheduler-simulator&lt;/a>
uses KWOK background.&lt;/dd>
&lt;dt>&lt;a href="https://github.com/kubernetes-sigs/descheduler">descheduler&lt;/a>&lt;/dt>
&lt;dd>Descheduler is a component recreating pods that are running on undesired Nodes. In Kubernetes,
scheduling constraints (&lt;code>PodAffinity&lt;/code>, &lt;code>NodeAffinity&lt;/code>, &lt;code>PodTopologySpread&lt;/code>, etc) are honored only at
Pod schedule, but it’s not guaranteed that the contrtaints are kept being satisfied afterwards.
Descheduler evicts Pods violating their scheduling constraints (or other undesired conditions) so
that they’re recreated and rescheduled.&lt;/dd>
&lt;dt>&lt;a href="https://github.com/kubernetes-sigs/descheduler/blob/master/keps/753-descheduling-framework/README.md">Descheduling Framework&lt;/a>&lt;/dt>
&lt;dd>One very interesting on-going project, similar to
&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">Scheduling Framework&lt;/a> in the
scheduler, aiming to make descheduling logic extensible and allow maintainers to focus on building
a core engine of descheduler.&lt;/dd>
&lt;/dl>
&lt;p>&lt;strong>AP: Thank you for letting us know! And I have to ask, what are some of your favorite things about
this SIG?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: What I really like about this SIG is how actively engaged everyone is. We come from various
companies and industries, bringing diverse perspectives to the table. Instead of these differences
causing division, they actually generate a wealth of opinions. Each view is respected, and this
makes our discussions both rich and productive.&lt;/p>
&lt;p>I really appreciate this collaborative atmosphere, and I believe it has been key to continuously
improving our components over the years.&lt;/p>
&lt;h2 id="contributing-to-sig-scheduling">Contributing to SIG Scheduling&lt;/h2>
&lt;p>&lt;strong>AP: Kubernetes is a community-driven project. Any recommendations for new contributors or
beginners looking to get involved and contribute to SIG scheduling? Where should they start?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: Let me start with a general recommendation for contributing to any SIG: a common approach is to look for
&lt;a href="https://github.com/kubernetes/kubernetes/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22">good-first-issue&lt;/a>.
However, you'll soon realize that many people worldwide are trying to contribute to the Kubernetes
repository.&lt;/p>
&lt;p>I suggest starting by examining the implementation of a component that interests you. If you have
any questions about it, ask in the corresponding Slack channel (e.g., #sig-scheduling for the
scheduler, #sig-node for kubelet, etc). Once you have a rough understanding of the implementation,
look at issues within the SIG (e.g.,
&lt;a href="https://github.com/kubernetes/kubernetes/issues?q=is%3Aopen+is%3Aissue+label%3Asig%2Fscheduling">sig-scheduling&lt;/a>),
where you'll find more unassigned issues compared to good-first-issue ones. You may also want to
filter issues with the
&lt;a href="https://github.com/kubernetes/kubernetes/issues?q=is%3Aopen+is%3Aissue++label%3Akind%2Fcleanup+">kind/cleanup&lt;/a>
label, which often indicates lower-priority tasks and can be starting points.&lt;/p>
&lt;p>Specifically for SIG Scheduling, you should first understand the
&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">Scheduling Framework&lt;/a>, which is
the fundamental architecture of kube-scheduler. Most of the implementation is found in
&lt;a href="https://github.com/kubernetes/kubernetes/tree/master/pkg/scheduler">pkg/scheduler&lt;/a>.
I suggest starting with
&lt;a href="https://github.com/kubernetes/kubernetes/blob/0590bb1ac495ae8af2a573f879408e48800da2c5/pkg/scheduler/schedule_one.go#L66">ScheduleOne&lt;/a>
function and then exploring deeper from there.&lt;/p>
&lt;p>Additionally, apart from the main kubernetes/kubernetes repository, consider looking into
sub-projects. These typically have fewer maintainers and offer more opportunities to make a
significant impact. Despite being called &amp;quot;sub&amp;quot; projects, many have a large number of users and a
considerable impact on the community.&lt;/p>
&lt;p>And last but not least, remember contributing to the community isn’t just about code. While I
talked a lot about the implementation contribution, there are many ways to contribute, and each one
is valuable. One comment to an issue, one feedback to an existing feature, one review comment in PR,
one clarification on the documentation; every small contribution helps drive the Kubernetes
ecosystem forward.&lt;/p>
&lt;p>&lt;strong>AP: Those are some pretty useful tips! And if I may ask, how do you assist new contributors in
getting started, and what skills are contributors likely to learn by participating in SIG Scheduling?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: Our maintainers are available to answer your questions in the #sig-scheduling Slack
channel. By participating, you'll gain a deeper understanding of Kubernetes scheduling and have the
opportunity to collaborate and network with maintainers from diverse backgrounds. You'll learn not
just how to write code, but also how to maintain a large project, design and discuss new features,
address bugs, and much more.&lt;/p>
&lt;h2 id="future-directions">Future Directions&lt;/h2>
&lt;p>&lt;strong>AP: What are some Kubernetes-specific challenges in terms of scheduling? Are there any particular
pain points?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: Scheduling in Kubernetes can be quite challenging because of the diverse needs of different
organizations with different business requirements. Supporting all possible use cases in
kube-scheduler is impossible. Therefore, extensibility is a key focus for us. A few years ago, we
rearchitected kube-scheduler with &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">Scheduling Framework&lt;/a>,
which offers flexible extensibility for users to implement various scheduling needs through plugins. This
allows maintainers to focus on the core scheduling features and the framework runtime.&lt;/p>
&lt;p>Another major issue is maintaining sufficient scheduling throughput. Typically, a Kubernetes cluster
has only one kube-scheduler, so its throughput directly affects the overall scheduling scalability
and, consequently, the cluster's scalability. Although we have an internal performance test
(&lt;a href="https://github.com/kubernetes/kubernetes/tree/master/test/integration/scheduler_perf">scheduler_perf&lt;/a>),
unfortunately, we sometimes overlook performance degradation in less common scenarios. It’s
difficult as even small changes, which look irrelevant to performance, can lead to degradation.&lt;/p>
&lt;p>&lt;strong>AP: What are some upcoming goals or initiatives for SIG Scheduling? How do you envision the SIG evolving in the future?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: Our primary goal is always to build and maintain &lt;em>extensible&lt;/em> and &lt;em>stable&lt;/em> scheduling
runtime, and I bet this goal will remain unchanged forever.&lt;/p>
&lt;p>As already mentioned, extensibility is key to solving the challenge of the diverse needs of
scheduling. Rather than trying to support every different use case directly in kube-scheduler, we
will continue to focus on enhancing extensibility so that it can accommodate various use
cases. &lt;a href="https://github.com/kubernetes-sigs/kube-scheduler-wasm-extension">kube-scheduler-wasm-extension&lt;/a>
that I mentioned is also part of this initiative.&lt;/p>
&lt;p>Regarding stability, introducing new optimizations like QueueHint is one of our
strategies. Additionally, maintaining throughput is also a crucial goal towards the future. We’re
planning to enhance our throughput monitoring
(&lt;a href="https://github.com/kubernetes/kubernetes/issues/124774">ref&lt;/a>), so that we can notice degradation
as much as possible on our own before releasing. But, realistically, we can't cover every possible
scenario. We highly appreciate any attention the community can give to scheduling throughput and
encourage feedback and alerts regarding performance issues!&lt;/p>
&lt;h2 id="closing-remarks">Closing Remarks&lt;/h2>
&lt;p>&lt;strong>AP: Finally, what message would you like to convey to those who are interested in learning more
about SIG Scheduling?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>KN&lt;/strong>: Scheduling is one of the most complicated areas in Kubernetes, and you may find it difficult
at first. But, as I shared earlier, you can find many opportunities for contributions, and many
maintainers are willing to help you understand things. We know your unique perspective and skills
are what makes our open source so powerful 😊&lt;/p>
&lt;p>Feel free to reach out to us in Slack
(&lt;a href="https://kubernetes.slack.com/archives/C09TP78DV">#sig-scheduling&lt;/a>) or
&lt;a href="https://github.com/kubernetes/community/blob/master/sig-scheduling/README.md#meetings">meetings&lt;/a>.
I hope this article interests everyone and we can see new contributors!&lt;/p>
&lt;p>&lt;strong>AP: Thank you so much for taking the time to do this! I'm confident that many will find this
information invaluable for understanding more about SIG Scheduling and for contributing to the SIG.&lt;/strong>&lt;/p></description></item><item><title>Kubernetes v1.31: kubeadm v1beta4</title><link>https://kubernetes.io/blog/2024/08/23/kubernetes-1-31-kubeadm-v1beta4/</link><pubDate>Fri, 23 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/23/kubernetes-1-31-kubeadm-v1beta4/</guid><description>
&lt;p>As part of the Kubernetes v1.31 release, &lt;a href="https://kubernetes.io/docs/reference/setup-tools/kubeadm/">&lt;code>kubeadm&lt;/code>&lt;/a> is
adopting a new (&lt;a href="https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta4/">v1beta4&lt;/a>) version of
its configuration file format. Configuration in the previous v1beta3 format is now formally
deprecated, which means it's supported but you should migrate to v1beta4 and stop using
the deprecated format.
Support for v1beta3 configuration will be removed after a minimum of 3 Kubernetes minor releases.&lt;/p>
&lt;p>In this article, I'll walk you through key changes;
I'll explain about the kubeadm v1beta4 configuration format,
and how to migrate from v1beta3 to v1beta4.&lt;/p>
&lt;p>You can read the reference for the v1beta4 configuration format:
&lt;a href="https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta4/">kubeadm Configuration (v1beta4)&lt;/a>.&lt;/p>
&lt;h3 id="a-list-of-changes-since-v1beta3">A list of changes since v1beta3&lt;/h3>
&lt;p>This version improves on the &lt;a href="https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/">v1beta3&lt;/a>
format by fixing some minor issues and adding a few new fields.&lt;/p>
&lt;p>To put it simply,&lt;/p>
&lt;ul>
&lt;li>Two new configuration elements: ResetConfiguration and UpgradeConfiguration&lt;/li>
&lt;li>For InitConfiguration and JoinConfiguration, &lt;code>dryRun&lt;/code> mode and &lt;code>nodeRegistration.imagePullSerial&lt;/code> are supported&lt;/li>
&lt;li>For ClusterConfiguration, there are new fields including &lt;code>certificateValidityPeriod&lt;/code>,
&lt;code>caCertificateValidityPeriod&lt;/code>, &lt;code>encryptionAlgorithm&lt;/code>, &lt;code>dns.disabled&lt;/code> and &lt;code>proxy.disabled&lt;/code>.&lt;/li>
&lt;li>Support &lt;code>extraEnvs&lt;/code> for all control plan components&lt;/li>
&lt;li>&lt;code>extraArgs&lt;/code> changed from a map to structured extra arguments for duplicates&lt;/li>
&lt;li>Add a &lt;code>timeouts&lt;/code> structure for init, join, upgrade and reset.&lt;/li>
&lt;/ul>
&lt;p>For details, you can see the &lt;a href="https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta4/">official document&lt;/a> below:&lt;/p>
&lt;ul>
&lt;li>Support custom environment variables in control plane components under &lt;code>ClusterConfiguration&lt;/code>.
Use &lt;code>apiServer.extraEnvs&lt;/code>, &lt;code>controllerManager.extraEnvs&lt;/code>, &lt;code>scheduler.extraEnvs&lt;/code>, &lt;code>etcd.local.extraEnvs&lt;/code>.&lt;/li>
&lt;li>The ResetConfiguration API type is now supported in v1beta4. Users are able to reset a node by passing
a &lt;code>--config&lt;/code> file to &lt;code>kubeadm reset&lt;/code>.&lt;/li>
&lt;li>&lt;code>dryRun&lt;/code> mode is now configurable in InitConfiguration and JoinConfiguration.&lt;/li>
&lt;li>Replace the existing string/string extra argument maps with structured extra arguments that support duplicates.
The change applies to &lt;code>ClusterConfiguration&lt;/code> - &lt;code>apiServer.extraArgs&lt;/code>, &lt;code>controllerManager.extraArgs&lt;/code>,
&lt;code>scheduler.extraArgs&lt;/code>, &lt;code>etcd.local.extraArgs&lt;/code>. Also to &lt;code>nodeRegistrationOptions.kubeletExtraArgs&lt;/code>.&lt;/li>
&lt;li>Added &lt;code>ClusterConfiguration.encryptionAlgorithm&lt;/code> that can be used to set the asymmetric encryption
algorithm used for this cluster's keys and certificates. Can be one of &amp;quot;RSA-2048&amp;quot; (default), &amp;quot;RSA-3072&amp;quot;,
&amp;quot;RSA-4096&amp;quot; or &amp;quot;ECDSA-P256&amp;quot;.&lt;/li>
&lt;li>Added &lt;code>ClusterConfiguration.dns.disabled&lt;/code> and &lt;code>ClusterConfiguration.proxy.disabled&lt;/code> that can be used
to disable the CoreDNS and kube-proxy addons during cluster initialization.
Skipping the related addons phases, during cluster creation will set the same fields to &lt;code>true&lt;/code>.&lt;/li>
&lt;li>Added the &lt;code>nodeRegistration.imagePullSerial&lt;/code> field in &lt;code>InitConfiguration&lt;/code> and &lt;code>JoinConfiguration&lt;/code>,
which can be used to control if kubeadm pulls images serially or in parallel.&lt;/li>
&lt;li>The UpgradeConfiguration kubeadm API is now supported in v1beta4 when passing &lt;code>--config&lt;/code> to
&lt;code>kubeadm upgrade&lt;/code> subcommands.
For upgrade subcommands, the usage of component configuration for kubelet and kube-proxy, as well as
InitConfiguration and ClusterConfiguration, is now deprecated and will be ignored when passing &lt;code>--config&lt;/code>.&lt;/li>
&lt;li>Added a &lt;code>timeouts&lt;/code> structure to &lt;code>InitConfiguration&lt;/code>, &lt;code>JoinConfiguration&lt;/code>, &lt;code>ResetConfiguration&lt;/code> and
&lt;code>UpgradeConfiguration&lt;/code> that can be used to configure various timeouts.
The &lt;code>ClusterConfiguration.timeoutForControlPlane&lt;/code> field is replaced by &lt;code>timeouts.controlPlaneComponentHealthCheck&lt;/code>.
The &lt;code>JoinConfiguration.discovery.timeout&lt;/code> is replaced by &lt;code>timeouts.discovery&lt;/code>.&lt;/li>
&lt;li>Added a &lt;code>certificateValidityPeriod&lt;/code> and &lt;code>caCertificateValidityPeriod&lt;/code> fields to &lt;code>ClusterConfiguration&lt;/code>.
These fields can be used to control the validity period of certificates generated by kubeadm during
sub-commands such as &lt;code>init&lt;/code>, &lt;code>join&lt;/code>, &lt;code>upgrade&lt;/code> and &lt;code>certs&lt;/code>.
Default values continue to be 1 year for non-CA certificates and 10 years for CA certificates.
Also note that only non-CA certificates are renewable by &lt;code>kubeadm certs renew&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>These changes simplify the configuration of tools that use kubeadm
and improve the extensibility of kubeadm itself.&lt;/p>
&lt;h3 id="how-to-migrate-v1beta3-configuration-to-v1beta4">How to migrate v1beta3 configuration to v1beta4?&lt;/h3>
&lt;p>If your configuration is not using the latest version, it is recommended that you migrate using
the &lt;a href="https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-config/#cmd-config-migrate">kubeadm config migrate&lt;/a> command.&lt;/p>
&lt;p>This command reads an existing configuration file that uses the old format, and writes a new
file that uses the current format.&lt;/p>
&lt;h4 id="example-kubeadm-config-migrate">Example&lt;/h4>
&lt;p>Using kubeadm v1.31, run &lt;code>kubeadm config migrate --old-config old-v1beta3.yaml --new-config new-v1beta4.yaml&lt;/code>&lt;/p>
&lt;h2 id="how-do-i-get-involved">How do I get involved?&lt;/h2>
&lt;p>Huge thanks to all the contributors who helped with the design, implementation,
and review of this feature:&lt;/p>
&lt;ul>
&lt;li>Lubomir I. Ivanov (&lt;a href="https://github.com/neolit123">neolit123&lt;/a>)&lt;/li>
&lt;li>Dave Chen(&lt;a href="https://github.com/chendave">chendave&lt;/a>)&lt;/li>
&lt;li>Paco Xu (&lt;a href="https://github.com/pacoxu">pacoxu&lt;/a>)&lt;/li>
&lt;li>Sata Qiu(&lt;a href="https://github.com/sataqiu">sataqiu&lt;/a>)&lt;/li>
&lt;li>Baofa Fan(&lt;a href="https://github.com/carlory">carlory&lt;/a>)&lt;/li>
&lt;li>Calvin Chen(&lt;a href="https://github.com/calvin0327">calvin0327&lt;/a>)&lt;/li>
&lt;li>Ruquan Zhao(&lt;a href="https://github.com/ruquanzhao">ruquanzhao&lt;/a>)&lt;/li>
&lt;/ul>
&lt;p>For those interested in getting involved in future discussions on kubeadm configuration,
you can reach out kubeadm or &lt;a href="https://github.com/kubernetes/community/blob/master/sig-cluster-lifecycle/README.md">SIG-cluster-lifecycle&lt;/a> by several means:&lt;/p>
&lt;ul>
&lt;li>v1beta4 related items are tracked in &lt;a href="https://github.com/kubernetes/kubeadm/issues/2890">kubeadm issue #2890&lt;/a>.&lt;/li>
&lt;li>Slack: &lt;a href="https://kubernetes.slack.com/messages/kubeadm">#kubeadm&lt;/a> or &lt;a href="https://kubernetes.slack.com/messages/sig-cluster-lifecycle">#sig-cluster-lifecycle&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://groups.google.com/forum/#!forum/kubernetes-sig-cluster-lifecycle">Mailing list&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes 1.31: Custom Profiling in Kubectl Debug Graduates to Beta</title><link>https://kubernetes.io/blog/2024/08/22/kubernetes-1-31-custom-profiling-kubectl-debug/</link><pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/22/kubernetes-1-31-custom-profiling-kubectl-debug/</guid><description>
&lt;p>There are many ways of troubleshooting the pods and nodes in the cluster. However, &lt;code>kubectl debug&lt;/code> is one of the easiest, highly used and most prominent ones. It
provides a set of static profiles and each profile serves for a different kind of role. For instance, from the network administrator's point of view,
debugging the node should be as easy as this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>$ kubectl debug node/mynode -it --image&lt;span style="color:#666">=&lt;/span>busybox --profile&lt;span style="color:#666">=&lt;/span>netadmin
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>On the other hand, static profiles also bring about inherent rigidity, which has some implications for some pods contrary to their ease of use.
Because there are various kinds of pods (or nodes) that all have their specific
necessities, and unfortunately, some can't be debugged by only using the static profiles.&lt;/p>
&lt;p>Take an instance of a simple pod consisting of a container whose healthiness relies on an environment variable:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>example-pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>example-container&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>customapp:latest&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">env&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>REQUIRED_ENV_VAR&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">value&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;value1&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Currently, copying the pod is the sole mechanism that supports debugging this pod in kubectl debug. Furthermore, what if user needs to modify the &lt;code>REQUIRED_ENV_VAR&lt;/code> to something different
for advanced troubleshooting?. There is no mechanism to achieve this.&lt;/p>
&lt;h2 id="custom-profiling">Custom Profiling&lt;/h2>
&lt;p>Custom profiling is a new functionality available under &lt;code>--custom&lt;/code> flag, introduced in kubectl debug to provide extensibility. It expects partial &lt;code>Container&lt;/code> spec in either YAML or JSON format.
In order to debug the example-container above by creating an ephemeral container, we simply have to define this YAML:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic"># partial_container.yaml&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">env&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>REQUIRED_ENV_VAR&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">value&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>value2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>and execute:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl debug example-pod -it --image&lt;span style="color:#666">=&lt;/span>customapp --custom&lt;span style="color:#666">=&lt;/span>partial_container.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here is another example that modifies multiple fields at once (change port number, add resource limits, modify environment variable) in JSON:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;ports&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;containerPort&amp;#34;&lt;/span>: &lt;span style="color:#666">80&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;resources&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;limits&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;cpu&amp;#34;&lt;/span>: &lt;span style="color:#b44">&amp;#34;0.5&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;memory&amp;#34;&lt;/span>: &lt;span style="color:#b44">&amp;#34;512Mi&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;requests&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;cpu&amp;#34;&lt;/span>: &lt;span style="color:#b44">&amp;#34;0.2&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;memory&amp;#34;&lt;/span>: &lt;span style="color:#b44">&amp;#34;256Mi&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;env&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#b44">&amp;#34;REQUIRED_ENV_VAR&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#008000;font-weight:bold">&amp;#34;value&amp;#34;&lt;/span>: &lt;span style="color:#b44">&amp;#34;value2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="constraints">Constraints&lt;/h2>
&lt;p>Uncontrolled extensibility hurts the usability. So that, custom profiling is not allowed for certain fields such as command, image, lifecycle, volume devices and container name.
In the future, more fields can be added to the disallowed list if required.&lt;/p>
&lt;h2 id="limitations">Limitations&lt;/h2>
&lt;p>The &lt;code>kubectl debug&lt;/code> command has 3 aspects: Debugging with ephemeral containers, pod copying, and node debugging. The largest intersection set of these aspects is the container spec within a Pod
That's why, custom profiling only supports the modification of the fields that are defined with &lt;code>containers&lt;/code>. This leads to a limitation that if user needs to modify the other fields in the Pod spec, it is not supported.&lt;/p>
&lt;h2 id="acknowledgments">Acknowledgments&lt;/h2>
&lt;p>Special thanks to all the contributors who reviewed and commented on this feature, from the initial conception to its actual implementation (alphabetical order):&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/eddiezane">Eddie Zaneski&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/soltysh">Maciej Szulik&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/verb">Lee Verberne&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes 1.31: Fine-grained SupplementalGroups control</title><link>https://kubernetes.io/blog/2024/08/22/fine-grained-supplementalgroups-control/</link><pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/22/fine-grained-supplementalgroups-control/</guid><description>
&lt;p>This blog discusses a new feature in Kubernetes 1.31 to improve the handling of supplementary groups in containers within Pods.&lt;/p>
&lt;h2 id="motivation-implicit-group-memberships-defined-in-etc-group-in-the-container-image">Motivation: Implicit group memberships defined in &lt;code>/etc/group&lt;/code> in the container image&lt;/h2>
&lt;p>Although this behavior may not be popular with many Kubernetes cluster users/admins, kubernetes, by default, &lt;em>merges&lt;/em> group information from the Pod with information defined in &lt;code>/etc/group&lt;/code> in the container image.&lt;/p>
&lt;p>Let's see an example, below Pod specifies &lt;code>runAsUser=1000&lt;/code>, &lt;code>runAsGroup=3000&lt;/code> and &lt;code>supplementalGroups=4000&lt;/code> in the Pod's security context.&lt;/p>
&lt;div class="highlight code-sample">
&lt;div class="copy-code-icon">
&lt;a href="https://raw.githubusercontent.com/kubernetes/website/release-1.32/content/en/examples/implicit-groups.yaml" download="implicit-groups.yaml">&lt;code>implicit-groups.yaml&lt;/code>
&lt;/a>&lt;img src="https://kubernetes.io/images/copycode.svg" class="icon-copycode" onclick="copyCode('implicit-groups-yaml')" title="Copy implicit-groups.yaml to clipboard">&lt;/img>&lt;/div>
&lt;div class="includecode" id="implicit-groups-yaml">&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>implicit-groups&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">securityContext&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">runAsUser&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">1000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">runAsGroup&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">3000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">supplementalGroups&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#666">4000&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ctr&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>registry.k8s.io/e2e-test-images/agnhost:2.45&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">command&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;sh&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;-c&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;sleep 1h&amp;#34;&lt;/span>&lt;span style="color:#bbb"> &lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">securityContext&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">allowPrivilegeEscalation&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">false&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;/div>
&lt;p>What is the result of &lt;code>id&lt;/code> command in the &lt;code>ctr&lt;/code> container?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> Create the Pod:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">$&lt;/span> kubectl apply -f https://k8s.io/blog/2024-08-22-Fine-grained-SupplementalGroups-control/implicit-groups.yaml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> Verify that the Pod&lt;span style="">&amp;#39;&lt;/span>s Container is running:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">$&lt;/span> kubectl get pod implicit-groups
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> Check the id &lt;span style="color:#a2f">command&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">$&lt;/span> kubectl &lt;span style="color:#a2f">exec&lt;/span> implicit-groups -- id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then, output should be similar to this:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-none" data-lang="none">uid=1000 gid=3000 groups=3000,4000,50000
&lt;/code>&lt;/pre>&lt;p>Where does group ID &lt;code>50000&lt;/code> in supplementary groups (&lt;code>groups&lt;/code> field) come from, even though &lt;code>50000&lt;/code> is not defined in the Pod's manifest at all? The answer is &lt;code>/etc/group&lt;/code> file in the container image.&lt;/p>
&lt;p>Checking the contents of &lt;code>/etc/group&lt;/code> in the container image should show below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">$&lt;/span> kubectl &lt;span style="color:#a2f">exec&lt;/span> implicit-groups -- cat /etc/group
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">user-defined-in-image:x:1000:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">group-defined-in-image:x:50000:user-defined-in-image
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Aha! The container's primary user &lt;code>1000&lt;/code> belongs to the group &lt;code>50000&lt;/code> in the last entry.&lt;/p>
&lt;p>Thus, the group membership defined in &lt;code>/etc/group&lt;/code> in the container image for the container's primary user is &lt;em>implicitly&lt;/em> merged to the information from the Pod. Please note that this was a design decision the current CRI implementations inherited from Docker, and the community never really reconsidered it until now.&lt;/p>
&lt;h3 id="what-s-wrong-with-it">What's wrong with it?&lt;/h3>
&lt;p>The &lt;em>implicitly&lt;/em> merged group information from &lt;code>/etc/group&lt;/code> in the container image may cause some concerns particularly in accessing volumes (see &lt;a href="https://issue.k8s.io/112879">kubernetes/kubernetes#112879&lt;/a> for details) because file permission is controlled by uid/gid in Linux. Even worse, the implicit gids from &lt;code>/etc/group&lt;/code> can not be detected/validated by any policy engines because there is no clue for the implicit group information in the manifest. This can also be a concern for Kubernetes security.&lt;/p>
&lt;h2 id="fine-grained-supplementalgroups-control-in-a-pod-supplementarygroupspolicy">Fine-grained SupplementalGroups control in a Pod: &lt;code>SupplementaryGroupsPolicy&lt;/code>&lt;/h2>
&lt;p>To tackle the above problem, Kubernetes 1.31 introduces new field &lt;code>supplementalGroupsPolicy&lt;/code> in Pod's &lt;code>.spec.securityContext&lt;/code>.&lt;/p>
&lt;p>This field provies a way to control how to calculate supplementary groups for the container processes in a Pod. The available policy is below:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;em>Merge&lt;/em>: The group membership defined in &lt;code>/etc/group&lt;/code> for the container's primary user will be merged. If not specified, this policy will be applied (i.e. as-is behavior for backword compatibility).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>Strict&lt;/em>: it only attaches specified group IDs in &lt;code>fsGroup&lt;/code>, &lt;code>supplementalGroups&lt;/code>, or &lt;code>runAsGroup&lt;/code> fields as the supplementary groups of the container processes. This means no group membership defined in &lt;code>/etc/group&lt;/code> for the container's primary user will be merged.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Let's see how &lt;code>Strict&lt;/code> policy works.&lt;/p>
&lt;div class="highlight code-sample">
&lt;div class="copy-code-icon">
&lt;a href="https://raw.githubusercontent.com/kubernetes/website/release-1.32/content/en/examples/strict-supplementalgroups-policy.yaml" download="strict-supplementalgroups-policy.yaml">&lt;code>strict-supplementalgroups-policy.yaml&lt;/code>
&lt;/a>&lt;img src="https://kubernetes.io/images/copycode.svg" class="icon-copycode" onclick="copyCode('strict-supplementalgroups-policy-yaml')" title="Copy strict-supplementalgroups-policy.yaml to clipboard">&lt;/img>&lt;/div>
&lt;div class="includecode" id="strict-supplementalgroups-policy-yaml">&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>strict-supplementalgroups-policy&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">securityContext&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">runAsUser&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">1000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">runAsGroup&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">3000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">supplementalGroups&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#666">4000&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">supplementalGroupsPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Strict&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ctr&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>registry.k8s.io/e2e-test-images/agnhost:2.45&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">command&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;sh&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;-c&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;sleep 1h&amp;#34;&lt;/span>&lt;span style="color:#bbb"> &lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">securityContext&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">allowPrivilegeEscalation&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">false&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;/div>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> Create the Pod:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">$&lt;/span> kubectl apply -f https://k8s.io/blog/2024-08-22-Fine-grained-SupplementalGroups-control/strict-supplementalgroups-policy.yaml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> Verify that the Pod&lt;span style="">&amp;#39;&lt;/span>s Container is running:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">$&lt;/span> kubectl get pod strict-supplementalgroups-policy
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>&lt;span style="color:#000080;font-weight:bold">#&lt;/span> Check the process identity:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">kubectl exec -it strict-supplementalgroups-policy -- id
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The output should be similar to this:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-none" data-lang="none">uid=1000 gid=3000 groups=3000,4000
&lt;/code>&lt;/pre>&lt;p>You can see &lt;code>Strict&lt;/code> policy can exclude group &lt;code>50000&lt;/code> from &lt;code>groups&lt;/code>!&lt;/p>
&lt;p>Thus, ensuring &lt;code>supplementalGroupsPolicy: Strict&lt;/code> (enforced by some policy mechanism) helps prevent the implicit supplementary groups in a Pod.&lt;/p>
&lt;div class="alert alert-info" role="alert">&lt;h4 class="alert-heading">Note:&lt;/h4>Actually, this is not enough because container with sufficient privileges / capability can change its process identity. Please see the following section for details.&lt;/div>
&lt;h2 id="attached-process-identity-in-pod-status">Attached process identity in Pod status&lt;/h2>
&lt;p>This feature also exposes the process identity attached to the first container process of the container
via &lt;code>.status.containerStatuses[].user.linux&lt;/code> field. It would be helpful to see if implicit group IDs are attached.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00f;font-weight:bold">...&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">status&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containerStatuses&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ctr&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">user&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">linux&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">gid&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">3000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">supplementalGroups&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#666">3000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#666">4000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">uid&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">1000&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">...&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;div class="alert alert-info" role="alert">&lt;h4 class="alert-heading">Note:&lt;/h4>Please note that the values in &lt;code>status.containerStatuses[].user.linux&lt;/code> field is &lt;em>the firstly attached&lt;/em>
process identity to the first container process in the container. If the container has sufficient privilege
to call system calls related to process identity (e.g. &lt;a href="https://man7.org/linux/man-pages/man2/setuid.2.html">&lt;code>setuid(2)&lt;/code>&lt;/a>, &lt;a href="https://man7.org/linux/man-pages/man2/setgid.2.html">&lt;code>setgid(2)&lt;/code>&lt;/a> or &lt;a href="https://man7.org/linux/man-pages/man2/setgroups.2.html">&lt;code>setgroups(2)&lt;/code>&lt;/a>, etc.), the container process can change its identity. Thus, the &lt;em>actual&lt;/em> process identity will be dynamic.&lt;/div>
&lt;h2 id="feature-availability">Feature availability&lt;/h2>
&lt;p>To enable &lt;code>supplementalGroupsPolicy&lt;/code> field, the following components have to be used:&lt;/p>
&lt;ul>
&lt;li>Kubernetes: v1.31 or later, with the &lt;code>SupplementalGroupsPolicy&lt;/code> &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/">feature gate&lt;/a> enabled. As of v1.31, the gate is marked as alpha.&lt;/li>
&lt;li>CRI runtime:
&lt;ul>
&lt;li>containerd: v2.0 or later&lt;/li>
&lt;li>CRI-O: v1.31 or later&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>You can see if the feature is supported in the Node's &lt;code>.status.features.supplementalGroupsPolicy&lt;/code> field.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Node&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">...&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">status&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">features&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">supplementalGroupsPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">true&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="what-s-next">What's next?&lt;/h2>
&lt;p>Kubernetes SIG Node hope - and expect - that the feature will be promoted to beta and eventually
general availability (GA) in future releases of Kubernetes, so that users no longer need to enable
the feature gate manually.&lt;/p>
&lt;p>&lt;code>Merge&lt;/code> policy is applied when &lt;code>supplementalGroupsPolicy&lt;/code> is not specified, for backwards compatibility.&lt;/p>
&lt;h2 id="how-can-i-learn-more">How can I learn more?&lt;/h2>
&lt;!-- https://github.com/kubernetes/website/pull/46920 -->
&lt;ul>
&lt;li>&lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/security-context/">Configure a Security Context for a Pod or Container&lt;/a>
for the further details of &lt;code>supplementalGroupsPolicy&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3619">KEP-3619: Fine-grained SupplementalGroups control&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="how-to-get-involved">How to get involved?&lt;/h2>
&lt;p>This feature is driven by the SIG Node community. Please join us to connect with
the community and share your ideas and feedback around the above feature and
beyond. We look forward to hearing from you!&lt;/p></description></item><item><title>Kubernetes v1.31: New Kubernetes CPUManager Static Policy: Distribute CPUs Across Cores</title><link>https://kubernetes.io/blog/2024/08/22/cpumanager-static-policy-distributed-cpu-across-cores/</link><pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/22/cpumanager-static-policy-distributed-cpu-across-cores/</guid><description>
&lt;p>In Kubernetes v1.31, we are excited to introduce a significant enhancement to CPU management capabilities: the &lt;code>distribute-cpus-across-cores&lt;/code> option for the &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/#static-policy-options">CPUManager static policy&lt;/a>. This feature is currently in alpha and hidden by default, marking a strategic shift aimed at optimizing CPU utilization and improving system performance across multi-core processors.&lt;/p>
&lt;h2 id="understanding-the-feature">Understanding the feature&lt;/h2>
&lt;p>Traditionally, Kubernetes' CPUManager tends to allocate CPUs as compactly as possible, typically packing them onto the fewest number of physical cores. However, allocation strategy matters, CPUs on the same physical host still share some resources of the physical core, such as the cache and execution units, etc.&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2024/08/22/cpumanager-static-policy-distributed-cpu-across-cores/cpu-cache-architecture.png"
alt="cpu-cache-architecture"/>
&lt;/figure>
&lt;p>While default approach minimizes inter-core communication and can be beneficial under certain scenarios, it also poses a challenge. CPUs sharing a physical core can lead to resource contention, which in turn may cause performance bottlenecks, particularly noticeable in CPU-intensive applications.&lt;/p>
&lt;p>The new &lt;code>distribute-cpus-across-cores&lt;/code> feature addresses this issue by modifying the allocation strategy. When enabled, this policy option instructs the CPUManager to spread out the CPUs (hardware threads) across as many physical cores as possible. This distribution is designed to minimize contention among CPUs sharing the same physical core, potentially enhancing the performance of applications by providing them dedicated core resources.&lt;/p>
&lt;p>Technically, within this static policy, the free CPU list is reordered in the manner depicted in the diagram, aiming to allocate CPUs from separate physical cores.&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2024/08/22/cpumanager-static-policy-distributed-cpu-across-cores/cpu-ordering.png"
alt="cpu-ordering"/>
&lt;/figure>
&lt;h2 id="enabling-the-feature">Enabling the feature&lt;/h2>
&lt;p>To enable this feature, users firstly need to add &lt;code>--cpu-manager-policy=static&lt;/code> kubelet flag or the &lt;code>cpuManagerPolicy: static&lt;/code> field in KubeletConfiuration. Then user can add &lt;code>--cpu-manager-policy-options distribute-cpus-across-cores=true&lt;/code> or &lt;code>distribute-cpus-across-cores=true&lt;/code> to their CPUManager policy options in the Kubernetes configuration or. This setting directs the CPUManager to adopt the new distribution strategy. It is important to note that this policy option cannot currently be used in conjunction with &lt;code>full-pcpus-only&lt;/code> or &lt;code>distribute-cpus-across-numa&lt;/code> options.&lt;/p>
&lt;h2 id="current-limitations-and-future-directions">Current limitations and future directions&lt;/h2>
&lt;p>As with any new feature, especially one in alpha, there are limitations and areas for future improvement. One significant current limitation is that &lt;code>distribute-cpus-across-cores&lt;/code> cannot be combined with other policy options that might conflict in terms of CPU allocation strategies. This restriction can affect compatibility with certain workloads and deployment scenarios that rely on more specialized resource management.&lt;/p>
&lt;p>Looking forward, we are committed to enhancing the compatibility and functionality of the &lt;code>distribute-cpus-across-cores&lt;/code> option. Future updates will focus on resolving these compatibility issues, allowing this policy to be combined with other CPUManager policies seamlessly. Our goal is to provide a more flexible and robust CPU allocation framework that can adapt to a variety of workloads and performance demands.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>The introduction of the &lt;code>distribute-cpus-across-cores&lt;/code> policy in Kubernetes CPUManager is a step forward in our ongoing efforts to refine resource management and improve application performance. By reducing the contention on physical cores, this feature offers a more balanced approach to CPU resource allocation, particularly beneficial for environments running heterogeneous workloads. We encourage Kubernetes users to test this new feature and provide feedback, which will be invaluable in shaping its future development.&lt;/p>
&lt;p>This draft aims to clearly explain the new feature while setting expectations for its current stage and future improvements.&lt;/p>
&lt;h2 id="further-reading">Further reading&lt;/h2>
&lt;p>Please check out the &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/">Control CPU Management Policies on the Node&lt;/a>
task page to learn more about the CPU Manager, and how it fits in relation to the other node-level resource managers.&lt;/p>
&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>This feature is driven by the &lt;a href="https://github.com/Kubernetes/community/blob/master/sig-node/README.md">SIG Node&lt;/a>. If you are interested in helping develop this feature, sharing feedback, or participating in any other ongoing SIG Node projects, please attend the SIG Node meeting for more details.&lt;/p></description></item><item><title>Kubernetes 1.31: Autoconfiguration For Node Cgroup Driver (beta)</title><link>https://kubernetes.io/blog/2024/08/21/cri-cgroup-driver-lookup-now-beta/</link><pubDate>Wed, 21 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/21/cri-cgroup-driver-lookup-now-beta/</guid><description>
&lt;p>Historically, configuring the correct cgroup driver has been a pain point for users running new
Kubernetes clusters. On Linux systems, there are two different cgroup drivers:
&lt;code>cgroupfs&lt;/code> and &lt;code>systemd&lt;/code>. In the past, both the &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/">kubelet&lt;/a>
and CRI implementation (like CRI-O or containerd) needed to be configured to use
the same cgroup driver, or else the kubelet would exit with an error. This was a
source of headaches for many cluster admins. However, there is light at the end of the tunnel!&lt;/p>
&lt;h2 id="automated-cgroup-driver-detection">Automated cgroup driver detection&lt;/h2>
&lt;p>In v1.28.0, the SIG Node community introduced the feature gate
&lt;code>KubeletCgroupDriverFromCRI&lt;/code>, which instructs the kubelet to ask the CRI
implementation which cgroup driver to use. A few minor releases of Kubernetes
happened whilst we waited for support to land in the major two CRI implementations
(containerd and CRI-O), but as of v1.31.0, this feature is now beta!&lt;/p>
&lt;p>In addition to setting the feature gate, a cluster admin needs to ensure their
CRI implementation is new enough:&lt;/p>
&lt;ul>
&lt;li>containerd: Support was added in v2.0.0&lt;/li>
&lt;li>CRI-O: Support was added in v1.28.0&lt;/li>
&lt;/ul>
&lt;p>Then, they should ensure their CRI implementation is configured to the
cgroup_driver they would like to use.&lt;/p>
&lt;h2 id="future-work">Future work&lt;/h2>
&lt;p>Eventually, support for the kubelet's &lt;code>cgroupDriver&lt;/code> configuration field will be
dropped, and the kubelet will fail to start if the CRI implementation isn't new
enough to have support for this feature.&lt;/p></description></item><item><title>Kubernetes 1.31: Streaming Transitions from SPDY to WebSockets</title><link>https://kubernetes.io/blog/2024/08/20/websockets-transition/</link><pubDate>Tue, 20 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/20/websockets-transition/</guid><description>
&lt;p>In Kubernetes 1.31, by default kubectl now uses the WebSocket protocol
instead of SPDY for streaming.&lt;/p>
&lt;p>This post describes what these changes mean for you and why these streaming APIs
matter.&lt;/p>
&lt;h2 id="streaming-apis-in-kubernetes">Streaming APIs in Kubernetes&lt;/h2>
&lt;p>In Kubernetes, specific endpoints that are exposed as an HTTP or RESTful
interface are upgraded to streaming connections, which require a streaming
protocol. Unlike HTTP, which is a request-response protocol, a streaming
protocol provides a persistent connection that's bi-directional, low-latency,
and lets you interact in real-time. Streaming protocols support reading and
writing data between your client and the server, in both directions, over the
same connection. This type of connection is useful, for example, when you create
a shell in a running container from your local workstation and run commands in
the container.&lt;/p>
&lt;h2 id="why-change-the-streaming-protocol">Why change the streaming protocol?&lt;/h2>
&lt;p>Before the v1.31 release, Kubernetes used the SPDY/3.1 protocol by default when
upgrading streaming connections. SPDY/3.1 has been deprecated for eight years,
and it was never standardized. Many modern proxies, gateways, and load balancers
no longer support the protocol. As a result, you might notice that commands like
&lt;code>kubectl cp&lt;/code>, &lt;code>kubectl attach&lt;/code>, &lt;code>kubectl exec&lt;/code>, and &lt;code>kubectl port-forward&lt;/code>
stop working when you try to access your cluster through a proxy or gateway.&lt;/p>
&lt;p>As of Kubernetes v1.31, SIG API Machinery has modified the streaming
protocol that a Kubernetes client (such as &lt;code>kubectl&lt;/code>) uses for these commands
to the more modern &lt;a href="https://datatracker.ietf.org/doc/html/rfc6455">WebSocket streaming protocol&lt;/a>.
The WebSocket protocol is a currently supported standardized streaming protocol
that guarantees compatibility and interoperability with different components and
programming languages. The WebSocket protocol is more widely supported by modern
proxies and gateways than SPDY.&lt;/p>
&lt;h2 id="how-streaming-apis-work">How streaming APIs work&lt;/h2>
&lt;p>Kubernetes upgrades HTTP connections to streaming connections by adding
specific upgrade headers to the originating HTTP request. For example, an HTTP
upgrade request for running the &lt;code>date&lt;/code> command on an &lt;code>nginx&lt;/code> container within
a cluster is similar to the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000080;font-weight:bold">$&lt;/span> kubectl &lt;span style="color:#a2f">exec&lt;/span> -v&lt;span style="color:#666">=&lt;/span>&lt;span style="color:#666">8&lt;/span> nginx -- date
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">GET https://127.0.0.1:43251/api/v1/namespaces/default/pods/nginx/exec?command=date…
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">Request Headers:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> Connection: Upgrade
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> Upgrade: websocket
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> Sec-Websocket-Protocol: v5.channel.k8s.io
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> User-Agent: kubectl/v1.31.0 (linux/amd64) kubernetes/6911225
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If the container runtime supports the WebSocket streaming protocol and at least
one of the subprotocol versions (e.g. &lt;code>v5.channel.k8s.io&lt;/code>), the server responds
with a successful &lt;code>101 Switching Protocols&lt;/code> status, along with the negotiated
subprotocol version:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">Response Status: 101 Switching Protocols in 3 milliseconds
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">Response Headers:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> Upgrade: websocket
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> Connection: Upgrade
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> Sec-Websocket-Accept: j0/jHW9RpaUoGsUAv97EcKw8jFM=
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888"> Sec-Websocket-Protocol: v5.channel.k8s.io
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At this point the TCP connection used for the HTTP protocol has changed to a
streaming connection. Subsequent STDIN, STDOUT, and STDERR data (as well as
terminal resizing data and process exit code data) for this shell interaction is
then streamed over this upgraded connection.&lt;/p>
&lt;h2 id="how-to-use-the-new-websocket-streaming-protocol">How to use the new WebSocket streaming protocol&lt;/h2>
&lt;p>If your cluster and kubectl are on version 1.29 or later, there are two
control plane feature gates and two kubectl environment variables that
govern the use of the WebSockets rather than SPDY. In Kubernetes 1.31,
all of the following feature gates are in beta and are enabled by
default:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/">Feature gates&lt;/a>
&lt;ul>
&lt;li>&lt;code>TranslateStreamCloseWebsocketRequests&lt;/code>
&lt;ul>
&lt;li>&lt;code>.../exec&lt;/code>&lt;/li>
&lt;li>&lt;code>.../attach&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>PortForwardWebsockets&lt;/code>
&lt;ul>
&lt;li>&lt;code>.../port-forward&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>kubectl feature control environment variables
&lt;ul>
&lt;li>&lt;code>KUBECTL_REMOTE_COMMAND_WEBSOCKETS&lt;/code>
&lt;ul>
&lt;li>&lt;code>kubectl exec&lt;/code>&lt;/li>
&lt;li>&lt;code>kubectl cp&lt;/code>&lt;/li>
&lt;li>&lt;code>kubectl attach&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>KUBECTL_PORT_FORWARD_WEBSOCKETS&lt;/code>
&lt;ul>
&lt;li>&lt;code>kubectl port-forward&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>If you're connecting to an older cluster but can manage the feature gate
settings, turn on both &lt;code>TranslateStreamCloseWebsocketRequests&lt;/code> (added in
Kubernetes v1.29) and &lt;code>PortForwardWebsockets&lt;/code> (added in Kubernetes
v1.30) to try this new behavior. Version 1.31 of &lt;code>kubectl&lt;/code> can automatically use
the new behavior, but you do need to connect to a cluster where the server-side
features are explicitly enabled.&lt;/p>
&lt;h2 id="learn-more-about-streaming-apis">Learn more about streaming APIs&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/4006-transition-spdy-to-websockets">KEP 4006 - Transitioning from SPDY to WebSockets&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://datatracker.ietf.org/doc/html/rfc6455">RFC 6455 - The WebSockets Protocol&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2024/05/01/cri-streaming-explained/">Container Runtime Interface streaming explained&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes 1.31: Pod Failure Policy for Jobs Goes GA</title><link>https://kubernetes.io/blog/2024/08/19/kubernetes-1-31-pod-failure-policy-for-jobs-goes-ga/</link><pubDate>Mon, 19 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/19/kubernetes-1-31-pod-failure-policy-for-jobs-goes-ga/</guid><description>
&lt;p>This post describes &lt;em>Pod failure policy&lt;/em>, which graduates to stable in Kubernetes
1.31, and how to use it in your Jobs.&lt;/p>
&lt;h2 id="about-pod-failure-policy">About Pod failure policy&lt;/h2>
&lt;p>When you run workloads on Kubernetes, Pods might fail for a variety of reasons.
Ideally, workloads like Jobs should be able to ignore transient, retriable
failures and continue running to completion.&lt;/p>
&lt;p>To allow for these transient failures, Kubernetes Jobs include the &lt;code>backoffLimit&lt;/code>
field, which lets you specify a number of Pod failures that you're willing to tolerate
during Job execution. However, if you set a large value for the &lt;code>backoffLimit&lt;/code> field
and rely solely on this field, you might notice unnecessary increases in operating
costs as Pods restart excessively until the backoffLimit is met.&lt;/p>
&lt;p>This becomes particularly problematic when running large-scale Jobs with
thousands of long-running Pods across thousands of nodes.&lt;/p>
&lt;p>The Pod failure policy extends the backoff limit mechanism to help you reduce
costs in the following ways:&lt;/p>
&lt;ul>
&lt;li>Gives you control to fail the Job as soon as a non-retriable Pod failure occurs.&lt;/li>
&lt;li>Allows you to ignore retriable errors without increasing the &lt;code>backoffLimit&lt;/code> field.&lt;/li>
&lt;/ul>
&lt;p>For example, you can use a Pod failure policy to run your workload on more affordable spot machines
by ignoring Pod failures caused by
&lt;a href="https://kubernetes.io/docs/concepts/cluster-administration/node-shutdown/#graceful-node-shutdown">graceful node shutdown&lt;/a>.&lt;/p>
&lt;p>The policy allows you to distinguish between retriable and non-retriable Pod
failures based on container exit codes or Pod conditions in a failed Pod.&lt;/p>
&lt;h2 id="how-it-works">How it works&lt;/h2>
&lt;p>You specify a Pod failure policy in the Job specification, represented as a list
of rules.&lt;/p>
&lt;p>For each rule you define &lt;em>match requirements&lt;/em> based on one of the following properties:&lt;/p>
&lt;ul>
&lt;li>Container exit codes: the &lt;code>onExitCodes&lt;/code> property.&lt;/li>
&lt;li>Pod conditions: the &lt;code>onPodConditions&lt;/code> property.&lt;/li>
&lt;/ul>
&lt;p>Additionally, for each rule, you specify one of the following actions to take
when a Pod matches the rule:&lt;/p>
&lt;ul>
&lt;li>&lt;code>Ignore&lt;/code>: Do not count the failure towards the &lt;code>backoffLimit&lt;/code> or &lt;code>backoffLimitPerIndex&lt;/code>.&lt;/li>
&lt;li>&lt;code>FailJob&lt;/code>: Fail the entire Job and terminate all running Pods.&lt;/li>
&lt;li>&lt;code>FailIndex&lt;/code>: Fail the index corresponding to the failed Pod.
This action works with the &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/job/#backoff-limit-per-index">Backoff limit per index&lt;/a> feature.&lt;/li>
&lt;li>&lt;code>Count&lt;/code>: Count the failure towards the &lt;code>backoffLimit&lt;/code> or &lt;code>backoffLimitPerIndex&lt;/code>.
This is the default behavior.&lt;/li>
&lt;/ul>
&lt;p>When Pod failures occur in a running Job, Kubernetes matches the
failed Pod status against the list of Pod failure policy rules, in the specified
order, and takes the corresponding actions for the first matched rule.&lt;/p>
&lt;p>Note that when specifying the Pod failure policy, you must also set the Job's
Pod template with &lt;code>restartPolicy: Never&lt;/code>. This prevents race conditions between
the kubelet and the Job controller when counting Pod failures.&lt;/p>
&lt;h3 id="kubernetes-initiated-pod-disruptions">Kubernetes-initiated Pod disruptions&lt;/h3>
&lt;p>To allow matching Pod failure policy rules against failures caused by
disruptions initiated by Kubernetes, this feature introduces the &lt;code>DisruptionTarget&lt;/code>
Pod condition.&lt;/p>
&lt;p>Kubernetes adds this condition to any Pod, regardless of whether it's managed by
a Job controller, that fails because of a retriable
&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#pod-disruption-conditions">disruption scenario&lt;/a>.
The &lt;code>DisruptionTarget&lt;/code> condition contains one of the following reasons that
corresponds to these disruption scenarios:&lt;/p>
&lt;ul>
&lt;li>&lt;code>PreemptionByKubeScheduler&lt;/code>: &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/">Preemption&lt;/a>
by &lt;code>kube-scheduler&lt;/code> to accommodate a new Pod that has a higher priority.&lt;/li>
&lt;li>&lt;code>DeletionByTaintManager&lt;/code> - the Pod is due to be deleted by
&lt;code>kube-controller-manager&lt;/code> due to a &lt;code>NoExecute&lt;/code> &lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/">taint&lt;/a>
that the Pod doesn't tolerate.&lt;/li>
&lt;li>&lt;code>EvictionByEvictionAPI&lt;/code> - the Pod is due to be deleted by an
&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/api-eviction/">API-initiated eviction&lt;/a>.&lt;/li>
&lt;li>&lt;code>DeletionByPodGC&lt;/code> - the Pod is bound to a node that no longer exists, and is due to
be deleted by &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-garbage-collection">Pod garbage collection&lt;/a>.&lt;/li>
&lt;li>&lt;code>TerminationByKubelet&lt;/code> - the Pod was terminated by
&lt;a href="https://kubernetes.io/docs/concepts/cluster-administration/node-shutdown/#graceful-node-shutdown">graceful node shutdown&lt;/a>,
&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">node pressure eviction&lt;/a>
or preemption for &lt;a href="https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/">system critical pods&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>In all other disruption scenarios, like eviction due to exceeding
&lt;a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/">Pod container limits&lt;/a>,
Pods don't receive the &lt;code>DisruptionTarget&lt;/code> condition because the disruptions were
likely caused by the Pod and would reoccur on retry.&lt;/p>
&lt;h3 id="example">Example&lt;/h3>
&lt;p>The Pod failure policy snippet below demonstrates an example use:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">podFailurePolicy&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">rules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">action&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Ignore&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">onPodConditions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>DisruptionTarget&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">action&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>FailJob&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">onPodConditions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ConfigIssue&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">action&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>FailJob&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">onExitCodes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>In&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">values&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">42&lt;/span>&lt;span style="color:#bbb"> &lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In this example, the Pod failure policy does the following:&lt;/p>
&lt;ul>
&lt;li>Ignores any failed Pods that have the built-in &lt;code>DisruptionTarget&lt;/code>
condition. These Pods don't count towards Job backoff limits.&lt;/li>
&lt;li>Fails the Job if any failed Pods have the custom user-supplied
&lt;code>ConfigIssue&lt;/code> condition, which was added either by a custom controller or webhook.&lt;/li>
&lt;li>Fails the Job if any containers exited with the exit code 42.&lt;/li>
&lt;li>Counts all other Pod failures towards the default &lt;code>backoffLimit&lt;/code> (or
&lt;code>backoffLimitPerIndex&lt;/code> if used).&lt;/li>
&lt;/ul>
&lt;h2 id="learn-more">Learn more&lt;/h2>
&lt;ul>
&lt;li>For a hands-on guide to using Pod failure policy, see
&lt;a href="https://kubernetes.io/docs/tasks/job/pod-failure-policy/">Handling retriable and non-retriable pod failures with Pod failure policy&lt;/a>&lt;/li>
&lt;li>Read the documentation for
&lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/job/#pod-failure-policy">Pod failure policy&lt;/a> and
&lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/job/#backoff-limit-per-index">Backoff limit per index&lt;/a>&lt;/li>
&lt;li>Read the documentation for
&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#pod-disruption-conditions">Pod disruption conditions&lt;/a>&lt;/li>
&lt;li>Read the KEP for &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-apps/3329-retriable-and-non-retriable-failures">Pod failure policy&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="related-work">Related work&lt;/h2>
&lt;p>Based on the concepts introduced by Pod failure policy, the following additional work is in progress:&lt;/p>
&lt;ul>
&lt;li>JobSet integration: &lt;a href="https://github.com/kubernetes-sigs/jobset/issues/262">Configurable Failure Policy API&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4443">Pod failure policy extension to add more granular failure reasons&lt;/a>&lt;/li>
&lt;li>Support for Pod failure policy via JobSet in &lt;a href="https://github.com/kubeflow/training-operator/pull/2171">Kubeflow Training v2&lt;/a>&lt;/li>
&lt;li>Proposal: &lt;a href="https://docs.google.com/document/d/1t25jgO_-LRHhjRXf4KJ5xY_t8BZYdapv7MDAxVGY6R8">Disrupted Pods should be removed from endpoints&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="get-involved">Get involved&lt;/h2>
&lt;p>This work was sponsored by
&lt;a href="https://github.com/kubernetes/community/tree/master/wg-batch">batch working group&lt;/a>
in close collaboration with the
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-apps">SIG Apps&lt;/a>,
and &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a>,
and &lt;a href="https://github.com/kubernetes/community/tree/master/sig-scheduling">SIG Scheduling&lt;/a>
communities.&lt;/p>
&lt;p>If you are interested in working on new features in the space we recommend
subscribing to our &lt;a href="https://kubernetes.slack.com/messages/wg-batch">Slack&lt;/a>
channel and attending the regular community meetings.&lt;/p>
&lt;h2 id="acknowledgments">Acknowledgments&lt;/h2>
&lt;p>I would love to thank everyone who was involved in this project over the years -
it's been a journey and a joint community effort! The list below is
my best-effort attempt to remember and recognize people who made an impact.
Thank you!&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/alculquicondor/">Aldo Culquicondor&lt;/a> for guidance and reviews throughout the process&lt;/li>
&lt;li>&lt;a href="https://github.com/liggitt">Jordan Liggitt&lt;/a> for KEP and API reviews&lt;/li>
&lt;li>&lt;a href="https://github.com/deads2k">David Eads&lt;/a> for API reviews&lt;/li>
&lt;li>&lt;a href="https://github.com/soltysh">Maciej Szulik&lt;/a> for KEP reviews from SIG Apps PoV&lt;/li>
&lt;li>&lt;a href="https://github.com/smarterclayton">Clayton Coleman&lt;/a> for guidance and SIG Node reviews&lt;/li>
&lt;li>&lt;a href="https://github.com/SergeyKanzhelev">Sergey Kanzhelev&lt;/a> for KEP reviews from SIG Node PoV&lt;/li>
&lt;li>&lt;a href="https://github.com/dchen1107">Dawn Chen&lt;/a> for KEP reviews from SIG Node PoV&lt;/li>
&lt;li>&lt;a href="https://github.com/lavalamp">Daniel Smith&lt;/a> for reviews from SIG API machinery PoV&lt;/li>
&lt;li>&lt;a href="https://github.com/apelisse">Antoine Pelisse&lt;/a> for reviews from SIG API machinery PoV&lt;/li>
&lt;li>&lt;a href="https://github.com/johnbelamaric">John Belamaric&lt;/a> for PRR reviews&lt;/li>
&lt;li>&lt;a href="https://github.com/atiratree">Filip Křepinský&lt;/a> for thorough reviews from SIG Apps PoV and bug-fixing&lt;/li>
&lt;li>&lt;a href="https://github.com/bobbypage">David Porter&lt;/a> for thorough reviews from SIG Node PoV&lt;/li>
&lt;li>&lt;a href="https://github.com/jensentanlo">Jensen Lo&lt;/a> for early requirements discussions, testing and reporting issues&lt;/li>
&lt;li>&lt;a href="https://github.com/danielvegamyhre">Daniel Vega-Myhre&lt;/a> for advancing JobSet integration and reporting issues&lt;/li>
&lt;li>&lt;a href="https://github.com/ahg-g">Abdullah Gharaibeh&lt;/a> for early design discussions and guidance&lt;/li>
&lt;li>&lt;a href="https://github.com/aojea">Antonio Ojea&lt;/a> for test reviews&lt;/li>
&lt;li>&lt;a href="https://github.com/tenzen-y">Yuki Iwai&lt;/a> for reviews and aligning implementation of the closely related Job features&lt;/li>
&lt;li>&lt;a href="https://github.com/kannon92">Kevin Hannon&lt;/a> for reviews and aligning implementation of the closely related Job features&lt;/li>
&lt;li>&lt;a href="https://github.com/sftim">Tim Bannister&lt;/a> for docs reviews&lt;/li>
&lt;li>&lt;a href="https://github.com/shannonxtreme">Shannon Kularathna&lt;/a> for docs reviews&lt;/li>
&lt;li>&lt;a href="https://github.com/cortespao">Paola Cortés&lt;/a> for docs reviews&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes 1.31: MatchLabelKeys in PodAffinity graduates to beta</title><link>https://kubernetes.io/blog/2024/08/16/matchlabelkeys-podaffinity/</link><pubDate>Fri, 16 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/16/matchlabelkeys-podaffinity/</guid><description>
&lt;p>Kubernetes 1.29 introduced new fields &lt;code>matchLabelKeys&lt;/code> and &lt;code>mismatchLabelKeys&lt;/code> in &lt;code>podAffinity&lt;/code> and &lt;code>podAntiAffinity&lt;/code>.&lt;/p>
&lt;p>In Kubernetes 1.31, this feature moves to beta and the corresponding feature gate (&lt;code>MatchLabelKeysInPodAffinity&lt;/code>) gets enabled by default.&lt;/p>
&lt;h2 id="matchlabelkeys-enhanced-scheduling-for-versatile-rolling-updates">&lt;code>matchLabelKeys&lt;/code> - Enhanced scheduling for versatile rolling updates&lt;/h2>
&lt;p>During a workload's (e.g., Deployment) rolling update, a cluster may have Pods from multiple versions at the same time.
However, the scheduler cannot distinguish between old and new versions based on the &lt;code>labelSelector&lt;/code> specified in &lt;code>podAffinity&lt;/code> or &lt;code>podAntiAffinity&lt;/code>. As a result, it will co-locate or disperse Pods regardless of their versions.&lt;/p>
&lt;p>This can lead to sub-optimal scheduling outcome, for example:&lt;/p>
&lt;ul>
&lt;li>New version Pods are co-located with old version Pods (&lt;code>podAffinity&lt;/code>), which will eventually be removed after rolling updates.&lt;/li>
&lt;li>Old version Pods are distributed across all available topologies, preventing new version Pods from finding nodes due to &lt;code>podAntiAffinity&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>&lt;code>matchLabelKeys&lt;/code> is a set of Pod label keys and addresses this problem.
The scheduler looks up the values of these keys from the new Pod's labels and combines them with &lt;code>labelSelector&lt;/code>
so that podAffinity matches Pods that have the same key-value in labels.&lt;/p>
&lt;p>By using label &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#pod-template-hash-label">pod-template-hash&lt;/a> in &lt;code>matchLabelKeys&lt;/code>,
you can ensure that only Pods of the same version are evaluated for &lt;code>podAffinity&lt;/code> or &lt;code>podAntiAffinity&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apps/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Deployment&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>application-server&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">...&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">affinity&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">podAffinity&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredDuringSchedulingIgnoredDuringExecution&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">labelSelector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchExpressions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>app&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>In&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">values&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- database&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">topologyKey&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>topology.kubernetes.io/zone&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchLabelKeys&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- pod-template-hash&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The above &lt;code>matchLabelKeys&lt;/code> will be translated in Pods like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>application-server&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">labels&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">pod-template-hash&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>xyz&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">...&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">affinity&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">podAffinity&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredDuringSchedulingIgnoredDuringExecution&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">labelSelector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchExpressions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>app&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>In&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">values&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- database&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>pod-template-hash&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Added from matchLabelKeys; Only Pods from the same replicaset will match this affinity.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>In&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">values&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- xyz&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">topologyKey&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>topology.kubernetes.io/zone&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchLabelKeys&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- pod-template-hash&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="mismatchlabelkeys-service-isolation">&lt;code>mismatchLabelKeys&lt;/code> - Service isolation&lt;/h2>
&lt;p>&lt;code>mismatchLabelKeys&lt;/code> is a set of Pod label keys, like &lt;code>matchLabelKeys&lt;/code>,
which looks up the values of these keys from the new Pod's labels, and merge them with &lt;code>labelSelector&lt;/code> as &lt;code>key notin (value)&lt;/code>
so that &lt;code>podAffinity&lt;/code> does &lt;em>not&lt;/em> match Pods that have the same key-value in labels.&lt;/p>
&lt;p>Suppose all Pods for each tenant get &lt;code>tenant&lt;/code> label via a controller or a manifest management tool like Helm.&lt;/p>
&lt;p>Although the value of &lt;code>tenant&lt;/code> label is unknown when composing each workload's manifest,
the cluster admin wants to achieve exclusive 1:1 tenant to domain placement for a tenant isolation.&lt;/p>
&lt;p>&lt;code>mismatchLabelKeys&lt;/code> works for this usecase;
By applying the following affinity globally using a mutating webhook,
the cluster admin can ensure that the Pods from the same tenant will land on the same domain exclusively,
meaning Pods from other tenants won't land on the same domain.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">affinity&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">podAffinity&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># ensures the pods of this tenant land on the same node pool&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredDuringSchedulingIgnoredDuringExecution&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">matchLabelKeys&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">topologyKey&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>node-pool&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">podAntiAffinity&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># ensures only Pods from this tenant lands on the same node pool&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredDuringSchedulingIgnoredDuringExecution&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">mismatchLabelKeys&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">labelSelector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchExpressions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Exists&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">topologyKey&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>node-pool&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The above &lt;code>matchLabelKeys&lt;/code> and &lt;code>mismatchLabelKeys&lt;/code> will be translated to like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>application-server&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">labels&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">tenant&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>service-a&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">affinity&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">podAffinity&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># ensures the pods of this tenant land on the same node pool&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredDuringSchedulingIgnoredDuringExecution&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">matchLabelKeys&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">topologyKey&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>node-pool&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">labelSelector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchExpressions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>In&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">values&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- service-a &lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">podAntiAffinity&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># ensures only Pods from this tenant lands on the same node pool&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredDuringSchedulingIgnoredDuringExecution&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">mismatchLabelKeys&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">labelSelector&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchExpressions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Exists&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>tenant&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">operator&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>NotIn&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">values&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- service-a&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">topologyKey&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>node-pool&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="getting-involved">Getting involved&lt;/h2>
&lt;p>These features are managed by Kubernetes &lt;a href="https://github.com/kubernetes/community/tree/master/sig-scheduling">SIG Scheduling&lt;/a>.&lt;/p>
&lt;p>Please join us and share your feedback. We look forward to hearing from you!&lt;/p>
&lt;h2 id="how-can-i-learn-more">How can I learn more?&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity">The official document of podAffinity&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/3633-matchlabelkeys-to-podaffinity/README.md#story-2">KEP-3633: Introduce matchLabelKeys and mismatchLabelKeys to podAffinity and podAntiAffinity&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes 1.31: Prevent PersistentVolume Leaks When Deleting out of Order</title><link>https://kubernetes.io/blog/2024/08/16/kubernetes-1-31-prevent-persistentvolume-leaks-when-deleting-out-of-order/</link><pubDate>Fri, 16 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/16/kubernetes-1-31-prevent-persistentvolume-leaks-when-deleting-out-of-order/</guid><description>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">PersistentVolume&lt;/a> (or PVs for short) are
associated with &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaim-policy">Reclaim Policy&lt;/a>.
The reclaim policy is used to determine the actions that need to be taken by the storage
backend on deletion of the PVC Bound to a PV.
When the reclaim policy is &lt;code>Delete&lt;/code>, the expectation is that the storage backend
releases the storage resource allocated for the PV. In essence, the reclaim
policy needs to be honored on PV deletion.&lt;/p>
&lt;p>With the recent Kubernetes v1.31 release, a beta feature lets you configure your
cluster to behave that way and honor the configured reclaim policy.&lt;/p>
&lt;h2 id="how-did-reclaim-work-in-previous-kubernetes-releases">How did reclaim work in previous Kubernetes releases?&lt;/h2>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#Introduction">PersistentVolumeClaim&lt;/a> (or PVC for short) is
a user's request for storage. A PV and PVC are considered &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#Binding">Bound&lt;/a>
if a newly created PV or a matching PV is found. The PVs themselves are
backed by volumes allocated by the storage backend.&lt;/p>
&lt;p>Normally, if the volume is to be deleted, then the expectation is to delete the
PVC for a bound PV-PVC pair. However, there are no restrictions on deleting a PV
before deleting a PVC.&lt;/p>
&lt;p>First, I'll demonstrate the behavior for clusters running an older version of Kubernetes.&lt;/p>
&lt;h4 id="retrieve-a-pvc-that-is-bound-to-a-pv">Retrieve a PVC that is bound to a PV&lt;/h4>
&lt;p>Retrieve an existing PVC &lt;code>example-vanilla-block-pvc&lt;/code>&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl get pvc example-vanilla-block-pvc
&lt;/code>&lt;/pre>&lt;p>The following output shows the PVC and its bound PV; the PV is shown under the &lt;code>VOLUME&lt;/code> column:&lt;/p>
&lt;pre tabindex="0">&lt;code>NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
example-vanilla-block-pvc Bound pvc-6791fdd4-5fad-438e-a7fb-16410363e3da 5Gi RWO example-vanilla-block-sc 19s
&lt;/code>&lt;/pre>&lt;h4 id="delete-pv">Delete PV&lt;/h4>
&lt;p>When I try to delete a bound PV, the kubectl session blocks and the &lt;code>kubectl&lt;/code>
tool does not return back control to the shell; for example:&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl delete pv pvc-6791fdd4-5fad-438e-a7fb-16410363e3da
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>persistentvolume &amp;#34;pvc-6791fdd4-5fad-438e-a7fb-16410363e3da&amp;#34; deleted
^C
&lt;/code>&lt;/pre>&lt;h4 id="retrieving-the-pv">Retrieving the PV&lt;/h4>
&lt;pre tabindex="0">&lt;code>kubectl get pv pvc-6791fdd4-5fad-438e-a7fb-16410363e3da
&lt;/code>&lt;/pre>&lt;p>It can be observed that the PV is in a &lt;code>Terminating&lt;/code> state&lt;/p>
&lt;pre tabindex="0">&lt;code>NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-6791fdd4-5fad-438e-a7fb-16410363e3da 5Gi RWO Delete Terminating default/example-vanilla-block-pvc example-vanilla-block-sc 2m23s
&lt;/code>&lt;/pre>&lt;h4 id="delete-pvc">Delete PVC&lt;/h4>
&lt;pre tabindex="0">&lt;code>kubectl delete pvc example-vanilla-block-pvc
&lt;/code>&lt;/pre>&lt;p>The following output is seen if the PVC gets successfully deleted:&lt;/p>
&lt;pre tabindex="0">&lt;code>persistentvolumeclaim &amp;#34;example-vanilla-block-pvc&amp;#34; deleted
&lt;/code>&lt;/pre>&lt;p>The PV object from the cluster also gets deleted. When attempting to retrieve the PV
it will be observed that the PV is no longer found:&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl get pv pvc-6791fdd4-5fad-438e-a7fb-16410363e3da
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>Error from server (NotFound): persistentvolumes &amp;#34;pvc-6791fdd4-5fad-438e-a7fb-16410363e3da&amp;#34; not found
&lt;/code>&lt;/pre>&lt;p>Although the PV is deleted, the underlying storage resource is not deleted and
needs to be removed manually.&lt;/p>
&lt;p>To sum up, the reclaim policy associated with the PersistentVolume is currently
ignored under certain circumstances. For a &lt;code>Bound&lt;/code> PV-PVC pair, the ordering of PV-PVC
deletion determines whether the PV reclaim policy is honored. The reclaim policy
is honored if the PVC is deleted first; however, if the PV is deleted prior to
deleting the PVC, then the reclaim policy is not exercised. As a result of this behavior,
the associated storage asset in the external infrastructure is not removed.&lt;/p>
&lt;h2 id="pv-reclaim-policy-with-kubernetes-v1-31">PV reclaim policy with Kubernetes v1.31&lt;/h2>
&lt;p>The new behavior ensures that the underlying storage object is deleted from the backend when users attempt to delete a PV manually.&lt;/p>
&lt;h4 id="how-to-enable-new-behavior">How to enable new behavior?&lt;/h4>
&lt;p>To take advantage of the new behavior, you must have upgraded your cluster to the v1.31 release of Kubernetes
and run the CSI &lt;a href="https://github.com/kubernetes-csi/external-provisioner">&lt;code>external-provisioner&lt;/code>&lt;/a> version &lt;code>5.0.1&lt;/code> or later.&lt;/p>
&lt;h4 id="how-does-it-work">How does it work?&lt;/h4>
&lt;p>For CSI volumes, the new behavior is achieved by adding a &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/">finalizer&lt;/a> &lt;code>external-provisioner.volume.kubernetes.io/finalizer&lt;/code>
on new and existing PVs. The finalizer is only removed after the storage from the backend is deleted.
`&lt;/p>
&lt;p>An example of a PV with the finalizer, notice the new finalizer in the finalizers list&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl get pv pvc-a7b7e3ba-f837-45ba-b243-dec7d8aaed53 -o yaml
&lt;/code>&lt;/pre>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PersistentVolume&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">annotations&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">pv.kubernetes.io/provisioned-by&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>csi.vsphere.vmware.com&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">creationTimestamp&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;2021-11-17T19:28:56Z&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">finalizers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- kubernetes.io/pv-protection&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- external-provisioner.volume.kubernetes.io/finalizer&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>pvc-a7b7e3ba-f837-45ba-b243-dec7d8aaed53&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">resourceVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;194711&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">uid&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>087f14f2-4157-4e95-8a70-8294b039d30e&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">accessModes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- ReadWriteOnce&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">capacity&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">storage&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>1Gi&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claimRef&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PersistentVolumeClaim&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>example-vanilla-block-pvc&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>default&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">resourceVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;194677&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">uid&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>a7b7e3ba-f837-45ba-b243-dec7d8aaed53&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">csi&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">driver&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>csi.vsphere.vmware.com&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">fsType&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ext4&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeAttributes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">storage.kubernetes.io/csiProvisionerIdentity&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">1637110610497-8081&lt;/span>-csi.vsphere.vmware.com&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>vSphere CNS Block Volume&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeHandle&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>2dacf297-803f-4ccc-afc7-3d3c3f02051e&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">persistentVolumeReclaimPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Delete&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">storageClassName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>example-vanilla-block-sc&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeMode&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Filesystem&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">status&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">phase&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Bound&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/">finalizer&lt;/a> prevents this
PersistentVolume from being removed from the
cluster. As stated previously, the finalizer is only removed from the PV object
after it is successfully deleted from the storage backend. To learn more about
finalizers, please refer to &lt;a href="https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/">Using Finalizers to Control Deletion&lt;/a>.&lt;/p>
&lt;p>Similarly, the finalizer &lt;code>kubernetes.io/pv-controller&lt;/code> is added to dynamically provisioned in-tree plugin volumes.&lt;/p>
&lt;h4 id="what-about-csi-migrated-volumes">What about CSI migrated volumes?&lt;/h4>
&lt;p>The fix applies to CSI migrated volumes as well.&lt;/p>
&lt;h3 id="some-caveats">Some caveats&lt;/h3>
&lt;p>The fix does not apply to statically provisioned in-tree plugin volumes.&lt;/p>
&lt;h3 id="references">References&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/2644-honor-pv-reclaim-policy">KEP-2644&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes-csi/external-provisioner/issues/546">Volume leak issue&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="how-do-i-get-involved">How do I get involved?&lt;/h3>
&lt;p>The Kubernetes Slack channel &lt;a href="https://github.com/kubernetes/community/blob/master/sig-storage/README.md#contact">SIG Storage communication channels&lt;/a> are great mediums to reach out to the SIG Storage and migration working group teams.&lt;/p>
&lt;p>Special thanks to the following people for the insightful reviews, thorough consideration and valuable contribution:&lt;/p>
&lt;ul>
&lt;li>Fan Baofa (carlory)&lt;/li>
&lt;li>Jan Šafránek (jsafrane)&lt;/li>
&lt;li>Xing Yang (xing-yang)&lt;/li>
&lt;li>Matthew Wong (wongma7)&lt;/li>
&lt;/ul>
&lt;p>Join the &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">Kubernetes Storage Special Interest Group (SIG)&lt;/a> if you're interested in getting involved with the design and development of CSI or any part of the Kubernetes Storage system. We’re rapidly growing and always welcome new contributors.&lt;/p></description></item><item><title>Kubernetes 1.31: Read Only Volumes Based On OCI Artifacts (alpha)</title><link>https://kubernetes.io/blog/2024/08/16/kubernetes-1-31-image-volume-source/</link><pubDate>Fri, 16 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/16/kubernetes-1-31-image-volume-source/</guid><description>
&lt;p>The Kubernetes community is moving towards fulfilling more Artificial
Intelligence (AI) and Machine Learning (ML) use cases in the future. While the
project has been designed to fulfill microservice architectures in the past,
it’s now time to listen to the end users and introduce features which have a
stronger focus on AI/ML.&lt;/p>
&lt;p>One of these requirements is to support &lt;a href="https://opencontainers.org">Open Container Initiative (OCI)&lt;/a>
compatible images and artifacts (referred as OCI objects) directly as a native
volume source. This allows users to focus on OCI standards as well as enables
them to store and distribute any content using OCI registries. A feature like
this gives the Kubernetes project a chance to grow into use cases which go
beyond running particular images.&lt;/p>
&lt;p>Given that, the Kubernetes community is proud to present a new alpha feature
introduced in v1.31: The Image Volume Source
(&lt;a href="https://kep.k8s.io/4639">KEP-4639&lt;/a>). This feature allows users to specify an
image reference as volume in a pod while reusing it as volume mount within
containers:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>…&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- …&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeMounts&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>my-volume&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">mountPath&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/path/to/directory&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>my-volume&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">reference&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>my-image:tag&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The above example would result in mounting &lt;code>my-image:tag&lt;/code> to
&lt;code>/path/to/directory&lt;/code> in the pod’s container.&lt;/p>
&lt;h2 id="use-cases">Use cases&lt;/h2>
&lt;p>The goal of this enhancement is to stick as close as possible to the existing
&lt;a href="https://kubernetes.io/docs/concepts/containers/images/">container image&lt;/a> implementation within the
kubelet, while introducing a new API surface to allow more extended use cases.&lt;/p>
&lt;p>For example, users could share a configuration file among multiple containers in
a pod without including the file in the main image, so that they can minimize
security risks and the overall image size. They can also package and distribute
binary artifacts using OCI images and mount them directly into Kubernetes pods,
so that they can streamline their CI/CD pipeline as an example.&lt;/p>
&lt;p>Data scientists, MLOps engineers, or AI developers, can mount large language
model weights or machine learning model weights in a pod alongside a
model-server, so that they can efficiently serve them without including them in
the model-server container image. They can package these in an OCI object to
take advantage of OCI distribution and ensure efficient model deployment. This
allows them to separate the model specifications/content from the executables
that process them.&lt;/p>
&lt;p>Another use case is that security engineers can use a public image for a malware
scanner and mount in a volume of private (commercial) malware signatures, so
that they can load those signatures without baking their own combined image
(which might not be allowed by the copyright on the public image). Those files
work regardless of the OS or version of the scanner software.&lt;/p>
&lt;p>But in the long term it will be up to &lt;strong>you&lt;/strong> as an end user of this project to
outline further important use cases for the new feature.
&lt;a href="https://github.com/kubernetes/community/blob/54a67f5/sig-node/README.md">SIG Node&lt;/a>
is happy to retrieve any feedback or suggestions for further enhancements to
allow more advanced usage scenarios. Feel free to provide feedback by either
using the &lt;a href="https://kubernetes.slack.com/messages/sig-node">Kubernetes Slack (#sig-node)&lt;/a>
channel or the &lt;a href="https://groups.google.com/g/kubernetes-sig-node">SIG Node mailinglist&lt;/a>.&lt;/p>
&lt;h2 id="example">Detailed example&lt;/h2>
&lt;p>The Kubernetes alpha feature gate &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/">&lt;code>ImageVolume&lt;/code>&lt;/a>
needs to be enabled on the &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/">API Server&lt;/a>
as well as the &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/">kubelet&lt;/a>
to make it functional. If that’s the case and the &lt;a href="https://kubernetes.io/docs/setup/production-environment/container-runtimes/">container runtime&lt;/a>
has support for the feature (like CRI-O ≥ v1.31), then an example &lt;code>pod.yaml&lt;/code>
like this can be created:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>pod&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>test&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>registry.k8s.io/e2e-test-images/echoserver:2.3&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeMounts&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>volume&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">mountPath&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/volume&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>volume&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">image&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">reference&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>quay.io/crio/artifact:v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">pullPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>IfNotPresent&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The pod declares a new volume using the &lt;code>image.reference&lt;/code> of
&lt;code>quay.io/crio/artifact:v1&lt;/code>, which refers to an OCI object containing two files.
The &lt;code>pullPolicy&lt;/code> behaves in the same way as for container images and allows the
following values:&lt;/p>
&lt;ul>
&lt;li>&lt;code>Always&lt;/code>: the kubelet always attempts to pull the reference and the container
creation will fail if the pull fails.&lt;/li>
&lt;li>&lt;code>Never&lt;/code>: the kubelet never pulls the reference and only uses a local image or
artifact. The container creation will fail if the reference isn’t present.&lt;/li>
&lt;li>&lt;code>IfNotPresent&lt;/code>: the kubelet pulls if the reference isn’t already present on
disk. The container creation will fail if the reference isn’t present and the
pull fails.&lt;/li>
&lt;/ul>
&lt;p>The &lt;code>volumeMounts&lt;/code> field is indicating that the container with the name &lt;code>test&lt;/code>
should mount the volume under the path &lt;code>/volume&lt;/code>.&lt;/p>
&lt;p>If you now create the pod:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl apply -f pod.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And exec into it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl &lt;span style="color:#a2f">exec&lt;/span> -it pod -- sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then you’re able to investigate what has been mounted:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-console" data-lang="console">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">/ # ls /volume
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">dir file
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">/ # cat /volume/file
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">2
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">/ # ls /volume/dir
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">file
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">/ # cat /volume/dir/file
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#888">1
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>You managed to consume an OCI artifact using Kubernetes!&lt;/strong>&lt;/p>
&lt;p>The container runtime pulls the image (or artifact), mounts it to the
container and makes it finally available for direct usage. There are a bunch of
details in the implementation, which closely align to the existing image pull
behavior of the kubelet. For example:&lt;/p>
&lt;ul>
&lt;li>If a &lt;code>:latest&lt;/code> tag as &lt;code>reference&lt;/code> is provided, then the &lt;code>pullPolicy&lt;/code> will
default to &lt;code>Always&lt;/code>, while in any other case it will default to &lt;code>IfNotPresent&lt;/code>
if unset.&lt;/li>
&lt;li>The volume gets re-resolved if the pod gets deleted and recreated, which means
that new remote content will become available on pod recreation. A failure to
resolve or pull the image during pod startup will block containers from
starting and may add significant latency. Failures will be retried using
normal volume backoff and will be reported on the pod reason and message.&lt;/li>
&lt;li>Pull secrets will be assembled in the same way as for the container image by
looking up node credentials, service account image pull secrets, and pod spec
image pull secrets.&lt;/li>
&lt;li>The OCI object gets mounted in a single directory by merging the manifest
layers in the same way as for container images.&lt;/li>
&lt;li>The volume is mounted as read-only (&lt;code>ro&lt;/code>) and non-executable files
(&lt;code>noexec&lt;/code>).&lt;/li>
&lt;li>Sub-path mounts for containers are not supported
(&lt;code>spec.containers[*].volumeMounts.subpath&lt;/code>).&lt;/li>
&lt;li>The field &lt;code>spec.securityContext.fsGroupChangePolicy&lt;/code> has no effect on this
volume type.&lt;/li>
&lt;li>The feature will also work with the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages">&lt;code>AlwaysPullImages&lt;/code> admission plugin&lt;/a>
if enabled.&lt;/li>
&lt;/ul>
&lt;p>Thank you for reading through the end of this blog post! SIG Node is proud and
happy to deliver this feature as part of Kubernetes v1.31.&lt;/p>
&lt;p>As writer of this blog post, I would like to emphasize my special thanks to
&lt;strong>all&lt;/strong> involved individuals out there! You all rock, let’s keep on hacking!&lt;/p>
&lt;h2 id="further-reading">Further reading&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/">Use an Image Volume With a Pod&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/#image">&lt;code>image&lt;/code> volume overview&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes 1.31: VolumeAttributesClass for Volume Modification Beta</title><link>https://kubernetes.io/blog/2024/08/15/kubernetes-1-31-volume-attributes-class/</link><pubDate>Thu, 15 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/15/kubernetes-1-31-volume-attributes-class/</guid><description>
&lt;p>Volumes in Kubernetes have been described by two attributes: their storage class, and
their capacity. The storage class is an immutable property of the volume, while the
capacity can be changed dynamically with &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#expanding-persistent-volumes-claims">volume
resize&lt;/a>.&lt;/p>
&lt;p>This complicates vertical scaling of workloads with volumes. While cloud providers and
storage vendors often offer volumes which allow specifying IO quality of service
(Performance) parameters like IOPS or throughput and tuning them as workloads operate,
Kubernetes has no API which allows changing them.&lt;/p>
&lt;p>We are pleased to announce that the &lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/3751-volume-attributes-class/README.md">VolumeAttributesClass
KEP&lt;/a>,
alpha since Kubernetes 1.29, will be beta in 1.31. This provides a generic,
Kubernetes-native API for modifying volume parameters like provisioned IO.&lt;/p>
&lt;p>Like all new volume features in Kubernetes, this API is implemented via the &lt;a href="https://kubernetes-csi.github.io/docs/">container
storage interface (CSI)&lt;/a>. In addition to the
VolumeAttributesClass feature gate, your provisioner-specific CSI driver must support the
new ModifyVolume API which is the CSI side of this feature.&lt;/p>
&lt;p>See the &lt;a href="https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/">full
documentation&lt;/a>
for all details. Here we show the common workflow.&lt;/p>
&lt;h3 id="dynamically-modifying-volume-attributes">Dynamically modifying volume attributes.&lt;/h3>
&lt;p>A &lt;code>VolumeAttributesClass&lt;/code> is a cluster-scoped resource that specifies provisioner-specific
attributes. These are created by the cluster administrator in the same way as storage
classes. For example, a series of gold, silver and bronze volume attribute classes can be
created for volumes with greater or lessor amounts of provisioned IO.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>storage.k8s.io/v1alpha1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeAttributesClass&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>silver&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">driverName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>your-csi-driver&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">parameters&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">provisioned-iops&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;500&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">provisioned-throughput&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;50MiB/s&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">---&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>storage.k8s.io/v1alpha1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeAttributesClass&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gold&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">driverName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>your-csi-driver&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">parameters&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">provisioned-iops&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;10000&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">provisioned-throughput&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;500MiB/s&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>An attribute class is added to a PVC in much the same way as a storage class.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>PersistentVolumeClaim&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>test-pv-claim&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">storageClassName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>any-storage-class&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeAttributesClassName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>silver&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">accessModes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- ReadWriteOnce&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">resources&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requests&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">storage&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>64Gi&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Unlike a storage class, the volume attributes class can be changed:&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl patch pvc test-pv-claim -p &amp;#39;{&amp;#34;spec&amp;#34;: &amp;#34;volumeAttributesClassName&amp;#34;: &amp;#34;gold&amp;#34;}&amp;#39;
&lt;/code>&lt;/pre>&lt;p>Kubernetes will work with the CSI driver to update the attributes of the
volume. The status of the PVC will track the current and desired attributes
class. The PV resource will also be updated with the new volume attributes class
which will be set to the currently active attributes of the PV.&lt;/p>
&lt;h3 id="limitations-with-the-beta">Limitations with the beta&lt;/h3>
&lt;p>As a beta feature, there are still some features which are planned for GA but not yet
present. The largest is quota support, see the
&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/3751-volume-attributes-class/README.md">KEP&lt;/a>
and discussion in
&lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">sig-storage&lt;/a> for details.&lt;/p>
&lt;p>See the &lt;a href="https://kubernetes-csi.github.io/docs/drivers.html">Kubernetes CSI driver
list&lt;/a> for up-to-date
information of support for this feature in CSI drivers.&lt;/p></description></item><item><title>Kubernetes v1.31: Accelerating Cluster Performance with Consistent Reads from Cache</title><link>https://kubernetes.io/blog/2024/08/15/consistent-read-from-cache-beta/</link><pubDate>Thu, 15 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/15/consistent-read-from-cache-beta/</guid><description>
&lt;p>Kubernetes is renowned for its robust orchestration of containerized applications,
but as clusters grow, the demands on the control plane can become a bottleneck.
A key challenge has been ensuring strongly consistent reads from the etcd datastore,
requiring resource-intensive quorum reads.&lt;/p>
&lt;p>Today, the Kubernetes community is excited to announce a major improvement:
&lt;em>consistent reads from cache&lt;/em>, graduating to Beta in Kubernetes v1.31.&lt;/p>
&lt;h3 id="why-consistent-reads-matter">Why consistent reads matter&lt;/h3>
&lt;p>Consistent reads are essential for ensuring that Kubernetes components have an accurate view of the latest cluster state.
Guaranteeing consistent reads is crucial for maintaining the accuracy and reliability of Kubernetes operations,
enabling components to make informed decisions based on up-to-date information.
In large-scale clusters, fetching and processing this data can be a performance bottleneck,
especially for requests that involve filtering results.
While Kubernetes can filter data by namespace directly within etcd,
any other filtering by labels or field selectors requires the entire dataset to be fetched from etcd and then filtered in-memory by the Kubernetes API server.
This is particularly impactful for components like the kubelet,
which only needs to list pods scheduled to its node - but previously required the API Server and etcd to process all pods in the cluster.&lt;/p>
&lt;h3 id="the-breakthrough-caching-with-confidence">The breakthrough: Caching with confidence&lt;/h3>
&lt;p>Kubernetes has long used a watch cache to optimize read operations.
The watch cache stores a snapshot of the cluster state and receives updates through etcd watches.
However, until now, it couldn't serve consistent reads directly, as there was no guarantee the cache was sufficiently up-to-date.&lt;/p>
&lt;p>The &lt;em>consistent reads from cache&lt;/em> feature addresses this by leveraging etcd's
&lt;a href="https://etcd.io/docs/v3.5/dev-guide/interacting_v3/#watch-progress">progress notifications&lt;/a>
mechanism.
These notifications inform the watch cache about how current its data is compared to etcd.
When a consistent read is requested, the system first checks if the watch cache is up-to-date.
If the cache is not up-to-date, the system queries etcd for progress notifications until it's confirmed that the cache is sufficiently fresh.
Once ready, the read is efficiently served directly from the cache,
which can significantly improve performance,
particularly in cases where it would require fetching a lot of data from etcd.
This enables requests that filter data to be served from the cache,
with only minimal metadata needing to be read from etcd.&lt;/p>
&lt;p>&lt;strong>Important Note:&lt;/strong> To benefit from this feature, your Kubernetes cluster must be running etcd version 3.4.31+ or 3.5.13+.
For older etcd versions, Kubernetes will automatically fall back to serving consistent reads directly from etcd.&lt;/p>
&lt;h3 id="performance-gains-you-ll-notice">Performance gains you'll notice&lt;/h3>
&lt;p>This seemingly simple change has a profound impact on Kubernetes performance and scalability:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Reduced etcd Load:&lt;/strong> Kubernetes v1.31 can offload work from etcd,
freeing up resources for other critical operations.&lt;/li>
&lt;li>&lt;strong>Lower Latency:&lt;/strong> Serving reads from cache is significantly faster than fetching
and processing data from etcd. This translates to quicker responses for components,
improving overall cluster responsiveness.&lt;/li>
&lt;li>&lt;strong>Improved Scalability:&lt;/strong> Large clusters with thousands of nodes and pods will
see the most significant gains, as the reduction in etcd load allows the
control plane to handle more requests without sacrificing performance.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>5k Node Scalability Test Results:&lt;/strong> In recent scalability tests on 5,000 node
clusters, enabling consistent reads from cache delivered impressive improvements:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>30% reduction&lt;/strong> in kube-apiserver CPU usage&lt;/li>
&lt;li>&lt;strong>25% reduction&lt;/strong> in etcd CPU usage&lt;/li>
&lt;li>&lt;strong>Up to 3x reduction&lt;/strong> (from 5 seconds to 1.5 seconds) in 99th percentile pod LIST request latency&lt;/li>
&lt;/ul>
&lt;h3 id="what-s-next">What's next?&lt;/h3>
&lt;p>With the graduation to beta, consistent reads from cache are enabled by default,
offering a seamless performance boost to all Kubernetes users running a supported
etcd version.&lt;/p>
&lt;p>Our journey doesn't end here. Kubernetes community is actively exploring
pagination support in the watch cache, which will unlock even more performance
optimizations in the future.&lt;/p>
&lt;h3 id="getting-started">Getting started&lt;/h3>
&lt;p>Upgrading to Kubernetes v1.31 and ensuring you are using etcd version 3.4.31+ or
3.5.13+ is the easiest way to experience the benefits of consistent reads from
cache.
If you have any questions or feedback, don't hesitate to reach out to the Kubernetes community.&lt;/p>
&lt;p>&lt;strong>Let us know how&lt;/strong> &lt;em>consistent reads from cache&lt;/em> &lt;strong>transforms your Kubernetes experience!&lt;/strong>&lt;/p>
&lt;p>Special thanks to @ah8ad3 and @p0lyn0mial for their contributions to this feature!&lt;/p></description></item><item><title>Kubernetes 1.31: Moving cgroup v1 Support into Maintenance Mode</title><link>https://kubernetes.io/blog/2024/08/14/kubernetes-1-31-moving-cgroup-v1-support-maintenance-mode/</link><pubDate>Wed, 14 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/14/kubernetes-1-31-moving-cgroup-v1-support-maintenance-mode/</guid><description>
&lt;p>As Kubernetes continues to evolve and adapt to the changing landscape of
container orchestration, the community has decided to move cgroup v1 support
into &lt;a href="#what-does-maintenance-mode-mean">maintenance mode&lt;/a> in v1.31.
This shift aligns with the broader industry's move towards cgroup v2, offering
improved functionalities: including scalability and a more consistent interface.
Before we dive into the consequences for Kubernetes, let's take a step back to
understand what cgroups are and their significance in Linux.&lt;/p>
&lt;h2 id="understanding-cgroups">Understanding cgroups&lt;/h2>
&lt;p>&lt;a href="https://man7.org/linux/man-pages/man7/cgroups.7.html">Control groups&lt;/a>, or
cgroups, are a Linux kernel feature that allows the allocation, prioritization,
denial, and management of system resources (such as CPU, memory, disk I/O,
and network bandwidth) among processes. This functionality is crucial for
maintaining system performance and ensuring that no single process can
monopolize system resources, which is especially important in multi-tenant
environments.&lt;/p>
&lt;p>There are two versions of cgroups:
&lt;a href="https://docs.kernel.org/admin-guide/cgroup-v1/index.html">v1&lt;/a> and
&lt;a href="https://docs.kernel.org/admin-guide/cgroup-v2.html">v2&lt;/a>. While cgroup v1
provided sufficient capabilities for resource management, it had limitations
that led to the development of cgroup v2. Cgroup v2 offers a more unified and
consistent interface, on top of better resource control features.&lt;/p>
&lt;h2 id="cgroups-in-kubernetes">Cgroups in Kubernetes&lt;/h2>
&lt;p>For Linux nodes, Kubernetes relies heavily on cgroups to manage and isolate the
resources consumed by containers running in pods. Each container in Kubernetes
is placed in its own cgroup, which allows Kubernetes to enforce resource limits,
monitor usage, and ensure fair resource distribution among all containers.&lt;/p>
&lt;h3 id="how-kubernetes-uses-cgroups">How Kubernetes uses cgroups&lt;/h3>
&lt;dl>
&lt;dt>&lt;strong>Resource Allocation&lt;/strong>&lt;/dt>
&lt;dd>Ensures that containers do not exceed their allocated CPU and memory limits.&lt;/dd>
&lt;dt>&lt;strong>Isolation&lt;/strong>&lt;/dt>
&lt;dd>Isolates containers from each other to prevent resource contention.&lt;/dd>
&lt;dt>&lt;strong>Monitoring&lt;/strong>&lt;/dt>
&lt;dd>Tracks resource usage for each container to provide insights and metrics.&lt;/dd>
&lt;/dl>
&lt;h2 id="transitioning-to-cgroup-v2">Transitioning to Cgroup v2&lt;/h2>
&lt;p>The Linux community has been focusing on cgroup v2 for new features and
improvements. Major Linux distributions and projects like
&lt;a href="https://systemd.io/">systemd&lt;/a> are
&lt;a href="https://github.com/systemd/systemd/issues/30852">transitioning&lt;/a> towards cgroup v2.
Using cgroup v2 provides several benefits over cgroupv1, such as Unified Hierarchy,
Improved Interface, Better Resource Control,
&lt;a href="https://github.com/kubernetes/kubernetes/pull/117793">cgroup aware OOM killer&lt;/a>,
&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/2033-kubelet-in-userns-aka-rootless/README.md#cgroup">rootless support&lt;/a> etc.&lt;/p>
&lt;p>Given these advantages, Kubernetes is also making the move to embrace cgroup
v2 more fully. However, this transition needs to be handled carefully to avoid
disrupting existing workloads and to provide a smooth migration path for users.&lt;/p>
&lt;h2 id="moving-cgroup-v1-support-into-maintenance-mode">Moving cgroup v1 support into maintenance mode&lt;/h2>
&lt;h3 id="what-does-maintenance-mode-mean">What does maintenance mode mean?&lt;/h3>
&lt;p>When cgroup v1 is placed into maintenance mode in Kubernetes, it means that:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Feature Freeze&lt;/strong>: No new features will be added to cgroup v1 support.&lt;/li>
&lt;li>&lt;strong>Security Fixes&lt;/strong>: Critical security fixes will still be provided.&lt;/li>
&lt;li>&lt;strong>Best-Effort Bug Fixes&lt;/strong>: Major bugs may be fixed if feasible, but some
issues might remain unresolved.&lt;/li>
&lt;/ol>
&lt;h3 id="why-move-to-maintenance-mode">Why move to maintenance mode?&lt;/h3>
&lt;p>The move to maintenance mode is driven by the need to stay in line with the
broader ecosystem and to encourage the adoption of cgroup v2, which offers
better performance, security, and usability. By transitioning cgroup v1 to
maintenance mode, Kubernetes can focus on enhancing support for cgroup v2
and ensure it meets the needs of modern workloads. It's important to note
that maintenance mode does not mean deprecation; cgroup v1 will continue to
receive critical security fixes and major bug fixes as needed.&lt;/p>
&lt;h2 id="what-this-means-for-cluster-administrators">What this means for cluster administrators&lt;/h2>
&lt;p>Users currently relying on cgroup v1 are highly encouraged to plan for the
transition to cgroup v2. This transition involves:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Upgrading Systems&lt;/strong>: Ensuring that the underlying operating systems and
container runtimes support cgroup v2.&lt;/li>
&lt;li>&lt;strong>Testing Workloads&lt;/strong>: Verifying that workloads and applications function
correctly with cgroup v2.&lt;/li>
&lt;/ol>
&lt;h2 id="further-reading">Further reading&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://man7.org/linux/man-pages/man7/cgroups.7.html">Linux cgroups&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/docs/concepts/architecture/cgroups/">Cgroup v2 in Kubernetes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2022/08/31/cgroupv2-ga-1-25/">Kubernetes 1.25: cgroup v2 graduates to GA&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Kubernetes v1.31: PersistentVolume Last Phase Transition Time Moves to GA</title><link>https://kubernetes.io/blog/2024/08/14/last-phase-transition-time-ga/</link><pubDate>Wed, 14 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/14/last-phase-transition-time-ga/</guid><description>
&lt;p>Announcing the graduation to General Availability (GA) of the PersistentVolume &lt;code>lastTransitionTime&lt;/code> status
field, in Kubernetes v1.31!&lt;/p>
&lt;p>The Kubernetes SIG Storage team is excited to announce that the &amp;quot;PersistentVolumeLastPhaseTransitionTime&amp;quot; feature, introduced
as an alpha in Kubernetes v1.28, has now reached GA status and is officially part of the Kubernetes v1.31 release. This enhancement
helps Kubernetes users understand when a &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">PersistentVolume&lt;/a> transitions between
different phases, allowing for more efficient and informed resource management.&lt;/p>
&lt;p>For a v1.31 cluster, you can now assume that every PersistentVolume object has a
&lt;code>.status.lastTransitionTime&lt;/code> field, that holds a timestamp of
when the volume last transitioned its phase. This change is not immediate; the new field will be populated whenever a PersistentVolume
is updated and first transitions between phases (&lt;code>Pending&lt;/code>, &lt;code>Bound&lt;/code>, or &lt;code>Released&lt;/code>) after upgrading to Kubernetes v1.31.&lt;/p>
&lt;h2 id="what-changed">What changed?&lt;/h2>
&lt;p>The API strategy for updating PersistentVolume objects has been modified to populate the &lt;code>.status.lastTransitionTime&lt;/code> field with the
current timestamp whenever a PersistentVolume transitions phases. Users are allowed to set this field manually if needed, but it will
be overwritten when the PersistentVolume transitions phases again.&lt;/p>
&lt;p>For more details, read about
&lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#phase-transition-timestamp">Phase transition timestamp&lt;/a> in the Kubernetes documentation.
You can also read the previous &lt;a href="https://kubernetes.io/blog/2023/10/23/persistent-volume-last-phase-transition-time">blog post&lt;/a> announcing the feature as alpha in v1.28.&lt;/p>
&lt;p>To provide feedback, join our &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">Kubernetes Storage Special-Interest-Group&lt;/a> (SIG)
or participate in discussions on our &lt;a href="https://app.slack.com/client/T09NY5SBT/C09QZFCE5">public Slack channel&lt;/a>.&lt;/p></description></item><item><title>Kubernetes v1.31: Elli</title><link>https://kubernetes.io/blog/2024/08/13/kubernetes-v1-31-release/</link><pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/13/kubernetes-v1-31-release/</guid><description>
&lt;p>&lt;strong>Editors:&lt;/strong> Matteo Bianchi, Yigit Demirbas, Abigail McCarthy, Edith Puclla, Rashan Smith&lt;/p>
&lt;p>Announcing the release of Kubernetes v1.31: Elli!&lt;/p>
&lt;p>Similar to previous releases, the release of Kubernetes v1.31 introduces new
stable, beta, and alpha features.
The consistent delivery of high-quality releases underscores the strength of our development cycle and the vibrant support from our community.
This release consists of 45 enhancements.
Of those enhancements, 11 have graduated to Stable, 22 are entering Beta,
and 12 have graduated to Alpha.&lt;/p>
&lt;h2 id="release-theme-and-logo">Release theme and logo&lt;/h2>
&lt;figure class="release-logo ">
&lt;img src="https://kubernetes.io/images/blog/2024-08-13-kubernetes-1.31-release/k8s-1.31.png"
alt="Kubernetes v1.31 Elli logo"/>
&lt;/figure>
&lt;p>The Kubernetes v1.31 Release Theme is &amp;quot;Elli&amp;quot;.&lt;/p>
&lt;p>Kubernetes v1.31's Elli is a cute and joyful dog, with a heart of gold and a nice sailor's cap, as a playful wink to the huge and diverse family of Kubernetes contributors.&lt;/p>
&lt;p>Kubernetes v1.31 marks the first release after the project has successfully celebrated &lt;a href="https://kubernetes.io/blog/2024/06/06/10-years-of-kubernetes/">its first 10 years&lt;/a>.
Kubernetes has come a very long way since its inception, and it's still moving towards exciting new directions with each release.
After 10 years, it is awe-inspiring to reflect on the effort, dedication, skill, wit and tiring work of the countless Kubernetes contributors who have made this a reality.&lt;/p>
&lt;p>And yet, despite the herculean effort needed to run the project, there is no shortage of people who show up, time and again, with enthusiasm, smiles and a sense of pride for contributing and being part of the community.
This &amp;quot;spirit&amp;quot; that we see from new and old contributors alike is the sign of a vibrant community, a &amp;quot;joyful&amp;quot; community, if we might call it that.&lt;/p>
&lt;p>Kubernetes v1.31's Elli is all about celebrating this wonderful spirit! Here's to the next decade of Kubernetes!&lt;/p>
&lt;h2 id="highlights-of-features-graduating-to-stable">Highlights of features graduating to Stable&lt;/h2>
&lt;p>&lt;em>This is a selection of some of the improvements that are now stable following the v1.31 release.&lt;/em>&lt;/p>
&lt;h3 id="apparmor-support-is-now-stable">AppArmor support is now stable&lt;/h3>
&lt;p>Kubernetes support for AppArmor is now GA. Protect your containers using AppArmor by setting the &lt;code>appArmorProfile.type&lt;/code> field in the container's &lt;code>securityContext&lt;/code>.
Note that before Kubernetes v1.30, AppArmor was controlled via annotations; starting in v1.30 it is controlled using fields.
It is recommended that you should migrate away from using annotations and start using the &lt;code>appArmorProfile.type&lt;/code> field.&lt;/p>
&lt;p>To learn more read the &lt;a href="https://kubernetes.io/docs/tutorials/security/apparmor/">AppArmor tutorial&lt;/a>.
This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/24">KEP #24&lt;/a>, by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a>.&lt;/p>
&lt;h3 id="improved-ingress-connectivity-reliability-for-kube-proxy">Improved ingress connectivity reliability for kube-proxy&lt;/h3>
&lt;p>Kube-proxy improved ingress connectivity reliability is stable in v1.31.
One of the common problems with load balancers in Kubernetes is the synchronization between the different components involved to avoid traffic drop.
This feature implements a mechanism in kube-proxy for load balancers to do connection draining for terminating Nodes exposed by services of &lt;code>type: LoadBalancer&lt;/code> and &lt;code>externalTrafficPolicy: Cluster&lt;/code> and establish some best practices for cloud providers and Kubernetes load balancers implementations.&lt;/p>
&lt;p>To use this feature, kube-proxy needs to run as default service proxy on the cluster and the load balancer needs to support connection draining.
There are no specific changes required for using this feature, it has been enabled by default in kube-proxy since v1.30 and been promoted to stable in v1.31.&lt;/p>
&lt;p>For more details about this feature please visit the &lt;a href="https://kubernetes.io/docs/reference/networking/virtual-ips/#external-traffic-policy">Virtual IPs and Service Proxies documentation page&lt;/a>.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3836">KEP #3836&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-network">SIG Network&lt;/a>.&lt;/p>
&lt;h3 id="persistent-volume-last-phase-transition-time">Persistent Volume last phase transition time&lt;/h3>
&lt;p>Persistent Volume last phase transition time feature moved to GA in v1.31.
This feature adds a &lt;code>PersistentVolumeStatus&lt;/code> field which holds a timestamp of when a PersistentVolume last transitioned to a different phase.
With this feature enabled, every PersistentVolume object will have a new field &lt;code>.status.lastTransitionTime&lt;/code>, that holds a timestamp of
when the volume last transitioned its phase.
This change is not immediate; the new field will be populated whenever a PersistentVolume is updated and first transitions between phases (&lt;code>Pending&lt;/code>, &lt;code>Bound&lt;/code>, or &lt;code>Released&lt;/code>) after upgrading to Kubernetes v1.31.
This allows you to measure time between when a PersistentVolume moves from &lt;code>Pending&lt;/code> to &lt;code>Bound&lt;/code>. This can be also useful for providing metrics and SLOs.&lt;/p>
&lt;p>For more details about this feature please visit the &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">PersistentVolume documentation page&lt;/a>.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3762">KEP #3762&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">SIG Storage&lt;/a>.&lt;/p>
&lt;h2 id="highlights-of-features-graduating-to-beta">Highlights of features graduating to Beta&lt;/h2>
&lt;p>&lt;em>This is a selection of some of the improvements that are now beta following the v1.31 release.&lt;/em>&lt;/p>
&lt;h3 id="nftables-backend-for-kube-proxy">nftables backend for kube-proxy&lt;/h3>
&lt;p>The nftables backend moves to beta in v1.31, behind the &lt;code>NFTablesProxyMode&lt;/code> feature gate which is now enabled by default.&lt;/p>
&lt;p>The nftables API is the successor to the iptables API and is designed to provide better performance and scalability than iptables.
The &lt;code>nftables&lt;/code> proxy mode is able to process changes to service endpoints faster and more efficiently than the &lt;code>iptables&lt;/code> mode, and is also able to more efficiently process packets in the kernel (though this only
becomes noticeable in clusters with tens of thousands of services).&lt;/p>
&lt;p>As of Kubernetes v1.31, the &lt;code>nftables&lt;/code> mode is still relatively new, and may not be compatible with all network plugins; consult the documentation for your network plugin.
This proxy mode is only available on Linux nodes, and requires kernel 5.13 or later.
Before migrating, note that some features, especially around NodePort services, are not implemented exactly the same in nftables mode as they are in iptables mode.
Check the &lt;a href="https://kubernetes.io/docs/reference/networking/virtual-ips/#migrating-from-iptables-mode-to-nftables">migration guide&lt;/a> to see if you need to override the default configuration.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3866">KEP #3866&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-network">SIG Network&lt;/a>.&lt;/p>
&lt;h3 id="changes-to-reclaim-policy-for-persistentvolumes">Changes to reclaim policy for PersistentVolumes&lt;/h3>
&lt;p>The Always Honor PersistentVolume Reclaim Policy feature has advanced to beta in Kubernetes v1.31.
This enhancement ensures that the PersistentVolume (PV) reclaim policy is respected even after the associated PersistentVolumeClaim (PVC) is deleted, thereby preventing the leakage of volumes.&lt;/p>
&lt;p>Prior to this feature, the reclaim policy linked to a PV could be disregarded under specific conditions, depending on whether the PV or PVC was deleted first.
Consequently, the corresponding storage resource in the external infrastructure might not be removed, even if the reclaim policy was set to &amp;quot;Delete&amp;quot;.
This led to potential inconsistencies and resource leaks.&lt;/p>
&lt;p>With the introduction of this feature, Kubernetes now guarantees that the &amp;quot;Delete&amp;quot; reclaim policy will be enforced, ensuring the deletion of the underlying storage object from the backend infrastructure, regardless of the deletion sequence of the PV and PVC.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/2644">KEP #2644&lt;/a> and by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">SIG Storage&lt;/a>.&lt;/p>
&lt;h3 id="bound-service-account-token-improvements">Bound service account token improvements&lt;/h3>
&lt;p>The &lt;code>ServiceAccountTokenNodeBinding&lt;/code> feature is promoted to beta in v1.31.
This feature allows requesting a token bound only to a node, not to a pod, which includes node information in claims in the token and validates the existence of the node when the token is used.
For more information, read the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#bound-service-account-tokens">bound service account tokens documentation&lt;/a>.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4193">KEP #4193&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-auth">SIG Auth&lt;/a>.&lt;/p>
&lt;h3 id="multiple-service-cidrs">Multiple Service CIDRs&lt;/h3>
&lt;p>Support for clusters with multiple Service CIDRs moves to beta in v1.31 (disabled by default).&lt;/p>
&lt;p>There are multiple components in a Kubernetes cluster that consume IP addresses: Nodes, Pods and Services.
Nodes and Pods IP ranges can be dynamically changed because depend on the infrastructure or the network plugin respectively.
However, Services IP ranges are defined during the cluster creation as a hardcoded flag in the kube-apiserver.
IP exhaustion has been a problem for long lived or large clusters, as admins needed to expand, shrink or even replace entirely the assigned Service CIDR range.
These operations were never supported natively and were performed via complex and delicate maintenance operations, often causing downtime on their clusters. This new feature allows users and cluster admins to dynamically modify Service CIDR ranges with zero downtime.&lt;/p>
&lt;p>For more details about this feature please visit the
&lt;a href="https://kubernetes.io/docs/reference/networking/virtual-ips/#ip-address-objects">Virtual IPs and Service Proxies&lt;/a> documentation page.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/1880">KEP #1880&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-network">SIG Network&lt;/a>.&lt;/p>
&lt;h3 id="traffic-distribution-for-services">Traffic distribution for Services&lt;/h3>
&lt;p>Traffic distribution for Services moves to beta in v1.31 and is enabled by default.&lt;/p>
&lt;p>After several iterations on finding the best user experience and traffic engineering capabilities for Services networking, SIG Networking implemented the &lt;code>trafficDistribution&lt;/code> field in the Service specification, which serves as a guideline for the underlying implementation to consider while making routing decisions.&lt;/p>
&lt;p>For more details about this feature please read the
&lt;a href="https://kubernetes.io/blog/2024/04/17/kubernetes-v1-30-release/#traffic-distribution-for-services-sig-network-https-github-com-kubernetes-community-tree-master-sig-network">1.30 Release Blog&lt;/a>
or visit the &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution">Service&lt;/a> documentation page.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4444">KEP #4444&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-network">SIG Network&lt;/a>.&lt;/p>
&lt;h3 id="kubernetes-volumeattributesclass-modifyvolume">Kubernetes VolumeAttributesClass ModifyVolume&lt;/h3>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/">VolumeAttributesClass&lt;/a> API is moving to beta in v1.31.
The VolumeAttributesClass provides a generic,
Kubernetes-native API for modifying dynamically volume parameters like provisioned IO.
This allows workloads to vertically scale their volumes on-line to balance cost and performance, if supported by their provider.
This feature had been alpha since Kubernetes 1.29.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3751">KEP #3751&lt;/a> and lead by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">SIG Storage&lt;/a>.&lt;/p>
&lt;h2 id="new-features-in-alpha">New features in Alpha&lt;/h2>
&lt;p>&lt;em>This is a selection of some of the improvements that are now alpha following the v1.31 release.&lt;/em>&lt;/p>
&lt;h3 id="new-dra-apis-for-better-accelerators-and-other-hardware-management">New DRA APIs for better accelerators and other hardware management&lt;/h3>
&lt;p>Kubernetes v1.31 brings an updated dynamic resource allocation (DRA) API and design.
The main focus in the update is on structured parameters because they make resource information and requests transparent to Kubernetes and clients and enable implementing features like cluster autoscaling.
DRA support in the kubelet was updated such that version skew between kubelet and the control plane is possible. With structured parameters, the scheduler allocates ResourceClaims while scheduling a pod.
Allocation by a DRA driver controller is still supported through what is now called &amp;quot;classic DRA&amp;quot;.&lt;/p>
&lt;p>With Kubernetes v1.31, classic DRA has a separate feature gate named &lt;code>DRAControlPlaneController&lt;/code>, which you need to enable explicitly.
With such a control plane controller, a DRA driver can implement allocation policies that are not supported yet through structured parameters.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/3063">KEP #3063&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a>.&lt;/p>
&lt;h3 id="support-for-image-volumes">Support for image volumes&lt;/h3>
&lt;p>The Kubernetes community is moving towards fulfilling more Artificial Intelligence (AI) and Machine Learning (ML) use cases in the future.&lt;/p>
&lt;p>One of the requirements to fulfill these use cases is to support Open Container Initiative (OCI) compatible images and artifacts (referred as OCI objects) directly as a native volume source.
This allows users to focus on OCI standards as well as enables them to store and distribute any content using OCI registries.&lt;/p>
&lt;p>Given that, v1.31 adds a new alpha feature to allow using an OCI image as a volume in a Pod.
This feature allows users to specify an image reference as volume in a pod while reusing it as volume
mount within containers. You need to enable the &lt;code>ImageVolume&lt;/code> feature gate to try this out.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4639">KEP #4639&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a> and &lt;a href="https://github.com/kubernetes/community/tree/master/sig-storage">SIG Storage&lt;/a>.&lt;/p>
&lt;h3 id="exposing-device-health-information-through-pod-status">Exposing device health information through Pod status&lt;/h3>
&lt;p>Expose device health information through the Pod Status is added as a new alpha feature in v1.31, disabled by default.&lt;/p>
&lt;p>Before Kubernetes v1.31, the way to know whether or not a Pod is associated with the failed device is to use the &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/#monitoring-device-plugin-resources">PodResources API&lt;/a>.&lt;/p>
&lt;p>By enabling this feature, the field &lt;code>allocatedResourcesStatus&lt;/code> will be added to each container status, within the &lt;code>.status&lt;/code> for each Pod. The &lt;code>allocatedResourcesStatus&lt;/code> field reports health information for each device assigned to the container.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4680">KEP #4680&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a>.&lt;/p>
&lt;h3 id="finer-grained-authorization-based-on-selectors">Finer-grained authorization based on selectors&lt;/h3>
&lt;p>This feature allows webhook authorizers and future (but not currently designed) in-tree authorizers to
allow &lt;strong>list&lt;/strong> and &lt;strong>watch&lt;/strong> requests, provided those requests use label and/or field selectors.
For example, it is now possible for an authorizer to express: this user cannot list all pods, but can list all pods where &lt;code>.spec.nodeName&lt;/code> matches some specific value. Or to allow a user to watch all Secrets in a namespace
that are &lt;em>not&lt;/em> labelled as &lt;code>confidential: true&lt;/code>.
Combined with CRD field selectors (also moving to beta in v1.31), it is possible to write more secure
per-node extensions.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4601">KEP #4601&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-auth">SIG Auth&lt;/a>.&lt;/p>
&lt;h3 id="restrictions-on-anonymous-api-access">Restrictions on anonymous API access&lt;/h3>
&lt;p>By enabling the feature gate &lt;code>AnonymousAuthConfigurableEndpoints&lt;/code> users can now use the authentication configuration file to configure the endpoints that can be accessed by anonymous requests.
This allows users to protect themselves against RBAC misconfigurations that can give anonymous users broad access to the cluster.&lt;/p>
&lt;p>This work was done as a part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4633">KEP #4633&lt;/a> and by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-auth">SIG Auth&lt;/a>.&lt;/p>
&lt;h2 id="graduations-deprecations-and-removals-in-1-31">Graduations, deprecations, and removals in 1.31&lt;/h2>
&lt;h3 id="graduations-to-stable">Graduations to Stable&lt;/h3>
&lt;p>This lists all the features that graduated to stable (also known as &lt;em>general availability&lt;/em>). For a full list of updates including new features and graduations from alpha to beta, see the release notes.&lt;/p>
&lt;p>This release includes a total of 11 enhancements promoted to Stable:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3762">PersistentVolume last phase transition time&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/2305">Metric cardinality enforcement&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3836">Kube-proxy improved ingress connectivity reliability&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4009">Add CDI devices to device plugin API&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/4569">Move cgroup v1 support into maintenance mode&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/24">AppArmor support&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3017">PodHealthyPolicy for PodDisruptionBudget&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3329">Retriable and non-retriable Pod failures for Jobs&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3715">Elastic Indexed Jobs&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/3335">Allow StatefulSet to control start replica ordinal numbering&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/issues/2185">Random Pod selection on ReplicaSet downscaling&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="deprecations-and-removals">Deprecations and Removals&lt;/h3>
&lt;p>As Kubernetes develops and matures, features may be deprecated, removed, or replaced with better ones for the project's overall health.
See the Kubernetes &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-policy/">deprecation and removal policy&lt;/a> for more details on this process.&lt;/p>
&lt;h4 id="cgroup-v1-enters-the-maintenance-mode">Cgroup v1 enters the maintenance mode&lt;/h4>
&lt;p>As Kubernetes continues to evolve and adapt to the changing landscape of container orchestration, the community has decided to move cgroup v1 support into maintenance mode in v1.31.
This shift aligns with the broader industry's move towards &lt;a href="https://kubernetes.io/docs/concepts/architecture/cgroups/">cgroup v2&lt;/a>, offering improved functionality, scalability, and a more consistent interface.
Kubernetes maintance mode means that no new features will be added to cgroup v1 support.
Critical security fixes will still be provided, however, bug-fixing is now best-effort, meaning major bugs may be fixed if feasible, but some issues might remain unresolved.&lt;/p>
&lt;p>It is recommended that you start switching to use cgroup v2 as soon as possible.
This transition depends on your architecture, including ensuring the underlying operating systems and container runtimes support cgroup v2 and testing workloads to verify that workloads and applications function correctly with cgroup v2.&lt;/p>
&lt;p>Please report any problems you encounter by filing an &lt;a href="https://github.com/kubernetes/kubernetes/issues/new/choose">issue&lt;/a>.&lt;/p>
&lt;p>This work was done as part of &lt;a href="https://github.com/kubernetes/enhancements/issues/4569">KEP #4569&lt;/a> by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-node">SIG Node&lt;/a>.&lt;/p>
&lt;h4 id="a-note-about-sha-1-signature-support">A note about SHA-1 signature support&lt;/h4>
&lt;p>In &lt;a href="https://go.dev/doc/go1.18#sha1">go1.18&lt;/a> (released in March 2022), the crypto/x509 library started to reject certificates signed with a SHA-1 hash function.
While SHA-1 is established to be unsafe and publicly trusted Certificate Authorities have not issued SHA-1 certificates since 2015, there might still be cases in the context of Kubernetes where user-provided certificates are signed using a SHA-1 hash function through private authorities with them being used for Aggregated API Servers or webhooks.
If you have relied on SHA-1 based certificates, you must explicitly opt back into its support by setting &lt;code>GODEBUG=x509sha1=1&lt;/code> in your environment.&lt;/p>
&lt;p>Given Go's &lt;a href="https://go.dev/blog/compat">compatibility policy for GODEBUGs&lt;/a>, the &lt;code>x509sha1&lt;/code> GODEBUG and the support for SHA-1 certificates will &lt;a href="https://tip.golang.org/doc/go1.23">fully go away in go1.24&lt;/a> which will be released in the first half of 2025.
If you rely on SHA-1 certificates, please start moving off them.&lt;/p>
&lt;p>Please see &lt;a href="https://github.com/kubernetes/kubernetes/issues/125689">Kubernetes issue #125689&lt;/a> to get a better idea of timelines around the support for SHA-1 going away, when Kubernetes releases plans to adopt go1.24, and for more details on how to detect usage of SHA-1 certificates via metrics and audit logging.&lt;/p>
&lt;h4 id="deprecation-of-status-nodeinfo-kubeproxyversion-field-for-nodes-kep-4004-https-github-com-kubernetes-enhancements-issues-4004">Deprecation of &lt;code>status.nodeInfo.kubeProxyVersion&lt;/code> field for Nodes (&lt;a href="https://github.com/kubernetes/enhancements/issues/4004">KEP 4004&lt;/a>)&lt;/h4>
&lt;p>The &lt;code>.status.nodeInfo.kubeProxyVersion&lt;/code> field of Nodes has been deprecated in Kubernetes v1.31,
and will be removed in a later release.
It's being deprecated because the value of this field wasn't (and isn't) accurate.
This field is set by the kubelet, which does not have reliable information about the kube-proxy version or whether kube-proxy is running.&lt;/p>
&lt;p>The &lt;code>DisableNodeKubeProxyVersion&lt;/code> &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/">feature gate&lt;/a> will be set to &lt;code>true&lt;/code> in by default in v1.31 and the kubelet will no longer attempt to set the &lt;code>.status.kubeProxyVersion&lt;/code> field for its associated Node.&lt;/p>
&lt;h4 id="removal-of-all-in-tree-integrations-with-cloud-providers">Removal of all in-tree integrations with cloud providers&lt;/h4>
&lt;p>As highlighted in a &lt;a href="https://kubernetes.io/blog/2024/05/20/completing-cloud-provider-migration/">previous article&lt;/a>, the last remaining in-tree support for cloud provider integration has been removed as part of the v1.31 release.
This doesn't mean you can't integrate with a cloud provider, however you now &lt;strong>must&lt;/strong> use the
recommended approach using an external integration. Some integrations are part of the Kubernetes
project and others are third party software.&lt;/p>
&lt;p>This milestone marks the completion of the externalization process for all cloud providers' integrations from the Kubernetes core (&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-cloud-provider/2395-removing-in-tree-cloud-providers/README.md">KEP-2395&lt;/a>), a process started with Kubernetes v1.26.
This change helps Kubernetes to get closer to being a truly vendor-neutral platform.&lt;/p>
&lt;p>For further details on the cloud provider integrations, read our &lt;a href="https://kubernetes.io/blog/2023/12/14/cloud-provider-integration-changes/">v1.29 Cloud Provider Integrations feature blog&lt;/a>.
For additional context about the in-tree code removal, we invite you to check the (&lt;a href="https://kubernetes.io/blog/2023/11/16/kubernetes-1-29-upcoming-changes/#removal-of-in-tree-integrations-with-cloud-providers-kep-2395-https-kep-k8s-io-2395">v1.29 deprecation blog&lt;/a>).&lt;/p>
&lt;p>The latter blog also contains useful information for users who need to migrate to version v1.29 and later.&lt;/p>
&lt;h4 id="removal-of-in-tree-provider-feature-gates">Removal of in-tree provider feature gates&lt;/h4>
&lt;p>In Kubernetes v1.31, the following alpha feature gates &lt;code>InTreePluginAWSUnregister&lt;/code>, &lt;code>InTreePluginAzureDiskUnregister&lt;/code>, &lt;code>InTreePluginAzureFileUnregister&lt;/code>, &lt;code>InTreePluginGCEUnregister&lt;/code>, &lt;code>InTreePluginOpenStackUnregister&lt;/code>, and &lt;code>InTreePluginvSphereUnregister&lt;/code> have been removed. These feature gates were introduced to facilitate the testing of scenarios where in-tree volume plugins were removed from the codebase, without actually removing them. Since Kubernetes 1.30 had deprecated these in-tree volume plugins, these feature gates were redundant and no longer served a purpose. The only CSI migration gate still standing is &lt;code>InTreePluginPortworxUnregister&lt;/code>, which will remain in alpha until the CSI migration for Portworx is completed and its in-tree volume plugin will be ready for removal.&lt;/p>
&lt;h4 id="removal-of-kubelet-keep-terminated-pod-volumes-command-line-flag">Removal of kubelet &lt;code>--keep-terminated-pod-volumes&lt;/code> command line flag&lt;/h4>
&lt;p>The kubelet flag &lt;code>--keep-terminated-pod-volumes&lt;/code>, which was deprecated in 2017, has been removed as
part of the v1.31 release.&lt;/p>
&lt;p>You can find more details in the pull request &lt;a href="https://github.com/kubernetes/kubernetes/pull/122082">#122082&lt;/a>.&lt;/p>
&lt;h4 id="removal-of-cephfs-volume-plugin">Removal of CephFS volume plugin&lt;/h4>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/#cephfs">CephFS volume plugin&lt;/a> was removed in this release and the &lt;code>cephfs&lt;/code> volume type became non-functional.&lt;/p>
&lt;p>It is recommended that you use the &lt;a href="https://github.com/ceph/ceph-csi/">CephFS CSI driver&lt;/a> as a third-party storage driver instead. If you were using the CephFS volume plugin before upgrading the cluster version to v1.31, you must re-deploy your application to use the new driver.&lt;/p>
&lt;p>CephFS volume plugin was formally marked as deprecated in v1.28.&lt;/p>
&lt;h4 id="removal-of-ceph-rbd-volume-plugin">Removal of Ceph RBD volume plugin&lt;/h4>
&lt;p>The v1.31 release removes the &lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/#rbd">Ceph RBD volume plugin&lt;/a> and its CSI migration support, making the &lt;code>rbd&lt;/code> volume type non-functional.&lt;/p>
&lt;p>It's recommended that you use the &lt;a href="https://github.com/ceph/ceph-csi/">RBD CSI driver&lt;/a> in your clusters instead.
If you were using Ceph RBD volume plugin before upgrading the cluster version to v1.31, you must re-deploy your application to use the new driver.&lt;/p>
&lt;p>The Ceph RBD volume plugin was formally marked as deprecated in v1.28.&lt;/p>
&lt;h4 id="deprecation-of-non-csi-volume-limit-plugins-in-kube-scheduler">Deprecation of non-CSI volume limit plugins in kube-scheduler&lt;/h4>
&lt;p>The v1.31 release will deprecate all non-CSI volume limit scheduler plugins, and will remove some
already deprected plugins from the &lt;a href="https://kubernetes.io/docs/reference/scheduling/config/">default plugins&lt;/a>, including:&lt;/p>
&lt;ul>
&lt;li>&lt;code>AzureDiskLimits&lt;/code>&lt;/li>
&lt;li>&lt;code>CinderLimits&lt;/code>&lt;/li>
&lt;li>&lt;code>EBSLimits&lt;/code>&lt;/li>
&lt;li>&lt;code>GCEPDLimits&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>It's recommended that you use the &lt;code>NodeVolumeLimits&lt;/code> plugin instead because it can handle the same functionality as the removed plugins since those volume types have been migrated to CSI.
Please replace the deprecated plugins with the &lt;code>NodeVolumeLimits&lt;/code> plugin if you explicitly use them in the &lt;a href="https://kubernetes.io/docs/reference/scheduling/config/">scheduler config&lt;/a>.
The &lt;code>AzureDiskLimits&lt;/code>, &lt;code>CinderLimits&lt;/code>, &lt;code>EBSLimits&lt;/code>, and &lt;code>GCEPDLimits&lt;/code> plugins will be removed in a future release.&lt;/p>
&lt;p>These plugins will be removed from the default scheduler plugins list as they have been deprecated since Kubernetes v1.14.&lt;/p>
&lt;h3 id="release-notes-and-upgrade-actions-required">Release notes and upgrade actions required&lt;/h3>
&lt;p>Check out the full details of the Kubernetes v1.31 release in our &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md">release notes&lt;/a>.&lt;/p>
&lt;h4 id="scheduler-now-uses-queueinghint-when-schedulerqueueinghints-is-enabled">Scheduler now uses QueueingHint when &lt;code>SchedulerQueueingHints&lt;/code> is enabled&lt;/h4>
&lt;p>Added support to the scheduler to start using a QueueingHint registered for Pod/Updated events,
to determine whether updates to previously unschedulable Pods have made them schedulable.
The new support is active when the feature gate &lt;code>SchedulerQueueingHints&lt;/code> is enabled.&lt;/p>
&lt;p>Previously, when unschedulable Pods were updated, the scheduler always put Pods back to into a queue
(&lt;code>activeQ&lt;/code> / &lt;code>backoffQ&lt;/code>). However not all updates to Pods make Pods schedulable, especially considering
many scheduling constraints nowadays are immutable. Under the new behaviour, once unschedulable Pods
are updated, the scheduling queue checks with QueueingHint(s) whether the update may make the
pod(s) schedulable, and requeues them to &lt;code>activeQ&lt;/code> or &lt;code>backoffQ&lt;/code> only when at least one
QueueingHint returns &lt;code>Queue&lt;/code>.&lt;/p>
&lt;p>&lt;strong>Action required for custom scheduler plugin developers&lt;/strong>:
Plugins have to implement a QueueingHint for Pod/Update event if the rejection from them could be resolved by updating unscheduled Pods themselves. Example: suppose you develop a custom plugin that denies Pods that have a &lt;code>schedulable=false&lt;/code> label. Given Pods with a &lt;code>schedulable=false&lt;/code> label will be schedulable if the &lt;code>schedulable=false&lt;/code> label is removed, this plugin would implement QueueingHint for Pod/Update event that returns Queue when such label changes are made in unscheduled Pods. You can find more details in the pull request &lt;a href="https://github.com/kubernetes/kubernetes/pull/122234">#122234&lt;/a>.&lt;/p>
&lt;h4 id="removal-of-kubelet-keep-terminated-pod-volumes-command-line-flag-1">Removal of kubelet --keep-terminated-pod-volumes command line flag&lt;/h4>
&lt;p>The kubelet flag &lt;code>--keep-terminated-pod-volumes&lt;/code>, which was deprecated in 2017, was removed as part of the v1.31 release.&lt;/p>
&lt;p>You can find more details in the pull request &lt;a href="https://github.com/kubernetes/kubernetes/pull/122082">#122082&lt;/a>.&lt;/p>
&lt;h2 id="availability">Availability&lt;/h2>
&lt;p>Kubernetes v1.31 is available for download on &lt;a href="https://github.com/kubernetes/kubernetes/releases/tag/v1.31.0">GitHub&lt;/a> or on the &lt;a href="https://kubernetes.io/releases/download/">Kubernetes download page&lt;/a>.&lt;/p>
&lt;p>To get started with Kubernetes, check out these &lt;a href="https://kubernetes.io/docs/tutorials/">interactive tutorials&lt;/a> or run local Kubernetes clusters using &lt;a href="https://minikube.sigs.k8s.io/">minikube&lt;/a>. You can also easily install v1.31 using &lt;a href="https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/">kubeadm&lt;/a>.&lt;/p>
&lt;h2 id="release-team">Release team&lt;/h2>
&lt;p>Kubernetes is only possible with the support, commitment, and hard work of its community.
Each release team is made up of dedicated community volunteers who work together to build the many pieces that make up the Kubernetes releases you rely on.
This requires the specialized skills of people from all corners of our community, from the code itself to its documentation and project management.&lt;/p>
&lt;p>We would like to thank the entire &lt;a href="https://github.com/kubernetes/sig-release/blob/master/releases/release-1.31/release-team.md">release team&lt;/a> for the hours spent hard at work to deliver the Kubernetes v1.31 release to our community.
The Release Team's membership ranges from first-time shadows to returning team leads with experience forged over several release cycles.
A very special thanks goes out our release lead, Angelos Kolaitis, for supporting us through a successful release cycle, advocating for us, making sure that we could all contribute in the best way possible, and challenging us to improve the release process.&lt;/p>
&lt;h2 id="project-velocity">Project velocity&lt;/h2>
&lt;p>The CNCF K8s DevStats project aggregates a number of interesting data points related to the velocity of Kubernetes and various sub-projects. This includes everything from individual contributions to the number of companies that are contributing and is an illustration of the depth and breadth of effort that goes into evolving this ecosystem.&lt;/p>
&lt;p>In the v1.31 release cycle, which ran for 14 weeks (May 7th to August 13th), we saw contributions to Kubernetes from 113 different companies and 528 individuals.&lt;/p>
&lt;p>In the whole Cloud Native ecosystem we have 379 companies counting 2268 total contributors - which means that respect to the previous release cycle we experienced an astounding 63% increase on individuals contributing!&lt;/p>
&lt;p>Source for this data:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://k8s.devstats.cncf.io/d/11/companies-contributing-in-repository-groups?orgId=1&amp;from=1715032800000&amp;to=1723586399000&amp;var-period=d28&amp;var-repogroup_name=Kubernetes&amp;var-repo_name=kubernetes%2Fkubernetes">Companies contributing to Kubernetes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://k8s.devstats.cncf.io/d/11/companies-contributing-in-repository-groups?orgId=1&amp;from=1715032800000&amp;to=1723586399000&amp;var-period=d28&amp;var-repogroup_name=All&amp;var-repo_name=kubernetes%2Fkubernetes">Overall ecosystem contributions&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>By contribution we mean when someone makes a commit, code review, comment, creates an issue or PR, reviews a PR (including blogs and documentation) or comments on issues and PRs.&lt;/p>
&lt;p>If you are interested in contributing visit &lt;a href="https://www.kubernetes.dev/docs/guide/#getting-started">this page&lt;/a> to get started.&lt;/p>
&lt;p>&lt;a href="https://k8s.devstats.cncf.io/d/11/companies-contributing-in-repository-groups?orgId=1&amp;var-period=m&amp;var-repogroup_name=All">Check out DevStats&lt;/a> to learn more about the overall velocity of the Kubernetes project and community.&lt;/p>
&lt;h2 id="event-update">Event update&lt;/h2>
&lt;p>Explore the upcoming Kubernetes and cloud-native events from August to November 2024, featuring KubeCon, KCD, and other notable conferences worldwide. Stay informed and engage with the Kubernetes community.&lt;/p>
&lt;p>&lt;strong>August 2024&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-open-source-summit-ai-dev-china/">&lt;strong>KubeCon + CloudNativeCon + Open Source Summit China 2024&lt;/strong>&lt;/a>: August 21-23, 2024 | Hong Kong&lt;/li>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubeday-japan/">&lt;strong>KubeDay Japan&lt;/strong>&lt;/a>: August 27, 2024 | Tokyo, Japan&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>September 2024&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-kcd-lahore-presents-kcd-lahore-pakistan-2024/">&lt;strong>KCD Lahore - Pakistan 2024&lt;/strong>&lt;/a>: September 1, 2024 | Lahore, Pakistan&lt;/li>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-stockholm-presents-kubertenes-birthday-bash-stockholm-a-couple-of-months-late/">&lt;strong>KuberTENes Birthday Bash Stockholm&lt;/strong>&lt;/a>: September 5, 2024 | Stockholm, Sweden&lt;/li>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-kcd-australia-presents-kcd-sydney-24/">&lt;strong>KCD Sydney ’24&lt;/strong>&lt;/a>: September 5-6, 2024 | Sydney, Australia&lt;/li>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-kcd-washington-dc-presents-kcd-washington-dc-2024/">&lt;strong>KCD Washington DC 2024&lt;/strong>&lt;/a>: September 24, 2024 | Washington, DC, United States&lt;/li>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-kcd-porto-presents-kcd-porto-2024/">&lt;strong>KCD Porto 2024&lt;/strong>&lt;/a>: September 27-28, 2024 | Porto, Portugal&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>October 2024&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-kcd-austria-presents-kcd-austria-2024/">&lt;strong>KCD Austria 2024&lt;/strong>&lt;/a>: October 8-10, 2024 | Wien, Austria&lt;/li>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubeday-australia/">&lt;strong>KubeDay Australia&lt;/strong>&lt;/a>: October 15, 2024 | Melbourne, Australia&lt;/li>
&lt;li>&lt;a href="https://community.cncf.io/events/details/cncf-kcd-uk-presents-kubernetes-community-days-uk-london-2024/">&lt;strong>KCD UK - London 2024&lt;/strong>&lt;/a>: October 22-23, 2024 | Greater London, United Kingdom&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>November 2024&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/">&lt;strong>KubeCon + CloudNativeCon North America 2024&lt;/strong>&lt;/a>: November 12-15, 2024 | Salt Lake City, United States&lt;/li>
&lt;li>&lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/co-located-events/kubernetes-on-edge-day/">&lt;strong>Kubernetes on EDGE Day North America&lt;/strong>&lt;/a>: November 12, 2024 | Salt Lake City, United States&lt;/li>
&lt;/ul>
&lt;h2 id="upcoming-release-webinar">Upcoming release webinar&lt;/h2>
&lt;p>Join members of the Kubernetes v1.31 release team on Thursday, Thu Sep 12, 2024 10am PT to learn about the major features of this release, as well as deprecations and removals to help plan for upgrades.
For more information and registration, visit the &lt;a href="https://community.cncf.io/events/details/cncf-cncf-online-programs-presents-cncf-live-webinar-kubernetes-131-release/">event page&lt;/a> on the CNCF Online Programs site.&lt;/p>
&lt;h2 id="get-involved">Get involved&lt;/h2>
&lt;p>The simplest way to get involved with Kubernetes is by joining one of the many &lt;a href="https://github.com/kubernetes/community/blob/master/sig-list.md">Special Interest Groups&lt;/a> (SIGs) that align with your interests.
Have something you’d like to broadcast to the Kubernetes community?
Share your voice at our weekly &lt;a href="https://github.com/kubernetes/community/tree/master/communication">community meeting&lt;/a>, and through the channels below.
Thank you for your continued feedback and support.&lt;/p>
&lt;ul>
&lt;li>Follow us on X &lt;a href="https://x.com/kubernetesio">@Kubernetesio&lt;/a> for latest updates&lt;/li>
&lt;li>Join the community discussion on &lt;a href="https://discuss.kubernetes.io/">Discuss&lt;/a>&lt;/li>
&lt;li>Join the community on &lt;a href="http://slack.k8s.io/">Slack&lt;/a>&lt;/li>
&lt;li>Post questions (or answer questions) on &lt;a href="http://stackoverflow.com/questions/tagged/kubernetes">Stack Overflow&lt;/a>&lt;/li>
&lt;li>Share your Kubernetes &lt;a href="https://docs.google.com/a/linuxfoundation.org/forms/d/e/1FAIpQLScuI7Ye3VQHQTwBASrgkjQDSS5TP0g3AXfFhwSM9YpHgxRKFA/viewform">story&lt;/a>&lt;/li>
&lt;li>Read more about what’s happening with Kubernetes on the &lt;a href="https://kubernetes.io/blog/">blog&lt;/a>&lt;/li>
&lt;li>Learn more about the &lt;a href="https://github.com/kubernetes/sig-release/tree/master/release-team">Kubernetes Release Team&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Introducing Feature Gates to Client-Go: Enhancing Flexibility and Control</title><link>https://kubernetes.io/blog/2024/08/12/feature-gates-in-client-go/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/12/feature-gates-in-client-go/</guid><description>
&lt;p>Kubernetes components use on-off switches called &lt;em>feature gates&lt;/em> to manage the risk of adding a new feature.
The feature gate mechanism is what enables incremental graduation of a feature through the stages Alpha, Beta, and GA.&lt;/p>
&lt;p>Kubernetes components, such as kube-controller-manager and kube-scheduler, use the client-go library to interact with the API.
The same library is used across the Kubernetes ecosystem to build controllers, tools, webhooks, and more. client-go now includes
its own feature gating mechanism, giving developers and cluster administrators more control over how they adopt client features.&lt;/p>
&lt;p>To learn more about feature gates in Kubernetes, visit &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/">Feature Gates&lt;/a>.&lt;/p>
&lt;h2 id="motivation">Motivation&lt;/h2>
&lt;p>In the absence of client-go feature gates, each new feature separated feature availability from enablement in its own way, if at all.
Some features were enabled by updating to a newer version of client-go. Others needed to be actively configured in each program that used them.
A few were configurable at runtime using environment variables. Consuming a feature-gated functionality exposed by the kube-apiserver sometimes
required a client-side fallback mechanism to remain compatible with servers that don’t support the functionality due to their age or configuration.
In cases where issues were discovered in these fallback mechanisms, mitigation required updating to a fixed version of client-go or rolling back.&lt;/p>
&lt;p>None of these approaches offer good support for enabling a feature by default in some, but not all, programs that consume client-go.
Instead of enabling a new feature at first only for a single component, a change in the default setting immediately affects the default
for all Kubernetes components, which broadens the blast radius significantly.&lt;/p>
&lt;h2 id="feature-gates-in-client-go">Feature gates in client-go&lt;/h2>
&lt;p>To address these challenges, substantial client-go features will be phased in using the new feature gate mechanism.
It will allow developers and users to enable or disable features in a way that will be familiar to anyone who has experience
with feature gates in the Kubernetes components.&lt;/p>
&lt;p>Out of the box, simply by using a recent version of client-go, this offers several benefits.&lt;/p>
&lt;p>For people who use software built with client-go:&lt;/p>
&lt;ul>
&lt;li>Early adopters can enable a default-off client-go feature on a per-process basis.&lt;/li>
&lt;li>Misbehaving features can be disabled without building a new binary.&lt;/li>
&lt;li>The state of all known client-go feature gates is logged, allowing users to inspect it.&lt;/li>
&lt;/ul>
&lt;p>For people who develop software built with client-go:&lt;/p>
&lt;ul>
&lt;li>By default, client-go feature gate overrides are read from environment variables.
If a bug is found in a client-go feature, users will be able to disable it without waiting for a new release.&lt;/li>
&lt;li>Developers can replace the default environment-variable-based overrides in a program to change defaults,
read overrides from another source, or disable runtime overrides completely.
The Kubernetes components use this customizability to integrate client-go feature gates with
the existing &lt;code>--feature-gates&lt;/code> command-line flag, feature enablement metrics, and logging.&lt;/li>
&lt;/ul>
&lt;h2 id="overriding-client-go-feature-gates">Overriding client-go feature gates&lt;/h2>
&lt;p>&lt;strong>Note&lt;/strong>: This describes the default method for overriding client-go feature gates at runtime.
It can be disabled or customized by the developer of a particular program.
In Kubernetes components, client-go feature gate overrides are controlled by the &lt;code>--feature-gates&lt;/code> flag.&lt;/p>
&lt;p>Features of client-go can be enabled or disabled by setting environment variables prefixed with &lt;code>KUBE_FEATURE&lt;/code>.
For example, to enable a feature named &lt;code>MyFeature&lt;/code>, set the environment variable as follows:&lt;/p>
&lt;pre tabindex="0">&lt;code> KUBE_FEATURE_MyFeature=true
&lt;/code>&lt;/pre>&lt;p>To disable the feature, set the environment variable to &lt;code>false&lt;/code>:&lt;/p>
&lt;pre tabindex="0">&lt;code> KUBE_FEATURE_MyFeature=false
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Note&lt;/strong>: Environment variables are case-sensitive on some operating systems.
Therefore, &lt;code>KUBE_FEATURE_MyFeature&lt;/code> and &lt;code>KUBE_FEATURE_MYFEATURE&lt;/code> would be considered two different variables.&lt;/p>
&lt;h2 id="customizing-client-go-feature-gates">Customizing client-go feature gates&lt;/h2>
&lt;p>The default environment-variable based mechanism for feature gate overrides can be sufficient for many programs in the Kubernetes ecosystem,
and requires no special integration. Programs that require different behavior can replace it with their own custom feature gate provider.
This allows a program to do things like force-disable a feature that is known to work poorly,
read feature gates directly from a remote configuration service, or accept feature gate overrides through command-line options.&lt;/p>
&lt;p>The Kubernetes components replace client-go’s default feature gate provider with a shim to the existing Kubernetes feature gate provider.
For all practical purposes, client-go feature gates are treated the same as other Kubernetes
feature gates: they are wired to the &lt;code>--feature-gates&lt;/code> command-line flag, included in feature enablement metrics, and logged on startup.&lt;/p>
&lt;p>To replace the default feature gate provider, implement the Gates interface and call ReplaceFeatureGates
at package initialization time, as in this simple example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">import&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="">“&lt;/span>k8s.io&lt;span style="color:#666">/&lt;/span>client&lt;span style="color:#666">-&lt;/span>&lt;span style="color:#a2f;font-weight:bold">go&lt;/span>&lt;span style="color:#666">/&lt;/span>features&lt;span style="">”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">type&lt;/span> AlwaysEnabledGates &lt;span style="color:#a2f;font-weight:bold">struct&lt;/span>{}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">func&lt;/span> (AlwaysEnabledGates) &lt;span style="color:#00a000">Enabled&lt;/span>(features.Feature) &lt;span style="color:#0b0;font-weight:bold">bool&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a2f;font-weight:bold">return&lt;/span> &lt;span style="color:#a2f;font-weight:bold">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">func&lt;/span> &lt;span style="color:#00a000">init&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> features.&lt;span style="color:#00a000">ReplaceFeatureGates&lt;/span>(AlwaysEnabledGates{})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Implementations that need the complete list of defined client-go features can get it by implementing the Registry interface
and calling &lt;code>AddFeaturesToExistingFeatureGates&lt;/code>.
For a complete example, refer to &lt;a href="https://github.com/kubernetes/kubernetes/blob/64ba17c605a41700f7f4c4e27dca3684b593b2b9/pkg/features/kube_features.go#L990-L997">the usage within Kubernetes&lt;/a>.&lt;/p>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>With the introduction of feature gates in client-go v1.30, rolling out a new client-go feature has become safer and easier.
Users and developers can control the pace of their own adoption of client-go features.
The work of Kubernetes contributors is streamlined by having a common mechanism for graduating features that span both sides of the Kubernetes API boundary.&lt;/p>
&lt;p>Special shoutout to &lt;a href="https://github.com/sttts">@sttts&lt;/a> and &lt;a href="https://github.com/deads2k">@deads2k&lt;/a> for their help in shaping this feature.&lt;/p></description></item><item><title>Spotlight on SIG API Machinery</title><link>https://kubernetes.io/blog/2024/08/07/sig-api-machinery-spotlight-2024/</link><pubDate>Wed, 07 Aug 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/08/07/sig-api-machinery-spotlight-2024/</guid><description>
&lt;p>We recently talked with &lt;a href="https://github.com/fedebongio">Federico Bongiovanni&lt;/a> (Google) and &lt;a href="https://github.com/deads2k">David
Eads&lt;/a> (Red Hat), Chairs of SIG API Machinery, to know a bit more about
this Kubernetes Special Interest Group.&lt;/p>
&lt;h2 id="introductions">Introductions&lt;/h2>
&lt;p>&lt;strong>Frederico (FSM): Hello, and thank your for your time. To start with, could you tell us about
yourselves and how you got involved in Kubernetes?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>David&lt;/strong>: I started working on
&lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift">OpenShift&lt;/a> (the Red Hat
distribution of Kubernetes) in the fall of 2014 and got involved pretty quickly in API Machinery. My
first PRs were fixing kube-apiserver error messages and from there I branched out to &lt;code>kubectl&lt;/code>
(&lt;em>kubeconfigs&lt;/em> are my fault!), &lt;code>auth&lt;/code> (&lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/">RBAC&lt;/a> and &lt;code>*Review&lt;/code> APIs are ports
from OpenShift), &lt;code>apps&lt;/code> (&lt;em>workqueues&lt;/em> and &lt;em>sharedinformers&lt;/em> for example). Don’t tell the others,
but API Machinery is still my favorite :)&lt;/p>
&lt;p>&lt;strong>Federico&lt;/strong>: I was not as early in Kubernetes as David, but now it's been more than six years. At
my previous company we were starting to use Kubernetes for our own products, and when I came across
the opportunity to work directly with Kubernetes I left everything and boarded the ship (no pun
intended). I joined Google and Kubernetes in early 2018, and have been involved since.&lt;/p>
&lt;h2 id="sig-machinery-s-scope">SIG Machinery's scope&lt;/h2>
&lt;p>&lt;strong>FSM: It only takes a quick look at the SIG API Machinery charter to see that it has quite a
significant scope, nothing less than the Kubernetes control plane. Could you describe this scope in
your own words?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>David&lt;/strong>: We own the &lt;code>kube-apiserver&lt;/code> and how to efficiently use it. On the backend, that includes
its contract with backend storage and how it allows API schema evolution over time. On the
frontend, that includes schema best practices, serialization, client patterns, and controller
patterns on top of all of it.&lt;/p>
&lt;p>&lt;strong>Federico&lt;/strong>: Kubernetes has a lot of different components, but the control plane has a really
critical mission: it's your communication layer with the cluster and also owns all the extensibility
mechanisms that make Kubernetes so powerful. We can't make mistakes like a regression, or an
incompatible change, because the blast radius is huge.&lt;/p>
&lt;p>&lt;strong>FSM: Given this breadth, how do you manage the different aspects of it?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Federico&lt;/strong>: We try to organize the large amount of work into smaller areas. The working groups and
subprojects are part of it. Different people on the SIG have their own areas of expertise, and if
everything fails, we are really lucky to have people like David, Joe, and Stefan who really are &amp;quot;all
terrain&amp;quot;, in a way that keeps impressing me even after all these years. But on the other hand this
is the reason why we need more people to help us carry the quality and excellence of Kubernetes from
release to release.&lt;/p>
&lt;h2 id="an-evolving-collaboration-model">An evolving collaboration model&lt;/h2>
&lt;p>&lt;strong>FSM: Was the existing model always like this, or did it evolve with time - and if so, what would
you consider the main changes and the reason behind them?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>David&lt;/strong>: API Machinery has evolved over time both growing and contracting in scope. When trying
to satisfy client access patterns it’s very easy to add scope both in terms of features and applying
them.&lt;/p>
&lt;p>A good example of growing scope is the way that we identified a need to reduce memory utilization by
clients writing controllers and developed shared informers. In developing shared informers and the
controller patterns use them (workqueues, error handling, and listers), we greatly reduced memory
utilization and eliminated many expensive lists. The downside: we grew a new set of capability to
support and effectively took ownership of that area from sig-apps.&lt;/p>
&lt;p>For an example of more shared ownership: building out cooperative resource management (the goal of
server-side apply), &lt;code>kubectl&lt;/code> expanded to take ownership of leveraging the server-side apply
capability. The transition isn’t yet complete, but &lt;a href="https://github.com/kubernetes/community/tree/master/sig-cli">SIG
CLI&lt;/a> manages that usage and owns it.&lt;/p>
&lt;p>&lt;strong>FSM: And for the boundary between approaches, do you have any guidelines?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>David&lt;/strong>: I think much depends on the impact. If the impact is local in immediate effect, we advise
other SIGs and let them move at their own pace. If the impact is global in immediate effect without
a natural incentive, we’ve found a need to press for adoption directly.&lt;/p>
&lt;p>&lt;strong>FSM: Still on that note, SIG Architecture has an API Governance subproject, is it mostly
independent from SIG API Machinery or are there important connection points?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>David&lt;/strong>: The projects have similar sounding names and carry some impacts on each other, but have
different missions and scopes. API Machinery owns the how and API Governance owns the what. API
conventions, the API approval process, and the final say on individual k8s.io APIs belong to API
Governance. API Machinery owns the REST semantics and non-API specific behaviors.&lt;/p>
&lt;p>&lt;strong>Federico&lt;/strong>: I really like how David put it: &lt;em>&amp;quot;API Machinery owns the how and API Governance owns
the what&amp;quot;&lt;/em>: we don't own the actual APIs, but the actual APIs live through us.&lt;/p>
&lt;h2 id="the-challenges-of-kubernetes-popularity">The challenges of Kubernetes popularity&lt;/h2>
&lt;p>&lt;strong>FSM: With the growth in Kubernetes adoption we have certainly seen increased demands from the
Control Plane: how is this felt and how does it influence the work of the SIG?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>David&lt;/strong>: It’s had a massive influence on API Machinery. Over the years we have often responded to
and many times enabled the evolutionary stages of Kubernetes. As the central orchestration hub of
nearly all capability on Kubernetes clusters, we both lead and follow the community. In broad
strokes I see a few evolution stages for API Machinery over the years, with constantly high
activity.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Finding purpose&lt;/strong>: &lt;code>pre-1.0&lt;/code> up until &lt;code>v1.3&lt;/code> (up to our first 1000+ nodes/namespaces) or
so. This time was characterized by rapid change. We went through five different versions of our
schemas and rose to meet the need. We optimized for quick, in-tree API evolution (sometimes to
the detriment of longer term goals), and defined patterns for the first time.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Scaling to meet the need&lt;/strong>: &lt;code>v1.3-1.9&lt;/code> (up to shared informers in controllers) or so. When we
started trying to meet customer needs as we gained adoption, we found severe scale limitations in
terms of CPU and memory. This was where we broadened API machinery to include access patterns, but
were still heavily focused on in-tree types. We built the watch cache, protobuf serialization,
and shared caches.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Fostering the ecosystem&lt;/strong>: &lt;code>v1.8-1.21&lt;/code> (up to CRD v1) or so. This was when we designed and wrote
CRDs (the considered replacement for third-party-resources), the immediate needs we knew were
coming (admission webhooks), and evolution to best practices we knew we needed (API schemas).
This enabled an explosion of early adopters willing to work very carefully within the constraints
to enable their use-cases for servicing pods. The adoption was very fast, sometimes outpacing
our capability, and creating new problems.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Simplifying deployments&lt;/strong>: &lt;code>v1.22+&lt;/code>. In the relatively recent past, we’ve been responding to
pressures or running kube clusters at scale with large numbers of sometimes-conflicting ecosystem
projects using our extensions mechanisms. Lots of effort is now going into making platform
extensions easier to write and safer to manage by people who don't hold PhDs in kubernetes. This
started with things like server-side-apply and continues today with features like webhook match
conditions and validating admission policies.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Work in API Machinery has a broad impact across the project and the ecosystem. It’s an exciting
area to work for those able to make a significant time investment on a long time horizon.&lt;/p>
&lt;h2 id="the-road-ahead">The road ahead&lt;/h2>
&lt;p>&lt;strong>FSM: With those different evolutionary stages in mind, what would you pinpoint as the top
priorities for the SIG at this time?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>David:&lt;/strong> &lt;strong>Reliability, efficiency, and capability&lt;/strong> in roughly that order.&lt;/p>
&lt;p>With the increased usage of our &lt;code>kube-apiserver&lt;/code> and extensions mechanisms, we find that our first
set of extensions mechanisms, while fairly complete in terms of capability, carry significant risks
in terms of potential mis-use with large blast radius. To mitigate these risks, we’re investing in
features that reduce the blast radius for accidents (webhook match conditions) and which provide
alternative mechanisms with lower risk profiles for most actions (validating admission policy).&lt;/p>
&lt;p>At the same time, the increased usage has made us more aware of scaling limitations that we can
improve both server and client-side. Efforts here include more efficient serialization (CBOR),
reduced etcd load (consistent reads from cache), and reduced peak memory usage (streaming lists).&lt;/p>
&lt;p>And finally, the increased usage has highlighted some long existing
gaps that we’re closing. Things like field selectors for CRDs which
the &lt;a href="https://github.com/kubernetes/community/blob/master/wg-batch/README.md">Batch Working Group&lt;/a>
is eager to leverage and will eventually form the basis for a new way
to prevent trampoline pod attacks from exploited nodes.&lt;/p>
&lt;h2 id="joining-the-fun">Joining the fun&lt;/h2>
&lt;p>&lt;strong>FSM: For anyone wanting to start contributing, what's your suggestions?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Federico&lt;/strong>: SIG API Machinery is not an exception to the Kubernetes motto: &lt;strong>Chop Wood and Carry
Water&lt;/strong>. There are multiple weekly meetings that are open to everybody, and there is always more
work to be done than people to do it.&lt;/p>
&lt;p>I acknowledge that API Machinery is not easy, and the ramp up will be steep. The bar is high,
because of the reasons we've been discussing: we carry a huge responsibility. But of course with
passion and perseverance many people has ramped up through the years, and we hope more will come.&lt;/p>
&lt;p>In terms of concrete opportunities, there is the SIG meeting every two weeks. Everyone is welcome to
attend and listen, see what the group talks about, see what's going on in this release, etc.&lt;/p>
&lt;p>Also two times a week, Tuesday and Thursday, we have the public Bug Triage, where we go through
everything new from the last meeting. We've been keeping this practice for more than 7 years
now. It's a great opportunity to volunteer to review code, fix bugs, improve documentation,
etc. Tuesday's it's at 1 PM (PST) and Thursday is on an EMEA friendly time (9:30 AM PST). We are
always looking to improve, and we hope to be able to provide more concrete opportunities to join and
participate in the future.&lt;/p>
&lt;p>&lt;strong>FSM: Excellent, thank you! Any final comments you would like to share with our readers?&lt;/strong>&lt;/p>
&lt;p>&lt;strong>Federico&lt;/strong>: As I mentioned, the first steps might be hard, but the reward is also larger. Working
on API Machinery is working on an area of huge impact (millions of users?), and your contributions
will have a direct outcome in the way that Kubernetes works and the way that it's used. For me
that's enough reward and motivation!&lt;/p></description></item><item><title>Kubernetes Removals and Major Changes In v1.31</title><link>https://kubernetes.io/blog/2024/07/19/kubernetes-1-31-upcoming-changes/</link><pubDate>Fri, 19 Jul 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/07/19/kubernetes-1-31-upcoming-changes/</guid><description>
&lt;p>As Kubernetes develops and matures, features may be deprecated, removed, or replaced with better ones for the project's overall health.
This article outlines some planned changes for the Kubernetes v1.31 release that the release team feels you should be aware of for the continued maintenance of your Kubernetes environment.
The information listed below is based on the current status of the v1.31 release.
It may change before the actual release date.&lt;/p>
&lt;h2 id="the-kubernetes-api-removal-and-deprecation-process">The Kubernetes API removal and deprecation process&lt;/h2>
&lt;p>The Kubernetes project has a well-documented &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-policy/">deprecation policy&lt;/a> for features.
This policy states that stable APIs may only be deprecated when a newer, stable version of that API is available and that APIs have a minimum lifetime for each stability level.
A deprecated API has been marked for removal in a future Kubernetes release.
It will continue to function until removal (at least one year from the deprecation), but usage will display a warning.
Removed APIs are no longer available in the current version, so you must migrate to using the replacement.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Generally available (GA) or stable API versions may be marked as deprecated but must not be removed within a major version of Kubernetes.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Beta or pre-release API versions must be supported for 3 releases after the deprecation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Alpha or experimental API versions may be removed in any release without prior deprecation notice.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Whether an API is removed because a feature graduated from beta to stable or because that API did not succeed, all removals comply with this deprecation policy.
Whenever an API is removed, migration options are communicated in the &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/">documentation&lt;/a>.&lt;/p>
&lt;h2 id="a-note-about-sha-1-signature-support">A note about SHA-1 signature support&lt;/h2>
&lt;p>In &lt;a href="https://go.dev/doc/go1.18#sha1">go1.18&lt;/a> (released in March 2022), the crypto/x509 library started to reject certificates signed with a SHA-1 hash function.
While SHA-1 is established to be unsafe and publicly trusted Certificate Authorities have not issued SHA-1 certificates since 2015, there might still be cases in the context of Kubernetes where user-provided certificates are signed using a SHA-1 hash function through private authorities with them being used for Aggregated API Servers or webhooks.
If you have relied on SHA-1 based certificates, you must explicitly opt back into its support by setting &lt;code>GODEBUG=x509sha1=1&lt;/code> in your environment.&lt;/p>
&lt;p>Given Go's &lt;a href="https://go.dev/blog/compat">compatibility policy for GODEBUGs&lt;/a>, the &lt;code>x509sha1&lt;/code> GODEBUG and the support for SHA-1 certificates will &lt;a href="https://tip.golang.org/doc/go1.23">fully go away in go1.24&lt;/a> which will be released in the first half of 2025.
If you rely on SHA-1 certificates, please start moving off them.&lt;/p>
&lt;p>Please see &lt;a href="https://github.com/kubernetes/kubernetes/issues/125689">Kubernetes issue #125689&lt;/a> to get a better idea of timelines around the support for SHA-1 going away, when Kubernetes releases plans to adopt go1.24, and for more details on how to detect usage of SHA-1 certificates via metrics and audit logging.&lt;/p>
&lt;h2 id="deprecations-and-removals-in-kubernetes-1-31">Deprecations and removals in Kubernetes 1.31&lt;/h2>
&lt;h3 id="deprecation-of-status-nodeinfo-kubeproxyversion-field-for-nodes-kep-4004-https-github-com-kubernetes-enhancements-issues-4004">Deprecation of &lt;code>status.nodeInfo.kubeProxyVersion&lt;/code> field for Nodes (&lt;a href="https://github.com/kubernetes/enhancements/issues/4004">KEP 4004&lt;/a>)&lt;/h3>
&lt;p>The &lt;code>.status.nodeInfo.kubeProxyVersion&lt;/code> field of Nodes is being deprecated in Kubernetes v1.31,
and will be removed in a later release.
It's being deprecated because the value of this field wasn't (and isn't) accurate.
This field is set by the kubelet, which does not have reliable information about the kube-proxy version or whether kube-proxy is running.&lt;/p>
&lt;p>The &lt;code>DisableNodeKubeProxyVersion&lt;/code> &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/">feature gate&lt;/a> will be set to &lt;code>true&lt;/code> in by default in v1.31 and the kubelet will no longer attempt to set the &lt;code>.status.kubeProxyVersion&lt;/code> field for its associated Node.&lt;/p>
&lt;h3 id="removal-of-all-in-tree-integrations-with-cloud-providers">Removal of all in-tree integrations with cloud providers&lt;/h3>
&lt;p>As highlighted in a &lt;a href="https://kubernetes.io/blog/2024/05/20/completing-cloud-provider-migration/">previous article&lt;/a>, the last remaining in-tree support for cloud provider integration will be removed as part of the v1.31 release.
This doesn't mean you can't integrate with a cloud provider, however you now &lt;strong>must&lt;/strong> use the
recommended approach using an external integration. Some integrations are part of the Kubernetes
project and others are third party software.&lt;/p>
&lt;p>This milestone marks the completion of the externalization process for all cloud providers' integrations from the Kubernetes core (&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-cloud-provider/2395-removing-in-tree-cloud-providers/README.md">KEP-2395&lt;/a>), a process started with Kubernetes v1.26.
This change helps Kubernetes to get closer to being a truly vendor-neutral platform.&lt;/p>
&lt;p>For further details on the cloud provider integrations, read our &lt;a href="https://kubernetes.io/blog/2023/12/14/cloud-provider-integration-changes/">v1.29 Cloud Provider Integrations feature blog&lt;/a>.
For additional context about the in-tree code removal, we invite you to check the (&lt;a href="https://kubernetes.io/blog/2023/11/16/kubernetes-1-29-upcoming-changes/#removal-of-in-tree-integrations-with-cloud-providers-kep-2395-https-kep-k8s-io-2395">v1.29 deprecation blog&lt;/a>).&lt;/p>
&lt;p>The latter blog also contains useful information for users who need to migrate to version v1.29 and later.&lt;/p>
&lt;h3 id="removal-of-kubelet-keep-terminated-pod-volumes-command-line-flag">Removal of kubelet &lt;code>--keep-terminated-pod-volumes&lt;/code> command line flag&lt;/h3>
&lt;p>The kubelet flag &lt;code>--keep-terminated-pod-volumes&lt;/code>, which was deprecated in 2017, will be removed as
part of the v1.31 release.&lt;/p>
&lt;p>You can find more details in the pull request &lt;a href="https://github.com/kubernetes/kubernetes/pull/122082">#122082&lt;/a>.&lt;/p>
&lt;h3 id="removal-of-cephfs-volume-plugin">Removal of CephFS volume plugin&lt;/h3>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/#cephfs">CephFS volume plugin&lt;/a> was removed in this release and the &lt;code>cephfs&lt;/code> volume type became non-functional.&lt;/p>
&lt;p>It is recommended that you use the &lt;a href="https://github.com/ceph/ceph-csi/">CephFS CSI driver&lt;/a> as a third-party storage driver instead. If you were using the CephFS volume plugin before upgrading the cluster version to v1.31, you must re-deploy your application to use the new driver.&lt;/p>
&lt;p>CephFS volume plugin was formally marked as deprecated in v1.28.&lt;/p>
&lt;h3 id="removal-of-ceph-rbd-volume-plugin">Removal of Ceph RBD volume plugin&lt;/h3>
&lt;p>The v1.31 release will remove the &lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/#rbd">Ceph RBD volume plugin&lt;/a> and its CSI migration support, making the &lt;code>rbd&lt;/code> volume type non-functional.&lt;/p>
&lt;p>It's recommended that you use the &lt;a href="https://github.com/ceph/ceph-csi/">RBD CSI driver&lt;/a> in your clusters instead.
If you were using Ceph RBD volume plugin before upgrading the cluster version to v1.31, you must re-deploy your application to use the new driver.&lt;/p>
&lt;p>The Ceph RBD volume plugin was formally marked as deprecated in v1.28.&lt;/p>
&lt;h3 id="deprecation-of-non-csi-volume-limit-plugins-in-kube-scheduler">Deprecation of non-CSI volume limit plugins in kube-scheduler&lt;/h3>
&lt;p>The v1.31 release will deprecate all non-CSI volume limit scheduler plugins, and will remove some
already deprected plugins from the &lt;a href="https://kubernetes.io/docs/reference/scheduling/config/">default plugins&lt;/a>, including:&lt;/p>
&lt;ul>
&lt;li>&lt;code>AzureDiskLimits&lt;/code>&lt;/li>
&lt;li>&lt;code>CinderLimits&lt;/code>&lt;/li>
&lt;li>&lt;code>EBSLimits&lt;/code>&lt;/li>
&lt;li>&lt;code>GCEPDLimits&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>It's recommended that you use the &lt;code>NodeVolumeLimits&lt;/code> plugin instead because it can handle the same functionality as the removed plugins since those volume types have been migrated to CSI.
Please replace the deprecated plugins with the &lt;code>NodeVolumeLimits&lt;/code> plugin if you explicitly use them in the &lt;a href="https://kubernetes.io/docs/reference/scheduling/config/">scheduler config&lt;/a>.
The &lt;code>AzureDiskLimits&lt;/code>, &lt;code>CinderLimits&lt;/code>, &lt;code>EBSLimits&lt;/code>, and &lt;code>GCEPDLimits&lt;/code> plugins will be removed in a future release.&lt;/p>
&lt;p>These plugins will be removed from the default scheduler plugins list as they have been deprecated since Kubernetes v1.14.&lt;/p>
&lt;h2 id="looking-ahead">Looking ahead&lt;/h2>
&lt;p>The official list of API removals planned for &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-32">Kubernetes v1.32&lt;/a> include:&lt;/p>
&lt;ul>
&lt;li>The &lt;code>flowcontrol.apiserver.k8s.io/v1beta3&lt;/code> API version of FlowSchema and PriorityLevelConfiguration will be removed.
To prepare for this, you can edit your existing manifests and rewrite client software to use the &lt;code>flowcontrol.apiserver.k8s.io/v1 API&lt;/code> version, available since v1.29.
All existing persisted objects are accessible via the new API. Notable changes in flowcontrol.apiserver.k8s.io/v1beta3 include that the PriorityLevelConfiguration &lt;code>spec.limited.nominalConcurrencyShares&lt;/code> field only defaults to 30 when unspecified, and an explicit value of 0 is not changed to 30.&lt;/li>
&lt;/ul>
&lt;p>For more information, please refer to the &lt;a href="https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-32">API deprecation guide&lt;/a>.&lt;/p>
&lt;h2 id="want-to-know-more">Want to know more?&lt;/h2>
&lt;p>The Kubernetes release notes announce deprecations.
We will formally announce the deprecations in &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md#deprecation">Kubernetes v1.31&lt;/a> as part of the CHANGELOG for that release.&lt;/p>
&lt;p>You can see the announcements of pending deprecations in the release notes for:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md#deprecation">Kubernetes v1.30&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md#deprecation">Kubernetes v1.29&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.28.md#deprecation">Kubernetes v1.28&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.27.md#deprecation">Kubernetes v1.27&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul></description></item><item><title>Spotlight on SIG Node</title><link>https://kubernetes.io/blog/2024/06/20/sig-node-spotlight-2024/</link><pubDate>Thu, 20 Jun 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/06/20/sig-node-spotlight-2024/</guid><description>
&lt;p>In the world of container orchestration, &lt;a href="https://kubernetes.io/">Kubernetes&lt;/a> reigns
supreme, powering some of the most complex and dynamic applications across the globe. Behind the
scenes, a network of Special Interest Groups (SIGs) drives Kubernetes' innovation and stability.&lt;/p>
&lt;p>Today, I have the privilege of speaking with &lt;a href="https://www.linkedin.com/in/matthias-bertschy-b427b815/">Matthias
Bertschy&lt;/a>, &lt;a href="https://www.linkedin.com/in/gunju-kim-916b33190/">Gunju
Kim&lt;/a>, and &lt;a href="https://www.linkedin.com/in/sergeykanzhelev/">Sergey
Kanzhelev&lt;/a>, members of &lt;a href="https://github.com/kubernetes/community/blob/master/sig-node/README.md">SIG
Node&lt;/a>, who will shed some
light on their roles, challenges, and the exciting developments within SIG Node.&lt;/p>
&lt;p>&lt;em>Answers given collectively by all interviewees will be marked by their initials.&lt;/em>&lt;/p>
&lt;h2 id="introductions">Introductions&lt;/h2>
&lt;p>&lt;strong>Arpit:&lt;/strong> Thank you for joining us today. Could you please introduce yourselves and provide a brief
overview of your roles within SIG Node?&lt;/p>
&lt;p>&lt;strong>Matthias:&lt;/strong> My name is Matthias Bertschy, I am French and live next to Lake Geneva, near the
French Alps. I have been a Kubernetes contributor since 2017, a reviewer for SIG Node and a
maintainer of &lt;a href="https://docs.prow.k8s.io/docs/overview/">Prow&lt;/a>. I work as a Senior Kubernetes
Developer for a security startup named &lt;a href="https://www.armosec.io/">ARMO&lt;/a>, which donated
&lt;a href="https://www.cncf.io/projects/kubescape/">Kubescape&lt;/a> to the CNCF.&lt;/p>
&lt;p>&lt;img alt="Lake Geneva and the Alps" src="https://kubernetes.io/blog/2024/06/20/sig-node-spotlight-2024/Lake_Geneva_and_the_Alps.jpg">&lt;/p>
&lt;p>&lt;strong>Gunju:&lt;/strong> My name is Gunju Kim. I am a software engineer at
&lt;a href="https://www.navercorp.com/naver/naverMain">NAVER&lt;/a>, where I focus on developing a cloud platform for
search services. I have been contributing to the Kubernetes project in my free time since 2021.&lt;/p>
&lt;p>&lt;strong>Sergey:&lt;/strong> My name is Sergey Kanzhelev. I have worked on Kubernetes and &lt;a href="https://cloud.google.com/kubernetes-engine">Google Kubernetes
Engine&lt;/a> for 3 years and have worked on open-source
projects for many years now. I am a chair of SIG Node.&lt;/p>
&lt;h2 id="understanding-sig-node">Understanding SIG Node&lt;/h2>
&lt;p>&lt;strong>Arpit:&lt;/strong> Thank you! Could you provide our readers with an overview of SIG Node's responsibilities
within the Kubernetes ecosystem?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> SIG Node is one of the first if not the very first SIG in Kubernetes. The SIG is
responsible for all iterations between Kubernetes and node resources, as well as node maintenance
itself. This is quite a large scope, and the SIG owns a large part of the Kubernetes codebase. Because
of this wide ownership, SIG Node is always in contact with other SIGs such as SIG Network, SIG
Storage, and SIG Security and almost any new features and developments in Kubernetes involves SIG
Node in some way.&lt;/p>
&lt;p>&lt;strong>Arpit&lt;/strong>: How does SIG Node contribute to Kubernetes' performance and stability?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> Kubernetes works on nodes of many different sizes and shapes, from small physical VMs
with cheap hardware to large AI/ML-optimized GPU-enabled nodes. Nodes may stay online for months or
maybe be short-lived and be preempted at any moment as they are running on excess compute of a cloud
provider.&lt;/p>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/architecture/#kubelet">&lt;code>kubelet&lt;/code>&lt;/a> — the
Kubernetes agent on a node — must work in all these environments reliably. As for the performance
of kubelet operations, this is becoming increasingly important today. On one hand, as Kubernetes is
being used on extra small nodes more and more often in telecom and retail environments, it needs to
scale into the smallest footprint possible. On the other hand, with AI/ML workloads where every node
is extremely expensive, every second of delayed operations can visibly change the price of
computation.&lt;/p>
&lt;h2 id="challenges-and-opportunities">Challenges and Opportunities&lt;/h2>
&lt;p>&lt;strong>Arpit:&lt;/strong> What upcoming challenges and opportunities is SIG Node keeping an eye on?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> As Kubernetes enters the second decade of its life, we see a huge demand to support new
workload types. And SIG Node will play a big role in this. The Sidecar KEP, which we will be talking
about later, is one of the examples of increased emphasis on supporting new workload types.&lt;/p>
&lt;p>The key challenge we will have in the next few years is how to keep innovations while maintaining
high quality and backward compatibility of existing scenarios. SIG Node will continue to play a
central role in Kubernetes.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> And are there any ongoing research or development areas within SIG Node that excite you?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> Supporting new workload types is a fascinating area for us. Our recent exploration of
sidecar containers is a testament to this. Sidecars offer a versatile solution for enhancing
application functionality without altering the core codebase.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> What are some of the challenges you've faced while maintaining SIG Node, and how have you
overcome them?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> The biggest challenge of SIG Node is its size and the many feature requests it
receives. We are encouraging more people to join as reviewers and are always open to improving
processes and addressing feedback. For every release, we run the feedback session at the SIG Node
meeting and identify problematic areas and action items.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> Are there specific technologies or advancements that SIG Node is closely monitoring or
integrating into Kubernetes?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> Developments in components that the SIG depends on, like
&lt;a href="https://kubernetes.io/docs/setup/production-environment/container-runtimes/">container runtimes&lt;/a>
(e.g. &lt;a href="https://containerd.io/">containerd&lt;/a> and &lt;a href="https://cri-o.io/">CRI-O&lt;/a>, and OS features are
something we contribute to and monitor closely. For example, there is an upcoming &lt;em>cgroup v1&lt;/em>
deprecation and removal that Kubernetes and SIG Node will need to guide Kubernetes users
through. Containerd is also releasing version &lt;code>2.0&lt;/code>, which removes deprecated features, which will
affect Kubernetes users.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> Could you share a memorable experience or achievement from your time as a SIG Node
maintainer that you're particularly proud of?&lt;/p>
&lt;p>&lt;strong>Mathias:&lt;/strong> I think the best moment was when my first KEP (introducing the
&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes">&lt;code>startupProbe&lt;/code>&lt;/a>)
finally graduated to GA (General Availability). I also enjoy seeing my contributions being used
daily by contributors, such as the comment containing the GitHub tree hash used to retain LGTM
despite squash commits.&lt;/p>
&lt;h2 id="sidecar-containers">Sidecar containers&lt;/h2>
&lt;p>&lt;strong>Arpit:&lt;/strong> Can you provide more context on the concept of sidecar containers and their evolution in
the context of Kubernetes?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> The concept of
&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/">sidecar containers&lt;/a> dates back to
2015 when Kubernetes introduced the idea of composite containers. These additional containers,
running alongside the main application container within the same pod, were seen as a way to extend
and enhance application functionality without modifying the core codebase. Early adopters of
sidecars employed custom scripts and configurations to manage them, but this approach presented
challenges in terms of consistency and scalability.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> Can you share specific use cases or examples where sidecar containers are particularly
beneficial?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> Sidecar containers are a versatile tool that can be used to enhance the functionality of
applications in a variety of ways:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Logging and monitoring:&lt;/strong> Sidecar containers can be used to collect logs and metrics from the
primary application container and send them to a centralized logging and monitoring system.&lt;/li>
&lt;li>&lt;strong>Traffic filtering and routing:&lt;/strong> Sidecar containers can be used to filter and route traffic to
and from the primary application container.&lt;/li>
&lt;li>&lt;strong>Encryption and decryption:&lt;/strong> Sidecar containers can be used to encrypt and decrypt data as it
flows between the primary application container and external services.&lt;/li>
&lt;li>&lt;strong>Data synchronization:&lt;/strong> Sidecar containers can be used to synchronize data between the primary
application container and external databases or services.&lt;/li>
&lt;li>&lt;strong>Fault injection:&lt;/strong> Sidecar containers can be used to inject faults into the primary application
container in order to test its resilience to failures.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Arpit:&lt;/strong> The proposal mentions that some companies are using a fork of Kubernetes with sidecar
functionality added. Can you provide insights into the level of adoption and community interest in
this feature?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> While we lack concrete metrics to measure adoption rates, the KEP has garnered
significant interest from the community, particularly among service mesh vendors like Istio, who
actively participated in its alpha testing phase. The KEP's visibility through numerous blog posts,
interviews, talks, and workshops further demonstrates its widespread appeal. The KEP addresses the
growing demand for additional capabilities alongside main containers in Kubernetes pods, such as
network proxies, logging systems, and security measures. The community acknowledges the importance
of providing easy migration paths for existing workloads to facilitate widespread adoption of the
feature.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> Are there any notable examples or success stories from companies using sidecar containers
in production?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> It is still too early to expect widespread adoption in production environments. The 1.29
release has only been available in Google Kubernetes Engine (GKE) since January 11, 2024, and there
still needs to be comprehensive documentation on how to enable and use them effectively via
universal injector. Istio, a popular service mesh platform, also lacks proper documentation for
enabling native sidecars, making it difficult for developers to get started with this new
feature. However, as native sidecar support matures and documentation improves, we can expect to see
wider adoption of this technology in production environments.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> The proposal suggests introducing a &lt;code>restartPolicy&lt;/code> field for init containers to indicate
sidecar functionality. Can you explain how this solution addresses the outlined challenges?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> The proposal to introduce a &lt;code>restartPolicy&lt;/code> field for init containers addresses the
outlined challenges by utilizing existing infrastructure and simplifying sidecar management. This
approach avoids adding new fields to the pod specification, keeping it manageable and avoiding more
clutter. By leveraging the existing init container mechanism, sidecars can be run alongside regular
init containers during pod startup, ensuring a consistent ordering of initialization. Additionally,
setting the restart policy of sidecar init containers to &lt;code>Always&lt;/code> explicitly states that they continue
running even after the main application container terminates, enabling persistent services like
logging and monitoring until the end of the workload.&lt;/p>
&lt;p>&lt;strong>Arpit:&lt;/strong> How will the introduction of the &lt;code>restartPolicy&lt;/code> field for init containers affect
backward compatibility with existing Kubernetes configurations?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> The introduction of the &lt;code>restartPolicy&lt;/code> field for init containers will maintain backward
compatibility with existing Kubernetes configurations. Existing init containers will continue to
function as they have before, and the new &lt;code>restartPolicy&lt;/code> field will only apply to init containers
explicitly marked as sidecars. This approach ensures that existing applications and deployments will
not be disrupted by the new feature, and provides a more streamlined way to define and manage
sidecars.&lt;/p>
&lt;h2 id="contributing-to-sig-node">Contributing to SIG Node&lt;/h2>
&lt;p>&lt;strong>Arpit:&lt;/strong> What is the best place for the new members and especially beginners to contribute?&lt;/p>
&lt;p>&lt;strong>M/G/S:&lt;/strong> New members and beginners can contribute to the Sidecar KEP (Kubernetes Enhancement
Proposal) by:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Raising awareness:&lt;/strong> Create content that highlights the benefits and use cases of sidecars. This
can educate others about the feature and encourage its adoption.&lt;/li>
&lt;li>&lt;strong>Providing feedback:&lt;/strong> Share your experiences with sidecars, both positive and negative. This
feedback can be used to improve the feature and make it more widely usable.&lt;/li>
&lt;li>&lt;strong>Sharing your use cases:&lt;/strong> If you are using sidecars in production,
share your experiences with others. This can help to demonstrate the
real-world value of the feature and encourage others to adopt it.&lt;/li>
&lt;li>&lt;strong>Improving the documentation:&lt;/strong> Help to clarify and expand the documentation for the
feature. This can make it easier for others to understand and use sidecars.&lt;/li>
&lt;/ul>
&lt;p>In addition to the Sidecar KEP, there are many other areas where SIG Node needs more contributors:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Test coverage:&lt;/strong> SIG Node is always looking for ways to improve the test coverage of Kubernetes
components.&lt;/li>
&lt;li>&lt;strong>CI maintenance:&lt;/strong> SIG Node maintains a suite of e2e tests ensuring Kubernetes components
function as intended across a variety of scenarios.&lt;/li>
&lt;/ul>
&lt;h1 id="conclusion">Conclusion&lt;/h1>
&lt;p>In conclusion, SIG Node stands as a cornerstone in Kubernetes' journey, ensuring its reliability and
adaptability in the ever-changing landscape of cloud-native computing. With dedicated members like
Matthias, Gunju, and Sergey leading the charge, SIG Node remains at the forefront of innovation,
driving Kubernetes towards new horizons.&lt;/p></description></item><item><title>10 Years of Kubernetes</title><link>https://kubernetes.io/blog/2024/06/06/10-years-of-kubernetes/</link><pubDate>Thu, 06 Jun 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/06/06/10-years-of-kubernetes/</guid><description>
&lt;p>&lt;img alt="KCSEU 2024 group photo" src="https://kubernetes.io/blog/2024/06/06/10-years-of-kubernetes/kcseu2024.jpg">&lt;/p>
&lt;p>Ten (10) years ago, on June 6th, 2014, the
&lt;a href="https://github.com/kubernetes/kubernetes/commit/2c4b3a562ce34cddc3f8218a2c4d11c7310e6d56">first commit&lt;/a>
of Kubernetes was pushed to GitHub. That first commit with 250 files and 47,501 lines of go, bash
and markdown kicked off the project we have today. Who could have predicted that 10 years later,
Kubernetes would grow to become one of the largest Open Source projects to date with over
&lt;a href="https://k8s.devstats.cncf.io/d/24/overall-project-statistics?orgId=1">88,000 contributors&lt;/a> from
more than &lt;a href="https://www.cncf.io/reports/kubernetes-project-journey-report/">8,000 companies&lt;/a>, across
44 countries.&lt;/p>
&lt;img src="kcscn2019.jpg" alt="KCSCN 2019" class="left" style="max-width: 20em; margin: 1em" >
&lt;p>This milestone isn't just for Kubernetes but for the Cloud Native ecosystem that blossomed from
it. There are close to &lt;a href="https://all.devstats.cncf.io/d/18/overall-project-statistics-table?orgId=1">200 projects&lt;/a>
within the CNCF itself, with contributions from
&lt;a href="https://all.devstats.cncf.io/d/18/overall-project-statistics-table?orgId=1">240,000+ individual contributors&lt;/a> and
thousands more in the greater ecosystem. Kubernetes would not be where it is today without them, the
&lt;a href="https://www.cncf.io/blog/2022/05/18/slashdata-cloud-native-continues-to-grow-with-more-than-7-million-developers-worldwide/">7M+ Developers&lt;/a>,
and the even larger user community that have all helped shape the ecosystem that it is today.&lt;/p>
&lt;h2 id="kubernetes-beginnings-a-converging-of-technologies">Kubernetes' beginnings - a converging of technologies&lt;/h2>
&lt;p>The ideas underlying Kubernetes started well before the first commit, or even the first prototype
(&lt;a href="https://kubernetes.io/blog/2018/07/20/the-history-of-kubernetes-the-community-behind-it/">which came about in 2013&lt;/a>).
In the early 2000s, Moore's Law was well in effect. Computing hardware was becoming more and more
powerful at an incredibly fast rate. Correspondingly, applications were growing more and more
complex. This combination of hardware commoditization and application complexity pointed to a need
to further abstract software from hardware, and solutions started to emerge.&lt;/p>
&lt;p>Like many companies at the time, Google was scaling rapidly, and its engineers were interested in
the idea of creating a form of isolation in the Linux kernel. Google engineer Rohit Seth described
the concept in an &lt;a href="https://lwn.net/Articles/199643/">email in 2006&lt;/a>:&lt;/p>
&lt;blockquote>
&lt;p>We use the term container to indicate a structure against which we track and charge utilization of
system resources like memory, tasks, etc. for a Workload.&lt;/p>
&lt;/blockquote>
&lt;img src="future.png" alt="The future of Linux containers" class="right" style="max-width: 20em; margin: 1em">
&lt;p>In March of 2013, a 5-minute lightning talk called
&lt;a href="https://youtu.be/wW9CAH9nSLs?si=VtK_VFQHymOT7BIB">&amp;quot;The future of Linux Containers,&amp;quot; presented by Solomon Hykes at PyCon&lt;/a>,
introduced an upcoming open source tool called &amp;quot;Docker&amp;quot; for creating and using Linux
Containers. Docker introduced a level of usability to Linux Containers that made them accessible to
more users than ever before, and the popularity of Docker, and thus of Linux Containers,
skyrocketed. With Docker making the abstraction of Linux Containers accessible to all, running
applications in much more portable and repeatable ways was suddenly possible, but the question of
scale remained.&lt;/p>
&lt;p>Google's Borg system for managing application orchestration at scale had adopted Linux containers as
they were developed in the mid-2000s. Since then, the company had also started working on a new
version of the system called &amp;quot;Omega.&amp;quot; Engineers at Google who were familiar with the Borg and Omega
systems saw the popularity of containerization driven by Docker. They recognized not only the need
for an open source container orchestration system but its &amp;quot;inevitability,&amp;quot; as described by Brendan
Burns in
&lt;a href="https://kubernetes.io/blog/2018/07/20/the-history-of-kubernetes-the-community-behind-it/">this blog post&lt;/a>.
That realization in the fall of 2013 inspired a small team to start working on a project that would
later become &lt;strong>Kubernetes&lt;/strong>. That team included Joe Beda, Brendan Burns, Craig McLuckie, Ville
Aikas, Tim Hockin, Dawn Chen, Brian Grant, and Daniel Smith.&lt;/p>
&lt;h2 id="a-decade-of-kubernetes">A decade of Kubernetes&lt;/h2>
&lt;img src="kubeconeu2017.jpg" alt="KubeCon EU 2017" class="left" style="max-width: 20em; margin: 1em">
&lt;p>Kubernetes' history begins with that historic commit on June 6th, 2014, and the subsequent
announcement of the project in a June 10th
&lt;a href="https://youtu.be/YrxnVKZeqK8?si=Q_wYBFn7dsS9H3k3">keynote by Google engineer Eric Brewer at DockerCon 2014&lt;/a>
(and its corresponding &lt;a href="https://cloudplatform.googleblog.com/2014/06/an-update-on-container-support-on-google-cloud-platform.html">Google blog&lt;/a>).&lt;/p>
&lt;p>Over the next year, a small community of
&lt;a href="https://k8s.devstats.cncf.io/d/9/companies-table?orgId=1&amp;var-period_name=Before%20joining%20CNCF&amp;var-metric=contributors">contributors, largely from Google and Red Hat&lt;/a>,
worked hard on the project, culminating in a &lt;a href="https://cloudplatform.googleblog.com/2015/07/Kubernetes-V1-Released.html">version 1.0 release on July 21st, 2015&lt;/a>.
Alongside 1.0, Google announced that Kubernetes would be donated to a newly formed branch of the
Linux Foundation called the
&lt;a href="https://www.cncf.io/announcements/2015/06/21/new-cloud-native-computing-foundation-to-drive-alignment-among-container-technologies/">Cloud Native Computing Foundation (CNCF)&lt;/a>.&lt;/p>
&lt;p>Despite reaching 1.0, the Kubernetes project was still very challenging to use and
understand. Kubernetes contributor Kelsey Hightower took special note of the project's shortcomings
in ease of use and on July 7, 2016, he pushed the
&lt;a href="https://github.com/kelseyhightower/kubernetes-the-hard-way/commit/9d7ace8b186f6ebd2e93e08265f3530ec2fba81c">first commit of his famed &amp;quot;Kubernetes the Hard Way&amp;quot; guide&lt;/a>.&lt;/p>
&lt;p>The project has changed enormously since its original 1.0 release; experiencing a number of big wins
such as
&lt;a href="https://kubernetes.io/blog/2019/09/18/kubernetes-1-16-release-announcement/">Custom Resource Definitions (CRD) going GA in 1.16&lt;/a>
or &lt;a href="https://kubernetes.io/blog/2021/12/08/dual-stack-networking-ga/">full dual stack support launching in 1.23&lt;/a> and
community &amp;quot;lessons learned&amp;quot; from the &lt;a href="https://kubernetes.io/blog/2021/07/14/upcoming-changes-in-kubernetes-1-22/">removal of widely used beta APIs in 1.22&lt;/a>
or the deprecation of &lt;a href="https://kubernetes.io/blog/2020/12/02/dockershim-faq/">Dockershim&lt;/a>.&lt;/p>
&lt;p>Some notable updates, milestones and events since 1.0 include:&lt;/p>
&lt;ul>
&lt;li>December 2016 - &lt;a href="https://kubernetes.io/blog/2016/12/kubernetes-1-5-supporting-production-workloads/">Kubernetes 1.5&lt;/a> introduces runtime pluggability with initial CRI support and alpha Windows node support. OpenAPI also appears for the first time, paving the way for clients to be able to discover extension APIs.
&lt;ul>
&lt;li>This release also introduced StatefulSets and PodDisruptionBudgets in Beta.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>April 2017 — &lt;a href="https://kubernetes.io/blog/2017/04/rbac-support-in-kubernetes/">Introduction of Role-Based Access Controls or RBAC&lt;/a>.&lt;/li>
&lt;li>June 2017 — In &lt;a href="https://kubernetes.io/blog/2017/06/kubernetes-1-7-security-hardening-stateful-application-extensibility-updates/">Kubernetes 1.7&lt;/a>, ThirdPartyResources or &amp;quot;TPRs&amp;quot; are replaced with CustomResourceDefinitions (CRDs).&lt;/li>
&lt;li>December 2017 — &lt;a href="https://kubernetes.io/blog/2017/12/kubernetes-19-workloads-expanded-ecosystem/">Kubernetes 1.9&lt;/a> sees the Workloads API becoming GA (Generally Available). The release blog states: &lt;em>&amp;quot;Deployment and ReplicaSet, two of the most commonly used objects in Kubernetes, are now stabilized after more than a year of real-world use and feedback.&amp;quot;&lt;/em>&lt;/li>
&lt;li>December 2018 — In 1.13, the Container Storage Interface (CSI) reaches GA, kubeadm tool for bootstrapping minimum viable clusters reaches GA, and CoreDNS becomes the default DNS server.&lt;/li>
&lt;li>September 2019 — &lt;a href="https://kubernetes.io/blog/2019/09/18/kubernetes-1-16-release-announcement/">Custom Resource Definitions go GA&lt;/a> in Kubernetes 1.16.&lt;/li>
&lt;li>August 2020 — &lt;a href="https://kubernetes.io/blog/2020/08/31/kubernetes-1-19-feature-one-year-support/">Kubernetes 1.19&lt;/a> increases the support window for releases to 1 year.&lt;/li>
&lt;li>December 2020 — &lt;a href="https://kubernetes.io/blog/2020/12/18/kubernetes-1.20-pod-impersonation-short-lived-volumes-in-csi/">Dockershim is deprecated&lt;/a> in 1.20&lt;/li>
&lt;li>April 2021 — the &lt;a href="https://kubernetes.io/blog/2021/07/20/new-kubernetes-release-cadence/#:~:text=On%20April%2023%2C%202021%2C%20the,Kubernetes%20community's%20contributors%20and%20maintainers.">Kubernetes release cadence changes&lt;/a> from 4 releases per year to 3 releases per year.&lt;/li>
&lt;li>July 2021 — Widely used beta APIs are &lt;a href="https://kubernetes.io/blog/2021/07/14/upcoming-changes-in-kubernetes-1-22/">removed&lt;/a> in Kubernetes 1.22.&lt;/li>
&lt;li>May 2022 — Kubernetes 1.24 sees &lt;a href="https://kubernetes.io/blog/2022/05/03/kubernetes-1-24-release-announcement/">beta APIs become disabled by default&lt;/a> to reduce upgrade conflicts and removal of &lt;a href="https://kubernetes.io/dockershim">Dockershim&lt;/a>, leading to &lt;a href="https://www.youtube.com/watch?v=a03Hh1kd6KE">widespread user confusion&lt;/a> (we've since &lt;a href="https://github.com/kubernetes/community/tree/master/communication/contributor-comms">improved our communication!&lt;/a>)&lt;/li>
&lt;li>December 2022 — In 1.26, there was a significant batch and &lt;a href="https://kubernetes.io/blog/2022/12/29/scalable-job-tracking-ga/">Job API overhaul&lt;/a> that paved the way for better support for AI /ML / batch workloads.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>PS:&lt;/strong> Curious to see how far the project has come for yourself? Check out this &lt;a href="https://github.com/spurin/kubernetes-v1.0-lab">tutorial for spinning up a Kubernetes 1.0 cluster&lt;/a> created by community members Carlos Santana, Amim Moises Salum Knabben, and James Spurin.&lt;/p>
&lt;hr>
&lt;p>Kubernetes offers more extension points than we can count. Originally designed to work with Docker
and only Docker, now you can plug in any container runtime that adheres to the CRI standard. There
are other similar interfaces: CSI for storage and CNI for networking. And that's far from all you
can do. In the last decade, whole new patterns have emerged, such as using&lt;/p>
&lt;p>&lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">Custom Resource Definitions&lt;/a>
(CRDs) to support third-party controllers - now a huge part of the Kubernetes ecosystem.&lt;/p>
&lt;p>The community building the project has also expanded immensely over the last decade. Using
&lt;a href="https://k8s.devstats.cncf.io/d/24/overall-project-statistics?orgId=1">DevStats&lt;/a>, we can see the
incredible volume of contribution over the last decade that has made Kubernetes the
&lt;a href="https://www.cncf.io/reports/kubernetes-project-journey-report/">second-largest open source project in the world&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>88,474&lt;/strong> contributors&lt;/li>
&lt;li>&lt;strong>15,121&lt;/strong> code committers&lt;/li>
&lt;li>&lt;strong>4,228,347&lt;/strong> contributions&lt;/li>
&lt;li>&lt;strong>158,530&lt;/strong> issues&lt;/li>
&lt;li>&lt;strong>311,787&lt;/strong> pull requests&lt;/li>
&lt;/ul>
&lt;h2 id="kubernetes-today">Kubernetes today&lt;/h2>
&lt;img src="welcome.jpg" alt="KubeCon NA 2023" class="left" style="max-width: 20em; margin: 1em">
&lt;p>Since its early days, the project has seen enormous growth in technical capability, usage, and
contribution. The project is still actively working to improve and better serve its users.&lt;/p>
&lt;p>In the upcoming 1.31 release, the project will celebrate the culmination of an important long-term
project: the removal of in-tree cloud provider code. In this
&lt;a href="https://kubernetes.io/blog/2024/05/20/completing-cloud-provider-migration/">largest migration in Kubernetes history&lt;/a>,
roughly 1.5 million lines of code have been removed, reducing the binary sizes of core components
by approximately 40%. In the project's early days, it was clear that extensibility would be key to
success. However, it wasn't always clear how that extensibility should be achieved. This migration
removes a variety of vendor-specific capabilities from the core Kubernetes code
base. Vendor-specific capabilities can now be better served by other pluggable extensibility
features or patterns, such as
&lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/">Custom Resource Definitions (CRDs)&lt;/a>
or API standards like the &lt;a href="https://gateway-api.sigs.k8s.io/">Gateway API&lt;/a>.
Kubernetes also faces new challenges in serving its vast user base, and the community is adapting
accordingly. One example of this is the migration of image hosting to the new, community-owned
registry.k8s.io. The egress bandwidth and costs of providing pre-compiled binary images for user
consumption have become immense. This new registry change enables the community to continue
providing these convenient images in more cost- and performance-efficient ways. Make sure you check
out the &lt;a href="https://kubernetes.io/blog/2022/11/28/registry-k8s-io-faster-cheaper-ga/">blog post&lt;/a> and
update any automation you have to use registry.k8s.io!&lt;/p>
&lt;h2 id="the-future-of-kubernetes">The future of Kubernetes&lt;/h2>
&lt;img src="lts.jpg" alt="" class="right" width="300px" style="max-width: 20em; margin: 1em">
&lt;p>A decade in, the future of Kubernetes still looks bright. The community is prioritizing changes that
both improve the user experiences, and enhance the sustainability of the project. The world of
application development continues to evolve, and Kubernetes is poised to change along with it.&lt;/p>
&lt;p>In 2024, the advent of AI changed a once-niche workload type into one of prominent
importance. Distributed computing and workload scheduling has always gone hand-in-hand with the
resource-intensive needs of Artificial Intelligence, Machine Learning, and High Performance
Computing workloads. Contributors are paying close attention to the needs of newly developed
workloads and how Kubernetes can best serve them. The new
&lt;a href="https://github.com/kubernetes/community/tree/master/wg-serving">Serving Working Group&lt;/a> is one
example of how the community is organizing to address these workloads' needs. It's likely that the
next few years will see improvements to Kubernetes' ability to manage various types of hardware, and
its ability to manage the scheduling of large batch-style workloads which are run across hardware in
chunks.&lt;/p>
&lt;p>The ecosystem around Kubernetes will continue to grow and evolve. In the future, initiatives to
maintain the sustainability of the project, like the migration of in-tree vendor code and the
registry change, will be ever more important.&lt;/p>
&lt;p>The next 10 years of Kubernetes will be guided by its users and the ecosystem, but most of all, by
the people who contribute to it. The community remains open to new contributors. You can find more
information about contributing in our New Contributor Course at
&lt;a href="https://k8s.dev/docs/onboarding">https://k8s.dev/docs/onboarding&lt;/a>.&lt;/p>
&lt;p>We look forward to building the future of Kubernetes with you!&lt;/p>
&lt;figure>
&lt;img src="https://kubernetes.io/blog/2024/06/06/10-years-of-kubernetes/kcsna2023.jpg"
alt="KCSNA 2023"/>
&lt;/figure></description></item><item><title>Completing the largest migration in Kubernetes history</title><link>https://kubernetes.io/blog/2024/05/20/completing-cloud-provider-migration/</link><pubDate>Mon, 20 May 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/05/20/completing-cloud-provider-migration/</guid><description>
&lt;p>Since as early as Kubernetes v1.7, the Kubernetes project has pursued the ambitious goal of removing built-in cloud provider integrations (&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-cloud-provider/2395-removing-in-tree-cloud-providers/README.md">KEP-2395&lt;/a>).
While these integrations were instrumental in Kubernetes' early development and growth, their removal was driven by two key factors:
the growing complexity of maintaining native support for every cloud provider across millions of lines of Go code, and the desire to establish
Kubernetes as a truly vendor-neutral platform.&lt;/p>
&lt;p>After many releases, we're thrilled to announce that all cloud provider integrations have been successfully migrated from the core Kubernetes repository to external plugins.
In addition to achieving our initial objectives, we've also significantly streamlined Kubernetes by removing roughly 1.5 million lines of code and reducing the binary sizes of core components by approximately 40%.&lt;/p>
&lt;p>This migration was a complex and long-running effort due to the numerous impacted components and the critical code paths that relied on the built-in integrations for the
five initial cloud providers: Google Cloud, AWS, Azure, OpenStack, and vSphere. To successfully complete this migration, we had to build four new subsystems from the ground up:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Cloud controller manager&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-cloud-provider/2392-cloud-controller-manager/README.md">KEP-2392&lt;/a>)&lt;/li>
&lt;li>&lt;strong>API server network proxy&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/1281-network-proxy">KEP-1281&lt;/a>)&lt;/li>
&lt;li>&lt;strong>kubelet credential provider plugins&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2133-kubelet-credential-providers">KEP-2133&lt;/a>)&lt;/li>
&lt;li>&lt;strong>Storage migration to use &lt;a href="https://github.com/container-storage-interface/spec?tab=readme-ov-file#container-storage-interface-csi-specification-">CSI&lt;/a>&lt;/strong> (&lt;a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/625-csi-migration/README.md">KEP-625&lt;/a>)&lt;/li>
&lt;/ol>
&lt;p>Each subsystem was critical to achieve full feature parity with built-in capabilities and required several releases to bring each subsystem to GA-level maturity with a safe and
reliable migration path. More on each subsystem below.&lt;/p>
&lt;h3 id="cloud-controller-manager">Cloud controller manager&lt;/h3>
&lt;p>The cloud controller manager was the first external component introduced in this effort, replacing functionality within the kube-controller-manager and kubelet that directly interacted with cloud APIs.
This essential component is responsible for initializing nodes by applying metadata labels that indicate the cloud region and zone a Node is running on, as well as IP addresses that are only known to the cloud provider.
Additionally, it runs the service controller, which is responsible for provisioning cloud load balancers for Services of type LoadBalancer.&lt;/p>
&lt;p>&lt;img alt="Kubernetes components" src="https://kubernetes.io/images/docs/components-of-kubernetes.svg">&lt;/p>
&lt;p>To learn more, read &lt;a href="https://kubernetes.io/docs/concepts/architecture/cloud-controller/">Cloud Controller Manager&lt;/a> in the Kubernetes documentation.&lt;/p>
&lt;h3 id="api-server-network-proxy">API server network proxy&lt;/h3>
&lt;p>The API Server Network Proxy project, initiated in 2018 in collaboration with SIG API Machinery, aimed to replace the SSH tunneler functionality within the kube-apiserver.
This tunneler had been used to securely proxy traffic between the Kubernetes control plane and nodes, but it heavily relied on provider-specific implementation details embedded in the kube-apiserver to establish these SSH tunnels.&lt;/p>
&lt;p>Now, the API Server Network Proxy is a GA-level extension point within the kube-apiserver. It offers a generic proxying mechanism that can route traffic from the API server to nodes through a secure proxy,
eliminating the need for the API server to have any knowledge of the specific cloud provider it is running on. This project also introduced the Konnectivity project, which has seen growing adoption in production environments.&lt;/p>
&lt;p>You can learn more about the API Server Network Proxy from its &lt;a href="https://github.com/kubernetes-sigs/apiserver-network-proxy#readme">README&lt;/a>.&lt;/p>
&lt;h3 id="credential-provider-plugins-for-the-kubelet">Credential provider plugins for the kubelet&lt;/h3>
&lt;p>The Kubelet credential provider plugin was developed to replace the kubelet's built-in functionality for dynamically fetching credentials for image registries hosted on Google Cloud, AWS, or Azure.
The legacy capability was convenient as it allowed the kubelet to seamlessly retrieve short-lived tokens for pulling images from GCR, ECR, or ACR. However, like other areas of Kubernetes, supporting
this required the kubelet to have specific knowledge of different cloud environments and APIs.&lt;/p>
&lt;p>Introduced in 2019, the credential provider plugin mechanism offers a generic extension point for the kubelet to execute plugin binaries that dynamically provide credentials for images hosted on various clouds.
This extensibility expands the kubelet's capabilities to fetch short-lived tokens beyond the initial three cloud providers.&lt;/p>
&lt;p>To learn more, read &lt;a href="https://kubernetes.io/docs/concepts/containers/images/#kubelet-credential-provider">kubelet credential provider for authenticated image pulls&lt;/a>.&lt;/p>
&lt;h3 id="storage-plugin-migration-from-in-tree-to-csi">Storage plugin migration from in-tree to CSI&lt;/h3>
&lt;p>The Container Storage Interface (CSI) is a control plane standard for managing block and file storage systems in Kubernetes and other container orchestrators that went GA in 1.13.
It was designed to replace the in-tree volume plugins built directly into Kubernetes with drivers that can run as Pods within the Kubernetes cluster.
These drivers communicate with kube-controller-manager storage controllers via the Kubernetes API, and with kubelet through a local gRPC endpoint.
Now there are over 100 CSI drivers available across all major cloud and storage vendors, making stateful workloads in Kubernetes a reality.&lt;/p>
&lt;p>However, a major challenge remained on how to handle all the existing users of in-tree volume APIs. To retain API backwards compatibility,
we built an API translation layer into our controllers that will convert the in-tree volume API into the equivalent CSI API. This allowed us to redirect all storage operations to the CSI driver,
paving the way for us to remove the code for the built-in volume plugins without removing the API.&lt;/p>
&lt;p>You can learn more about In-tree Storage migration in &lt;a href="https://kubernetes.io/blog/2019/12/09/kubernetes-1-17-feature-csi-migration-beta/">Kubernetes In-Tree to CSI Volume Migration Moves to Beta&lt;/a>.&lt;/p>
&lt;h2 id="what-s-next">What's next?&lt;/h2>
&lt;p>This migration has been the primary focus for SIG Cloud Provider over the past few years. With this significant milestone achieved, we will be shifting our efforts towards exploring new
and innovative ways for Kubernetes to better integrate with cloud providers, leveraging the external subsystems we've built over the years. This includes making Kubernetes smarter in
hybrid environments where nodes in the cluster can run on both public and private clouds, as well as providing better tools and frameworks for developers of external providers to simplify and streamline their integration efforts.&lt;/p>
&lt;p>With all the new features, tools, and frameworks being planned, SIG Cloud Provider is not forgetting about the other side of the equation: testing. Another area of focus for the SIG's future activities is the improvement of
cloud controller testing to include more providers. The ultimate goal of this effort being to create a testing framework that will include as many providers as possible so that we give the Kubernetes community the highest
levels of confidence about their Kubernetes environments.&lt;/p>
&lt;p>If you're using a version of Kubernetes older than v1.29 and haven't migrated to an external cloud provider yet, we recommend checking out our previous blog post &lt;a href="https://kubernetes.io/blog/2023/12/14/cloud-provider-integration-changes/">Kubernetes 1.29: Cloud Provider Integrations Are Now Separate Components&lt;/a>.It provides detailed information on the changes we've made and offers guidance on how to migrate to an external provider. Starting in v1.31, in-tree cloud providers will be permanently disabled and removed from core Kubernetes components.&lt;/p>
&lt;p>If you’re interested in contributing, come join our &lt;a href="https://github.com/kubernetes/community/tree/master/sig-cloud-provider#meetings">bi-weekly SIG meetings&lt;/a>!&lt;/p></description></item><item><title>Gateway API v1.1: Service mesh, GRPCRoute, and a whole lot more</title><link>https://kubernetes.io/blog/2024/05/09/gateway-api-v1-1/</link><pubDate>Thu, 09 May 2024 09:00:00 -0800</pubDate><guid>https://kubernetes.io/blog/2024/05/09/gateway-api-v1-1/</guid><description>
&lt;p>&lt;img alt="Gateway API logo" src="https://kubernetes.io/blog/2024/05/09/gateway-api-v1-1/gateway-api-logo.svg">&lt;/p>
&lt;p>Following the GA release of Gateway API last October, Kubernetes
SIG Network is pleased to announce the v1.1 release of
&lt;a href="https://gateway-api.sigs.k8s.io/">Gateway API&lt;/a>. In this release, several features are graduating to
&lt;em>Standard Channel&lt;/em> (GA), notably including support for service mesh and
GRPCRoute. We're also introducing some new experimental features, including
session persistence and client certificate verification.&lt;/p>
&lt;h2 id="what-s-new">What's new&lt;/h2>
&lt;h3 id="graduation-to-standard">Graduation to Standard&lt;/h3>
&lt;p>This release includes the graduation to Standard of four eagerly awaited features.
This means they are no longer experimental concepts; inclusion in the Standard
release channel denotes a high level of confidence in the API surface and
provides guarantees of backward compatibility. Of course, as with any other
Kubernetes API, Standard Channel features can continue to evolve with
backward-compatible additions over time, and we certainly expect further
refinements and improvements to these new features in the future.
For more information on how all of this works, refer to the
&lt;a href="https://gateway-api.sigs.k8s.io/concepts/versioning/">Gateway API Versioning Policy&lt;/a>.&lt;/p>
&lt;h4 id="service-mesh-support-https-gateway-api-sigs-k8s-io-mesh">&lt;a href="https://gateway-api.sigs.k8s.io/mesh/">Service Mesh Support&lt;/a>&lt;/h4>
&lt;p>Service mesh support in Gateway API allows service mesh users to use the same
API to manage ingress traffic and mesh traffic, reusing the same policy and
routing interfaces. In Gateway API v1.1, routes (such as HTTPRoute) can now have
a Service as a &lt;code>parentRef&lt;/code>, to control how traffic to specific services behave.
For more information, read the
&lt;a href="https://gateway-api.sigs.k8s.io/mesh/">Gateway API service mesh documentation&lt;/a>
or see the
&lt;a href="https://gateway-api.sigs.k8s.io/implementations/#service-mesh-implementation-status">list of Gateway API implementations&lt;/a>.&lt;/p>
&lt;p>As an example, one could do a canary deployment of a workload deep in an
application's call graph with an HTTPRoute as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gateway.networking.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>HTTPRoute&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color-canary&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>faces&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">parentRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Service&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">rules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">backendRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">weight&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">50&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>color2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">80&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">weight&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">50&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This would split traffic sent to the &lt;code>color&lt;/code> Service in the &lt;code>faces&lt;/code> namespace
50/50 between the original &lt;code>color&lt;/code> Service and the &lt;code>color2&lt;/code> Service, using a
portable configuration that's easy to move from one mesh to another.&lt;/p>
&lt;h4 id="grpcroute-https-gateway-api-sigs-k8s-io-guides-grpc-routing">&lt;a href="https://gateway-api.sigs.k8s.io/guides/grpc-routing/">GRPCRoute&lt;/a>&lt;/h4>
&lt;p>If you are already using the experimental version of GRPCRoute, we recommend holding
off on upgrading to the standard channel version of GRPCRoute until the
controllers you're using have been updated to support GRPCRoute v1. Until then,
it is safe to upgrade to the experimental channel version of GRPCRoute in v1.1
that includes both v1alpha2 and v1 API versions.&lt;/p>
&lt;h4 id="parentreference-port-https-gateway-api-sigs-k8s-io-reference-spec-gateway-networking-k8s-io-2fv1-parentreference">&lt;a href="https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1.ParentReference">ParentReference Port&lt;/a>&lt;/h4>
&lt;p>The &lt;code>port&lt;/code> field was added to ParentReference, allowing you to attach resources
to Gateway Listeners, Services, or other parent resources
(depending on the implementation). Binding to a port also allows you to attach
to multiple Listeners at once.&lt;/p>
&lt;p>For example, you can attach an HTTPRoute to one or more specific Listeners of a
Gateway as specified by the Listener &lt;code>port&lt;/code>, instead of the Listener &lt;code>name&lt;/code> field.&lt;/p>
&lt;p>For more information, see
&lt;a href="https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways">Attaching to Gateways&lt;/a>.&lt;/p>
&lt;h4 id="conformance-profiles-and-reports-https-gateway-api-sigs-k8s-io-concepts-conformance-conformance-profiles">&lt;a href="https://gateway-api.sigs.k8s.io/concepts/conformance/#conformance-profiles">Conformance Profiles and Reports&lt;/a>&lt;/h4>
&lt;p>The conformance report API has been expanded with the &lt;code>mode&lt;/code> field (intended to
specify the working mode of the implementation), and the &lt;code>gatewayAPIChannel&lt;/code>
(standard or experimental). The &lt;code>gatewayAPIVersion&lt;/code> and &lt;code>gatewayAPIChannel&lt;/code> are
now filled in automatically by the suite machinery, along with a brief
description of the testing outcome. The Reports have been reorganized in a more
structured way, and the implementations can now add information on how the tests
have been run and provide reproduction steps.&lt;/p>
&lt;h3 id="new-additions-to-experimental-channel">New additions to Experimental channel&lt;/h3>
&lt;h4 id="gateway-client-certificate-verification-https-gateway-api-sigs-k8s-io-geps-gep-91">&lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-91/">Gateway Client Certificate Verification&lt;/a>&lt;/h4>
&lt;p>Gateways can now configure client cert verification for each Gateway Listener by
introducing a new &lt;code>frontendValidation&lt;/code> field within &lt;code>tls&lt;/code>. This field
supports configuring a list of CA Certificates that can be used as a trust
anchor to validate the certificates presented by the client.&lt;/p>
&lt;p>The following example shows how the CACertificate stored in
the &lt;code>foo-example-com-ca-cert&lt;/code> ConfigMap can be used to validate the certificates
presented by clients connecting to the &lt;code>foo-https&lt;/code> Gateway Listener.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gateway.networking.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Gateway&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>client-validation-basic&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">gatewayClassName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>acme-lb&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">listeners&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>foo-https&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">protocol&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>HTTPS&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">port&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#666">443&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">hostname&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>foo.example.com&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">tls&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">certificateRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Secret&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>foo-example-com-cert&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">frontendValidation&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">caCertificateRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ConfigMap&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>foo-example-com-ca-cert&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="session-persistence-and-backendlbpolicy-https-gateway-api-sigs-k8s-io-geps-gep-1619">&lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-1619/">Session Persistence and BackendLBPolicy&lt;/a>&lt;/h4>
&lt;p>&lt;a href="https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1.SessionPersistence">Session Persistence&lt;/a>
is being introduced to Gateway API via a new policy
(&lt;a href="https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1alpha2.BackendLBPolicy">BackendLBPolicy&lt;/a>)
for Service-level configuration and as fields within HTTPRoute
and GRPCRoute for route-level configuration. The BackendLBPolicy and route-level
APIs provide the same session persistence configuration, including session
timeouts, session name, session type, and cookie lifetime type.&lt;/p>
&lt;p>Below is an example configuration of &lt;code>BackendLBPolicy&lt;/code> that enables cookie-based
session persistence for the &lt;code>foo&lt;/code> service. It sets the session name to
&lt;code>foo-session&lt;/code>, defines absolute and idle timeouts, and configures the cookie to
be a session cookie:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>gateway.networking.k8s.io/v1alpha2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>BackendLBPolicy&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>lb-policy&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>foo-ns&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">targetRefs&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>core&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>service&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>foo&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">sessionPersistence&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">sessionName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>foo-session&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">absoluteTimeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>1h&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">idleTimeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>30m&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Cookie&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">cookieConfig&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">lifetimeType&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Session&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="everything-else">Everything else&lt;/h3>
&lt;h4 id="tls-terminology-clarifications-https-gateway-api-sigs-k8s-io-geps-gep-2907">&lt;a href="https://gateway-api.sigs.k8s.io/geps/gep-2907/">TLS Terminology Clarifications&lt;/a>&lt;/h4>
&lt;p>As part of a broader goal of making our TLS terminology more consistent
throughout the API, we've introduced some breaking changes to BackendTLSPolicy.
This has resulted in a new API version (v1alpha3) and will require any existing
implementations of this policy to properly handle the version upgrade, e.g.
by backing up data and uninstalling the v1alpha2 version before installing this
newer version.&lt;/p>
&lt;p>Any references to v1alpha2 BackendTLSPolicy fields will need to be updated to
v1alpha3. Specific changes to fields include:&lt;/p>
&lt;ul>
&lt;li>&lt;code>targetRef&lt;/code> becomes &lt;code>targetRefs&lt;/code> to allow a BackendTLSPolicy to attach to
multiple targets&lt;/li>
&lt;li>&lt;code>tls&lt;/code> becomes &lt;code>validation&lt;/code>&lt;/li>
&lt;li>&lt;code>tls.caCertRefs&lt;/code> becomes &lt;code>validation.caCertificateRefs&lt;/code>&lt;/li>
&lt;li>&lt;code>tls.wellKnownCACerts&lt;/code> becomes &lt;code>validation.wellKnownCACertificates&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>For a full list of the changes included in this release, please refer to the
&lt;a href="https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.1.0">v1.1.0 release notes&lt;/a>.&lt;/p>
&lt;h2 id="gateway-api-background">Gateway API background&lt;/h2>
&lt;p>The idea of Gateway API was initially &lt;a href="https://youtu.be/Ne9UJL6irXY?si=wgtC9w8PMB5ZHil2">proposed&lt;/a>
at the 2019 KubeCon San Diego as the next generation
of Ingress API. Since then, an incredible community has formed to develop what
has likely become the
&lt;a href="https://www.youtube.com/watch?v=V3Vu_FWb4l4">most collaborative API in Kubernetes history&lt;/a>.
Over 200 people have contributed to this API so far, and that number continues to grow.&lt;/p>
&lt;p>The maintainers would like to thank &lt;em>everyone&lt;/em> who's contributed to Gateway API, whether in the
form of commits to the repo, discussion, ideas, or general support. We literally
couldn't have gotten this far without the support of this dedicated and active
community.&lt;/p>
&lt;h2 id="try-it-out">Try it out&lt;/h2>
&lt;p>Unlike other Kubernetes APIs, you don't need to upgrade to the latest version of
Kubernetes to get the latest version of Gateway API. As long as you're running
Kubernetes 1.26 or later, you'll be able to get up and running with this
version of Gateway API.&lt;/p>
&lt;p>To try out the API, follow our &lt;a href="https://gateway-api.sigs.k8s.io/guides/">Getting Started Guide&lt;/a>.&lt;/p>
&lt;h2 id="get-involved">Get involved&lt;/h2>
&lt;p>There are lots of opportunities to get involved and help define the future of
Kubernetes routing APIs for both ingress and service mesh.&lt;/p>
&lt;ul>
&lt;li>Check out the &lt;a href="https://gateway-api.sigs.k8s.io/guides">user guides&lt;/a> to see what use-cases can be addressed.&lt;/li>
&lt;li>Try out one of the &lt;a href="https://gateway-api.sigs.k8s.io/implementations/">existing Gateway controllers&lt;/a>.&lt;/li>
&lt;li>Or &lt;a href="https://gateway-api.sigs.k8s.io/contributing/">join us in the community&lt;/a>
and help us build the future of Gateway API together!&lt;/li>
&lt;/ul>
&lt;h2 id="related-kubernetes-blog-articles">Related Kubernetes blog articles&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/11/28/gateway-api-ga/">New Experimental Features in Gateway API v1.0&lt;/a>
11/2023&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/10/31/gateway-api-ga/">Gateway API v1.0: GA Release&lt;/a>
10/2023&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/10/25/introducing-ingress2gateway/">Introducing ingress2gateway; Simplifying Upgrades to Gateway API&lt;/a>
10/2023&lt;/li>
&lt;li>&lt;a href="https://kubernetes.io/blog/2023/08/29/gateway-api-v0-8/">Gateway API v0.8.0: Introducing Service Mesh Support&lt;/a>
08/2023&lt;/li>
&lt;/ul></description></item><item><title>Container Runtime Interface streaming explained</title><link>https://kubernetes.io/blog/2024/05/01/cri-streaming-explained/</link><pubDate>Wed, 01 May 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/05/01/cri-streaming-explained/</guid><description>
&lt;p>The Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/architecture/cri/">Container Runtime Interface (CRI)&lt;/a>
acts as the main connection between the &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/">kubelet&lt;/a>
and the &lt;a href="https://kubernetes.io/docs/setup/production-environment/container-runtimes/">Container Runtime&lt;/a>.
Those runtimes have to provide a &lt;a href="https://grpc.io">gRPC&lt;/a> server which has to
fulfill a Kubernetes defined &lt;a href="https://protobuf.dev">Protocol Buffer&lt;/a> interface.
&lt;a href="https://github.com/kubernetes/cri-api/blob/63929b3/pkg/apis/runtime/v1/api.proto">This API definition&lt;/a>
evolves over time, for example when contributors add new features or fields are
going to become deprecated.&lt;/p>
&lt;p>In this blog post, I'd like to dive into the functionality and history of three
extraordinary Remote Procedure Calls (RPCs), which are truly outstanding in
terms of how they work: &lt;code>Exec&lt;/code>, &lt;code>Attach&lt;/code> and &lt;code>PortForward&lt;/code>.&lt;/p>
&lt;p>&lt;strong>Exec&lt;/strong> can be used to run dedicated commands within the container and stream
the output to a client like &lt;a href="https://kubernetes.io/docs/reference/kubectl/">kubectl&lt;/a> or
&lt;a href="https://kubernetes.io/docs/tasks/debug/debug-cluster/crictl/">crictl&lt;/a>. It also allows interaction with
that process using standard input (stdin), for example if users want to run a
new shell instance within an existing workload.&lt;/p>
&lt;p>&lt;strong>Attach&lt;/strong> streams the output of the currently running process via &lt;a href="https://en.wikipedia.org/wiki/Standard_streams">standard I/O&lt;/a>
from the container to the client and also allows interaction with them. This is
particularly useful if users want to see what is going on in the container and
be able to interact with the process.&lt;/p>
&lt;p>&lt;strong>PortForward&lt;/strong> can be utilized to forward a port from the host to the container
to be able to interact with it using third party network tools. This allows it
to bypass &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/">Kubernetes services&lt;/a>
for a certain workload and interact with its network interface.&lt;/p>
&lt;h2 id="what-is-so-special-about-them">What is so special about them?&lt;/h2>
&lt;p>All RPCs of the CRI either use the &lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/#unary-rpc">gRPC unary calls&lt;/a>
for communication or the &lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/#server-streaming-rpc">server side streaming&lt;/a>
feature (only &lt;code>GetContainerEvents&lt;/code> right now). This means that mainly all RPCs
retrieve a single client request and have to return a single server response.
The same applies to &lt;code>Exec&lt;/code>, &lt;code>Attach&lt;/code>, and &lt;code>PortForward&lt;/code>, where their &lt;a href="https://github.com/kubernetes/cri-api/blob/63929b3/pkg/apis/runtime/v1/api.proto#L94-L99">protocol definition&lt;/a>
looks like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">// Exec prepares a streaming endpoint to execute a command in the container.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>&lt;span style="color:#a2f;font-weight:bold">rpc&lt;/span> Exec(ExecRequest) &lt;span style="color:#a2f;font-weight:bold">returns&lt;/span> (ExecResponse) {}&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">// Attach prepares a streaming endpoint to attach to a running container.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>&lt;span style="color:#a2f;font-weight:bold">rpc&lt;/span> Attach(AttachRequest) &lt;span style="color:#a2f;font-weight:bold">returns&lt;/span> (AttachResponse) {}&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">// PortForward prepares a streaming endpoint to forward ports from a PodSandbox.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>&lt;span style="color:#a2f;font-weight:bold">rpc&lt;/span> PortForward(PortForwardRequest) &lt;span style="color:#a2f;font-weight:bold">returns&lt;/span> (PortForwardResponse) {}&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The requests carry everything required to allow the server to do the work,
for example, the &lt;code>ContainerId&lt;/code> or command (&lt;code>Cmd&lt;/code>) to be run in case of &lt;code>Exec&lt;/code>.
More interestingly, all of their responses only contain a &lt;code>url&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">message&lt;/span> &lt;span style="color:#00f">ExecResponse&lt;/span> {&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span> &lt;span style="color:#080;font-style:italic">// Fully qualified URL of the exec streaming server.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> &lt;span style="color:#0b0;font-weight:bold">string&lt;/span> url &lt;span style="color:#666">=&lt;/span> &lt;span style="color:#666">1&lt;/span>;&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>}&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">message&lt;/span> &lt;span style="color:#00f">AttachResponse&lt;/span> {&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span> &lt;span style="color:#080;font-style:italic">// Fully qualified URL of the attach streaming server.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> &lt;span style="color:#0b0;font-weight:bold">string&lt;/span> url &lt;span style="color:#666">=&lt;/span> &lt;span style="color:#666">1&lt;/span>;&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>}&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-protobuf" data-lang="protobuf">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">message&lt;/span> &lt;span style="color:#00f">PortForwardResponse&lt;/span> {&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span> &lt;span style="color:#080;font-style:italic">// Fully qualified URL of the port-forward streaming server.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> &lt;span style="color:#0b0;font-weight:bold">string&lt;/span> url &lt;span style="color:#666">=&lt;/span> &lt;span style="color:#666">1&lt;/span>;&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="">&lt;/span>}&lt;span style="">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Why is it implemented like that? Well, &lt;a href="https://docs.google.com/document/d/1MreuHzNvkBW6q7o_zehm1CBOBof3shbtMTGtUpjpRmY">the original design document&lt;/a>
for those RPCs even predates &lt;a href="https://github.com/kubernetes/enhancements">Kubernetes Enhancements Proposals (KEPs)&lt;/a>
and was originally outlined back in 2016. The kubelet had a native
implementation for &lt;code>Exec&lt;/code>, &lt;code>Attach&lt;/code>, and &lt;code>PortForward&lt;/code> before the
initiative to bring the functionality to the CRI started. Before that,
everything was bound to &lt;a href="https://www.docker.com">Docker&lt;/a> or the later abandoned
container runtime &lt;a href="https://github.com/rkt/rkt">rkt&lt;/a>.&lt;/p>
&lt;p>The CRI related design document also elaborates on the option to use native RPC
streaming for exec, attach, and port forward. The downsides outweighed this
approach: the kubelet would still create a network bottleneck and future
runtimes would not be free in choosing the server implementation details. Also,
another option that the Kubelet implements a portable, runtime-agnostic solution
has been abandoned over the final one, because this would mean another project
to maintain which nevertheless would be runtime dependent.&lt;/p>
&lt;p>This means, that the basic flow for &lt;code>Exec&lt;/code>, &lt;code>Attach&lt;/code> and &lt;code>PortForward&lt;/code>
was proposed to look like this:&lt;/p>
&lt;figure class="diagram-large ">
&lt;img src="https://kubernetes.io/blog/2024/05/01/cri-streaming-explained/flow.svg"
alt="CRI Streaming flow"/>
&lt;/figure>
&lt;p>Clients like crictl or the kubelet (via kubectl) request a new exec, attach or
port forward session from the runtime using the gRPC interface. The runtime
implements a streaming server that also manages the active sessions. This
streaming server provides an HTTP endpoint for the client to connect to. The
client upgrades the connection to use the &lt;a href="https://en.wikipedia.org/wiki/SPDY">SPDY&lt;/a>
streaming protocol or (in the future) to a &lt;a href="https://en.wikipedia.org/wiki/WebSocket">WebSocket&lt;/a>
connection and starts to stream the data back and forth.&lt;/p>
&lt;p>This implementation allows runtimes to have the flexibility to implement
&lt;code>Exec&lt;/code>, &lt;code>Attach&lt;/code> and &lt;code>PortForward&lt;/code> the way they want, and also allows a
simple test path. Runtimes can change the underlying implementation to support
any kind of feature without having a need to modify the CRI at all.&lt;/p>
&lt;p>Many smaller enhancements to this overall approach have been merged into
Kubernetes in the past years, but the general pattern has always stayed the
same. The kubelet source code transformed into &lt;a href="https://github.com/kubernetes/kubernetes/blob/db9fcfe/staging/src/k8s.io/kubelet/pkg/cri/streaming">a reusable library&lt;/a>,
which is nowadays usable from container runtimes to implement the basic
streaming capability.&lt;/p>
&lt;h2 id="how-does-the-streaming-actually-work">How does the streaming actually work?&lt;/h2>
&lt;p>At a first glance, it looks like all three RPCs work the same way, but that's
not the case. It's possible to group the functionality of &lt;strong>Exec&lt;/strong> and
&lt;strong>Attach&lt;/strong>, while &lt;strong>PortForward&lt;/strong> follows a distinct internal protocol
definition.&lt;/p>
&lt;h3 id="exec-and-attach">Exec and Attach&lt;/h3>
&lt;p>Kubernetes defines &lt;strong>Exec&lt;/strong> and &lt;strong>Attach&lt;/strong> as &lt;em>remote commands&lt;/em>, where its
protocol definition exists in &lt;a href="https://github.com/kubernetes/kubernetes/blob/9791f0d/staging/src/k8s.io/apimachinery/pkg/util/remotecommand/constants.go#L28-L52">five different versions&lt;/a>:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>#&lt;/th>
&lt;th>Version&lt;/th>
&lt;th>Note&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>&lt;code>channel.k8s.io&lt;/code>&lt;/td>
&lt;td>Initial (unversioned) SPDY sub protocol (&lt;a href="https://issues.k8s.io/13394">#13394&lt;/a>, &lt;a href="https://issues.k8s.io/13395">#13395&lt;/a>)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>&lt;code>v2.channel.k8s.io&lt;/code>&lt;/td>
&lt;td>Resolves the issues present in the first version (&lt;a href="https://github.com/kubernetes/kubernetes/pull/15961">#15961&lt;/a>)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>&lt;code>v3.channel.k8s.io&lt;/code>&lt;/td>
&lt;td>Adds support for resizing container terminals (&lt;a href="https://github.com/kubernetes/kubernetes/pull/25273">#25273&lt;/a>)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4&lt;/td>
&lt;td>&lt;code>v4.channel.k8s.io&lt;/code>&lt;/td>
&lt;td>Adds support for exit codes using JSON errors (&lt;a href="https://github.com/kubernetes/kubernetes/pull/26541">#26541&lt;/a>)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>&lt;code>v5.channel.k8s.io&lt;/code>&lt;/td>
&lt;td>Adds support for a CLOSE signal (&lt;a href="https://github.com/kubernetes/kubernetes/pull/119157">#119157&lt;/a>)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>On top of that, there is an overall effort to replace the SPDY transport
protocol using WebSockets as part &lt;a href="https://github.com/kubernetes/enhancements/issues/4006">KEP #4006&lt;/a>.
Runtimes have to satisfy those protocols over their life cycle to stay up to
date with the Kubernetes implementation.&lt;/p>
&lt;p>Let's assume that a client uses the latest (&lt;code>v5&lt;/code>) version of the protocol as
well as communicating over WebSockets. In that case, the general flow would be:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The client requests an URL endpoint for &lt;strong>Exec&lt;/strong> or &lt;strong>Attach&lt;/strong> using the CRI.&lt;/p>
&lt;ul>
&lt;li>The server (runtime) validates the request, inserts it into a connection
tracking cache, and provides the HTTP endpoint URL for that request.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>The client connects to that URL, upgrades the connection to establish
a WebSocket, and starts to stream data.&lt;/p>
&lt;ul>
&lt;li>In the case of &lt;strong>Attach&lt;/strong>, the server has to stream the main container process
data to the client.&lt;/li>
&lt;li>In the case of &lt;strong>Exec&lt;/strong>, the server has to create the subprocess command within
the container and then streams the output to the client.&lt;/li>
&lt;/ul>
&lt;p>If stdin is required, then the server needs to listen for that as well and
redirect it to the corresponding process.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Interpreting data for the defined protocol is fairly simple: The first
byte of every input and output packet &lt;a href="https://github.com/kubernetes/kubernetes/blob/9791f0d/staging/src/k8s.io/apimachinery/pkg/util/remotecommand/constants.go#L57-L64">defines&lt;/a>
the actual stream:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>First Byte&lt;/th>
&lt;th>Type&lt;/th>
&lt;th>Description&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>0&lt;/code>&lt;/td>
&lt;td>standard input&lt;/td>
&lt;td>Data streamed from stdin&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>1&lt;/code>&lt;/td>
&lt;td>standard output&lt;/td>
&lt;td>Data streamed to stdout&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>2&lt;/code>&lt;/td>
&lt;td>standard error&lt;/td>
&lt;td>Data streamed to stderr&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>3&lt;/code>&lt;/td>
&lt;td>stream error&lt;/td>
&lt;td>A streaming error occurred&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>4&lt;/code>&lt;/td>
&lt;td>stream resize&lt;/td>
&lt;td>A terminal resize event&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>255&lt;/code>&lt;/td>
&lt;td>stream close&lt;/td>
&lt;td>Stream should be closed (for WebSockets)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>How should runtimes now implement the streaming server methods for &lt;strong>Exec&lt;/strong> and
&lt;strong>Attach&lt;/strong> by using the provided kubelet library? The key is that the streaming
server implementation in the kubelet &lt;a href="https://github.com/kubernetes/kubernetes/blob/db9fcfe/staging/src/k8s.io/kubelet/pkg/cri/streaming/server.go#L63-L68">outlines an interface&lt;/a>
called &lt;code>Runtime&lt;/code> which has to be fulfilled by the actual container runtime if it
wants to use that library:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">// Runtime is the interface to execute the commands and provide the streams.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>&lt;span style="color:#a2f;font-weight:bold">type&lt;/span> Runtime &lt;span style="color:#a2f;font-weight:bold">interface&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a000">Exec&lt;/span>(ctx context.Context, containerID &lt;span style="color:#0b0;font-weight:bold">string&lt;/span>, cmd []&lt;span style="color:#0b0;font-weight:bold">string&lt;/span>, in io.Reader, out, err io.WriteCloser, tty &lt;span style="color:#0b0;font-weight:bold">bool&lt;/span>, resize &lt;span style="color:#666">&amp;lt;-&lt;/span>&lt;span style="color:#a2f;font-weight:bold">chan&lt;/span> remotecommand.TerminalSize) &lt;span style="color:#0b0;font-weight:bold">error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a000">Attach&lt;/span>(ctx context.Context, containerID &lt;span style="color:#0b0;font-weight:bold">string&lt;/span>, in io.Reader, out, err io.WriteCloser, tty &lt;span style="color:#0b0;font-weight:bold">bool&lt;/span>, resize &lt;span style="color:#666">&amp;lt;-&lt;/span>&lt;span style="color:#a2f;font-weight:bold">chan&lt;/span> remotecommand.TerminalSize) &lt;span style="color:#0b0;font-weight:bold">error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a000">PortForward&lt;/span>(ctx context.Context, podSandboxID &lt;span style="color:#0b0;font-weight:bold">string&lt;/span>, port &lt;span style="color:#0b0;font-weight:bold">int32&lt;/span>, stream io.ReadWriteCloser) &lt;span style="color:#0b0;font-weight:bold">error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Everything related to the protocol interpretation is
already in place and runtimes only have to implement the actual &lt;code>Exec&lt;/code> and
&lt;code>Attach&lt;/code> logic. For example, the container runtime &lt;a href="https://github.com/cri-o/cri-o">CRI-O&lt;/a>
does it &lt;a href="https://github.com/cri-o/cri-o/blob/2a0867/server/container_exec.go#L27-L46">like this pseudo code&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">func&lt;/span> (s StreamService) &lt;span style="color:#00a000">Exec&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ctx context.Context,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> containerID &lt;span style="color:#0b0;font-weight:bold">string&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cmd []&lt;span style="color:#0b0;font-weight:bold">string&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stdin io.Reader, stdout, stderr io.WriteCloser,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tty &lt;span style="color:#0b0;font-weight:bold">bool&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resizeChan &lt;span style="color:#666">&amp;lt;-&lt;/span>&lt;span style="color:#a2f;font-weight:bold">chan&lt;/span> remotecommand.TerminalSize,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>) &lt;span style="color:#0b0;font-weight:bold">error&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// Retrieve the container by the provided containerID
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> &lt;span style="color:#080;font-style:italic">// …
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// Update the container status and verify that the workload is running
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> &lt;span style="color:#080;font-style:italic">// …
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// Execute the command and stream the data
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> &lt;span style="color:#a2f;font-weight:bold">return&lt;/span> s.runtimeServer.&lt;span style="color:#00a000">Runtime&lt;/span>().&lt;span style="color:#00a000">ExecContainer&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s.ctx, c, cmd, stdin, stdout, stderr, tty, resizeChan,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="portforward">PortForward&lt;/h3>
&lt;p>Forwarding ports to a container works a bit differently when comparing it to
streaming IO data from a workload. The server still has to provide a URL
endpoint for the client to connect to, but then the container runtime has to
enter the network namespace of the container, allocate the port as well as
stream the data back and forth. There is no simple protocol definition available
like for &lt;strong>Exec&lt;/strong> or &lt;strong>Attach&lt;/strong>. This means that the client will stream the
plain SPDY frames (with or without an additional WebSocket connection) which can
be interpreted using libraries like &lt;a href="https://github.com/moby/spdystream">moby/spdystream&lt;/a>.&lt;/p>
&lt;p>Luckily, the kubelet library already provides the &lt;code>PortForward&lt;/code> interface method
which has to be implemented by the runtime. &lt;a>CRI-O does that&lt;/a> by (simplified):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a2f;font-weight:bold">func&lt;/span> (s StreamService) &lt;span style="color:#00a000">PortForward&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ctx context.Context,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> podSandboxID &lt;span style="color:#0b0;font-weight:bold">string&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> port &lt;span style="color:#0b0;font-weight:bold">int32&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stream io.ReadWriteCloser,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>) &lt;span style="color:#0b0;font-weight:bold">error&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// Retrieve the pod sandbox by the provided podSandboxID
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> sandboxID, err &lt;span style="color:#666">:=&lt;/span> s.runtimeServer.&lt;span style="color:#00a000">PodIDIndex&lt;/span>().&lt;span style="color:#00a000">Get&lt;/span>(podSandboxID)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sb &lt;span style="color:#666">:=&lt;/span> s.runtimeServer.&lt;span style="color:#00a000">GetSandbox&lt;/span>(sandboxID)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// …
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// Get the network namespace path on disk for that sandbox
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> netNsPath &lt;span style="color:#666">:=&lt;/span> sb.&lt;span style="color:#00a000">NetNsPath&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// …
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#080;font-style:italic">// Enter the network namespace and stream the data
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#080;font-style:italic">&lt;/span> &lt;span style="color:#a2f;font-weight:bold">return&lt;/span> s.runtimeServer.&lt;span style="color:#00a000">Runtime&lt;/span>().&lt;span style="color:#00a000">PortForwardContainer&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ctx, sb.&lt;span style="color:#00a000">InfraContainer&lt;/span>(), netNsPath, port, stream,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="future-work">Future work&lt;/h2>
&lt;p>The flexibility Kubernetes provides for the RPCs &lt;code>Exec&lt;/code>, &lt;code>Attach&lt;/code> and
&lt;code>PortForward&lt;/code> is truly outstanding compared to other methods. Nevertheless,
container runtimes have to keep up with the latest and greatest implementations
to support those features in a meaningful way. The general effort to support
WebSockets is not only a plain Kubernetes thing, it also has to be supported by
container runtimes as well as clients like &lt;code>crictl&lt;/code>.&lt;/p>
&lt;p>For example, &lt;code>crictl&lt;/code> v1.30 features a new &lt;code>--transport&lt;/code> flag for the
subcommands &lt;code>exec&lt;/code>, &lt;code>attach&lt;/code> and &lt;code>port-forward&lt;/code>
(&lt;a href="https://github.com/kubernetes-sigs/cri-tools/pull/1383">#1383&lt;/a>,
&lt;a href="https://github.com/kubernetes-sigs/cri-tools/pull/1385">#1385&lt;/a>)
to allow choosing between &lt;code>websocket&lt;/code> and &lt;code>spdy&lt;/code>.&lt;/p>
&lt;p>CRI-O is going an experimental path by moving the streaming server
implementation into &lt;a href="https://github.com/containers/conmon-rs">conmon-rs&lt;/a>
(a substitute for the container monitor &lt;a href="https://github.com/containers/conmon">conmon&lt;/a>). conmon-rs is
a &lt;a href="https://www.rust-lang.org">Rust&lt;/a> implementation of the original container
monitor and allows streaming WebSockets directly using supported libraries
(&lt;a href="https://github.com/containers/conmon-rs/pull/2070">#2070&lt;/a>). The major benefit
of this approach is that CRI-O does not even have to be running while conmon-rs
can keep active &lt;strong>Exec&lt;/strong>, &lt;strong>Attach&lt;/strong> and &lt;strong>PortForward&lt;/strong> sessions open. The
simplified flow when using crictl directly will then look like this:&lt;/p>
&lt;figure>
&lt;div class="mermaid">
sequenceDiagram
autonumber
participant crictl
participant runtime as Container Runtime
participant conmon-rs
Note over crictl,runtime: Container Runtime Interface (CRI)
crictl->>runtime: Exec, Attach, PortForward
Note over runtime,conmon-rs: Cap’n Proto
runtime->>conmon-rs: Serve Exec, Attach, PortForward
conmon-rs->>runtime: HTTP endpoint (URL)
runtime->>crictl: Response URL
crictl-->>conmon-rs: Connection upgrade to WebSocket
conmon-rs-)crictl: Stream data
&lt;/div>
&lt;/figure>
&lt;noscript>
&lt;div class="alert alert-secondary callout" role="alert">
&lt;em class="javascript-required">JavaScript must be &lt;a href="https://www.enable-javascript.com/">enabled&lt;/a> to view this content&lt;/em>
&lt;/div>
&lt;/noscript>
&lt;p>All of those enhancements require iterative design decisions, while the original
well-conceived implementation acts as the foundation for those. I really hope
you've enjoyed this compact journey through the history of CRI RPCs. Feel free
to reach out to me anytime for suggestions or feedback using the
&lt;a href="https://kubernetes.slack.com/team/U53SUDBD4">official Kubernetes Slack&lt;/a>.&lt;/p></description></item><item><title>Kubernetes 1.30: Preventing unauthorized volume mode conversion moves to GA</title><link>https://kubernetes.io/blog/2024/04/30/prevent-unauthorized-volume-mode-conversion-ga/</link><pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/04/30/prevent-unauthorized-volume-mode-conversion-ga/</guid><description>
&lt;p>With the release of Kubernetes 1.30, the feature to prevent the modification of the volume mode
of a &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">PersistentVolumeClaim&lt;/a> that was created from
an existing VolumeSnapshot in a Kubernetes cluster, has moved to GA!&lt;/p>
&lt;h2 id="the-problem">The problem&lt;/h2>
&lt;p>The &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-mode">Volume Mode&lt;/a> of a PersistentVolumeClaim
refers to whether the underlying volume on the storage device is formatted into a filesystem or
presented as a raw block device to the Pod that uses it.&lt;/p>
&lt;p>Users can leverage the VolumeSnapshot feature, which has been stable since Kubernetes v1.20,
to create a PersistentVolumeClaim (shortened as PVC) from an existing VolumeSnapshot in
the Kubernetes cluster. The PVC spec includes a dataSource field, which can point to an
existing VolumeSnapshot instance.
Visit &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#create-persistent-volume-claim-from-volume-snapshot">Create a PersistentVolumeClaim from a Volume Snapshot&lt;/a>
for more details on how to create a PVC from an existing VolumeSnapshot in a Kubernetes cluster.&lt;/p>
&lt;p>When leveraging the above capability, there is no logic that validates whether the mode of the
original volume, whose snapshot was taken, matches the mode of the newly created volume.&lt;/p>
&lt;p>This presents a security gap that allows malicious users to potentially exploit an
as-yet-unknown vulnerability in the host operating system.&lt;/p>
&lt;p>There is a valid use case to allow some users to perform such conversions. Typically, storage backup
vendors convert the volume mode during the course of a backup operation, to retrieve changed blocks
for greater efficiency of operations. This prevents Kubernetes from blocking the operation completely
and presents a challenge in distinguishing trusted users from malicious ones.&lt;/p>
&lt;h2 id="preventing-unauthorized-users-from-converting-the-volume-mode">Preventing unauthorized users from converting the volume mode&lt;/h2>
&lt;p>In this context, an authorized user is one who has access rights to perform &lt;strong>update&lt;/strong>
or &lt;strong>patch&lt;/strong> operations on VolumeSnapshotContents, which is a cluster-level resource.&lt;br>
It is up to the cluster administrator to provide these rights only to trusted users
or applications, like backup vendors.
Users apart from such authorized ones will never be allowed to modify the volume mode
of a PVC when it is being created from a VolumeSnapshot.&lt;/p>
&lt;p>To convert the volume mode, an authorized user must do the following:&lt;/p>
&lt;ol>
&lt;li>Identify the VolumeSnapshot that is to be used as the data source for a newly
created PVC in the given namespace.&lt;/li>
&lt;li>Identify the VolumeSnapshotContent bound to the above VolumeSnapshot.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl describe volumesnapshot -n &amp;lt;namespace&amp;gt; &amp;lt;name&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>Add the annotation &lt;a href="https://kubernetes.io/docs/reference/labels-annotations-taints/#snapshot-storage-kubernetes-io-allowvolumemodechange">&lt;code>snapshot.storage.kubernetes.io/allow-volume-mode-change: &amp;quot;true&amp;quot;&lt;/code>&lt;/a>
to the above VolumeSnapshotContent. The VolumeSnapshotContent annotations must include one similar to the following manifest fragment:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeSnapshotContent&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">annotations&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">snapshot.storage.kubernetes.io/allow-volume-mode-change&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#00f;font-weight:bold">...&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Note&lt;/strong>: For pre-provisioned VolumeSnapshotContents, you must take an extra
step of setting &lt;code>spec.sourceVolumeMode&lt;/code> field to either &lt;code>Filesystem&lt;/code> or &lt;code>Block&lt;/code>,
depending on the mode of the volume from which this snapshot was taken.&lt;/p>
&lt;p>An example is shown below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>snapshot.storage.k8s.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>VolumeSnapshotContent&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">annotations&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">snapshot.storage.kubernetes.io/allow-volume-mode-change&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;lt;volume-snapshot-content-name&amp;gt;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">deletionPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Delete&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">driver&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>hostpath.csi.k8s.io&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">source&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">snapshotHandle&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;lt;snapshot-handle&amp;gt;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">sourceVolumeMode&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Filesystem&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">volumeSnapshotRef&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;lt;volume-snapshot-name&amp;gt;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;lt;namespace&amp;gt;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Repeat steps 1 to 3 for all VolumeSnapshotContents whose volume mode needs to be
converted during a backup or restore operation. This can be done either via software
with credentials of an authorized user or manually by the authorized user(s).&lt;/p>
&lt;p>If the annotation shown above is present on a VolumeSnapshotContent object,
Kubernetes will not prevent the volume mode from being converted.
Users should keep this in mind before they attempt to add the annotation
to any VolumeSnapshotContent.&lt;/p>
&lt;h2 id="action-required">Action required&lt;/h2>
&lt;p>The &lt;code>prevent-volume-mode-conversion&lt;/code> feature flag is enabled by default in the
external-provisioner &lt;code>v4.0.0&lt;/code> and external-snapshotter &lt;code>v7.0.0&lt;/code>. Volume mode change
will be rejected when creating a PVC from a VolumeSnapshot unless the steps
described above have been performed.&lt;/p>
&lt;h2 id="what-s-next">What's next&lt;/h2>
&lt;p>To determine which CSI external sidecar versions support this feature, please head
over to the &lt;a href="https://kubernetes-csi.github.io/docs/">CSI docs page&lt;/a>.
For any queries or issues, join &lt;a href="https://slack.k8s.io/">Kubernetes on Slack&lt;/a> and
create a thread in the #csi or #sig-storage channel. Alternately, create an issue in the
CSI external-snapshotter &lt;a href="https://github.com/kubernetes-csi/external-snapshotter">repository&lt;/a>.&lt;/p></description></item><item><title>Kubernetes 1.30: Multi-Webhook and Modular Authorization Made Much Easier</title><link>https://kubernetes.io/blog/2024/04/26/multi-webhook-and-modular-authorization-made-much-easier/</link><pubDate>Fri, 26 Apr 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/04/26/multi-webhook-and-modular-authorization-made-much-easier/</guid><description>
&lt;p>With Kubernetes 1.30, we (SIG Auth) are moving Structured Authorization
Configuration to beta.&lt;/p>
&lt;p>Today's article is about &lt;em>authorization&lt;/em>: deciding what someone can and cannot
access. Check a previous article from yesterday to find about what's new in
Kubernetes v1.30 around &lt;em>authentication&lt;/em> (finding out who's performing a task,
and checking that they are who they say they are).&lt;/p>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>Kubernetes continues to evolve to meet the intricate requirements of system
administrators and developers alike. A critical aspect of Kubernetes that
ensures the security and integrity of the cluster is the API server
authorization. Until recently, the configuration of the authorization chain in
kube-apiserver was somewhat rigid, limited to a set of command-line flags and
allowing only a single webhook in the authorization chain. This approach, while
functional, restricted the flexibility needed by cluster administrators to
define complex, fine-grained authorization policies. The latest Structured
Authorization Configuration feature (&lt;a href="https://kep.k8s.io/3221">KEP-3221&lt;/a>) aims
to revolutionize this aspect by introducing a more structured and versatile way
to configure the authorization chain, focusing on enabling multiple webhooks and
providing explicit control mechanisms.&lt;/p>
&lt;h2 id="the-need-for-improvement">The Need for Improvement&lt;/h2>
&lt;p>Cluster administrators have long sought the ability to specify multiple
authorization webhooks within the API Server handler chain and have control over
detailed behavior like timeout and failure policy for each webhook. This need
arises from the desire to create layered security policies, where requests can
be validated against multiple criteria or sets of rules in a specific order. The
previous limitations also made it difficult to dynamically configure the
authorizer chain, leaving no room to manage complex authorization scenarios
efficiently.&lt;/p>
&lt;p>The &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authorization/#configuring-the-api-server-using-an-authorization-config-file">Structured Authorization Configuration
feature&lt;/a>
addresses these limitations by introducing a configuration file format to
configure the Kubernetes API Server Authorization chain. This format allows
specifying multiple webhooks in the authorization chain (all other authorization
types are specified no more than once). Each webhook authorizer has well-defined
parameters, including timeout settings, failure policies, and conditions for
invocation with &lt;a href="https://kubernetes.io/docs/reference/using-api/cel/">CEL&lt;/a> rules to pre-filter
requests before they are dispatched to webhooks, helping you prevent unnecessary
invocations. The configuration also supports automatic reloading, ensuring
changes can be applied dynamically without restarting the kube-apiserver. This
feature addresses current limitations and opens up new possibilities for
securing and managing Kubernetes clusters more effectively.&lt;/p>
&lt;h2 id="sample-configurations">Sample Configurations&lt;/h2>
&lt;p>Here is a sample structured authorization configuration along with descriptions
for all fields, their defaults, and possible values.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apiserver.config.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>AuthorizationConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">authorizers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Webhook&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Name used to describe the authorizer&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># This is explicitly used in monitoring machinery for metrics&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Note:&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># - Validation for this field is similar to how K8s labels are validated today.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Required, with no default&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>webhook&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">webhook&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># The duration to cache &amp;#39;authorized&amp;#39; responses from the webhook&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># authorizer.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Same as setting `--authorization-webhook-cache-authorized-ttl` flag&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Default: 5m0s&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">authorizedTTL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>30s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># The duration to cache &amp;#39;unauthorized&amp;#39; responses from the webhook&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># authorizer.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Same as setting `--authorization-webhook-cache-unauthorized-ttl` flag&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Default: 30s&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">unauthorizedTTL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>30s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Timeout for the webhook request&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Maximum allowed is 30s.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Required, with no default.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">timeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>3s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># The API version of the authorization.k8s.io SubjectAccessReview to&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># send to and expect from the webhook.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Same as setting `--authorization-webhook-version` flag&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Required, with no default&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Valid values: v1beta1, v1&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">subjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># MatchConditionSubjectAccessReviewVersion specifies the SubjectAccessReview&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># version the CEL expressions are evaluated against&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Valid values: v1&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Required, no default value&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditionSubjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Controls the authorization decision when a webhook request fails to&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># complete or returns a malformed response or errors evaluating&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># matchConditions.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Valid values:&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># - NoOpinion: continue to subsequent authorizers to see if one of&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># them allows the request&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># - Deny: reject the request without consulting subsequent authorizers&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Required, with no default.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">failurePolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Deny&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">connectionInfo&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Controls how the webhook should communicate with the server.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Valid values:&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># - KubeConfigFile: use the file specified in kubeConfigFile to locate the&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># server.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># - InClusterConfig: use the in-cluster configuration to call the&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># SubjectAccessReview API hosted by kube-apiserver. This mode is not&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># allowed for kube-apiserver.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>KubeConfigFile&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Path to KubeConfigFile for connection info&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Required, if connectionInfo.Type is KubeConfigFile&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kubeConfigFile&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/kube-system-authz-webhook.yaml&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># matchConditions is a list of conditions that must be met for a request to be sent to this&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># webhook. An empty list of matchConditions matches all requests.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># There are a maximum of 64 match conditions allowed.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic">#&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># The exact matching logic is (in order):&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># 1. If at least one matchCondition evaluates to FALSE, then the webhook is skipped.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># 2. If ALL matchConditions evaluate to TRUE, then the webhook is called.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># 3. If at least one matchCondition evaluates to an error (but none are FALSE):&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># - If failurePolicy=Deny, then the webhook rejects the request&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># - If failurePolicy=NoOpinion, then the error is ignored and the webhook is skipped&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># expression represents the expression which will be evaluated by CEL. Must evaluate to bool.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># CEL expressions have access to the contents of the SubjectAccessReview in v1 version.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># If version specified by subjectAccessReviewVersion in the request variable is v1beta1,&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># the contents would be converted to the v1 version before evaluating the CEL expression.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic">#&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic">#&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only send resource requests to the webhook&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>has(request.resourceAttributes)&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only intercept requests to kube-system&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.namespace == &amp;#39;kube-system&amp;#39;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># don&amp;#39;t intercept requests from kube-system service accounts&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;!(&amp;#39;system:serviceaccounts:kube-system&amp;#39; in request.groups)&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Node&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>node&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>RBAC&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>rbac&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Webhook&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>in-cluster-authorizer&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">webhook&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">authorizedTTL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>5m&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">unauthorizedTTL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>30s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">timeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>3s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">subjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">failurePolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>NoOpinion&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">connectionInfo&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>InClusterConfig&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The following configuration examples illustrate real-world scenarios that need
the ability to specify multiple webhooks with distinct settings, precedence
order, and failure modes.&lt;/p>
&lt;h3 id="protecting-installed-crds">Protecting Installed CRDs&lt;/h3>
&lt;p>Ensuring of Custom Resource Definitions (CRDs) availability at cluster startup
has been a key demand. One of the blockers of having a controller reconcile
those CRDs is having a protection mechanism for them, which can be achieved
through multiple authorization webhooks. This was not possible before as
specifying multiple authorization webhooks in the Kubernetes API Server
authorization chain was simply not possible. Now, with the Structured
Authorization Configuration feature, administrators can specify multiple
webhooks, offering a solution where RBAC falls short, especially when denying
permissions to 'non-system' users for certain CRDs.&lt;/p>
&lt;p>Assuming the following for this scenario:&lt;/p>
&lt;ul>
&lt;li>The &amp;quot;protected&amp;quot; CRDs are installed.&lt;/li>
&lt;li>They can only be modified by users in the group &lt;code>admin&lt;/code>.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apiserver.config.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>AuthorizationConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">authorizers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Webhook&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>system-crd-protector&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">webhook&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">unauthorizedTTL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>30s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">timeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>3s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">subjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditionSubjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">failurePolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Deny&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">connectionInfo&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>KubeConfigFile&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kubeConfigFile&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/files/kube-system-authz-webhook.yaml&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only send resource requests to the webhook&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>has(request.resourceAttributes)&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only intercept requests for CRDs&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.resource.resource = &amp;#34;customresourcedefinitions&amp;#34;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.resource.group = &amp;#34;&amp;#34;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only intercept update, patch, delete, or deletecollection requests&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.verb in [&amp;#39;update&amp;#39;, &amp;#39;patch&amp;#39;, &amp;#39;delete&amp;#39;,&amp;#39;deletecollection&amp;#39;]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Node&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>RBAC&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="preventing-unnecessarily-nested-webhooks">Preventing unnecessarily nested webhooks&lt;/h3>
&lt;p>A system administrator wants to apply specific validations to requests before
handing them off to webhooks using frameworks like Open Policy Agent. In the
past, this would require running nested webhooks within the one added to the
authorization chain to achieve the desired result. The Structured Authorization
Configuration feature simplifies this process, offering a structured API to
selectively trigger additional webhooks when needed. It also enables
administrators to set distinct failure policies for each webhook, ensuring more
consistent and predictable responses.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apiserver.config.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>AuthorizationConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">authorizers&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Webhook&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>system-crd-protector&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">webhook&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">unauthorizedTTL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>30s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">timeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>3s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">subjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditionSubjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">failurePolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Deny&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">connectionInfo&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>KubeConfigFile&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kubeConfigFile&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/files/kube-system-authz-webhook.yaml&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only send resource requests to the webhook&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>has(request.resourceAttributes)&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only intercept requests for CRDs&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.resource.resource = &amp;#34;customresourcedefinitions&amp;#34;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.resource.group = &amp;#34;&amp;#34;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only intercept update, patch, delete, or deletecollection requests&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.verb in [&amp;#39;update&amp;#39;, &amp;#39;patch&amp;#39;, &amp;#39;delete&amp;#39;,&amp;#39;deletecollection&amp;#39;]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Node&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>RBAC&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>opa&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Webhook&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">webhook&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">unauthorizedTTL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>30s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">timeout&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>3s&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">subjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditionSubjectAccessReviewVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">failurePolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Deny&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">connectionInfo&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>KubeConfigFile&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">kubeConfigFile&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/files/opa-default-authz-webhook.yaml&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">matchConditions&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only send resource requests to the webhook&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>has(request.resourceAttributes)&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># only intercept requests to default namespace&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>request.resourceAttributes.namespace == &amp;#39;default&amp;#39;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># don&amp;#39;t intercept requests from default service accounts&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;!(&amp;#39;system:serviceaccounts:default&amp;#39; in request.groups)&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="what-s-next">What's next?&lt;/h2>
&lt;p>From Kubernetes 1.30, the feature is in beta and enabled by default. For
Kubernetes v1.31, we expect the feature to stay in beta while we get more
feedback from users. Once it is ready for GA, the feature flag will be removed,
and the configuration file version will be promoted to v1.&lt;/p>
&lt;p>Learn more about this feature on the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authorization/#configuring-the-api-server-using-an-authorization-config-file">structured authorization
configuration&lt;/a>
Kubernetes doc website. You can also follow along with
&lt;a href="https://kep.k8s.io/3221">KEP-3221&lt;/a> to track progress in coming Kubernetes
releases.&lt;/p>
&lt;h2 id="call-to-action">Call to action&lt;/h2>
&lt;p>In this post, we have covered the benefits of the Structured Authorization
Configuration feature in Kubernetes v1.30 and a few sample configurations for
real-world scenarios. To use this feature, you must specify the path to the
authorization configuration using the &lt;code>--authorization-config&lt;/code> command line
argument. From Kubernetes 1.30, the feature is in beta and enabled by default.
If you want to keep using command line flags instead of a configuration file,
those will continue to work as-is. Specifying both &lt;code>--authorization-config&lt;/code> and
&lt;code>--authorization-modes&lt;/code>/&lt;code>--authorization-webhook-*&lt;/code> won't work. You need to drop
the older flags from your kube-apiserver command.&lt;/p>
&lt;p>The following kind Cluster configuration sets that command argument on the
APIserver to load an AuthorizationConfiguration from a file
(&lt;code>authorization_config.yaml&lt;/code>) in the files folder. Any needed kubeconfig and
certificate files can also be put in the files directory.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Cluster&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>kind.x-k8s.io/v1alpha4&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">featureGates&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">StructuredAuthorizationConfiguration&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#a2f;font-weight:bold">true&lt;/span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#080;font-style:italic"># enabled by default in v1.30&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kubeadmConfigPatches&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- |&lt;span style="color:#b44;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> kind: ClusterConfiguration
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> metadata:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> name: config
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> apiServer:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> extraArgs:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> authorization-config: &amp;#34;/files/authorization_config.yaml&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> extraVolumes:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> - name: files
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> hostPath: &amp;#34;/files&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> mountPath: &amp;#34;/files&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#b44;font-style:italic"> readOnly: true&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">nodes&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#008000;font-weight:bold">role&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>control-plane&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">extraMounts&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">hostPath&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>files&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">containerPath&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/files&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We would love to hear your feedback on this feature. In particular, we would
like feedback from Kubernetes cluster administrators and authorization webhook
implementors as they build their integrations with this new API. Please reach
out to us on the
&lt;a href="https://kubernetes.slack.com/archives/C05EZFX1Z2L">#sig-auth-authorizers-dev&lt;/a>
channel on Kubernetes Slack.&lt;/p>
&lt;h2 id="how-to-get-involved">How to get involved&lt;/h2>
&lt;p>If you are interested in helping develop this feature, sharing feedback, or
participating in any other ongoing SIG Auth projects, please reach out on the
&lt;a href="https://kubernetes.slack.com/archives/C0EN96KUY">#sig-auth&lt;/a> channel on
Kubernetes Slack.&lt;/p>
&lt;p>You are also welcome to join the bi-weekly &lt;a href="https://github.com/kubernetes/community/blob/master/sig-auth/README.md#meetings">SIG Auth
meetings&lt;/a>
held every other Wednesday.&lt;/p>
&lt;h2 id="acknowledgments">Acknowledgments&lt;/h2>
&lt;p>This feature was driven by contributors from several different companies. We
would like to extend a huge thank you to everyone who contributed their time and
effort to make this possible.&lt;/p></description></item><item><title>Kubernetes 1.30: Structured Authentication Configuration Moves to Beta</title><link>https://kubernetes.io/blog/2024/04/25/structured-authentication-moves-to-beta/</link><pubDate>Thu, 25 Apr 2024 00:00:00 +0000</pubDate><guid>https://kubernetes.io/blog/2024/04/25/structured-authentication-moves-to-beta/</guid><description>
&lt;p>With Kubernetes 1.30, we (SIG Auth) are moving Structured Authentication Configuration to beta.&lt;/p>
&lt;p>Today's article is about &lt;em>authentication&lt;/em>: finding out who's performing a task, and checking
that they are who they say they are. Check back in tomorrow to find about what's new in
Kubernetes v1.30 around &lt;em>authorization&lt;/em> (deciding what someone can and can't access).&lt;/p>
&lt;h2 id="motivation">Motivation&lt;/h2>
&lt;p>Kubernetes has had a long-standing need for a more flexible and extensible
authentication system. The current system, while powerful, has some limitations
that make it difficult to use in certain scenarios. For example, it is not
possible to use multiple authenticators of the same type (e.g., multiple JWT
authenticators) or to change the configuration without restarting the API server. The
Structured Authentication Configuration feature is the first step towards
addressing these limitations and providing a more flexible and extensible way
to configure authentication in Kubernetes.&lt;/p>
&lt;h2 id="what-is-structured-authentication-configuration">What is structured authentication configuration?&lt;/h2>
&lt;p>Kubernetes v1.30 builds on the experimental support for configurating authentication based on
a file, that was added as alpha in Kubernetes v1.30. At this beta stage, Kubernetes only supports configuring JWT
authenticators, which serve as the next iteration of the existing OIDC
authenticator. JWT authenticator is an authenticator to
authenticate Kubernetes users using JWT compliant tokens. The authenticator
will attempt to parse a raw ID token, verify it's been signed by the configured
issuer.&lt;/p>
&lt;p>The Kubernetes project added configuration from a file so that it can provide more
flexibility than using command line options (which continue to work, and are still supported).
Supporting a configuration file also makes it easy to deliver further improvements in upcoming
releases.&lt;/p>
&lt;h3 id="benefits-of-structured-authentication-configuration">Benefits of structured authentication configuration&lt;/h3>
&lt;p>Here's why using a configuration file to configure cluster authentication is a benefit:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Multiple JWT authenticators&lt;/strong>: You can configure multiple JWT authenticators
simultaneously. This allows you to use multiple identity providers (e.g.,
Okta, Keycloak, GitLab) without needing to use an intermediary like Dex
that handles multiplexing between multiple identity providers.&lt;/li>
&lt;li>&lt;strong>Dynamic configuration&lt;/strong>: You can change the configuration without
restarting the API server. This allows you to add, remove, or modify
authenticators without disrupting the API server.&lt;/li>
&lt;li>&lt;strong>Any JWT-compliant token&lt;/strong>: You can use any JWT-compliant token for
authentication. This allows you to use tokens from any identity provider that
supports JWT. The minimum valid JWT payload must contain the claims documented
in &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/#using-authentication-configuration">structured authentication configuration&lt;/a>
page in the Kubernetes documentation.&lt;/li>
&lt;li>&lt;strong>CEL (Common Expression Language) support&lt;/strong>: You can use &lt;a href="https://kubernetes.io/docs/reference/using-api/cel/">CEL&lt;/a>
to determine whether the token's claims match the user's attributes in Kubernetes (e.g.,
username, group). This allows you to use complex logic to determine whether a
token is valid.&lt;/li>
&lt;li>&lt;strong>Multiple audiences&lt;/strong>: You can configure multiple audiences for a single
authenticator. This allows you to use the same authenticator for multiple
audiences, such as using a different OAuth client for &lt;code>kubectl&lt;/code> and dashboard.&lt;/li>
&lt;li>&lt;strong>Using identity providers that don't support OpenID connect discovery&lt;/strong>: You
can use identity providers that don't support &lt;a href="https://openid.net/specs/openid-connect-discovery-1_0.html">OpenID Connect
discovery&lt;/a>. The only
requirement is to host the discovery document at a different location than the
issuer (such as locally in the cluster) and specify the &lt;code>issuer.discoveryURL&lt;/code> in
the configuration file.&lt;/li>
&lt;/ol>
&lt;h2 id="how-to-use-structured-authentication-configuration">How to use Structured Authentication Configuration&lt;/h2>
&lt;p>To use structured authentication configuration, you specify
the path to the authentication configuration using the &lt;code>--authentication-config&lt;/code>
command line argument in the API server. The configuration file is a YAML file
that specifies the authenticators and their configuration. Here is an example
configuration file that configures two JWT authenticators:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apiserver.config.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>AuthenticationConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#080;font-style:italic"># Someone with a valid token from either of these issuers could authenticate&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#080;font-style:italic"># against this cluster.&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">jwt&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#008000;font-weight:bold">issuer&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">url&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>https://issuer1.example.com&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">audiences&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- audience1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- audience2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">audienceMatchPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>MatchAny&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claimValidationRules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.hd == &amp;#34;example.com&amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">message&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;the hosted domain name must be example.com&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claimMappings&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">username&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.username&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">groups&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.groups&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">uid&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.uid&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">extra&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;example.com/tenant&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.tenant&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">userValidationRules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;!user.username.startsWith(&amp;#39;system:&amp;#39;)&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">message&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;username cannot use reserved system: prefix&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#080;font-style:italic"># second authenticator that exposes the discovery document at a different location&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#080;font-style:italic"># than the issuer&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#008000;font-weight:bold">issuer&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">url&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>https://issuer2.example.com&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">discoveryURL&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>https://discovery.example.com/.well-known/openid-configuration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">audiences&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- audience3&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- audience4&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">audienceMatchPolicy&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>MatchAny&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claimValidationRules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.hd == &amp;#34;example.com&amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">message&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;the hosted domain name must be example.com&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claimMappings&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">username&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.username&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">groups&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.groups&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">uid&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.uid&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">extra&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;example.com/tenant&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#39;claims.tenant&amp;#39;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">userValidationRules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">expression&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;!user.username.startsWith(&amp;#39;system:&amp;#39;)&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">message&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;username cannot use reserved system: prefix&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="migration-from-command-line-arguments-to-configuration-file">Migration from command line arguments to configuration file&lt;/h2>
&lt;p>The Structured Authentication Configuration feature is designed to be
backwards-compatible with the existing approach, based on command line options, for
configuring the JWT authenticator. This means that you can continue to use the existing
command-line options to configure the JWT authenticator. However, we (Kubernetes SIG Auth)
recommend migrating to the new configuration file-based approach, as it provides more
flexibility and extensibility.&lt;/p>
&lt;div class="alert alert-primary" role="alert">
&lt;h4 class="alert-heading">Note&lt;/h4>
&lt;p>If you specify &lt;code>--authentication-config&lt;/code> along with any of the &lt;code>--oidc-*&lt;/code> command line arguments, this is
a misconfiguration. In this situation, the API server reports an error and then immediately exits.&lt;/p>
&lt;p>If you want to switch to using structured authentication configuration, you have to remove the &lt;code>--oidc-*&lt;/code>
command line arguments, and use the configuration file instead.&lt;/p>
&lt;/div>
&lt;p>Here is an example of how to migrate from the command-line flags to the
configuration file:&lt;/p>
&lt;h3 id="command-line-arguments">Command-line arguments&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>--oidc-issuer-url&lt;span style="color:#666">=&lt;/span>https://issuer.example.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-client-id&lt;span style="color:#666">=&lt;/span>example-client-id
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-username-claim&lt;span style="color:#666">=&lt;/span>username
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-groups-claim&lt;span style="color:#666">=&lt;/span>groups
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-username-prefix&lt;span style="color:#666">=&lt;/span>oidc:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-groups-prefix&lt;span style="color:#666">=&lt;/span>oidc:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-required-claim&lt;span style="color:#666">=&lt;/span>&lt;span style="color:#b44">&amp;#34;hd=example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-required-claim&lt;span style="color:#666">=&lt;/span>&lt;span style="color:#b44">&amp;#34;admin=true&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>--oidc-ca-file&lt;span style="color:#666">=&lt;/span>/path/to/ca.pem
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There is no equivalent in the configuration file for the &lt;code>--oidc-signing-algs&lt;/code>.
For Kubernetes v1.30, the authenticator supports all the asymmetric algorithms listed in
&lt;a href="https://github.com/kubernetes/kubernetes/blob/b4935d910dcf256288694391ef675acfbdb8e7a3/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc.go#L222-L233">&lt;code>oidc.go&lt;/code>&lt;/a>.&lt;/p>
&lt;h3 id="configuration-file">Configuration file&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#008000;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apiserver.config.k8s.io/v1beta1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>AuthenticationConfiguration&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#008000;font-weight:bold">jwt&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#008000;font-weight:bold">issuer&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">url&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>https://issuer.example.com&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">audiences&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- example-client-id&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">certificateAuthority&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&amp;lt;value is the content of file /path/to/ca.pem&amp;gt;&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claimMappings&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">username&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claim&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>username&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">prefix&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;oidc:&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">groups&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claim&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>groups&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">prefix&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;oidc:&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">claimValidationRules&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">claim&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>hd&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredValue&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;example.com&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#008000;font-weight:bold">claim&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>admin&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#008000;font-weight:bold">requiredValue&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#b44">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="what-s-next">What's next?&lt;/h2>
&lt;p>For Kubernetes v1.31, we expect the feature to stay in beta while we get more
feedback. In the coming releases, we want to investigate:&lt;/p>
&lt;ul>
&lt;li>Making distributed claims work via CEL expressions.&lt;/li>
&lt;li>Egress selector configuration support for calls to &lt;code>issuer.url&lt;/code> and
&lt;code>issuer.discoveryURL&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>You can learn more about this feature on the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/#using-authentication-configuration">structured authentication
configuration&lt;/a>
page in the Kubernetes documentation. You can also follow along on the
&lt;a href="https://kep.k8s.io/3331">KEP-3331&lt;/a> to track progress across the coming
Kubernetes releases.&lt;/p>
&lt;h2 id="try-it-out">Try it out&lt;/h2>
&lt;p>In this post, I have covered the benefits the Structured Authentication
Configuration feature brings in Kubernetes v1.30. To use this feature, you must specify the path to the
authentication configuration using the &lt;code>--authentication-config&lt;/code> command line
argument. From Kubernetes v1.30, the feature is in beta and enabled by default.
If you want to keep using command line arguments instead of a configuration file,
those will continue to work as-is.&lt;/p>
&lt;p>We would love to hear your feedback on this feature. Please reach out to us on the
&lt;a href="https://kubernetes.slack.com/archives/C04UMAUC4UA">#sig-auth-authenticators-dev&lt;/a>
channel on Kubernetes Slack (for an invitation, visit &lt;a href="https://slack.k8s.io/">https://slack.k8s.io/&lt;/a>).&lt;/p>
&lt;h2 id="how-to-get-involved">How to get involved&lt;/h2>
&lt;p>If you are interested in getting involved in the development of this feature,
share feedback, or participate in any other ongoing SIG Auth projects, please
reach out on the &lt;a href="https://kubernetes.slack.com/archives/C0EN96KUY">#sig-auth&lt;/a>
channel on Kubernetes Slack.&lt;/p>
&lt;p>You are also welcome to join the bi-weekly &lt;a href="https://github.com/kubernetes/community/blob/master/sig-auth/README.md#meetings">SIG Auth
meetings&lt;/a>
held every-other Wednesday.&lt;/p></description></item></channel></rss>