<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Olivier Bourgeois</title>
    <description>The latest articles on DEV Community by Olivier Bourgeois (@olivi-eh).</description>
    <link>https://dev.to/olivi-eh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F164593%2F5fc8f88c-e999-4d1e-805a-673d4c13d128.jpg</url>
      <title>DEV Community: Olivier Bourgeois</title>
      <link>https://dev.to/olivi-eh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olivi-eh"/>
    <language>en</language>
    <item>
      <title>Tunable CrashLoopBackOff in GKE: Accelerating AI/ML recovery and eliminating risky node hacks</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Mon, 31 Aug 2026 18:21:41 +0000</pubDate>
      <link>https://dev.to/googlecloud/tunable-crashloopbackoff-in-gke-accelerating-aiml-recovery-and-eliminating-risky-node-hacks-1o6k</link>
      <guid>https://dev.to/googlecloud/tunable-crashloopbackoff-in-gke-accelerating-aiml-recovery-and-eliminating-risky-node-hacks-1o6k</guid>
      <description>&lt;p&gt;In Kubernetes, few status messages are as familiar as &lt;code&gt;CrashLoopBackOff&lt;/code&gt;. When a container exits unexpectedly, the kubelet steps in to prevent the failing process from overwhelming the host node. To achieve this, it applies an exponential backoff delay before each restart attempt. While this defensive mechanism protects node stability, its rigid default parameters create friction for modern workloads.&lt;/p&gt;

&lt;p&gt;The default Kubernetes restart logic starts at a 10-second delay and doubles after each failure (10s, 20s, 40s, 80s, 160s) until reaching a 5-minute (300-second) ceiling. In fast-moving development environments, distributed AI/ML training runs, and architectures with critical sidecars, waiting up to five minutes for a container to retry stalls entire pipelines.&lt;/p&gt;

&lt;p&gt;To solve this operational bottleneck, the GKE team launched the General Availability of &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/node-system-config#container_restart_delay" rel="noopener noreferrer"&gt;tunable CrashLoopBackOff&lt;/a&gt;. By exposing &lt;code&gt;crashLoopBackOff.maxContainerRestartPeriod&lt;/code&gt; through the GKE NodeSystemConfig API and Custom Compute Classes (CCC), platform teams can now securely reduce restart delays down to 1 second.&lt;/p&gt;

&lt;p&gt;In this article, I will explain why fixed restart delays impact modern workloads, how GKE enables native tuning without privileged host workarounds, and how to configure and monitor this capability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost of fixed restart backoffs
&lt;/h2&gt;

&lt;p&gt;Kubernetes designed exponential backoff to protect the kubelet and runtime from CPU exhaustion caused by rapid restart loops. However, a maximum backoff delay of 300 seconds introduces severe delays across several workload patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI/ML training and inference pipelines&lt;/strong&gt;: Large-scale distributed training jobs synchronize state across hundreds of accelerator nodes hosting GPUs or TPUs. If a single worker encounters a temporary network timeout, initialization hiccup, or dependency race condition, the container enters &lt;code&gt;CrashLoopBackOff&lt;/code&gt;. When one Pod delays by 5 minutes, the entire gang-scheduled training job stalls, leaving expensive accelerators idle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critical sidecar initialization&lt;/strong&gt;: Modern microservices frequently depend on sidecars for service mesh routing, mTLS credential renewal, or secret injection. If a sidecar crashes due to transient backend unavailability, the primary application container cannot serve traffic until the sidecar restarts and passes readiness checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast developer iteration cycles&lt;/strong&gt;: During active debugging and CI runs, engineers need containers to restart immediately after updating an environment variable or dependency. Waiting through several minutes of backoff adds unnecessary latency to test suites.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The risks of legacy node workarounds
&lt;/h2&gt;

&lt;p&gt;Because upstream Kubernetes historically lacked a supported interface to tune restart delays, platform teams turned to dangerous workarounds.&lt;/p&gt;

&lt;p&gt;The most common hack involved running privileged &lt;code&gt;DaemonSets&lt;/code&gt; with host filesystem access (&lt;code&gt;hostPID: true&lt;/code&gt;, &lt;code&gt;hostPath: /etc/kubernetes&lt;/code&gt;). These DaemonSets executed scripts to overwrite &lt;code&gt;kubelet.config.json&lt;/code&gt; or modify systemd unit flags directly on the node, forcing kubelet restarts to apply non-standard configurations.&lt;/p&gt;

&lt;p&gt;This approach creates significant liabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security perimeter violations&lt;/strong&gt;: Granting containers root privileges and host access bypasses Kubernetes security boundaries, exposing worker nodes to container escape risks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node stability and auto-repair failures&lt;/strong&gt;: Custom filesystem edits interfere with GKE node auto-upgrade and auto-repair mechanisms. When GKE reprovisions or updates a node, custom file modifications can lead to bootstrap failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accelerator node instability&lt;/strong&gt;: Running unsupported background scripts on GPU and TPU nodes risks disrupting specialized accelerator drivers, device plugins, and NUMA-aware scheduling routines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tunable CrashLoopBackOff eliminates these workarounds by providing a native, fully managed control plane configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native tuning through NodeSystemConfig and ComputeClass
&lt;/h2&gt;

&lt;p&gt;GKE allows administrators to configure the maximum restart delay per node pool using the &lt;code&gt;NodeSystemConfig&lt;/code&gt; API in GKE Standard, or via &lt;code&gt;ComputeClass&lt;/code&gt; custom resources in GKE Autopilot.&lt;/p&gt;

&lt;p&gt;The configuration exposes the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configurable range&lt;/strong&gt;: The &lt;code&gt;maxContainerRestartPeriod&lt;/code&gt; must be an integer between 1 second and 300 seconds. Setting it to &lt;code&gt;1s&lt;/code&gt; forces the kubelet to retry failed containers almost immediately, while values like &lt;code&gt;10s&lt;/code&gt; or &lt;code&gt;30s&lt;/code&gt; provide a balanced compromise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node pool isolation&lt;/strong&gt;: The setting applies at the node pool level, allowing you to configure low restart delays for specialized AI/ML pools while keeping default backoff behavior for standard application pools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upstream alignment&lt;/strong&gt;: This capability builds upon upstream Kubernetes enhancement &lt;a href="https://github.com/kubernetes/enhancements/issues/4603" rel="noopener noreferrer"&gt;KEP-4603&lt;/a&gt;, ensuring compatibility with core Kubernetes architectural standards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring restart backoffs on your node pools
&lt;/h2&gt;

&lt;p&gt;You can configure tunable CrashLoopBackOff when creating new node pools or updating existing pools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring GKE Standard node pools
&lt;/h3&gt;

&lt;p&gt;To create a node pool with a custom restart delay, pass the configuration using a system config file with &lt;code&gt;gcloud&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# node-system-config.yaml&lt;/span&gt;
&lt;span class="na"&gt;kubeletConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;crashLoopBackOff&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;maxContainerRestartPeriod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the following command to apply the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container node-pools create accelerator-pool &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--cluster&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production-cluster &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1-a &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--system-config-from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node-system-config.yaml &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--machine-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;g2-standard-24 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nvidia-l4,count&lt;span class="o"&gt;=&lt;/span&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To update an existing node pool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container node-pools update accelerator-pool &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--cluster&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production-cluster &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1-a &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--system-config-from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node-system-config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring GKE Autopilot via ComputeClass
&lt;/h3&gt;

&lt;p&gt;For clusters leveraging GKE Autopilot or Custom Compute Classes, declare the restart delay inside a &lt;code&gt;ComputeClass&lt;/code&gt; manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloud.google.com/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ComputeClass&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fast-recovery-accelerator&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nodeConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;systemConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;kubeletConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;crashLoopBackOff&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;maxContainerRestartPeriod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Workloads requesting this compute class automatically land on nodes provisioned with the 5-second maximum restart delay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and operational best practices
&lt;/h2&gt;

&lt;p&gt;Reducing the maximum restart period causes failing containers to restart more frequently. To maintain cluster health, apply these operational practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monitor restart rates&lt;/strong&gt;: Track the &lt;code&gt;kubernetes.io/container/restart_count&lt;/code&gt; metric in Cloud Monitoring. A sudden surge in restarts indicates an unrecoverable crash requiring debugging rather than rapid retries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track node resource utilization&lt;/strong&gt;: Observe kubelet CPU and memory consumption (&lt;code&gt;kubernetes.io/node/cpu/allocatable_utilization&lt;/code&gt;). Rapid restarts generate more container runtime and lifecycle events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine with proper health probes&lt;/strong&gt;: Ensure Pod definitions use realistic &lt;code&gt;startupProbe&lt;/code&gt; and &lt;code&gt;livenessProbe&lt;/code&gt; timeouts. Probes must allow sufficient initialization time before failing containers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Tunable CrashLoopBackOff removes a major constraint for high-performance workloads on GKE. By replacing risky DaemonSet workarounds with native control plane configuration, platform teams can accelerate AI training recovery, streamline sidecar startup, and protect node stability.&lt;/p&gt;

&lt;p&gt;To configure restart periods for your clusters, review the official &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/node-system-config#container_restart_delay" rel="noopener noreferrer"&gt;GKE node system configuration documentation&lt;/a&gt;, explore the &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/reference/crds/computeclass" rel="noopener noreferrer"&gt;GKE ComputeClass reference&lt;/a&gt;, and read upstream &lt;a href="https://github.com/kubernetes/enhancements/issues/4603" rel="noopener noreferrer"&gt;Kubernetes KEP-4603&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Native CORS support on GKE Gateway: Offloading cross-origin policy management to infrastructure</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Sun, 30 Aug 2026 19:09:03 +0000</pubDate>
      <link>https://dev.to/googlecloud/native-cors-support-on-gke-gateway-offloading-cross-origin-policy-management-to-infrastructure-3c0m</link>
      <guid>https://dev.to/googlecloud/native-cors-support-on-gke-gateway-offloading-cross-origin-policy-management-to-infrastructure-3c0m</guid>
      <description>&lt;p&gt;Web browsers enforce the Same-Origin Policy by default to protect users from malicious scripts trying to read data across distinct origins. However, modern application architectures almost always require cross-origin communication. Single-page applications, mobile clients, and embedded web components regularly fetch data and stream AI model inferences across separate domains, subdomains, and ports.&lt;/p&gt;

&lt;p&gt;To allow these interactions safely, applications must implement Cross-Origin Resource Sharing (CORS). For years, teams running Kubernetes workloads on Ingress-Nginx handled this using annotations like &lt;code&gt;nginx.ingress.kubernetes.io/enable-cors&lt;/code&gt;. When migrating to the Kubernetes Gateway API and GKE Gateway, the lack of native CORS support was a frequent operational pain point, making it one of the most requested missing capabilities.&lt;/p&gt;

&lt;p&gt;The GKE team addressed this gap with the Preview release of &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/deploying-gateways#configure-cors" rel="noopener noreferrer"&gt;native CORS support for GKE Gateway and Inference Gateway&lt;/a&gt;. In this article, I will break down how the new CORS filter works, why moving cross-origin policy management to the load balancer matters, and the operational nuances you need to consider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why manage CORS at the ingress layer?
&lt;/h2&gt;

&lt;p&gt;Implementing CORS inside individual backend applications introduces architectural friction across three main areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redundant application logic&lt;/strong&gt;: Every backend service or framework (Node.js, FastAPI, Spring, or inference engines like vLLM) must include middleware to evaluate incoming headers and generate preflight responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preflight resource consumption&lt;/strong&gt;: Complex web requests trigger preflight &lt;code&gt;OPTIONS&lt;/code&gt; calls. Routing these preflight requests to backend containers wastes application memory, CPU cycles, and network bandwidth on pure protocol negotiation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration sprawl and drift&lt;/strong&gt;: When dozens of microservices manage their own CORS policies, subtle discrepancies in allowed headers, exposed headers, or origin validation create security vulnerabilities and broken client integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By shifting CORS processing to GKE Gateway, Google Cloud Load Balancing terminates &lt;code&gt;OPTIONS&lt;/code&gt; preflight requests directly at the network edge and injects required response headers (&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt;, &lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt;, and &lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt;). Your backend applications only receive validated application requests, removing boilerplate code and reducing compute overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the CORS filter in HTTPRoute
&lt;/h2&gt;

&lt;p&gt;GKE Gateway implements CORS support directly through the open-source Gateway API specification. You define policies declaratively using a &lt;code&gt;CORS&lt;/code&gt; filter within the &lt;code&gt;rules&lt;/code&gt; section of an &lt;code&gt;HTTPRoute&lt;/code&gt; manifest.&lt;/p&gt;

&lt;p&gt;Here is an example configuring a CORS policy on an API route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gateway.networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPRoute&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-cors-route&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;parentRefs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;external-gateway&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PathPrefix&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api&lt;/span&gt;
    &lt;span class="na"&gt;backendRefs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-service&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
    &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CORS&lt;/span&gt;
      &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;allowOrigins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://app.example.com"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://*.partner-domain.com"&lt;/span&gt;
        &lt;span class="na"&gt;allowMethods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POST&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUT&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DELETE&lt;/span&gt;
        &lt;span class="na"&gt;allowHeaders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Authorization&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Content-Type&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;X-Requested-With&lt;/span&gt;
        &lt;span class="na"&gt;exposeHeaders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;X-Request-ID&lt;/span&gt;
        &lt;span class="na"&gt;allowCredentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3600&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;cors&lt;/code&gt; configuration block gives you granular control over the negotiation parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allowOrigins&lt;/code&gt;&lt;/strong&gt;: Specifies the allowed origins via explicit URLs (&lt;code&gt;https://app.example.com&lt;/code&gt;), wildcard patterns (&lt;code&gt;https://*.partner-domain.com&lt;/code&gt;), or a catch-all wildcard (&lt;code&gt;*&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allowMethods&lt;/code&gt;&lt;/strong&gt;: Lists the permitted HTTP methods. You can also specify &lt;code&gt;*&lt;/code&gt; to allow all methods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allowHeaders&lt;/code&gt;&lt;/strong&gt;: Defines the HTTP request headers that clients can send in their requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;exposeHeaders&lt;/code&gt;&lt;/strong&gt;: Lists response headers that the browser makes accessible to client scripts beyond simple response headers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allowCredentials&lt;/code&gt;&lt;/strong&gt;: Sets the &lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt; header to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, dictating whether browsers can share responses with requests carrying cookies or authentication headers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;maxAge&lt;/code&gt;&lt;/strong&gt;: Defines the number of seconds the browser can cache the preflight response (defaulting to 5 seconds), significantly cutting down subsequent &lt;code&gt;OPTIONS&lt;/code&gt; traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security considerations with credentials and wildcards
&lt;/h2&gt;

&lt;p&gt;When designing your CORS policies on GKE Gateway, pay careful attention to the interaction between &lt;code&gt;allowOrigins&lt;/code&gt; and &lt;code&gt;allowCredentials&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Under standard browser security rules, browsers block responses to credentialed requests if &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; is set to a literal wildcard (&lt;code&gt;*&lt;/code&gt;). However, when you configure wildcard patterns or a wildcard in &lt;code&gt;allowOrigins&lt;/code&gt; in GKE Gateway, the controller dynamically matches and reflects the incoming request origin rather than returning a literal asterisk.&lt;/p&gt;

&lt;p&gt;Because the browser sees an explicit origin returned alongside &lt;code&gt;allowCredentials: true&lt;/code&gt;, it permits the response. If you configure &lt;code&gt;allowOrigins: ["*"]&lt;/code&gt; with &lt;code&gt;allowCredentials: true&lt;/code&gt;, any arbitrary website can potentially read authenticated user responses. For authenticated APIs, always define explicit domain lists rather than catch-all wildcards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported GatewayClasses and architectural constraints
&lt;/h2&gt;

&lt;p&gt;This Preview release supports single-cluster GKE Gateway deployments across three primary GatewayClasses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gke-l7-rilb&lt;/code&gt;&lt;/strong&gt;: Regional internal Application Load Balancer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gke-l7-regional-external-managed&lt;/code&gt;&lt;/strong&gt;: Regional external Application Load Balancer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gke-l7-global-external-managed&lt;/code&gt;&lt;/strong&gt;: Global external Application Load Balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also supports AI inference workloads exposed via Inference Gateway, allowing frontend chat interfaces or client SDKs to query served models directly across origins.&lt;/p&gt;

&lt;p&gt;Before implementing this in production, keep the following technical limits in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-cluster only&lt;/strong&gt;: Multi-cluster gateways (&lt;code&gt;gke-l7-gmc-*&lt;/code&gt;) do not currently support the CORS filter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter conflicts&lt;/strong&gt;: You cannot combine a &lt;code&gt;CORS&lt;/code&gt; filter and a &lt;code&gt;RequestRedirect&lt;/code&gt; filter within the same route rule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL map regular expression limits&lt;/strong&gt;: The GKE Gateway controller translates wildcard origin patterns into regular expressions on the underlying Cloud Load Balancing URL maps. For &lt;code&gt;gke-l7-global-external-managed&lt;/code&gt;, there is a limit of one regular expression per Gateway listener, and combining wildcard origins with &lt;code&gt;PathPrefix&lt;/code&gt; matches is not supported. For regional external and regional internal GatewayClasses, you can use up to five regular expressions per hostname. Note that exact origins and catch-all &lt;code&gt;*&lt;/code&gt; entries do not count against these regex quotas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Native CORS support in GKE Gateway eliminates one of the biggest functional gaps for organizations migrating workloads from legacy Ingress controllers to the Kubernetes Gateway API. By managing cross-origin policies declaratively at the routing layer, platform teams can simplify application code and centralize security posture across all services.&lt;/p&gt;

&lt;p&gt;To learn more and begin testing CORS in your clusters, check out the official &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/deploying-gateways#configure-cors" rel="noopener noreferrer"&gt;GKE Gateway CORS documentation&lt;/a&gt; and the upstream &lt;a href="https://gateway-api.sigs.k8s.io/guides/user-guides/http-cors/" rel="noopener noreferrer"&gt;Gateway API CORS User Guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Unlocking workload rightsizing visibility on GKE: How VPA decision logs bring observability to autoscaling</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Sat, 29 Aug 2026 18:57:42 +0000</pubDate>
      <link>https://dev.to/googlecloud/unlocking-workload-rightsizing-visibility-on-gke-how-vpa-decision-logs-bring-observability-to-17md</link>
      <guid>https://dev.to/googlecloud/unlocking-workload-rightsizing-visibility-on-gke-how-vpa-decision-logs-bring-observability-to-17md</guid>
      <description>&lt;p&gt;Automating resource management in Kubernetes has always required a high degree of trust. When you hand over CPU and memory sizing to the Vertical Pod Autoscaler (VPA), you expect it to rightsize containers efficiently without introducing unexpected restarts or performance regressions. Yet for many platform engineers, running VPA in production has felt like operating a black box.&lt;/p&gt;

&lt;p&gt;Until recently, inspecting VPA decisions meant relying on standard Kubernetes events or running &lt;code&gt;kubectl describe vpa&lt;/code&gt;. These events are transient, often expiring after an hour. If a Pod was evicted unexpectedly during an overnight batch job, or if an in-place resize failed silently due to node capacity limits, diagnosing the root cause the next morning was frustratingly difficult.&lt;/p&gt;

&lt;p&gt;To solve this observability gap, the GKE team launched the Public Preview of &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/view-vertical-pod-autoscaling-events" rel="noopener noreferrer"&gt;VerticalPodAutoscaler (VPA) Logs&lt;/a&gt;. Available on GKE clusters running version 1.36.0-gke.1601000 or newer, this feature streams structured VPA decision events directly into Cloud Logging.&lt;/p&gt;

&lt;p&gt;In this article, I will explain what VPA logs capture, how they demystify autoscaler decisions, and how you can use them to troubleshoot scaling actions and build reliable autonomous workload management.&lt;/p&gt;

&lt;h2&gt;
  
  
  The missing link in workload autoscaling observability
&lt;/h2&gt;

&lt;p&gt;Vertical autoscaling decisions are inherently complex. The VPA controller continuously evaluates historical CPU and memory utilization, computes recommendations with upper and lower safety bounds, and determines whether an active container needs adjustment.&lt;/p&gt;

&lt;p&gt;Without persistent logging, answering essential operational questions was difficult:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why did VPA decide to evict a specific Pod instead of keeping it running?&lt;/li&gt;
&lt;li&gt;Was an applied resource recommendation modified by Autopilot compute ratios or custom resource policies?&lt;/li&gt;
&lt;li&gt;Did an in-place resource resize fail, forcing the controller to fall back to recreation?&lt;/li&gt;
&lt;li&gt;How much confidence did the recommendation engine have when calculating new targets?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By exporting VPA decision events to Cloud Logging as first-class control plane logs (&lt;code&gt;KCP_VPA&lt;/code&gt;), GKE gives platform operators a permanent audit trail. Combined with existing Horizontal Pod Autoscaler (HPA) logging, teams now have complete visibility across horizontal and vertical scaling dimensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the structure of VPA decision logs
&lt;/h2&gt;

&lt;p&gt;VPA logs are emitted by the &lt;code&gt;vpa-controller&lt;/code&gt; control plane component and stored under the log destination &lt;code&gt;container.googleapis.com/vpa-controller&lt;/code&gt; in Cloud Logging. Each log entry arrives as a structured JSON payload containing detailed metadata about the target workload, the evaluation state, and the calculated resource bounds.&lt;/p&gt;

&lt;p&gt;The controller categorizes decision logs across four primary operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Update recommendation (&lt;code&gt;UPDATE_RECOMMENDATION&lt;/code&gt;)&lt;/strong&gt;: Emitted periodically (once per minute per VPA object). This log details the raw recommendation calculated by the recommender, including lower bound, upper bound, target, uncapped target, and recommendation confidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evict Pod (&lt;code&gt;EVICT_POD&lt;/code&gt;)&lt;/strong&gt;: Emitted when the VPA updater decides to evict a Pod to apply new resource requests under &lt;code&gt;Recreate&lt;/code&gt; mode (or as a fallback if in-place resize fails).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply recommendation on eviction (&lt;code&gt;APPLY_RECOMMENDATION_ON_EVICTION&lt;/code&gt;)&lt;/strong&gt;: Emitted when a newly scheduled replacement Pod receives resized resource requests during admission.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply recommendation in place (&lt;code&gt;APPLY_RECOMMENDATION_IN_PLACE&lt;/code&gt;)&lt;/strong&gt;: Emitted when VPA modifies container resource limits and requests live on a running Pod without a restart under &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each log entry includes a &lt;code&gt;state&lt;/code&gt; field (&lt;code&gt;SUCCEEDED&lt;/code&gt;, &lt;code&gt;SKIPPED&lt;/code&gt;, or &lt;code&gt;FAILED&lt;/code&gt;) and an explanatory &lt;code&gt;reason&lt;/code&gt; string. When an operation succeeds, the reason field clarifies whether applied recommendations diverged from raw recommendations due to policy caps or Autopilot ratio constraints.&lt;/p&gt;

&lt;p&gt;Crucially, the payload includes a &lt;code&gt;confidence&lt;/code&gt; field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;LOW&lt;/code&gt;: The recommender has processed fewer than 10 metric samples.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HIGH&lt;/code&gt;: The recommender has processed 10 or more metric samples, indicating a mature usage profile.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enabling VPA decision logs on GKE
&lt;/h2&gt;

&lt;p&gt;VPA logs can be enabled on both new and existing GKE clusters using the Google Cloud CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling logs on cluster creation
&lt;/h3&gt;

&lt;p&gt;To create a new GKE cluster with VPA decision logs enabled, include &lt;code&gt;KCP_VPA&lt;/code&gt; in the &lt;code&gt;--logging&lt;/code&gt; flag alongside &lt;code&gt;SYSTEM&lt;/code&gt; logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters create CLUSTER_NAME &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LOCATION &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PROJECT_ID &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--logging&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SYSTEM,KCP_VPA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updating an existing cluster
&lt;/h3&gt;

&lt;p&gt;When updating an existing cluster, preserve your currently configured logging components so you do not inadvertently overwrite them. Add &lt;code&gt;KCP_VPA&lt;/code&gt; to your existing configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters update CLUSTER_NAME &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LOCATION &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PROJECT_ID &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--logging&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SYSTEM,KCP_VPA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verifying the logging configuration
&lt;/h3&gt;

&lt;p&gt;You can confirm that &lt;code&gt;KCP_VPA&lt;/code&gt; is active by retrieving the enabled logging components for the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters describe CLUSTER_NAME &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LOCATION &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--flatten&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;loggingConfig &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'csv[delimiter=",",no-heading](componentConfig.enableComponents)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will list &lt;code&gt;KCP_VPA&lt;/code&gt; alongside your other active control plane components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical queries for Logs Explorer
&lt;/h2&gt;

&lt;p&gt;Once enabled, you can search and analyze VPA events directly in Google Cloud Logs Explorer.&lt;/p&gt;

&lt;p&gt;To view all decision events for a specific workload within a cluster, use the following filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource.type="k8s_control_plane_component"
resource.labels.cluster_name="CLUSTER_NAME"
logName="projects/PROJECT_ID/logs/container.googleapis.com%2Fvpa-controller"
jsonPayload.target.name="WORKLOAD_NAME"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To find instances where VPA skipped or failed an in-place resize operation, query by operation and state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;logName="projects/PROJECT_ID/logs/container.googleapis.com%2Fvpa-controller"
jsonPayload.operation="APPLY_RECOMMENDATION_IN_PLACE"
jsonPayload.state=("SKIPPED" OR "FAILED")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To audit recommendations generated with low confidence, filter on the confidence attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;logName="projects/PROJECT_ID/logs/container.googleapis.com%2Fvpa-controller"
jsonPayload.operation="UPDATE_RECOMMENDATION"
jsonPayload.confidence="LOW"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These queries enable site reliability teams to quickly diagnose scaling anomalies, track resize frequency, and identify workloads that require longer profiling before enforcing automated actuation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling autonomous, intent-based workload autoscaling
&lt;/h2&gt;

&lt;p&gt;The launch of VPA decision logs represents more than a troubleshooting convenience. In modern cloud-native architectures, platform engineering teams are moving toward intent-based infrastructure where autonomous agents monitor, optimize, and heal application environments.&lt;/p&gt;

&lt;p&gt;For an AI agent or automated governance pipeline to safely manage container resources, it requires complete observability into both horizontal and vertical scaling lifecycles. By providing a structured, historical record of why the VPA made every sizing decision, GKE equips platform teams and intelligent systems with the data needed to automate workload rightsizing with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;VerticalPodAutoscaler logs bring much-needed clarity to container resource optimization on GKE, turning automated rightsizing into a transparent, auditable process.&lt;/p&gt;

&lt;p&gt;To get started with VPA logs on your clusters, review the official &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/view-vertical-pod-autoscaling-events" rel="noopener noreferrer"&gt;GKE vertical Pod autoscaler event logs documentation&lt;/a&gt; and learn more about configuring &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/verticalpodautoscaler" rel="noopener noreferrer"&gt;Vertical Pod Autoscaling in GKE&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Accelerating JVM startup on GKE: How VPA CPU startup boost eliminates ongoing resource waste</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Sat, 29 Aug 2026 05:03:06 +0000</pubDate>
      <link>https://dev.to/googlecloud/accelerating-jvm-startup-on-gke-how-vpa-cpu-startup-boost-eliminates-ongoing-resource-waste-33i2</link>
      <guid>https://dev.to/googlecloud/accelerating-jvm-startup-on-gke-how-vpa-cpu-startup-boost-eliminates-ongoing-resource-waste-33i2</guid>
      <description>&lt;p&gt;Running Java and other JVM-based workloads in Kubernetes has long presented an infrastructure sizing challenge. During initialization, JVM applications require substantial CPU capacity to perform class loading, bytecode verification, framework dependency injection, and Just-In-Time (JIT) compilation. Once this initialization phase finishes, steady-state CPU consumption frequently drops by 50% to 80%.&lt;/p&gt;

&lt;p&gt;To avoid slow startups and ensure new Pods pass readiness probes quickly, platform teams have historically over-provisioned CPU requests permanently. This compromise introduces persistent CPU waste—unutilized allocations that inflate infrastructure spend and degrade workload packing density on worker nodes.&lt;/p&gt;

&lt;p&gt;To resolve this trade-off, the GKE team launched the Public Preview of &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/boost-application-startup" rel="noopener noreferrer"&gt;VerticalPodAutoscaler (VPA) CPU Startup Boost&lt;/a&gt;. Available on GKE clusters running version 1.36.0-gke.4447000 or newer in the Rapid Channel, this feature provides up to 2x faster startup latency while dynamically reclaiming CPU capacity once the application stabilizes.&lt;/p&gt;

&lt;p&gt;In this article, I will explain how CPU startup boost operates under the hood, how it leverages Kubernetes In-Place Pod Resize (IPPR), and how to configure it effectively for your clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The JVM startup and CPU waste dilemma
&lt;/h2&gt;

&lt;p&gt;When configuring CPU requests for a container, Kubernetes uses that value for scheduling decisions and CPU bandwidth enforcement through CFS quotas. If you rightsize a Java container for its steady-state requirement—say, 500m CPU—the application may experience severe CPU throttling during boot, stretching startup times from seconds into minutes.&lt;/p&gt;

&lt;p&gt;Slow startups create cascading operational challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal scaling lag&lt;/strong&gt;: When traffic spikes occur, Horizontal Pod Autoscaler (HPA) creates new replicas, but those replicas take too long to start serving requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flapping readiness probes&lt;/strong&gt;: Applications that exceed initial startup budgets can fail health checks, triggering unwanted container restarts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource waste&lt;/strong&gt;: To avoid throttling, teams routinely allocate 2 to 4 vCPUs permanently. After the bootstrap window, those vCPUs sit idle across GKE Standard and Autopilot clusters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CPU startup boost solves this by providing temporary CPU headroom during initialization, then reducing the allocation back to baseline without restarting the Pod.&lt;/p&gt;

&lt;h2&gt;
  
  
  How CPU startup boost works under the hood
&lt;/h2&gt;

&lt;p&gt;The CPU startup boost lifecycle executes across three distinct phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Admission phase&lt;/strong&gt;: When a Pod is created, the GKE VPA mutating admission webhook intercepts the request. The webhook calculates the boosted CPU request based on your policy and injects both the elevated CPU values and a tracking annotation (&lt;code&gt;vpaCpuStartupBoost/&amp;lt;container-name&amp;gt;&lt;/code&gt;) before the scheduler places the Pod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startup phase&lt;/strong&gt;: The container starts on a node with the higher CPU allocation, allowing JVM class loading and JIT compilation to run without CFS throttling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unboosting phase&lt;/strong&gt;: Once the Pod satisfies its readiness checks and reaches &lt;code&gt;Ready&lt;/code&gt; status, the configured &lt;code&gt;durationSeconds&lt;/code&gt; timer begins. When the duration expires, the VPA Updater initiates an in-place resize back to baseline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because GKE utilizes Kubernetes In-Place Pod Resize (IPPR), this downscale happens live. The container is never terminated or restarted when the boost ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring startup boost for your workloads
&lt;/h2&gt;

&lt;p&gt;You configure CPU startup boost directly inside a standard &lt;code&gt;VerticalPodAutoscaler&lt;/code&gt; Custom Resource. You can use VPA exclusively for startup boost or combine it with continuous autoscaling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using startup boost without continuous VPA actuation
&lt;/h3&gt;

&lt;p&gt;If you manage steady-state resource requests manually in your Deployment manifest, set &lt;code&gt;updateMode: "Off"&lt;/code&gt; in the VPA policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VerticalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;java-app-startup-boost&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;customer-service&lt;/span&gt;
  &lt;span class="na"&gt;updatePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;updateMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Off"&lt;/span&gt;
  &lt;span class="na"&gt;startupBoost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Factor&lt;/span&gt;
      &lt;span class="na"&gt;factor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="na"&gt;durationSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this manifest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;type: Factor&lt;/code&gt;: Multiplies the baseline CPU request (doubling 1 vCPU to 2 vCPUs during startup). You can also specify &lt;code&gt;type: Quantity&lt;/code&gt; with a fixed addition like &lt;code&gt;quantity: "2"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;durationSeconds: 10&lt;/code&gt;: Keeps boosted CPU active for 10 seconds after the Pod reaches &lt;code&gt;Ready&lt;/code&gt; state before reclaiming the resource.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Container-level targeting and continuous autoscaling
&lt;/h3&gt;

&lt;p&gt;For multi-container Pods containing sidecars, you can isolate the boost to the primary application container using &lt;code&gt;containerPolicies&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VerticalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;java-app-advanced-boost&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payment-service&lt;/span&gt;
  &lt;span class="na"&gt;updatePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;updateMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;InPlaceOrRecreate&lt;/span&gt;
  &lt;span class="na"&gt;resourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;containerPolicies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-server&lt;/span&gt;
      &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Auto&lt;/span&gt;
      &lt;span class="na"&gt;startupBoost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Quantity&lt;/span&gt;
          &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
          &lt;span class="na"&gt;durationSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;envoy-proxy&lt;/span&gt;
      &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Off"&lt;/span&gt;
      &lt;span class="na"&gt;startupBoost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Factor&lt;/span&gt;
          &lt;span class="na"&gt;factor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting &lt;code&gt;updateMode: InPlaceOrRecreate&lt;/code&gt; allows GKE to boost startup resources, return to baseline, and then continue evaluating ongoing usage to rightsize the workload over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key architecture and operational considerations
&lt;/h2&gt;

&lt;p&gt;When adopting CPU startup boost across your clusters, keep the following operational rules in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HPA integration&lt;/strong&gt;: When pairing startup boost with HPA based on CPU utilization, always define a &lt;code&gt;readinessProbe&lt;/code&gt; and set &lt;code&gt;durationSeconds: 0&lt;/code&gt;. This configuration ensures the Pod unboosts immediately upon becoming ready, preventing startup CPU spikes from triggering false scale-out events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GKE Autopilot resource rules&lt;/strong&gt;: Autopilot validates compute ratios during Pod admission. Make sure your Pod's baseline memory allocation can support the boosted CPU ratio. Because the Scale-Out ComputeClass enforces a fixed 1:4 ratio, standard or performance compute classes are recommended.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node capacity and autoscaling&lt;/strong&gt;: On GKE Standard, ensure worker nodes have sufficient allocatable CPU to schedule boosted Pods. If a node lacks capacity, GKE caps the boost to what the node can fit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pod restart semantics&lt;/strong&gt;: Startup boost triggers during initial Pod creation. If a container crashes and restarts within an existing Pod, the boost is not reapplied.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verifying boost and in-place downscale
&lt;/h2&gt;

&lt;p&gt;You can confirm that startup boost is active by inspecting Pod annotations and cluster events with &lt;code&gt;kubectl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check for the tracking annotation injected at admission&lt;/span&gt;
kubectl get pod &amp;lt;pod-name&amp;gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.metadata.annotations.vpaCpuStartupBoost/*}'&lt;/span&gt;

&lt;span class="c"&gt;# Observe the in-place downscale event after readiness&lt;/span&gt;
kubectl get events &lt;span class="nt"&gt;--field-selector&lt;/span&gt; &lt;span class="nv"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;InPlaceResizedByVPA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;InPlaceResizedByVPA&lt;/code&gt; event confirms that the container returned to baseline requests without a restart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;VPA CPU Startup Boost eliminates a longstanding trade-off in Kubernetes workload sizing, helping Java microservices start faster while cutting idle resource costs.&lt;/p&gt;

&lt;p&gt;To start testing startup boost on your GKE clusters, review the official &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/boost-application-startup" rel="noopener noreferrer"&gt;GKE CPU startup boost documentation&lt;/a&gt; and explore &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/vertical-pod-autoscaling" rel="noopener noreferrer"&gt;Vertical Pod Autoscaling in GKE&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Two-step control plane upgrades in GKE: How minor version rollbacks work under the hood</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Thu, 27 Aug 2026 17:56:45 +0000</pubDate>
      <link>https://dev.to/googlecloud/two-step-control-plane-upgrades-in-gke-how-minor-version-rollbacks-work-under-the-hood-i1l</link>
      <guid>https://dev.to/googlecloud/two-step-control-plane-upgrades-in-gke-how-minor-version-rollbacks-work-under-the-hood-i1l</guid>
      <description>&lt;p&gt;Kubernetes control plane minor version upgrades have historically been an all-or-nothing proposition. In standard Kubernetes clusters, upgrading a control plane from one minor version to the next—such as moving from 1.33 to 1.34—commits changes to storage schemas immediately. If an unexpected regression emerges after upgrading the API server, rolling back to the previous minor version was impossible without restoring etcd snapshots.&lt;/p&gt;

&lt;p&gt;To eliminate this operational risk, the GKE team drove upstream contributions in &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-architecture/4330-compatibility-versions" rel="noopener noreferrer"&gt;Kubernetes Enhancement Proposal KEP-4330 (Compatibility Versions)&lt;/a&gt; and introduced &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/upgrading-a-cluster#two-step-cp-upgrade" rel="noopener noreferrer"&gt;two-step control plane upgrades&lt;/a&gt;. Following public preview validation with enterprise customers, this capability is now Generally Available (GA) across all GKE release channels.&lt;/p&gt;

&lt;p&gt;In this article, I will explain how two-step upgrades work under the hood, how automated rollouts leverage canary analysis, and how to manage rollback-safe upgrades using the Google Cloud CLI and Terraform.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with minor version upgrades
&lt;/h2&gt;

&lt;p&gt;In Kubernetes, minor version releases introduce storage schema changes, deprecated API removals, and modified controller behaviors. When the &lt;code&gt;kube-apiserver&lt;/code&gt; binary starts on a newer minor version, it writes resources using newer internal schemas.&lt;/p&gt;

&lt;p&gt;Because earlier binary versions cannot parse data stored in newer schemas, Kubernetes prohibits control plane downgrades across minor versions. If an organization encountered an issue after upgrading, platform operators had to either run the degraded control plane or rebuild the cluster.&lt;/p&gt;

&lt;p&gt;Two-step upgrades decouple binary execution from API capability enablement. By separating the upgrade into two distinct phases, GKE provides an observation period (also known as a soak window) during which operators or automated systems can monitor cluster behavior and roll back the control plane to the previous minor version with zero data loss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoupling binary execution from emulated versions
&lt;/h2&gt;

&lt;p&gt;The foundation of two-step upgrades is running a newer control plane binary in an emulated compatibility mode.&lt;/p&gt;

&lt;p&gt;When a two-step upgrade begins, GKE advances the control plane through two sequential stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1: Binary upgrade (emulated mode)&lt;/strong&gt;: GKE upgrades the control plane binary to the target minor version (e.g., 1.34), but configures the API server to emulate the previous minor version (1.33). In this state, the control plane executes the new binary logic, while API schemas match the older version. APIs removed in 1.34 remain accessible. During this soak period, you can safely roll back to 1.33.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2: Emulated version upgrade (finalization)&lt;/strong&gt;: Once the soak window completes without incident, GKE updates the emulated version to match the binary version. This step permanently enables the new minor version API schemas and feature deprecations. After this point, rollback is no longer possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During the soak period, worker node pools cannot be upgraded beyond the emulated version to preserve Kubernetes version skew rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated orchestration with CPRS and Canary Analysis Service
&lt;/h2&gt;

&lt;p&gt;For clusters configured for auto-upgrades, two-step upgrades are enabled out of the box with zero manual configuration required. The GKE rollout engine, known as Control Plane Rollout Service (CPRS), orchestrates the staged lifecycle natively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPRS upgrades the control plane binary while locking the emulated version to the previous minor release.&lt;/li&gt;
&lt;li&gt;CPRS initiates an automated 24-hour soak window.&lt;/li&gt;
&lt;li&gt;The Canary Analysis Service (CAS) monitors cluster health signals throughout the soak duration, including API latency, error rates, and Pod health metrics.&lt;/li&gt;
&lt;li&gt;If CAS detects unexpected regressions, the rollout halts to allow automated or user-driven rollbacks.&lt;/li&gt;
&lt;li&gt;Once the cluster passes all CAS evaluations and satisfies the soak timer, CPRS triggers step 2 to finalize the emulated version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This validation framework has helped GKE control plane upgrades achieve a 99.999% (five nines) rolling 30-day success rate across the global fleet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initiating manual two-step upgrades
&lt;/h2&gt;

&lt;p&gt;If your team manages upgrades manually, you can execute two-step upgrades using the Google Cloud CLI or Terraform.&lt;/p&gt;

&lt;p&gt;To initiate a two-step upgrade with a custom soak duration using &lt;code&gt;gcloud&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud beta container clusters upgrade my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--cluster-version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.34.1-gke.1829001 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--control-plane-soak-duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;48h &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--control-plane-soak-duration&lt;/code&gt; flag defines the rollback-safe window, supporting values from 6 hours up to 7 days (e.g., &lt;code&gt;48h&lt;/code&gt; or &lt;code&gt;2d&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For infrastructure-as-code workflows, Terraform includes official support for managing two-step control plane upgrades declaratively by specifying the target version and soak parameters in your GKE cluster resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying upgrade status and executing a rollback
&lt;/h2&gt;

&lt;p&gt;While the cluster is soaking in emulated mode, you can inspect the active rollback state using the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters describe my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yaml(rollbackSafeUpgradeStatus)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output includes a &lt;code&gt;rollbackSafeUpgradeStatus&lt;/code&gt; block with the target binary version, emulated version, remaining soak time, and &lt;code&gt;previousVersion&lt;/code&gt; string.&lt;/p&gt;

&lt;p&gt;If your monitoring tools uncover a regression during the soak window, you can roll back the control plane to the previous minor patch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters upgrade my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--cluster-version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.33.5-gke.1080000 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the control plane ran in emulated mode, no new data formats were written to etcd. GKE downgrades the control plane binary back to the specified version without risking data corruption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Completing the upgrade early
&lt;/h2&gt;

&lt;p&gt;If your validation tests pass and you want to unlock new minor version features immediately without waiting for the soak duration to expire, you can finalize the upgrade manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud beta container clusters clusters complete-control-plane-upgrade my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once executed, GKE promotes the emulated version to match the binary version, completing the upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operational requirements and limits
&lt;/h2&gt;

&lt;p&gt;When planning two-step control plane upgrades, keep the following operational rules in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two-step upgrades apply to minor version upgrades to GKE 1.33 and later.&lt;/li&gt;
&lt;li&gt;Control plane upgrades must proceed one minor version at a time.&lt;/li&gt;
&lt;li&gt;Maintenance windows and exclusions are strictly respected.&lt;/li&gt;
&lt;li&gt;Autopilot and regional Standard clusters maintain continuous control plane availability during both phases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Two-step control plane upgrades eliminate the risk of irreversible minor version updates in Kubernetes, providing platform engineers with automated safety and an emergency rollback mechanism.&lt;/p&gt;

&lt;p&gt;To learn more about configuring two-step upgrades, read the official &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/upgrading-a-cluster#two-step-cp-upgrade" rel="noopener noreferrer"&gt;GKE cluster upgrade documentation&lt;/a&gt; and explore &lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-architecture/4330-compatibility-versions" rel="noopener noreferrer"&gt;KEP-4330: Compatibility Versions&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Progressive cluster upgrades at scale: A technical guide to GKE rollout sequencing with custom stages</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Thu, 27 Aug 2026 03:10:21 +0000</pubDate>
      <link>https://dev.to/googlecloud/progressive-cluster-upgrades-at-scale-a-technical-guide-to-gke-rollout-sequencing-with-custom-g63</link>
      <guid>https://dev.to/googlecloud/progressive-cluster-upgrades-at-scale-a-technical-guide-to-gke-rollout-sequencing-with-custom-g63</guid>
      <description>&lt;p&gt;Upgrading Kubernetes clusters across a large enterprise fleet is often a balancing act between staying current with security patches and avoiding outages. By default, Google Kubernetes Engine (GKE) rolls out automatic upgrades progressively according to Google Cloud regional timelines. While regional rollout works well for standalone clusters, it does not understand your organization's business topology. If you run staging clusters in &lt;code&gt;us-central1&lt;/code&gt; and critical production clusters in &lt;code&gt;us-east1&lt;/code&gt;, a standard regional rollout could upgrade your production environment before your pre-production validation completes.&lt;/p&gt;

&lt;p&gt;The General Availability (GA) release of &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/rollout-sequencing-custom-stages/about-rollout-sequencing" rel="noopener noreferrer"&gt;GKE rollout sequencing with custom stages&lt;/a&gt; solves this challenge. It provides platform teams with declarative control to sequence cluster upgrades across fleets, environments, and even distinct Google Cloud organizations according to business criticality rather than cloud geography.&lt;/p&gt;

&lt;h2&gt;
  
  
  How rollout sequencing works
&lt;/h2&gt;

&lt;p&gt;Rollout sequencing builds on GKE fleet management. Fleets serve as logical boundaries for environments such as development, staging, and production. With rollout sequencing, you define an ordered pipeline of upgrade stages managed by a central resource called &lt;code&gt;RolloutSequence&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When GKE publishes a new automatic upgrade target for a release channel, or when you explicitly trigger a target version, the system creates a &lt;code&gt;Rollout&lt;/code&gt; object. This rollout progresses through your defined stages sequentially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control plane upgrades start in the first stage. Once all control planes in that stage reach the target version, a stage soak timer begins.&lt;/li&gt;
&lt;li&gt;Node upgrades run in parallel with control plane upgrades, respecting node pool upgrade strategies such as surge or blue-green.&lt;/li&gt;
&lt;li&gt;When both control planes and nodes complete their upgrade and satisfy the configured soak duration, the rollout advances to the next stage in the sequence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If an individual stage contains clusters that take longer than 30 days to finish upgrading—due to restrictive maintenance windows or exclusions—GKE triggers a forced soak period to avoid stalling the entire multi-stage pipeline indefinitely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Granular stages with label selectors
&lt;/h2&gt;

&lt;p&gt;Earlier fleet-based rollout sequencing operated strictly at the fleet level, meaning an entire fleet had to upgrade before another fleet could begin. Custom stages introduce the ability to split a single fleet into multiple granular rollout phases using Common Expression Language (CEL) label selectors.&lt;/p&gt;

&lt;p&gt;For example, within a production fleet, you can label a subset of clusters as canary targets and upgrade them before the rest of production.&lt;/p&gt;

&lt;p&gt;Here is an example YAML manifest defining a three-stage sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fleet-projects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;projects/dev-fleet-host&lt;/span&gt;
  &lt;span class="na"&gt;soak-duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3d&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fleet-projects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;projects/prod-fleet-host&lt;/span&gt;
  &lt;span class="na"&gt;label-selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;resource.labels.tier=='canary'&lt;/span&gt;
  &lt;span class="na"&gt;soak-duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;4d&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fleet-projects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;projects/prod-fleet-host&lt;/span&gt;
  &lt;span class="na"&gt;soak-duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;7d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When structuring custom stages, keep two architectural rules in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Catch-all requirement&lt;/strong&gt;: If you use a label selector to target a subset of clusters in a fleet, the final stage referencing that fleet must omit the label selector. This acts as a catch-all stage to guarantee that all remaining clusters in the fleet are upgraded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict resolution&lt;/strong&gt;: If a cluster matches multiple stages within a sequence, GKE assigns that cluster exclusively to the earliest matching stage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can register this configuration using the Google Cloud CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container fleet rolloutsequences create prod-rollout-sequence &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--display-name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Production rollout sequence"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stage-config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rollout-sequence.yaml &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;central-management-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Operational controls and upgrade scoping
&lt;/h2&gt;

&lt;p&gt;Real-world production environments require operational agility when unexpected workload anomalies occur. Rollout sequencing with custom stages provides real-time lifecycle controls over active rollouts without requiring you to dismantle your configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pause and resume&lt;/strong&gt;: If an issue arises during validation in a canary stage, you can pause the active rollout. Pausing stops GKE from initiating new cluster upgrades in that stage and subsequent stages while allowing running operations to finish. Once mitigated, you can resume the rollout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stage completion&lt;/strong&gt;: If automated testing confirms stability before a soak timer finishes, platform operators can execute a stage completion action (&lt;code&gt;force-complete-stage&lt;/code&gt;). This skips the remaining soak duration and moves the rollout immediately to the next stage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollout cancellation&lt;/strong&gt;: If a version introduces an unresolvable regression, you can cancel the rollout. Canceling stops the progression of that specific target version across the sequence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to runtime actions, you can restrict the automatic upgrade scope for a rollout sequence. If your platform policy requires manual control over major and minor Kubernetes version changes while automating security patches, you can configure your sequence to roll out only control plane patch upgrades and node patch upgrades.&lt;/p&gt;

&lt;p&gt;However, mandatory upgrades—such as control planes that have not received a patch in 90 days or clusters reaching the end of version support—will continue to execute to preserve cluster stability and security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-tenant and cross-organization management
&lt;/h2&gt;

&lt;p&gt;For enterprises with distributed topologies, rollout sequences support cross-project and cross-organization fleet memberships. Following continuous delivery best practices, Google recommends creating and maintaining &lt;code&gt;RolloutSequence&lt;/code&gt; resources in a dedicated host project.&lt;/p&gt;

&lt;p&gt;A single rollout sequence can define up to 15 distinct stages, and fleets can accommodate up to 250 clusters (or up to 2,000 clusters when using lightweight memberships with an approved quota increase). Across all stages in a sequence, you can configure a total soak duration of up to 90 days, with individual stage soak times configured up to 30 days.&lt;/p&gt;

&lt;p&gt;By shifting from regional upgrade schedules to business-aligned rollout sequences, platform engineers can automate Kubernetes lifecycle management while maintaining safety, visibility, and control across their entire fleet.&lt;/p&gt;

&lt;p&gt;To implement progressive cluster upgrades in your environment, explore the official &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/rollout-sequencing-custom-stages/about-rollout-sequencing" rel="noopener noreferrer"&gt;GKE rollout sequencing documentation&lt;/a&gt; to review detailed configuration parameters, CEL filter syntax, and gcloud CLI commands.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Taking control of cluster security: A deep dive into GKE ClusterNetworkPolicy</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Tue, 25 Aug 2026 20:44:29 +0000</pubDate>
      <link>https://dev.to/googlecloud/taking-control-of-cluster-security-a-deep-dive-into-gke-clusternetworkpolicy-536c</link>
      <guid>https://dev.to/googlecloud/taking-control-of-cluster-security-a-deep-dive-into-gke-clusternetworkpolicy-536c</guid>
      <description>&lt;p&gt;In Kubernetes, network security has historically been a developer-centric responsibility. Standard Kubernetes &lt;code&gt;NetworkPolicy&lt;/code&gt; objects are namespace-scoped. While this works beautifully for isolating individual microservices within a single application boundary, it introduces major operational headaches at scale. As clusters grow to accommodate multiple teams, business units, and environments, platform administrators are left without a native mechanism to enforce global security guardrails.&lt;/p&gt;

&lt;p&gt;If you want to ensure that every pod in your cluster is blocked from reaching the cloud metadata server, or that certain namespaces are completely isolated from all others, you are forced to rely on complex policy engines, custom admission controllers, or automating the injection of namespace-scoped policies. This approach is fragile and difficult to audit.&lt;/p&gt;

&lt;p&gt;The introduction of the &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/configure-cluster-network-policy/" rel="noopener noreferrer"&gt;GKE ClusterNetworkPolicy&lt;/a&gt; (currently in Public Preview) addresses this challenge. It introduces a cluster-scoped resource that allows security and platform teams to establish non-overridable security boundaries across the entire cluster, spanning all namespaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluation hierarchy
&lt;/h2&gt;

&lt;p&gt;To understand ClusterNetworkPolicy, you must first understand how GKE evaluates network traffic. Unlike standard namespace-scoped &lt;code&gt;NetworkPolicy&lt;/code&gt; resources, which are additive (meaning if multiple policies select a pod, the traffic is allowed if any policy permits it), ClusterNetworkPolicy uses a strict, sequential evaluation pipeline where the first matching rule wins.&lt;/p&gt;

&lt;p&gt;Traffic flows through three distinct policy tiers in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Admin tier&lt;/strong&gt;: Policies in this tier are evaluated first. This is where administrators define mandatory guardrails that developers cannot bypass. If a rule in this tier matches a traffic flow with an &lt;code&gt;Accept&lt;/code&gt; or &lt;code&gt;Deny&lt;/code&gt; verdict, evaluation stops immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NetworkPolicy tier&lt;/strong&gt;: If traffic is not explicitly allowed or blocked by the Admin tier, it falls through to standard namespace-scoped &lt;code&gt;NetworkPolicy&lt;/code&gt; resources configured by DevOps teams and developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Baseline tier&lt;/strong&gt;: If no namespace-scoped policies match the traffic, it falls through to the Baseline tier. Here, administrators can define fallback policies, such as a default-deny posture, which developers can choose to override in their respective namespaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default GKE behavior&lt;/strong&gt;: If a packet matches no rules in any tier, it falls back to GKE's default behavior, which is an implicit allow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Within each tier, policies are evaluated based on an explicit numeric priority (0 to 1000, where lower numbers indicate higher precedence). Inside a single policy object, rules are evaluated from top to bottom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict actions: Accept, deny, pass
&lt;/h2&gt;

&lt;p&gt;Every rule in a ClusterNetworkPolicy must trigger one of three actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deny&lt;/strong&gt;: Blocks the traffic immediately. This action short-circuits the evaluation pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept&lt;/strong&gt;: Permits the traffic immediately. This also short-circuits the pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pass&lt;/strong&gt;: Transfers the evaluation to the next tier in the hierarchy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Pass&lt;/code&gt; action is particularly powerful. It enables platform administrators to target specific traffic flows—for example, web traffic on port 8080—and delegate the final decision to namespace owners. The traffic will bypass any remaining rules in the Admin tier and be evaluated against standard namespace-scoped network policies. If the namespace owners configure a policy to accept the traffic, it is allowed; if they have no policy, the traffic proceeds to the Baseline tier. This strikes a balance between centralized compliance and developer agility.&lt;/p&gt;

&lt;h2&gt;
  
  
  YAML examples
&lt;/h2&gt;

&lt;p&gt;Let's examine how to write these policies. Consider a scenario where you want to isolate a sensitive namespace from all internal cluster traffic. By placing this policy in the &lt;code&gt;Admin&lt;/code&gt; tier, you guarantee that namespace-scoped policies cannot override it.&lt;/p&gt;

&lt;p&gt;Here is a manifest for a global deny policy targeting a sensitive namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;policy.networking.k8s.io/v1alpha2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterNetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cluster-wide-deny-sensitive&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Admin&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;namespaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;kubernetes.io/metadata.name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sensitive-ns&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deny&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny-all-ingress&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;namespaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;egress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deny&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny-all-egress&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;namespaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, consider a different scenario: you want to establish a default-deny posture across the cluster, but you want to allow developers to open up traffic as needed for their applications. For this, you use the &lt;code&gt;Baseline&lt;/code&gt; tier.&lt;/p&gt;

&lt;p&gt;Here is a baseline default-deny policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;policy.networking.k8s.io/v1alpha2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterNetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default-deny-baseline&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Baseline&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;namespaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deny&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;baseline-deny-all&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;namespaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a developer in the namespace &lt;code&gt;my-app-ns&lt;/code&gt; needs to allow ingress traffic to their frontend service from an external ingress controller, they can simply deploy a standard namespace-scoped &lt;code&gt;NetworkPolicy&lt;/code&gt; that permits that traffic. Because the standard policy is evaluated in the &lt;code&gt;NetworkPolicy&lt;/code&gt; tier (which runs before the &lt;code&gt;Baseline&lt;/code&gt; tier), GKE will permit the traffic without needing platform admin intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;The GKE implementation of ClusterNetworkPolicy is built entirely on open-source Cilium, reinforcing a commitment to community-driven foundations. GKE backported this support to Cilium 1.19 for GKE clusters, and the upstream capability will be generally available to the broader open-source ecosystem starting with Cilium 1.20.&lt;/p&gt;

&lt;p&gt;To use this feature, your GKE clusters must meet the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run GKE version 1.36.0-gke.4447000 or later.&lt;/li&gt;
&lt;li&gt;Use GKE Dataplane V2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As this feature is in Public Preview, there are a few scale limits to keep in mind. Specifically, a single &lt;code&gt;ClusterNetworkPolicy&lt;/code&gt; object can contain a maximum of 100 ingress rules and 100 egress rules. You can monitor traffic flow verdicts and troubleshoot your policies using GKE Dataplane V2 Observability tools.&lt;/p&gt;

&lt;p&gt;By decoupling cluster-wide guardrails from namespace-level configurations, ClusterNetworkPolicy gives security teams the control they need without hindering developer speed.&lt;/p&gt;

&lt;p&gt;To get started with configuring cluster-wide security policies on your clusters, check out the official &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/configure-cluster-network-policy/" rel="noopener noreferrer"&gt;GKE ClusterNetworkPolicy documentation&lt;/a&gt; for step-by-step guides and YAML examples.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Seamless scaling with VPA In-place Pod Resize on GKE</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Thu, 04 Jun 2026 18:19:03 +0000</pubDate>
      <link>https://dev.to/googlecloud/seamless-scaling-with-vpa-in-place-pod-resize-on-gke-117p</link>
      <guid>https://dev.to/googlecloud/seamless-scaling-with-vpa-in-place-pod-resize-on-gke-117p</guid>
      <description>&lt;p&gt;Right-sizing Kubernetes workloads is a common platform engineering challenge. Set your requests too high, and you burn cloud budgets on idle capacity; set your limits too low, and your applications face throttling or dreaded OOMKills.&lt;/p&gt;

&lt;p&gt;For years, the &lt;a href="https://cloud.google.com/kubernetes-engine/docs/concepts/verticalpodautoscaler?utm_campaign=CDR_0x5723eddc_default_b464422378&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Vertical Pod Autoscaler (VPA)&lt;/strong&gt;&lt;/a&gt; has been the standard answer to this problem, automatically adjusting CPU and memory requirements based on actual usage. However, this method of scaling came with a significant catch that prevented widespread adoption for critical workloads: applying new resource parameters required evicting and restarting the pod.&lt;/p&gt;

&lt;p&gt;This disruption was often unacceptable for stateful applications, long-running connections, or latency-sensitive services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing In-place Pod Resize (IPPR) on GKE
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/kubernetes-engine/docs/concepts/verticalpodautoscaler?utm_campaign=CDR_0x5723eddc_default_b464422378&amp;amp;utm_medium=external&amp;amp;utm_source=blog#inplaceorrecreate_mode" rel="noopener noreferrer"&gt;&lt;strong&gt;In-place Pod Resize (IPPR)&lt;/strong&gt;&lt;/a&gt; changes the game by allowing Kubernetes to modify resource requests and limits on live, running containers directly through the underlying container runtime, &lt;em&gt;without&lt;/em&gt; triggering a restart.&lt;/p&gt;

&lt;p&gt;By combining the intelligence of VPA with the non-disruptive nature of IPPR, GKE users finally have a viable path to dynamic, seamless, and automated right-sizing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: As of writing, VPA IPPR is in Preview on GKE. While it is a massive step forward, I recommend evaluating it in staging environments before rolling it out to production workloads.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with IPPR
&lt;/h2&gt;

&lt;p&gt;To use In-place Pod Resize, you need a &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/choose-cluster-mode?utm_campaign=CDR_0x5723eddc_default_b464422378&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;GKE cluster&lt;/a&gt; running version &lt;strong&gt;1.34.0-gke.2201000 or later&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GKE Autopilot:&lt;/strong&gt; VPA is enabled by default.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GKE Standard:&lt;/strong&gt; Requires the Vertical Pod Autoscaling feature to be enabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Enable the feature
&lt;/h3&gt;

&lt;p&gt;If you aren't using Autopilot, ensure your cluster is created or updated with the necessary feature flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters create CLUSTER_NAME &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PROJECT_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--release-channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rapid &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--enable-vertical-pod-autoscaling&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Define your VPA object
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;VerticalPodAutoscaler&lt;/code&gt; resource targeting your Deployment or StatefulSet. The crucial element here is setting &lt;code&gt;spec.updatePolicy.updateMode&lt;/code&gt; to &lt;code&gt;InPlaceOrRecreate&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;autoscaling.k8s.io/v1"&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VerticalPodAutoscaler"&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-vpa"&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps/v1"&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deployment"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-deployment"&lt;/span&gt;
  &lt;span class="na"&gt;updatePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;updateMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;InPlaceOrRecreate"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Watch it scale
&lt;/h3&gt;

&lt;p&gt;Apply the resource to your cluster and monitor your application under load. Instead of watching Pods terminate and recreate, you can watch the resources modify live using &lt;code&gt;kubectl describe&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe pod POD_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the &lt;em&gt;AllocatedResources&lt;/em&gt; field or check the events section. You will see the requests change in real-time to match the VPA recommendations, while the &lt;em&gt;Restart Count&lt;/em&gt; remains exactly the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Or Recreate" Fallback:&lt;/strong&gt; Keep in mind that physics still apply. If VPA recommends a resource size that exceeds the remaining capacity of the Node your Pod is currently running on, an in-place resize is impossible. In this scenario, VPA will fall back to evicting and recreating the Pod so it can be scheduled onto a larger or emptier Node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to dive deeper?
&lt;/h2&gt;

&lt;p&gt;While this introduction covers the basics of IPPR, right-sizing is just one part of a robust scaling strategy. Implementing VPA often goes hand-in-hand with horizontal scaling and cluster autoscaling. Check out the guide to master scaling on GKE: &lt;a href="https://cloud.google.com/kubernetes-engine/docs/tutorials/full-stack-scale?utm_campaign=CDR_0x5723eddc_default_b464422378&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Run full-stack workloads at scale on GKE&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Surviving the eviction: How to build interrupt-resilient AI workloads on GKE</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Tue, 02 Jun 2026 20:02:20 +0000</pubDate>
      <link>https://dev.to/googlecloud/surviving-the-eviction-how-to-build-interrupt-resilient-ai-workloads-on-gke-5581</link>
      <guid>https://dev.to/googlecloud/surviving-the-eviction-how-to-build-interrupt-resilient-ai-workloads-on-gke-5581</guid>
      <description>&lt;p&gt;You did everything right. You containerized your massive model training job, deployed it to Google Kubernetes Engine (GKE), and cleverly routed it to a Spot VM node pool to save up to 90% on compute costs.&lt;/p&gt;

&lt;p&gt;Everything is humming along perfectly for 38 hours. Then, a priority on-demand customer needs capacity, Google Cloud reclaims your underlying Spot VM, and your node vanishes.&lt;/p&gt;

&lt;p&gt;Whether you are using preemptible &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/spot-vms?utm_campaign=CDR_0x5723eddc_default_b510018167&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Spot VMs&lt;/strong&gt;&lt;/a&gt; to save money, or leveraging the &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/how-to/provisioningrequest?utm_campaign=CDR_0x5723eddc_default_b510018167&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Dynamic Workload Scheduler (DWS)&lt;/strong&gt;&lt;/a&gt; to queue for scarce GPUs, you are building on top of ephemeral compute. The hardware &lt;em&gt;will&lt;/em&gt; eventually be taken away. To successfully run critical AI workloads on un-committed capacity, your application architecture must assume failure is a given.&lt;/p&gt;

&lt;p&gt;Here is a practical guide to building interruptible workloads on GKE.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Trap the warning
&lt;/h2&gt;

&lt;p&gt;When Google Cloud reclaims a Spot VM, it doesn't just pull the power cord immediately. It sends an &lt;a href="https://uefi.org/acpi" rel="noopener noreferrer"&gt;ACPI signal&lt;/a&gt; to the underlying node to begin a power off cycle. Kubernetes intercepts this and translates it into a SIGTERM signal sent directly to your running containers.&lt;/p&gt;

&lt;p&gt;You have a &lt;strong&gt;grace period&lt;/strong&gt; (up to 15 seconds for non-system pods) between that SIGTERM and the fatal SIGKILL.&lt;/p&gt;

&lt;p&gt;Your application must explicitly listen for this signal. When caught, your code should immediately stop accepting new batches, finish its current loop, flush any in-memory data to disk, and exit with a 0 (success) status.&lt;/p&gt;

&lt;p&gt;Here is a simple example on how to catch this signal in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_sigterm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Received SIGTERM. Initiating graceful shutdown...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Stop processing new data
&lt;/span&gt;    &lt;span class="c1"&gt;# 2. Flush memory to persistent storage
&lt;/span&gt;    &lt;span class="c1"&gt;# 3. Save final checkpoint
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;State saved. Exiting cleanly.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Register the signal handler
&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGTERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handle_sigterm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Your main training loop
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting training loop...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Train model...
&lt;/span&gt;    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Externalize your checkpoints
&lt;/h2&gt;

&lt;p&gt;If your container dies, everything inside its local filesystem dies with it. To survive an interruption, you must periodically save your progress (model weights, optimizer states, epoch counters, etc.) to an external storage location.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/storage?utm_campaign=CDR_0x5723eddc_default_b510018167&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Cloud Storage (GCS)&lt;/strong&gt;&lt;/a&gt; is a common solution for this on Google Cloud.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Save frequently:&lt;/strong&gt; Decide on a checkpointing interval that balances the cost of lost work against the overhead of writing to storage. Saving every epoch or every few thousand steps is common, but this can vary based on your needs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it local:&lt;/strong&gt; Ensure your GCS buckets are in the same region as your GKE cluster (e.g., us-central1) to minimize latency and avoid outbound data transfer fees.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resume, don't restart:&lt;/strong&gt; The first thing your container's startup script should do is to check for that GCS bucket. If a checkpoint exists in the bucket, load it and resume from that exact step.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Design for Idempotency
&lt;/h2&gt;

&lt;p&gt;"Idempotency" is a fancy way of saying that doing something twice yields the same result as doing it once.&lt;/p&gt;

&lt;p&gt;Imagine a batch inference job that reads an image, processes it, and writes the result to a database. If your pod is preempted milliseconds &lt;em&gt;after&lt;/em&gt; writing to the database but &lt;em&gt;before&lt;/em&gt; it can mark the task as complete, the rescheduled pod will likely process that image again.&lt;/p&gt;

&lt;p&gt;If your database blindly inserts new rows, you now have unintentional, duplicate data.&lt;/p&gt;

&lt;p&gt;To build an idempotent pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use UPSERT (update or insert) operations in your database based on a unique identifier (like an image ID).
&lt;/li&gt;
&lt;li&gt;Check if a record already exists before spending expensive GPU cycles processing it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Decouple work queues for batch processing
&lt;/h2&gt;

&lt;p&gt;If you are running a massive batch processing or inference job across thousands of files, do not write a monolithic Python script that iterates through a static CSV list. If the node dies at row 5,000, managing the state of where to restart is a nightmare.&lt;/p&gt;

&lt;p&gt;Instead, decouple the workload:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Publish the work:&lt;/strong&gt; Break your dataset down into discrete messages and push them into a message broker like &lt;a href="https://docs.cloud.google.com/pubsub/docs?utm_campaign=CDR_0x5723eddc_default_b510018167&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Pub/Sub&lt;/strong&gt;&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull the work:&lt;/strong&gt; Have your Spot VM worker pods pull messages off the queue one by one or as a small chunk (e.g. 10 at a time).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acknowledge completion:&lt;/strong&gt; Only send an "ACK" (acknowledgment) back to Pub/Sub once the result is safely stored.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a Spot node is preempted mid-inference, the worker dies before sending the ACK. After a brief timeout, Pub/Sub will automatically make that specific message available again. Another surviving worker pod will pick it up seamlessly. No data lost, no manual intervention required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;Running on ephemeral compute like Spot VMs isn't just an infrastructure choice; it is a design choice. By handling termination signals, checkpointing aggressively to GCS, ensuring idempotent operations, and decoupling your queues, you can unlock massive cost savings and tap into scarce GPU pools without sacrificing reliability.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Strategies for running AI workloads on GKE without committed quota</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Mon, 01 Jun 2026 18:54:52 +0000</pubDate>
      <link>https://dev.to/googlecloud/strategies-for-running-ai-workloads-on-gke-without-committed-quota-484l</link>
      <guid>https://dev.to/googlecloud/strategies-for-running-ai-workloads-on-gke-without-committed-quota-484l</guid>
      <description>&lt;p&gt;You’ve built your model, your training code is containerized, and you’re ready to scale up on Google Kubernetes Engine (GKE). You go to provision your nvidia-h100-80gb node pool and... QUOTA_EXCEEDED.&lt;/p&gt;

&lt;p&gt;It’s one of the most common (and frustrating) roadblocks in modern AI development. High-end accelerators like H100s, A100s, and TPUs are in massive demand, and securing permanent, on-demand quota for them can be difficult. But a lack of &lt;em&gt;on-demand&lt;/em&gt; quota doesn't mean you're out of options.&lt;/p&gt;

&lt;p&gt;GKE provides two powerful, cost-effective strategies for acquiring these scarce resources when you can't get standard, on-demand instances: &lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/spot-vms?utm_campaign=CDR_0x5723eddc_default_b455559749&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Spot VMs&lt;/strong&gt;&lt;/a&gt; and the &lt;a href="https://cloud.google.com/kubernetes-engine/docs/how-to/provisioningrequest?utm_campaign=CDR_0x5723eddc_default_b455559749&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Dynamic Workload Scheduler (DWS)&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's break down what they are, when to use each, and how to implement them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategy 1: Spot VMs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/spot-vms?utm_campaign=CDR_0x5723eddc_default_b455559749&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Spot VMs&lt;/strong&gt;&lt;/a&gt; are Google Cloud's excess compute capacity sold at a massive discount, up to 90% off the price of standard on-demand VMs. They are perfect for workloads that can be interrupted.&lt;/p&gt;

&lt;p&gt;The catch is that Spot VMs have no availability guarantee. Google Cloud can "preempt" (i.e., terminate) them at any time if that capacity is needed for on-demand customers. GKE gets a &lt;strong&gt;30-second warning&lt;/strong&gt; before the node is terminated. Kubernetes uses this window to gracefully shut down your application (giving non-system pods up to 15 seconds to wrap up) before the node vanishes.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use Spot VMs for accelerators
&lt;/h3&gt;

&lt;p&gt;Spot VMs are ideal for workloads that are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fault-tolerant and stateless:&lt;/strong&gt; Your application can handle a node vanishing and having its pods rescheduled elsewhere.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch processing:&lt;/strong&gt; Jobs that can be easily restarted or have checkpointing built-in.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipelines:&lt;/strong&gt; Running tests or builds that don't need 100% uptime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to use Spot VMs in GKE
&lt;/h3&gt;

&lt;p&gt;You can easily add a Spot VM node pool to your GKE Standard cluster. The key is to use Spot VMs for your workers, not your critical system pods.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a dedicated Spot VM node pool:&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;When creating a node pool, simply add the --spot flag and apply a taint so standard pods don't accidentally schedule there.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container node-pools create spot-gpu-pool &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;northamerica-northeast2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--machine-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;g2-standard-4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nvidia-l4,count&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--spot&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node-taints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cloud.google.com/gke-spot&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;:NoSchedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add the toleration to your workload's YAML:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# You want to "tolerate" that taint only on the specific workloads you want to run there.&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-batch-job&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ... other specs&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cloud.google.com/gke-spot"&lt;/span&gt;
        &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Equal"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NoSchedule"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This architecture ensures your critical components stay on reliable on-demand nodes, while your interruptible training jobs run on the preemptible Spot nodes. &lt;em&gt;(Note: If you are using GKE Autopilot, you simply request a Spot class in your pod spec and GKE handles the taints and nodes automatically!)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategy 2: Dynamic Workload Scheduler (DWS) with flex-start
&lt;/h2&gt;

&lt;p&gt;What if your job &lt;em&gt;can't&lt;/em&gt; be interrupted? Many large-scale training jobs can take days. While they might have checkpointing, restarting from scratch every few hours due to Spot preemptions is inefficient and costly.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://cloud.google.com/kubernetes-engine/docs/how-to/provisioningrequest?utm_campaign=CDR_0x5723eddc_default_b455559749&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;&lt;strong&gt;Dynamic Workload Scheduler (DWS)&lt;/strong&gt;&lt;/a&gt; comes in.&lt;/p&gt;

&lt;p&gt;DWS is a feature designed specifically for acquiring large amounts of scarce resources (like GPUs and TPUs) for batch workloads. It changes the request from "Give me this GPU &lt;em&gt;right now&lt;/em&gt;" to "Give me this GPU &lt;em&gt;when it becomes available&lt;/em&gt;."&lt;/p&gt;

&lt;p&gt;The catch here is that your job doesn't start immediately. It enters a queue and might wait for minutes, hours, or even days for the resources to be provisioned.&lt;/p&gt;

&lt;p&gt;There are a few massive upsides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It's a "get-in-line" system:&lt;/strong&gt; Instead of you writing a script to retry the gcloud command every 5 minutes, DWS queues your request and provisions the nodes automatically when capacity is found.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No preemptions:&lt;/strong&gt; Once your DWS nodes are provisioned, they are &lt;strong&gt;yours for the entire duration&lt;/strong&gt; of your job (up to seven days). They are not Spot VMs and will not be preempted.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost savings:&lt;/strong&gt; DWS workloads are also offered at a significant discount (up to 53% for L4 GPUs) compared to on-demand instances.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  When to use DWS
&lt;/h3&gt;

&lt;p&gt;DWS is perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model training or reinforcement learning (RL):&lt;/strong&gt; Jobs that need to run uninterrupted for many hours or days.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch inference:&lt;/strong&gt; Running a large inference job on a massive dataset.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Any workload that is not time-sensitive to &lt;em&gt;start&lt;/em&gt;, but is sensitive to &lt;em&gt;interruptions&lt;/em&gt;.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to use DWS with flex-start
&lt;/h3&gt;

&lt;p&gt;The flex-start mode in DWS is what enables this "wait-in-queue" behavior. If you are using a &lt;strong&gt;GKE Autopilot&lt;/strong&gt; cluster (or a Standard cluster with Node Auto-provisioning enabled), implementing this is incredibly simple.&lt;/p&gt;

&lt;p&gt;You do not need to create complex custom resources; you simply signal your intent via a nodeSelector in your standard Kubernetes Job object.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Request flex-start in your Job:&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In your Job.yaml, add the cloud.google.com/gke-flex-start: "true" node selector alongside your accelerator request.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Job&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-training-job&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;cloud.google.com/gke-flex-start&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
        &lt;span class="na"&gt;cloud.google.com/gke-accelerator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nvidia-tesla-a100&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-trainer&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gcr.io/my-project/my-training-image"&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Never&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you apply this Job, GKE sees the flex-start selector. It puts the Job's Pods into a Pending state until the DWS queueing system can provision the requested A100 node. Once the node is ready, the Pod is scheduled, your job runs to completion without interruption, and the node is automatically deprovisioned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which strategy should you choose?
&lt;/h2&gt;

&lt;p&gt;Here's a simple cheat sheet:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/spot-vms?utm_campaign=CDR_0x5723eddc_default_b455559749&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;Spot VMs&lt;/a&gt;&lt;/th&gt;
&lt;th&gt;&lt;a href="https://cloud.google.com/kubernetes-engine/docs/how-to/provisioningrequest?utm_campaign=CDR_0x5723eddc_default_b455559749&amp;amp;utm_medium=external&amp;amp;utm_source=blog" rel="noopener noreferrer"&gt;DWS with flex-start&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fault-tolerant, interruptible workloads&lt;/td&gt;
&lt;td&gt;Long-running, uninterruptible batch jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary trade-off&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Starts fast, can be preempted at any time&lt;/td&gt;
&lt;td&gt;Can wait hours/days to start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost savings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 90%&lt;/td&gt;
&lt;td&gt;Up to 50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GKE mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standard or Autopilot&lt;/td&gt;
&lt;td&gt;Standard or Autopilot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;--spot flag in a Node Pool&lt;/td&gt;
&lt;td&gt;cloud.google.com/gke-flex-start nodeSelector&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;By mastering both Spot VMs and the Dynamic Workload Scheduler, you can build a resilient and cost-effective AI platform on GKE, even when on-demand accelerator quota seems impossible to find.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>ai</category>
      <category>gke</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Hands-on with Gemma 3 on Google Cloud</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Fri, 05 Dec 2025 16:31:49 +0000</pubDate>
      <link>https://dev.to/googleai/hands-on-with-gemma-3-on-google-cloud-6e7</link>
      <guid>https://dev.to/googleai/hands-on-with-gemma-3-on-google-cloud-6e7</guid>
      <description>&lt;p&gt;The landscape of generative AI is shifting. While proprietary APIs are powerful, there is a growing demand for &lt;strong&gt;open models&lt;/strong&gt;—models where the architecture and weights are publicly available. This shift puts control back in the hands of developers, offering transparency, data privacy, and the ability to fine-tune for specific use cases.&lt;/p&gt;

&lt;p&gt;To help you navigate this landscape, we are releasing &lt;strong&gt;two new hands-on labs&lt;/strong&gt; featuring &lt;a href="https://ai.google.dev/gemma?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;Gemma 3&lt;/a&gt;, Google’s latest family of lightweight, state-of-the-art open models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Gemma?
&lt;/h2&gt;

&lt;p&gt;Built from the same research and technology as Gemini, Gemma models are designed for responsible AI development. Gemma 3 is particularly exciting because it offers multimodal capabilities (text and image) and fits efficiently on smaller hardware footprints while delivering massive performance.&lt;/p&gt;

&lt;p&gt;But running a model on your laptop is very different from running it in production. You need scale, reliability, and hardware acceleration (GPUs). The question is: &lt;strong&gt;Where should you deploy?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have prepared two different paths for you, depending on your infrastructure needs: &lt;a href="https://docs.cloud.google.com/run/docs?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;Cloud Run&lt;/a&gt; or &lt;a href="https://cloud.google.com/kubernetes-engine/docs?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;Google Kubernetes Engine (GKE)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Path 1: The Serverless Approach (Cloud Run)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers who want an API up and running instantly without managing infrastructure, scaling to zero when not in use.&lt;/p&gt;

&lt;p&gt;If your priority is simplicity and cost-efficiency for stateless workloads, Cloud Run is your answer. It abstracts away the server management entirely. With the recent addition of GPU support on Cloud Run, you can now serve modern LLMs without provisioning a cluster.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  
&lt;h3&gt;
  
  
  Start the lab!
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab:&lt;/strong&gt; &lt;a href="https://codelabs.developers.google.com/devsite/codelabs/serve-gemma3-with-vllm-on-cloud-run#0?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;Serving Gemma 3 with vLLM on Cloud Run&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objectives:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Containerize &lt;strong&gt;vLLM&lt;/strong&gt; (a high-throughput serving engine).&lt;/li&gt;
&lt;li&gt;Deploy Gemma 3 to &lt;strong&gt;Cloud Run&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Leverage GPU acceleration for fast inference.&lt;/li&gt;
&lt;li&gt;Expose an OpenAI-compatible API endpoint.&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;h2&gt;
  
  
  Path 2: The Platform Approach (GKE)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Engineering teams building complex AI platforms, requiring high throughput, custom orchestration, or integration with a broader microservices ecosystem.&lt;/p&gt;

&lt;p&gt;When your application graduates from a prototype to a high-traffic production system, you need the control of Kubernetes. GKE Autopilot gives you that power while still handling the heavy lifting of node management. This path creates a seamless journey from local testing to cloud production.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  
&lt;h3&gt;
  
  
  Start the lab!
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Lab:&lt;/strong&gt; &lt;a href="https://codelabs.developers.google.com/codelabs/production-ready-ai-with-gc/5-deploying-agents/deploying-open-models-gke#0?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;Deploying Open Models on GKE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this lab, you will learn how to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prototype locally using &lt;strong&gt;&lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Containerize your setup and transition to &lt;strong&gt;&lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/autopilot-overview?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;GKE Autopilot&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Deploy a scalable inference service using standard Kubernetes manifests.&lt;/li&gt;
&lt;li&gt;Manage resources effectively for production workloads.&lt;/li&gt;
&lt;/ul&gt;


&lt;/div&gt;


&lt;h2&gt;
  
  
  Which Path Will You Choose?
&lt;/h2&gt;

&lt;p&gt;Whether you are looking for the serverless simplicity of Cloud Run or the robust orchestration of GKE, Google Cloud provides the tools to take Gemma 3 from a concept to a deployed application.&lt;/p&gt;

&lt;p&gt;Dive into the labs today and start building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codelabs.developers.google.com/devsite/codelabs/serve-gemma3-with-vllm-on-cloud-run#0?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;Serving Gemma 3 with vLLM on Cloud Run&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codelabs.developers.google.com/codelabs/production-ready-ai-with-gc/5-deploying-agents/deploying-open-models-gke#0?utm_campaign=CDR_0x5723eddc_default_b459438884&amp;amp;utm_medium=external&amp;amp;utm_source=lab" rel="noopener noreferrer"&gt;Deploying Open Models on GKE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Share your progress and connect with others on the journey using the hashtag &lt;strong&gt;#ProductionReadyAI&lt;/strong&gt;. Happy learning!&lt;/p&gt;

&lt;p&gt;These labs are part of the &lt;strong&gt;Open Models&lt;/strong&gt; module in our official &lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/production-ready-ai-with-google-cloud-learning-path" rel="noopener noreferrer"&gt;Production-Ready AI with Google Cloud&lt;/a&gt; program. Explore the full curriculum for more content that will help you bridge the gap from a promising prototype to a production-grade AI application.&lt;/p&gt;

</description>
      <category>gemma</category>
      <category>ai</category>
      <category>cloud</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Observability in Action: A Google Cloud Next demo</title>
      <dc:creator>Olivier Bourgeois</dc:creator>
      <pubDate>Mon, 05 May 2025 18:17:47 +0000</pubDate>
      <link>https://dev.to/googlecloud/observability-in-action-a-google-cloud-next-demo-2fkb</link>
      <guid>https://dev.to/googlecloud/observability-in-action-a-google-cloud-next-demo-2fkb</guid>
      <description>&lt;p&gt;It was only a few weeks ago that over 32,000 cloud practitioners from all over the world came together in Las Vegas to attend &lt;a href="https://cloud.withgoogle.com/next/25" rel="noopener noreferrer"&gt;Google Cloud Next 2025&lt;/a&gt;. Beyond the keynotes, the workshops, and the multiple jam-packed tracks of talks and sessions, an entire expo hall offered attendees the opportunity to observe or play around with more than 500 live demos. Let’s check out one of these demos!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Overview of the demo
&lt;/h2&gt;

&lt;p&gt;The main goals of the Observability in Action demo were twofold. We wanted to showcase various ways of interacting with metrics and logs. And we wanted to give attendees a little bit of an interactive experience. For the interactive part of the demo, we utilized various oversized physical buttons and pedals that could be used to select answers or confirm inputs.&lt;/p&gt;

&lt;p&gt;The flow of the demo was as followed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We ask the attendee to type in a prompt that they wanted sent to an AI model.
&lt;/li&gt;
&lt;li&gt;The prompt was sent in the background to three different models: Gemma 3 on Cloud Run, Gemini 2.0 Flash on Vertex AI, and Gemini 2.0 Flash-Lite on Vertex AI. This generated logs and metrics.
&lt;/li&gt;
&lt;li&gt;The attendee was then given a short quiz about these three models. Each quiz input also generated logs and metrics.
&lt;/li&gt;
&lt;li&gt;At the end of the quiz, we give the attendee a rundown of their answers, and then flip over to the Google Cloud Console.
&lt;/li&gt;
&lt;li&gt;In Cloud Monitoring, we showcase the various native metrics that Cloud Run offers, custom metrics implemented using OpenTelemetry, as well as the Cloud Trace functionality.
&lt;/li&gt;
&lt;li&gt;Finally, we turn to BigQuery to showcase how we can mirror logs to a database for further analysis using Jupyter Notebooks.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;While the demo frontend runs locally, the backend is deployed as a Cloud Run instance. This instance is then talking to Gemini through the Vertex AI SDK and to Gemma through its own Cloud Run instance. The persistent state of the demo resides in a Firestore database. All Cloud Run logs are mirrored to BigQuery using a simple sink.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Visualizing metrics using Cloud Monitoring
&lt;/h2&gt;

&lt;p&gt;Cloud Monitoring provides visibility into the performance and health of your cloud applications and infrastructure. It collects metrics, events, and metadata from Google Cloud services and other sources, allowing you to visualize this data on dashboards and create alerts for critical issues. This is useful for proactively identifying and resolving problems, optimizing resource utilization, improving uptime, and understanding system behavior, ultimately leading to more reliable and cost-effective applications.&lt;/p&gt;

&lt;p&gt;For services like Cloud Run which we’re using for the backend of this demo, Cloud Monitoring automatically collects a wide array of native metrics without any setup needed. This includes data points such as request latency, count, container CPU and memory usage, and instance counts. This out-of-the-box integration means developers get immediate insights into their serverless application's performance and resource consumption, simplifying troubleshooting and optimization efforts.&lt;/p&gt;

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

&lt;p&gt;Cloud Trace is a distributed tracing system within Google Cloud that helps you understand request latency across your application and its services. It tracks how long different parts of your application take to process requests, visualizing the entire request flow. This is particularly valuable for identifying performance bottlenecks in microservices architectures by showing where time is spent during a request's lifecycle.&lt;/p&gt;

&lt;p&gt;Here’s a real life example: In this demo we send a prompt to multiple models. We were sure we implemented concurrency correctly (so the calls to the three different models should’ve happened in parallel) yet the latency seems significantly higher than expected. When we dug into the trace of a call, we quickly realized that we were accidentally making those calls sequentially! These traces were made available to us via an OpenTelemetry instrumentation we added to our code.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Interact with your logs with BigQuery
&lt;/h2&gt;

&lt;p&gt;BigQuery is a serverless enterprise data warehouse that enables super-fast SQL queries on large datasets without infrastructure management. It's built for scalable analytics, supports diverse data types, and integrates machine learning, offering a powerful platform for insights from real-time and historical data.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://cloud.google.com/logging/docs/export/configure_export_v2" rel="noopener noreferrer"&gt;a simple sink&lt;/a&gt;, you can directly stream logs from Cloud Logging into BigQuery, transforming it into a powerful, long-term log analytics platform. This allows you to run complex SQL queries across extensive historical log data, which is invaluable for in-depth security audits, compliance, and identifying subtle operational trends.&lt;/p&gt;

&lt;p&gt;Connecting BigQuery to Jupyter Notebooks further enhances log analysis capabilities. This empowers users to leverage Python and data science libraries for advanced data exploration, custom visualizations, and machine learning on log data, facilitating deeper insights and shareable, interactive analysis beyond standard logging tools.&lt;/p&gt;

&lt;p&gt;For this demo, we &lt;a href="https://github.com/GoogleCloudDevRel/next25-observability-in-action/blob/main/Log_Exploration_in_BigQuery.ipynb" rel="noopener noreferrer"&gt;built a Jupyter Notebook&lt;/a&gt; that did analysis on the various interactive quiz events, cross-referenced answers with an external Firestore database, and built tables and charts of the resulting data.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Try it out!
&lt;/h2&gt;

&lt;p&gt;Want to try this demo from home? The source code is &lt;a href="https://github.com/GoogleCloudDevRel/next25-observability-in-action" rel="noopener noreferrer"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Want to learn more about observability on Google Cloud? Check out these resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/stackdriver/docs" rel="noopener noreferrer"&gt;Documentation: Observability in Google Cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cloudskillsboost.google/course_templates/864" rel="noopener noreferrer"&gt;Online course: Observability in Google Cloud&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>googlecloud</category>
      <category>observability</category>
      <category>googlecloudnext</category>
      <category>bigquery</category>
    </item>
  </channel>
</rss>
