<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[thecaptainhub's blog]]></title><description><![CDATA[thecaptainhub's blog]]></description><link>https://thecaptainhub.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1723297009903/74156d48-e769-4255-9195-4502f8682e54.png</url><title>thecaptainhub&apos;s blog</title><link>https://thecaptainhub.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 07 Sep 2026 05:03:57 GMT</lastBuildDate><atom:link href="https://thecaptainhub.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A Guide to Kubernetes Resource Optimization: Using Goldilocks with Prometheus and VPA]]></title><description><![CDATA[Introduction
Kubernetes provides unparalleled flexibility in deploying and managing containerized applications, but with this comes the challenge of optimizing resource usage. Proper resource allocation is crucial to prevent over-provisioning, which ...]]></description><link>https://thecaptainhub.hashnode.dev/a-guide-to-kubernetes-resource-optimization-using-goldilocks-with-prometheus-and-vpa</link><guid isPermaLink="true">https://thecaptainhub.hashnode.dev/a-guide-to-kubernetes-resource-optimization-using-goldilocks-with-prometheus-and-vpa</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[kubernetes architecture]]></category><category><![CDATA[goldilocks]]></category><category><![CDATA[VPA]]></category><category><![CDATA[Resource Optimization Techniques]]></category><dc:creator><![CDATA[Ravichandra]]></dc:creator><pubDate>Mon, 19 Aug 2024 14:48:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/npxXWgQ33ZQ/upload/c91f809801c55130d3a1bd760a062c7e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h3 id="heading-introduction"><strong>Introduction</strong></h3>
<p>Kubernetes provides unparalleled flexibility in deploying and managing containerized applications, but with this comes the challenge of optimizing resource usage. Proper resource allocation is crucial to prevent over-provisioning, which can inflate costs, and under-provisioning, which can lead to application instability.</p>
<p>This guide will walk you through deploying Goldilocks with Vertical Pod Autoscaler (VPA) on a Kubernetes cluster and integrating it with Prometheus for enhanced historical metrics. You'll also deploy a sample workload and learn how to visualize resource recommendations.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before starting, ensure you have the following:</p>
<ul>
<li><p><strong>kubectl</strong>: Installed and configured to access your Kubernetes cluster.</p>
</li>
<li><p><strong>Helm</strong>: Installed for managing Kubernetes applications.</p>
</li>
<li><p><strong>Kubernetes Cluster</strong>: A running cluster with the metrics server installed.</p>
</li>
<li><p>Basic knowledge of Kubernetes concepts (namespaces, deployments, services).</p>
</li>
</ul>
<hr />
<h2 id="heading-the-importance-of-efficient-resource-management-in-kubernetes">The Importance of Efficient Resource Management in Kubernetes</h2>
<h3 id="heading-challenges-in-resource-allocation">Challenges in Resource Allocation</h3>
<p>Kubernetes allows you to define resource requests and limits for containers, which are critical for ensuring efficient use of cluster resources. These settings dictate how much CPU and memory a container will consume and its maximum usage. Proper configuration is vital for:</p>
<ul>
<li><p><strong>Avoiding Over-Provisioning</strong>: Excessive resource allocation can lead to wasted capacity and inflated costs.</p>
</li>
<li><p><strong>Preventing Under-Provisioning</strong>: Insufficient resource allocation may cause throttling or out-of-memory errors, destabilizing applications.</p>
</li>
</ul>
<h3 id="heading-impact-of-inefficient-resource-management">Impact of Inefficient Resource Management</h3>
<p>Poor resource management can have several negative effects on your cluster:</p>
<ul>
<li><p><strong>Increased Costs</strong>: Over-provisioning resources leads to higher cloud expenses without tangible performance improvements.</p>
</li>
<li><p><strong>Application Downtime</strong>: Under-provisioned resources can cause application crashes, impacting user experience and potentially affecting revenue.</p>
</li>
<li><p><strong>Cluster Instability</strong>: Inadequate resource allocation can result in resource contention, compromising the stability of the entire cluster.</p>
</li>
</ul>
<hr />
<h2 id="heading-basics-of-kubernetes-resource-management">Basics of Kubernetes Resource Management</h2>
<h3 id="heading-understanding-resource-requests-and-limits">Understanding Resource Requests and Limits</h3>
<ul>
<li><p><strong>Resource Requests</strong>: Define the minimum amount of CPU and memory guaranteed to a container. Kubernetes uses these values to schedule pods on nodes that have sufficient resources available.</p>
</li>
<li><p><strong>Resource Limits</strong>: Define the maximum CPU and memory a container can consume. Exceeding these limits can lead to throttling or termination of the container.</p>
</li>
</ul>
<p>Properly setting requests and limits ensures that applications receive the necessary resources while avoiding unnecessary waste of cluster capacity.</p>
<h3 id="heading-kubernetes-pod-scheduling">Kubernetes Pod Scheduling</h3>
<p>Kubernetes schedules pods based on resource requests, placing them on nodes with adequate available resources. If requests are set too high, nodes may be underutilized. Conversely, if requests are set too low, the pod might not be scheduled at all.</p>
<h3 id="heading-common-pitfalls-in-resource-allocation">Common Pitfalls in Resource Allocation</h3>
<ul>
<li><p><strong>Limits Without Requests</strong>: Setting limits without corresponding requests can result in pods running without guaranteed resources, leading to performance issues.</p>
</li>
<li><p><strong>Overly Conservative Requests</strong>: Setting requests too high can lead to wasted resources and increased costs.</p>
</li>
<li><p><strong>Ignoring Limits</strong>: Not setting resource limits can lead to scenarios where one pod consumes excessive resources, negatively impacting others on the same node.</p>
</li>
</ul>
<hr />
<h2 id="heading-introducing-goldilocks-and-vertical-pod-autoscaler-vpa">Introducing Goldilocks and Vertical Pod Autoscaler (VPA)</h2>
<h3 id="heading-overview-of-goldilocks">Overview of Goldilocks</h3>
<p>Goldilocks is a tool that simplifies the process of optimizing resource allocations by providing visibility into VPA recommendations. The main components include:</p>
<ul>
<li><p><strong>Goldilocks Controller</strong>: Monitors namespaces for the Goldilocks label and instructs VPA to generate resource recommendations.</p>
</li>
<li><p><strong>Vertical Pod Autoscaler (VPA)</strong>: Analyzes resource usage of pods and provides recommendations for optimal resource settings.</p>
</li>
<li><p><strong>Goldilocks Dashboard</strong>: Displays VPA recommendations in an intuitive interface for easy review and application.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724007313868/405e650c-45ae-4581-a2ec-5786cfcb2419.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h3 id="heading-how-goldilocks-works">How Goldilocks Works</h3>
<ol>
<li><p><strong>Namespace Labeling</strong>: Apply the label <a target="_blank" href="http://goldilocks.fairwinds.com/enabled=true"><code>goldilocks.fairwinds.com/enabled=true</code></a> to activate Goldilocks monitoring in a namespace.</p>
</li>
<li><p><strong>Monitoring Resource Usage</strong>: The Goldilocks Controller collaborates with VPA to track CPU and memory usage of pods in the labeled namespace.</p>
</li>
<li><p><strong>Generating Recommendations</strong>: VPA processes usage data and offers recommendations for resource requests and limits.</p>
</li>
<li><p><strong>Dashboard Visualization</strong>: Recommendations are presented in the Goldilocks Dashboard, allowing users to review and adjust settings.</p>
</li>
</ol>
<h3 id="heading-optional-integrating-prometheus-for-enhanced-accuracy">Optional: Integrating Prometheus for Enhanced Accuracy</h3>
<p>Integrating Prometheus can improve VPA recommendations by providing historical data. This integration helps in making more accurate resource recommendations based on past usage trends.</p>
<hr />
<h2 id="heading-installation-and-configuration">Installation and Configuration</h2>
<p><strong>Step 1: Set Up Your Kubernetes Cluster</strong></p>
<p>We’ll use Kind (Kubernetes in Docker) to create a local cluster:</p>
<p>This command sets up a Kubernetes cluster named <code>kreintoconfigs</code>. Please checkout the link for detailed installation steps and configuration of kind cluster. <a target="_blank" href="https://gist.github.com/ravichandrapatel/90f6721a0858e38d08755a265ab3e74a">kind-cluster-configuration</a></p>
<pre><code class="lang-bash">kind create cluster --config kind-with-kubeproxy.yaml --name kreintoconfigs
Creating cluster <span class="hljs-string">"kreintoconfigs"</span> ...
 • Ensuring node image (kindest/node:v1.30.0) 🖼  ...
 ✓ Ensuring node image (kindest/node:v1.30.0) 🖼
 • Preparing nodes 📦 📦 📦 📦 📦   ...
 ✓ Preparing nodes 📦 📦 📦 📦 📦
 • Writing configuration 📜  ...
 ✓ Writing configuration 📜
 • Starting control-plane 🕹️  ...
 ✓ Starting control-plane 🕹️
 • Installing CNI 🔌  ...
 ✓ Installing CNI 🔌
 • Installing StorageClass 💾  ...
 ✓ Installing StorageClass 💾
 • Joining worker nodes 🚜  ...
 ✓ Joining worker nodes 🚜
Set kubectl context to <span class="hljs-string">"kind-kreintoconfigs"</span>
You can now use your cluster with:

kubectl cluster-info --context kind-kreintoconfigs

Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/<span class="hljs-comment">#community 🙂</span>
</code></pre>
<p><strong>Step 2: Install the Metrics Server</strong></p>
<p>The metrics server is necessary for gathering resource usage data, which VPA and Goldilocks will use:</p>
<pre><code class="lang-bash">kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
</code></pre>
<p><strong>Step 3: Install Vertical Pod Autoscaler (VPA)</strong></p>
<p>VPA helps adjust resource requests based on usage. Install it using Helm with the following configuration:</p>
<p><strong>Create</strong> <code>values.yaml</code> for VPA:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">rbac:</span>
  <span class="hljs-attr">create:</span> <span class="hljs-literal">true</span>
<span class="hljs-attr">admissionController:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">generateCertificate:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">registerWebhook:</span> <span class="hljs-literal">true</span>
<span class="hljs-attr">recommender:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">replicaCount:</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">resources:</span>
    <span class="hljs-attr">requests:</span>
      <span class="hljs-attr">cpu:</span> <span class="hljs-string">50m</span>
      <span class="hljs-attr">memory:</span> <span class="hljs-string">500Mi</span>
<span class="hljs-attr">updater:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">false</span>
</code></pre>
<p><strong>Install VPA</strong>:</p>
<pre><code class="lang-yaml"><span class="hljs-string">helm</span> <span class="hljs-string">repo</span> <span class="hljs-string">add</span> <span class="hljs-string">fairwinds-stable</span> <span class="hljs-string">https://charts.fairwinds.com/stable</span>
<span class="hljs-string">helm</span> <span class="hljs-string">install</span> <span class="hljs-string">vpa</span> <span class="hljs-string">fairwinds-stable/vpa</span> <span class="hljs-string">--create-namespace</span> <span class="hljs-string">--namespace</span> <span class="hljs-string">vpa</span> <span class="hljs-string">-f</span> <span class="hljs-string">values.yaml</span>
</code></pre>
<p>Verify VPA installation:</p>
<pre><code class="lang-bash">kubectl get pods -n vpa
</code></pre>
<p><strong>Step 4: Install Goldilocks</strong></p>
<p>Goldilocks provides a dashboard for visualizing VPA recommendations. Use the following configuration:</p>
<p><strong>Create</strong> <code>values.yaml</code> for Goldilocks:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">uninstallVPA:</span> <span class="hljs-literal">false</span>
<span class="hljs-attr">vpa:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">false</span>
  <span class="hljs-attr">updater:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">false</span>
<span class="hljs-attr">metrics-server:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">false</span>
  <span class="hljs-attr">apiService:</span>
    <span class="hljs-attr">create:</span> <span class="hljs-literal">true</span>
<span class="hljs-attr">controller:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">rbac:</span>
    <span class="hljs-attr">create:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">enableArgoproj:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">resources:</span>
    <span class="hljs-attr">requests:</span>
      <span class="hljs-attr">cpu:</span> <span class="hljs-string">25m</span>
      <span class="hljs-attr">memory:</span> <span class="hljs-string">256Mi</span>
<span class="hljs-attr">dashboard:</span>
  <span class="hljs-attr">ingress:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">ingressClassName:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">hosts:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">host:</span> <span class="hljs-string">goldilocks.kreintoconfigs.io</span>
        <span class="hljs-attr">paths:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/</span>
            <span class="hljs-attr">type:</span> <span class="hljs-string">ImplementationSpecific</span>
</code></pre>
<p><strong>Install Goldilocks:</strong></p>
<pre><code class="lang-bash">helm install goldilocks fairwinds-stable/goldilocks --create-namespace --namespace goldilocks -f values.yaml
</code></pre>
<p>Ensure Goldilocks is running:</p>
<pre><code class="lang-bash">kubectl get pods -n goldilocks
</code></pre>
<p>To access the ingress:</p>
<pre><code class="lang-bash">kubectl get ingress -n goldilocks
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724057073464/cd5d968f-8a65-4022-88ce-7ba853ef5933.png" alt class="image--center mx-auto" /></p>
<p>At this point, there will be no data in the UI because Goldilocks is not yet enabled for any namespace.</p>
<p><strong>Step 5: Deploy a Sample Workload</strong></p>
<p>Deploy a sample Nginx application to see how Goldilocks optimizes resource allocations:</p>
<pre><code class="lang-bash">kubectl create deployment nginx --image=nginx --replicas=2
kubectl expose deployment nginx --port=80 --<span class="hljs-built_in">type</span>=ClusterIP
</code></pre>
<p>Enable Goldilocks monitoring by labeling the namespace:</p>
<pre><code class="lang-bash">kubectl label ns default goldilocks.fairwinds.com/enabled=<span class="hljs-literal">true</span>
</code></pre>
<p>Goldilocks will now generate VPA objects for your deployments automatically. You can verify if vpa is created or not</p>
<pre><code class="lang-bash">kubectl get vpa
NAME                          MODE   CPU   MEM   PROVIDED   AGE
goldilocks-nginx-deployment   Off                           15s
</code></pre>
<p>Once you've applied the<a target="_blank" href="http://goldilocks.fairwinds.com/enabled=true"><code>goldilocks.fairwinds.com/enabled=true</code></a>label to your namespace, the Goldilocks tool will begin analyzing your pod resource usage. You can then view recommended resource requests and limits for your workloads in the Goldilocks dashboard or by examining the Vertical Pod Autoscaler (VPA) objects created for each workload.</p>
<pre><code class="lang-bash">kubectl describe vpa goldilocks-nginx-deployment
Name:         goldilocks-nginx-deployment
Namespace:    default
Labels:       creator=Fairwinds
              <span class="hljs-built_in">source</span>=goldilocks
Annotations:  &lt;none&gt;
API Version:  autoscaling.k8s.io/v1
Kind:         VerticalPodAutoscaler
Metadata:
  Creation Timestamp:  2024-08-18T19:23:40Z
  Generation:          1
  Resource Version:    71936
  UID:                 828bfebf-43c4-46ea-b2e3-92df68773695
Spec:
  Target Ref:
    API Version:  apps/v1
    Kind:         Deployment
    Name:         nginx-deployment
  Update Policy:
    Update Mode:  Off
Status:
  Conditions:
    Last Transition Time:  2024-08-18T19:24:12Z
    Status:                True
    Type:                  RecommendationProvided
  Recommendation:
    Container Recommendations:
      Container Name:  nginx
      Lower Bound:
        Cpu:     15m
        Memory:  104857600
      Target:
        Cpu:     15m
        Memory:  104857600
      Uncapped Target:
        Cpu:     15m
        Memory:  104857600
      Upper Bound:
        Cpu:     44m
        Memory:  104857600
Events:          &lt;none&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724057550696/940aa9ef-b7ad-495e-8f87-1b06d837ffac.png" alt class="image--center mx-auto" /></p>
<p><strong>Step 6: Integrate Prometheus for Enhanced Metrics (Optional)</strong></p>
<p><strong>Why Integrate Prometheus?</strong></p>
<p>In a dynamic Kubernetes environment, resource utilization can fluctuate due to various factors like traffic spikes, batch jobs, or changes in workload patterns. While Vertical Pod Autoscaler (VPA) provides valuable recommendations based on real-time metrics, these metrics only offer a snapshot of your current resource usage. To achieve more accurate and reliable recommendations, it's crucial to consider historical data, which is where Prometheus comes into play.</p>
<p>Prometheus is a powerful, open-source monitoring and alerting toolkit designed to collect and store time-series data. By integrating Prometheus with Goldilocks, you can enrich the VPA recommendations with historical performance metrics, leading to more comprehensive insights.</p>
<p><strong>How It Works:</strong></p>
<p>When you configure Goldilocks to use Prometheus as a metrics source, you allow it to access a broader dataset that includes not only the current resource usage but also past trends, patterns, and anomalies. This historical data enables Goldilocks to provide more nuanced recommendations, helping you identify the optimal resource allocation for your workloads.</p>
<p>For example, consider a workload that experiences periodic spikes in CPU usage due to a scheduled task. A VPA configured without Prometheus might recommend a CPU request based on the average usage at a given moment, potentially overlooking these spikes. However, with Prometheus, Goldilocks can account for these recurring patterns, resulting in a more accurate recommendation that ensures your application remains responsive even during peak periods.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724007782722/bfa30d9e-c158-43aa-901a-37dff557d388.png" alt class="image--center mx-auto" /></p>
<p><strong>1. Install Prometheus and Grafana:</strong></p>
<p><strong>Create</strong> <code>values.yaml</code> for Goldilocks:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">grafana:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">defaultDashboardsEnabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">defaultDashboardsTimezone:</span> <span class="hljs-string">utc</span>
  <span class="hljs-attr">defaultDashboardsEditable:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">adminPassword:</span> <span class="hljs-string">prom-operator</span>
  <span class="hljs-attr">ingress:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">ingressClassName:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">hosts:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">grafana.kreintoconfigs.io</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">/</span>

<span class="hljs-attr">kubeStateMetrics:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>

<span class="hljs-attr">kube-state-metrics:</span>
  <span class="hljs-attr">rbac:</span>
    <span class="hljs-attr">create:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">extraRules:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">apiGroups:</span> [<span class="hljs-string">"autoscaling.k8s.io"</span>]
       <span class="hljs-attr">resources:</span> [<span class="hljs-string">"verticalpodautoscalers"</span>]
       <span class="hljs-attr">verbs:</span> [<span class="hljs-string">"list"</span>, <span class="hljs-string">"watch"</span>]
  <span class="hljs-attr">releaseLabel:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">prometheus:</span>
    <span class="hljs-attr">monitor:</span>
      <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-comment"># https://github.com/kubernetes/kube-state-metrics/blob/main/docs/customresourcestate-metrics.md#verticalpodautoscaler</span>
  <span class="hljs-comment"># https://github.com/kubernetes/kube-state-metrics/issues/2041#issuecomment-1614327806</span>
  <span class="hljs-attr">customResourceState:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">config:</span>
     <span class="hljs-attr">kind:</span> <span class="hljs-string">CustomResourceStateMetrics</span>
     <span class="hljs-attr">spec:</span>
       <span class="hljs-attr">resources:</span>
         <span class="hljs-bullet">-</span> <span class="hljs-attr">groupVersionKind:</span>
              <span class="hljs-attr">group:</span> <span class="hljs-string">autoscaling.k8s.io</span>
              <span class="hljs-attr">kind:</span> <span class="hljs-string">"VerticalPodAutoscaler"</span>
              <span class="hljs-attr">version:</span> <span class="hljs-string">"v1"</span>
           <span class="hljs-attr">labelsFromPath:</span>
              <span class="hljs-attr">verticalpodautoscaler:</span> [<span class="hljs-string">metadata</span>, <span class="hljs-string">name</span>]
              <span class="hljs-attr">namespace:</span> [<span class="hljs-string">metadata</span>, <span class="hljs-string">namespace</span>]
              <span class="hljs-attr">target_api_version:</span> [<span class="hljs-string">spec</span>, <span class="hljs-string">targetRef</span>, <span class="hljs-string">apiVersion</span>]
              <span class="hljs-attr">target_kind:</span> [<span class="hljs-string">spec</span>, <span class="hljs-string">targetRef</span>, <span class="hljs-string">kind</span>]
              <span class="hljs-attr">target_name:</span> [<span class="hljs-string">spec</span>, <span class="hljs-string">targetRef</span>, <span class="hljs-string">name</span>]
           <span class="hljs-attr">metrics:</span> 
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_labels"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations. Kubernetes labels converted to Prometheus labels"</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Info</span>
                  <span class="hljs-attr">info:</span>
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">name:</span> [<span class="hljs-string">metadata</span>, <span class="hljs-string">name</span>]
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_target"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for memory. Target resources the VerticalPodAutoscaler recommends for the container."</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">target</span>, <span class="hljs-string">memory</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"memory"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"byte"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_lowerbound"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for memory. Minimum resources the container can use before the VerticalPodAutoscaler updater evicts it"</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">lowerBound</span>, <span class="hljs-string">memory</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"memory"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"byte"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_upperbound"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for memory. Maximum resources the container can use before the VerticalPodAutoscaler updater evicts it"</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">upperBound</span>, <span class="hljs-string">memory</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"memory"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"byte"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_uncappedtarget"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for memory. Target resources the VerticalPodAutoscaler recommends for the container ignoring bounds"</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">uncappedTarget</span>, <span class="hljs-string">memory</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"memory"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"byte"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_target"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for cpu. Target resources the VerticalPodAutoscaler recommends for the container."</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">target</span>, <span class="hljs-string">cpu</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"cpu"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"core"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_lowerbound"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for cpu. Minimum resources the container can use before the VerticalPodAutoscaler updater evicts it"</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">lowerBound</span>, <span class="hljs-string">cpu</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"cpu"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"core"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_upperbound"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for cpu. Maximum resources the container can use before the VerticalPodAutoscaler updater evicts it"</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">upperBound</span>, <span class="hljs-string">cpu</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"cpu"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"core"</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"verticalpodautoscaler_status_recommendation_containerrecommendations_uncappedtarget"</span>
                <span class="hljs-attr">help:</span> <span class="hljs-string">"VPA container recommendations for cpu. Target resources the VerticalPodAutoscaler recommends for the container ignoring bounds"</span>
                <span class="hljs-attr">each:</span>
                  <span class="hljs-attr">type:</span> <span class="hljs-string">Gauge</span>
                  <span class="hljs-attr">gauge:</span>
                    <span class="hljs-attr">path:</span> [<span class="hljs-string">status</span>, <span class="hljs-string">recommendation</span>, <span class="hljs-string">containerRecommendations</span>]
                    <span class="hljs-attr">valueFrom:</span> [<span class="hljs-string">uncappedTarget</span>, <span class="hljs-string">cpu</span>]
                    <span class="hljs-attr">labelsFromPath:</span>
                      <span class="hljs-attr">container:</span> [<span class="hljs-string">containerName</span>]
                <span class="hljs-attr">commonLabels:</span>
                  <span class="hljs-attr">resource:</span> <span class="hljs-string">"cpu"</span>
                  <span class="hljs-attr">unit:</span> <span class="hljs-string">"core"</span>
  <span class="hljs-attr">selfMonitor:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>

<span class="hljs-attr">prometheusOperator:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
<span class="hljs-attr">prometheus:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">agentMode:</span> <span class="hljs-literal">false</span>
  <span class="hljs-attr">prometheusSpec:</span>
    <span class="hljs-attr">persistentVolumeClaimRetentionPolicy:</span> 
     <span class="hljs-attr">whenDeleted:</span> <span class="hljs-string">Retain</span>
     <span class="hljs-attr">whenScaled:</span> <span class="hljs-string">Retain</span>
    <span class="hljs-attr">retention:</span> <span class="hljs-string">30d</span>
    <span class="hljs-attr">storageSpec:</span> 
     <span class="hljs-attr">volumeClaimTemplate:</span>
       <span class="hljs-attr">spec:</span>
         <span class="hljs-attr">accessModes:</span> [<span class="hljs-string">"ReadWriteOnce"</span>]
         <span class="hljs-attr">resources:</span>
           <span class="hljs-attr">requests:</span>
             <span class="hljs-attr">storage:</span> <span class="hljs-string">2Gi</span>
    <span class="hljs-attr">serviceMonitorSelectorNilUsesHelmValues:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">ingress:</span>
    <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">ingressClassName:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">hosts:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">prometheus.kreintoconfigs.io</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">/</span>
</code></pre>
<pre><code class="lang-bash">helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --namespace monitoring --create-namespace
</code></pre>
<p><strong>2. Configure VPA to Use Prometheus Metrics</strong></p>
<p>By default, the Vertical Pod Autoscaler (VPA) retains up to 7 days of historical metrics. While this might be sufficient for many use cases, extending the retention period to 30 days can provide a broader view of resource usage patterns, leading to more accurate recommendations. This extension is especially useful for workloads with fluctuating usage patterns over longer periods, such as end-of-month reporting or seasonal spikes.</p>
<h4 id="heading-why-extend-historical-metrics-retention">Why Extend Historical Metrics Retention?</h4>
<p>Extending the retention period of metrics allows VPA to analyze a larger dataset, capturing a wider range of usage scenarios. This can result in more balanced recommendations that consider both short-term and long-term trends. For example, a workload that experiences occasional spikes may need different resource recommendations compared to one with consistent usage. With a 30-day retention period, VPA can better differentiate between these patterns, avoiding over-provisioning during peaks and under-provisioning during lulls.</p>
<p><strong>Update</strong> <code>vpa-values.yaml</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">recommender:</span>
  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">extraArgs:</span>
    <span class="hljs-attr">v:</span> <span class="hljs-string">"4"</span>
    <span class="hljs-attr">pod-recommendation-min-cpu-millicores:</span> <span class="hljs-number">15</span>
    <span class="hljs-attr">pod-recommendation-min-memory-mb:</span> <span class="hljs-number">100</span>
    <span class="hljs-attr">prometheus-address:</span> <span class="hljs-string">|
      http://prometheus-agent-operated.monitoring.svc.cluster.local:9090
</span>    <span class="hljs-attr">storage:</span> <span class="hljs-string">prometheus</span>
    <span class="hljs-attr">history-length:</span> <span class="hljs-string">30d</span>
    <span class="hljs-attr">history-resolution:</span> <span class="hljs-string">1h</span>
    <span class="hljs-attr">prometheus-cadvisor-job-name:</span> <span class="hljs-string">kubelet</span>
    <span class="hljs-attr">container-pod-name-label:</span> <span class="hljs-string">pod</span>
    <span class="hljs-attr">container-name-label:</span> <span class="hljs-string">container</span>
    <span class="hljs-attr">metric-for-pod-labels:</span>  <span class="hljs-string">kube_pod_labels{job="kube-state-metrics"}[30d]</span>
    <span class="hljs-attr">pod-namespace-label:</span> <span class="hljs-string">namespace</span>
    <span class="hljs-attr">pod-name-label:</span> <span class="hljs-string">pod</span>
</code></pre>
<p><strong>Upgrade VPA:</strong></p>
<pre><code class="lang-yaml"><span class="hljs-string">helm</span> <span class="hljs-string">upgrade</span> <span class="hljs-string">vpa</span> <span class="hljs-string">fairwinds-stable/vpa</span> <span class="hljs-string">--namespace</span> <span class="hljs-string">vpa</span> <span class="hljs-string">-f</span> <span class="hljs-string">vpa-values.yaml</span>
</code></pre>
<h4 id="heading-considerations">Considerations</h4>
<ul>
<li><p><strong>Performance Impact:</strong> Storing a larger amount of historical data can increase the load on both your monitoring system (e.g., Prometheus) and the VPA itself. Ensure that your infrastructure can handle the increased data volume without performance degradation.</p>
</li>
<li><p><strong>Fine-Tuning:</strong> The 30-day retention period is a starting point, but it may require adjustment based on your specific workload patterns and infrastructure capacity. You may need to perform load testing and adjust the retention period accordingly to achieve optimal results.</p>
</li>
<li><p><strong>Data Relevance:</strong> While more data can lead to better recommendations, it's important to balance this with the relevance of the data. Older data might not always reflect current usage patterns, especially in environments with rapidly changing workloads.</p>
</li>
</ul>
<p>Extending the retention period for historical metrics allows the VPA to make more informed and precise recommendations, enhancing the optimization of your Kubernetes environment. With an extended retention period, VPA can analyze a broader dataset, leading to more accurate resource adjustments.</p>
<p>Once VPA is configured, it will automatically start using the metrics from Prometheus to generate its recommendations.</p>
<p>Since Goldilocks doesn't have built-in authentication, it's a good practice to send the recommendation metrics to Prometheus. This approach enables secure visualization through Grafana, ensuring that your metrics are accessible only through a secured interface.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724075302955/3c8b9867-c696-4058-93c2-b4988a4b1604.png" alt class="image--center mx-auto" /></p>
<p><strong>Step 8: Securing Goldilocks Dashboard (Optional)</strong></p>
<p>Since Goldilocks does not include built-in authentication, you can either add a layer of security with an OAuth proxy or use Grafana to visualize the recommendations securely. Alternatively, you can scale down the Goldilocks dashboard deployment to zero replicas to disable it when not needed.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>With Goldilocks and VPA set up on your Kubernetes cluster, and optionally enhanced with Prometheus for deeper insights, you're now equipped to maintain an optimized, cost-effective environment. Regularly review and apply the recommendations provided by Goldilocks to ensure your applications remain stable and your resources are efficiently utilized.</p>
<p>This guide has taken you through each step—from setting up your cluster to deploying sample workloads and integrating with Prometheus. By following these practices, you can confidently manage resources in your Kubernetes cluster, ensuring both performance and cost efficiency.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Scaling Smart: My Journey to Cost-Effective and Optimized EKS Clusters with Karpenter, KEDA, and Goldilocks]]></title><description><![CDATA[“Welcome to my first tech blog! As someone who’s been deeply immersed in optimizing cloud infrastructure, I’m excited to share my journey and insights on EKS cost optimization. This is my debut into the world of tech blogging, and I hope you find thi...]]></description><link>https://thecaptainhub.hashnode.dev/scaling-smart-my-journey-to-cost-effective-and-optimized-eks-clusters-with-karpenter-keda-and-goldilocks</link><guid isPermaLink="true">https://thecaptainhub.hashnode.dev/scaling-smart-my-journey-to-cost-effective-and-optimized-eks-clusters-with-karpenter-keda-and-goldilocks</guid><category><![CDATA[goldilocks]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[cost-optimisation]]></category><category><![CDATA[EKS]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[karpenter]]></category><category><![CDATA[#kubernetes #container ]]></category><dc:creator><![CDATA[Ravichandra]]></dc:creator><pubDate>Sat, 10 Aug 2024 12:23:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/CmF_5GYc6c0/upload/5a0938de4b04a9b20bfc1f4fe29a444f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>“Welcome to my first tech blog! As someone who’s been deeply immersed in optimizing cloud infrastructure, I’m excited to share my journey and insights on EKS cost optimization. This is my debut into the world of tech blogging, and I hope you find this exploration into the world of Karpenter, KEDA, and Goldilocks both informative and engaging.”</em></p>
<h3 id="heading-introduction">Introduction</h3>
<p>Navigating cloud infrastructure management, particularly with Amazon EKS (Elastic Kubernetes Service), is no small feat. Balancing performance, scalability, and cost efficiency can feel like a constant juggling act. Our multi-tenant EKS cluster, handling around 6000+ pods across over 180+ nodes, presented a significant financial challenge. This blog details our journey to optimizing EKS costs, culminating in a remarkable $300,000 in savings through the strategic implementation of Karpenter, KEDA, and Goldilocks.</p>
<h3 id="heading-the-challenge-rising-eks-costs-and-the-need-for-efficient-optimization">The Challenge: Rising EKS Costs and the Need for Efficient Optimization</h3>
<p>Our initial approach relied on the Cluster Autoscaler, which worked reasonably well but struggled to keep up with our scaling demands as our environment grew. We found ourselves in a situation where our resource allocation was akin to booking a grand banquet hall for a small gathering—resulting in wasted capacity and soaring costs. Recognizing the urgency to refine our strategy, we turned to more advanced solutions.</p>
<h3 id="heading-our-solution-a-triumvirate-of-tools-for-enhanced-cost-efficiency">Our Solution: A Triumvirate of Tools for Enhanced Cost Efficiency</h3>
<p>To address our cost challenges, we implemented three powerful tools—Karpenter, KEDA, and Goldilocks. Each tool addressed different aspects of cost optimization and resource management, providing a holistic approach to our scaling and efficiency issues.</p>
<h4 id="heading-karpenter-transforming-node-provisioning">Karpenter: Transforming Node Provisioning</h4>
<p>Karpenter revolutionized our approach to node provisioning with its dynamic, just-in-time provisioning capabilities.</p>
<p><strong>Key Benefits:</strong></p>
<ul>
<li><p><strong>Dynamic Node Provisioning:</strong> Karpenter provisions nodes based on real-time application needs, spinning up or down nodes as required. This approach ensures we only pay for what we use, dynamically adjusting to traffic spikes and reducing costs during periods of lower demand.</p>
</li>
<li><p><strong>Cost-Effective Instances:</strong> We configured our default nodepool to include a mix of on-demand and spot instances. Spot instances, being more cost-effective, were used for non-critical applications, while on-demand instances ensured reliability for high-priority workloads.</p>
</li>
<li><p><strong>ARM64(GRAVITON) Instances:</strong> Introducing ARM64 architecture into our nodepools resulted in up to 20% cost savings, as ARM64 instances offer competitive performance at lower costs compared to x86 counterparts.</p>
</li>
</ul>
<p><strong>Challenges and Solutions:</strong></p>
<ul>
<li><p><strong>Deployment Issues:</strong> Initial deployment conflicts arose when Karpenter was installed on the same nodes it was managing. We resolved this by redeploying Karpenter on Fargate, separating the management layer from the managed nodes.</p>
</li>
<li><p><strong>Max Pods Issue:</strong> Karpenter’s handling of max pod limits with custom VPC CNI configurations caused problems. We addressed this by integrating a max_pods calculation script from AWS during node bootstrapping to ensure accurate pod density.</p>
</li>
</ul>
<ol start="2">
<li><h4 id="heading-keda-scaling-event-driven-workloads-with-precision">KEDA: Scaling Event-Driven Workloads with Precision</h4>
<p> KEDA (Kubernetes Event-Driven Autoscaler) was instrumental in scaling workloads based on real-time metrics, such as API request counts and message queue lengths.</p>
<p> <strong>Key Benefits:</strong></p>
<ul>
<li><p><strong>Custom Metrics:</strong> KEDA enabled scaling based on diverse metrics beyond CPU and memory usage. For example, we scaled applications based on queue length and request rates, ensuring precise resource allocation according to demand.</p>
</li>
<li><p><strong>Cron-Based Scaling:</strong> KEDA’s cron scheduler allowed us to scale down non-production environments to zero during off-hours, significantly reducing costs for development and staging environments that didn’t require 24/7 operation.</p>
</li>
</ul>
</li>
</ol>
<p>    <strong>Challenges and Solutions:</strong></p>
<ul>
<li><strong>Implementation Complexity:</strong> Implementing KEDA involved updating our scaling strategies and training application teams. We provided comprehensive documentation and hands-on training sessions to facilitate effective use of KEDA’s features.</li>
</ul>
<ol start="3">
<li><h4 id="heading-goldilocks-achieving-the-perfect-resource-allocation">Goldilocks: Achieving the Perfect Resource Allocation</h4>
<p> Goldilocks was crucial in identifying and eliminating over-provisioned resources, ensuring we only used and paid for what was necessary.</p>
<p> <strong>Key Benefits:</strong></p>
<ul>
<li><p><strong>Resource Utilization Analysis:</strong> Goldilocks analyzed pod resource usage and offered recommendations for right-sizing. By integrating it with Prometheus, we utilized historical data to optimize resource allocation. Goldilocks highlighted that many pods were over-provisioned by 30-40%, leading to significant cost reductions.</p>
</li>
<li><p><strong>Visualization and Reporting:</strong> Goldilocks’ visualization capabilities helped pinpoint resource waste. We created custom Grafana dashboards with SSO integration to provide secure, real-time access to optimization recommendations.</p>
</li>
</ul>
</li>
</ol>
<p>    <strong>Challenges and Solutions:</strong></p>
<ul>
<li><p><strong>Security and Accessibility:</strong> Goldilocks Opensource version lacked certain security features and user access controls. We addressed this by developing custom Grafana dashboards with SSO integration, ensuring secure and convenient access to recommendations.</p>
</li>
<li><p><strong>Automated Reporting:</strong> We created a Python script to generate and email optimization reports based on namespace labels, ensuring that even teams without direct dashboard access received actionable insights.</p>
</li>
</ul>
<h3 id="heading-our-journey-implementing-and-optimizing">Our Journey: Implementing and Optimizing</h3>
<h4 id="heading-phase-one-preparation-and-initial-setup">Phase One: Preparation and Initial Setup</h4>
<ul>
<li><p><strong>Resource Quotas:</strong> Implemented resource quotas for each namespace to prevent over-provisioning and ensure fair distribution of resources. This approach helped manage our multi-tenant environment effectively.</p>
</li>
<li><p><strong>Annotations &amp; Labels:</strong> Added metadata to applications, including team names, owners, and support contacts. This metadata facilitated targeted communications and streamlined responsibility tracking during optimization.</p>
</li>
</ul>
<h4 id="heading-phase-two-migrating-to-karpenter-for-advanced-node-provisioning">Phase Two: Migrating to Karpenter for Advanced Node Provisioning</h4>
<ul>
<li><strong>Deployment and Configuration:</strong> Resolved initial deployment issues by moving Karpenter to Fargate and configuring nodepools with appropriate instance types. Introducing ARM64 instances into the default nodepool provided additional cost savings and performance benefits.</li>
</ul>
<h4 id="heading-phase-three-right-sizing-with-vpa-and-goldilocks">Phase Three: Right-Sizing with VPA and Goldilocks</h4>
<ul>
<li><p><strong>Prometheus Integration:</strong> Deployed Prometheus to monitor resource usage and feed data into the Vertical Pod Autoscaler (VPA). VPA used 30 days of historical data for balanced recommendations, leading to more efficient resource allocation.</p>
</li>
<li><p><strong>Goldilocks Dashboards:</strong> Custom Grafana dashboards with SSO integration provided secure access to optimization insights. Automated email reports ensured teams received timely information on resource recommendations.</p>
</li>
</ul>
<h4 id="heading-phase-four-dynamic-scaling-with-keda">Phase Four: Dynamic Scaling with KEDA</h4>
<ul>
<li><strong>KEDA Deployment:</strong> Deployed KEDA to manage dynamic scaling based on custom metrics, enhancing our ability to handle event-driven workloads efficiently. The cron scheduler was particularly effective for reducing costs in non-production environments.</li>
</ul>
<h3 id="heading-lessons-learned-and-challenges">Lessons Learned and Challenges</h3>
<ul>
<li><p><strong>Effective Communication:</strong> Keeping application teams informed and engaged was crucial for successful optimization. Regular updates, clear documentation, and training sessions drove adoption and alignment with new strategies.</p>
</li>
<li><p><strong>Spot Instance Management:</strong> Spot instances provided substantial cost savings but posed risks of interruptions. We carefully selected workloads for spot instances and implemented fallback strategies for critical applications to mitigate potential disruptions.</p>
</li>
<li><p><strong>Tooling Limitations:</strong> While Karpenter, KEDA, and Goldilocks offered powerful capabilities, we faced limitations that required custom solutions. For instance, integrating Karpenter with VPC CNI configurations and enhancing Goldilocks with secure visualization were necessary for realizing the full potential of these tools.</p>
</li>
<li><p><strong>Continuous Monitoring:</strong> Optimization is an ongoing process. We set up continuous monitoring to track resource utilization and adjust configurations as needed to maintain efficiency and cost-effectiveness.</p>
</li>
</ul>
<h3 id="heading-key-takeaways">Key Takeaways</h3>
<ul>
<li><p><strong>Holistic Approach:</strong> Combining Karpenter, KEDA, and Goldilocks provided a comprehensive solution for cost optimization, addressing node provisioning, scaling, and resource allocation.</p>
</li>
<li><p><strong>Efficiency Through Automation:</strong> Automating node provisioning and scaling with Karpenter and KEDA led to substantial cost reductions and improved resource management.</p>
</li>
<li><p><strong>Right-Sizing for Savings:</strong> Goldilocks’ insights into resource utilization helped us eliminate over-provisioning and achieve significant cost savings.</p>
</li>
</ul>
<h3 id="heading-practical-tips">Practical Tips</h3>
<ul>
<li><p><strong>Implement Resource Quotas:</strong> Set quotas for each namespace to manage resource allocation and prevent over-provisioning.</p>
</li>
<li><p><strong>Use Annotations &amp; Labels:</strong> Add metadata to applications for better tracking and communication.</p>
</li>
<li><p><strong>Configure Karpenter Properly:</strong> Ensure accurate node provisioning by deploying Karpenter on separate infrastructure and using max_pods calculation scripts.</p>
</li>
<li><p><strong>Leverage Goldilocks and VPA:</strong> Utilize these tools for precise right-sizing and visualization of resource usage.</p>
</li>
<li><p><strong>Utilize KEDA Effectively:</strong> Implement dynamic scaling based on custom metrics and use cron scheduling for non-production environments.</p>
</li>
</ul>
<h3 id="heading-call-to-action">Call to Action</h3>
<p>Have you faced similar challenges with EKS cost management? Share your experiences in the comments below or reach out for more insights and tips. If you found this blog helpful, explore these tools further to optimize your own EKS deployments. Let’s drive innovation in cloud cost optimization together!</p>
]]></content:encoded></item></channel></rss>