<?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: Kacey Gambill</title>
    <description>The latest articles on DEV Community by Kacey Gambill (@klip_klop).</description>
    <link>https://dev.to/klip_klop</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F32904%2Fdd948db4-dcd1-4869-b76d-194d66eae4ae.jpg</url>
      <title>DEV Community: Kacey Gambill</title>
      <link>https://dev.to/klip_klop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/klip_klop"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Sat, 20 Dec 2025 15:28:23 +0000</pubDate>
      <link>https://dev.to/klip_klop/-49n1</link>
      <guid>https://dev.to/klip_klop/-49n1</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/klip_klop/sleep-tight-cluster-right-stop-burning-cash-at-3-am-3jpm" class="crayons-story__hidden-navigation-link"&gt;Sleep Tight, Cluster Right: Stop Burning Cash at 3 AM&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/klip_klop" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F32904%2Fdd948db4-dcd1-4869-b76d-194d66eae4ae.jpg" alt="klip_klop profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/klip_klop" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Kacey Gambill
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Kacey Gambill
                
              
              &lt;div id="story-author-preview-content-3117505" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/klip_klop" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F32904%2Fdd948db4-dcd1-4869-b76d-194d66eae4ae.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Kacey Gambill&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/klip_klop/sleep-tight-cluster-right-stop-burning-cash-at-3-am-3jpm" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 20 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/klip_klop/sleep-tight-cluster-right-stop-burning-cash-at-3-am-3jpm" id="article-link-3117505"&gt;
          Sleep Tight, Cluster Right: Stop Burning Cash at 3 AM
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/cloud"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;cloud&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/observability"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;observability&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/klip_klop/sleep-tight-cluster-right-stop-burning-cash-at-3-am-3jpm#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




</description>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>observability</category>
      <category>sre</category>
    </item>
    <item>
      <title>Sleep Tight, Cluster Right: Stop Burning Cash at 3 AM</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Sat, 20 Dec 2025 15:28:08 +0000</pubDate>
      <link>https://dev.to/klip_klop/sleep-tight-cluster-right-stop-burning-cash-at-3-am-3jpm</link>
      <guid>https://dev.to/klip_klop/sleep-tight-cluster-right-stop-burning-cash-at-3-am-3jpm</guid>
      <description>&lt;p&gt;Most Kubernetes clusters are wide awake 24/7, even if you users aren't! &lt;/p&gt;

&lt;p&gt;CPU-based HPAs try to help, but quickly fall apart. Especially when we add the VPA to the mix. These two can work in tandem, but only if we implement some smart scaling with KEDA, otherwise it is just a battle between the two, and it makes our clusters tired!&lt;/p&gt;

&lt;p&gt;Queues, request rates, latency, and time of day can tell us far more about whether or not our workloads should exist at all.&lt;/p&gt;

&lt;p&gt;This is where KEDA shines!&lt;/p&gt;

&lt;p&gt;Instead of guessing how busy something &lt;em&gt;could&lt;/em&gt; be, we scale based on events!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prometheus metrics when work exists.&lt;/li&gt;
&lt;li&gt;Cron schedules when traffic in the cluster drops.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During the day, we rely on metric triggers, which help drive rapid scaling decisions.&lt;br&gt;
At night, cron or empty signals help pull our workloads to a minimum amount, sometimes down to zero!&lt;/p&gt;

&lt;p&gt;Our VPA is no longer fighting with our HPA, and we are not running idle pods.&lt;br&gt;
The best part, we are no longer paying our cluster to work, while we are asleep.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduled Scaling: Night Shift
&lt;/h3&gt;

&lt;p&gt;Traffic Patterns are predictable, but lets not guess, we can schedule this with a trigger.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cron Scalers set explicit windows to scale down a workload during off hours&lt;/li&gt;
&lt;li&gt;Prometheus Scalers scale our workloads based on metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can use these both in tandem to create a workload that only runs when there is work to do. As soon as we start to get requests, we quickly scale out, and start to serve the traffic, then with a longer scale-down period, we can handle any remaining traffic while the cluster gets ready to scale back down. &lt;/p&gt;

&lt;p&gt;Workload scaling is only half of the story. We aren't getting these crazy savings if we are still paying for nodes on standby! &lt;/p&gt;

&lt;p&gt;The cluster autoscaler can do a decent job, but here is where Karpenter really shines.&lt;/p&gt;

&lt;p&gt;As soon as our workloads are gone, Karpenter is consolidating and terminating nodes that are empty, allowing us to use beefy nodes when we need to, but also scales way down in the event that our workloads are ready for bed!&lt;/p&gt;

&lt;h3&gt;
  
  
  Day Shift
&lt;/h3&gt;

&lt;p&gt;We use Cron triggers to ensure our workloads are warmed and ready to go in the morning. Pairing this with Karpenter, we end up with zero toil and a fully awake cluster ready to go before the first few developers start signing on!&lt;/p&gt;

&lt;p&gt;In the event that there are some early birds, during the night, we still do fallback to metric scaling after our cron triggers. This allows us to ensure the pods are always available if needed. &lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Autoscaling is not just about surviving peak traffic, it's about efficiency. By combining KEDA's event based triggers, and Karpenter's node management, we no longer burn cash on empty compute. &lt;/p&gt;

&lt;p&gt;Stop paying for idle time. Make your infrastructure work for you, not the other way around.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>observability</category>
      <category>devops</category>
    </item>
    <item>
      <title>Rightsizing Kubernetes Requests with the In-Place Vertical Pod Autoscaler</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Tue, 09 Dec 2025 15:29:49 +0000</pubDate>
      <link>https://dev.to/klip_klop/rightsizing-kubernetes-requests-with-the-in-place-vertical-pod-autoscaler-299m</link>
      <guid>https://dev.to/klip_klop/rightsizing-kubernetes-requests-with-the-in-place-vertical-pod-autoscaler-299m</guid>
      <description>&lt;p&gt;The Vertical Pod Autoscaler was not production ready. Initially it required restarting pods in order to change resource limits, but with the new &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; feature, we are now able to right-size our requests dynamically without killing the application.&lt;/p&gt;

&lt;p&gt;Here is how we are using it to cut pod waste and reduce churn.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The "Over-Provisioning" Tax&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When deploying a new, or even an old service, it's a common pattern to pad the requests to be safe and ensure the service is operating healthily and happily. &lt;/p&gt;

&lt;p&gt;Given this example:&lt;/p&gt;

&lt;p&gt;We are deploying a service to process PDFs in a job queue. We load test this and we estimate that it takes around 250MB's of memory and 250m of CPU. Just in case though, we are going to pad the service and give it 500MB's, and 500m of CPU to ensure nothing goes wrong, now multiply that by 10-500 microservices, and suddenly our cluster is running at 30% utilization while we basically pay to reduce toil.&lt;/p&gt;

&lt;p&gt;Historically, fixing this was a manual nightmare of checking Grafana dashboards and adjusting YAML files.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why We Avoided VPA Before&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We initially avoided the Vertical Pod Autoscaler due to it's destructive updates. &lt;/p&gt;

&lt;p&gt;To change a pod's CPU or Memory requests, VPA had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Evict the Pod.&lt;/li&gt;
&lt;li&gt;Wait for the Scheduler to recreate it with new numbers.&lt;/li&gt;
&lt;li&gt;Hope your application handles the graceful shutdown correctly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For any stateful workloads, or services with larger docker files, this restart tax was painful. &lt;/p&gt;

&lt;p&gt;Initially we could run the VPA and set the &lt;code&gt;updateMode: off&lt;/code&gt; and then double check the recommendations, but that becomes a painful and manual process. Especially if our load fluctuates significantly throughout the day. Why pay for 500m of CPU at 2 A.M. if we only actually need it during normal business hours?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Game Changer: In-Place Updates&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Introduced in Kubernetes version 1.33, in beta, the &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; update mode for the Vertical Pod Autoscaler! &lt;/p&gt;

&lt;p&gt;Instead of only resizing pods during creation using a web-hook, the &lt;code&gt;kubelet&lt;/code&gt; can now resize resources allocated to running containers without even restarting it! If the node is full, then it goes ahead and reschedules the pod to a new node with the desired compute / memory available.&lt;/p&gt;

&lt;p&gt;This moves VPA from "scary experimental tool" to "essential cost-saving infrastructure."&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How We Implemented It&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We shifted our strategy to use the &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; update mode. Here is the configuration we are rolling out to our stateless workers:&lt;/p&gt;

&lt;p&gt;YAML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: backend-service
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: backend
  resourcePolicy:
    containerPolicies:
      - containerName: '*'
        minAllowed:
          cpu: 100m
          memory: 100Mi
        maxAllowed:
          cpu: 1000m
          memory: 1000Mi
        controlledResources: ["cpu", "memory"]
  updatePolicy:
    minReplicas: 1
    updateMode: InPlaceOrRecreate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Our Rightsizing Workflow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We don't just turn this on blindly. Here is the safety workflow we use for existing services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audit Mode:&lt;/strong&gt; (&lt;code&gt;updateMode: Off&lt;/code&gt;): We deploy the VPA with updates disabled. We let it run for 1 week to gather metrics on actual usage vs. requests.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review Recommendations&lt;/strong&gt;: We check the VPA object status (&lt;code&gt;kubectl describe vpa &amp;lt;name&amp;gt;&lt;/code&gt;) to see what the engine &lt;em&gt;would&lt;/em&gt; do. &lt;em&gt;Pro-tip: If the recommendation is 50% lower than current requests, we know we are wasting money.&lt;/em&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable In-Place&lt;/strong&gt;: Once we trust the baseline, we switch to &lt;code&gt;InPlaceOrRecreate&lt;/code&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor:&lt;/strong&gt; We monitor to make sure that we aren’t getting OOMkills and to verify that application metrics are not trending in the wrong direction.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Things to Note&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Three things to note before going through this workflow! &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Some runtime’s do not currently support the update mode &lt;code&gt;InPlaceOrRecreate&lt;/code&gt;, it’s dependent on application code or runtimes to support this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When Using an HPA and a VPA on the same resource, be careful that you are not increasing your CPU while the HPA is testing the CPU to see whether or not to scale up additional replicas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using KEDA to horizontally scale applications based on: &lt;strong&gt;latency, traffic, errors&lt;/strong&gt; or &lt;strong&gt;saturation&lt;/strong&gt; metrics has essentially solved this for us.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The In-place VPA allows us to treat resource requests as fluid, living values rather than static guesses. It’s helping us pack nodes tighter and stop paying for wasted resources in our clusters.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>linux</category>
      <category>sre</category>
    </item>
    <item>
      <title>Rightsizing Kubernetes Requests with the In-Place Vertical Pod Autoscaler</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Tue, 09 Dec 2025 15:29:49 +0000</pubDate>
      <link>https://dev.to/klip_klop/rightsizing-kubernetes-requests-with-the-in-place-vertical-pod-autoscaler-3b41</link>
      <guid>https://dev.to/klip_klop/rightsizing-kubernetes-requests-with-the-in-place-vertical-pod-autoscaler-3b41</guid>
      <description>&lt;p&gt;The Vertical Pod Autoscaler was not production ready. Initially it required restarting pods in order to change resource limits, but with the new &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; feature, we are now able to right-size our requests dynamically without killing the application.&lt;/p&gt;

&lt;p&gt;Here is how we are using it to cut pod waste and reduce churn.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The "Over-Provisioning" Tax&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When deploying a new, or even an old service, it's a common pattern to pad the requests to be safe and ensure the service is operating healthily and happily. &lt;/p&gt;

&lt;p&gt;Given this example:&lt;/p&gt;

&lt;p&gt;We are deploying a service to process PDFs in a job queue. We load test this and we estimate that it takes around 250MB's of memory and 250m of CPU. Just in case though, we are going to pad the service and give it 500MB's, and 500m of CPU to ensure nothing goes wrong, now multiply that by 10-500 microservices, and suddenly our cluster is running at 30% utilization while we basically pay to reduce toil.&lt;/p&gt;

&lt;p&gt;Historically, fixing this was a manual nightmare of checking Grafana dashboards and adjusting YAML files.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why We Avoided VPA Before&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We initially avoided the Vertical Pod Autoscaler due to it's destructive updates. &lt;/p&gt;

&lt;p&gt;To change a pod's CPU or Memory requests, VPA had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Evict the Pod.&lt;/li&gt;
&lt;li&gt;Wait for the Scheduler to recreate it with new numbers.&lt;/li&gt;
&lt;li&gt;Hope your application handles the graceful shutdown correctly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For any stateful workloads, or services with larger docker files, this restart tax was painful. &lt;/p&gt;

&lt;p&gt;Initially we could run the VPA and set the &lt;code&gt;updateMode: off&lt;/code&gt; and then double check the recommendations, but that becomes a painful and manual process. Especially if our load fluctuates significantly throughout the day. Why pay for 500m of CPU at 2 A.M. if we only actually need it during normal business hours?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Game Changer: In-Place Updates&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Introduced in Kubernetes version 1.33, in beta, the &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; update mode for the Vertical Pod Autoscaler! &lt;/p&gt;

&lt;p&gt;Instead of only resizing pods during creation using a web-hook, the &lt;code&gt;kubelet&lt;/code&gt; can now resize resources allocated to running containers without even restarting it! If the node is full, then it goes ahead and reschedules the pod to a new node with the desired compute / memory available.&lt;/p&gt;

&lt;p&gt;This moves VPA from "scary experimental tool" to "essential cost-saving infrastructure."&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How We Implemented It&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We shifted our strategy to use the &lt;code&gt;InPlaceOrRecreate&lt;/code&gt; update mode. Here is the configuration we are rolling out to our stateless workers:&lt;/p&gt;

&lt;p&gt;YAML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: backend-service
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: backend
  resourcePolicy:
    containerPolicies:
      - containerName: '*'
        minAllowed:
          cpu: 100m
          memory: 100Mi
        maxAllowed:
          cpu: 1000m
          memory: 1000Mi
        controlledResources: ["cpu", "memory"]
  updatePolicy:
    minReplicas: 1
    updateMode: InPlaceOrRecreate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Our Rightsizing Workflow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We don't just turn this on blindly. Here is the safety workflow we use for existing services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audit Mode:&lt;/strong&gt; (&lt;code&gt;updateMode: Off&lt;/code&gt;): We deploy the VPA with updates disabled. We let it run for 1 week to gather metrics on actual usage vs. requests.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review Recommendations&lt;/strong&gt;: We check the VPA object status (&lt;code&gt;kubectl describe vpa &amp;lt;name&amp;gt;&lt;/code&gt;) to see what the engine &lt;em&gt;would&lt;/em&gt; do. &lt;em&gt;Pro-tip: If the recommendation is 50% lower than current requests, we know we are wasting money.&lt;/em&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable In-Place&lt;/strong&gt;: Once we trust the baseline, we switch to &lt;code&gt;InPlaceOrRecreate&lt;/code&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor:&lt;/strong&gt; We monitor to make sure that we aren’t getting OOMkills and to verify that application metrics are not trending in the wrong direction.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Things to Note&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Three things to note before going through this workflow! &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Some runtime’s do not currently support the update mode &lt;code&gt;InPlaceOrRecreate&lt;/code&gt;, it’s dependent on application code or runtimes to support this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When Using an HPA and a VPA on the same resource, be careful that you are not increasing your CPU while the HPA is testing the CPU to see whether or not to scale up additional replicas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using KEDA to horizontally scale applications based on: &lt;strong&gt;latency, traffic, errors&lt;/strong&gt; or &lt;strong&gt;saturation&lt;/strong&gt; metrics has essentially solved this for us.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The In-place VPA allows us to treat resource requests as fluid, living values rather than static guesses. It’s helping us pack nodes tighter and stop paying for "air" in our clusters.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>linux</category>
      <category>sre</category>
    </item>
    <item>
      <title>What is eBPF?</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Sat, 07 Dec 2024 21:26:47 +0000</pubDate>
      <link>https://dev.to/klip_klop/what-is-ebpf-ke0</link>
      <guid>https://dev.to/klip_klop/what-is-ebpf-ke0</guid>
      <description>&lt;h3&gt;
  
  
  Intro
&lt;/h3&gt;

&lt;p&gt;The goal of this post is to introduce what eBPF is and give an example as to why we should care about it. At the end, I will share my Dockerfile that you can use to work on eBPF programs, on a Macbook with a m series chip.&lt;/p&gt;

&lt;p&gt;If you don’t plan on sticking around, please at least read the word of caution regarding eBPF, it’s only magic, if we decide not to understand it!&lt;br&gt;
A Word Of Caution Regarding eBPF&lt;/p&gt;

&lt;p&gt;I also want to provide an upfront warning. Just because a tool markets itself as using “eBPF” does not mean that it is performant. All tools should be measured and understood before being using in an environment where latency matters. The more middleware we add to an application, the longer calls take. The same is true about running tools in the kernel space.&lt;/p&gt;

&lt;p&gt;When running a program on Kubernetes, or anywhere really, we need to think about security. Do we trust this program to have access to read everything we do.. We should always provision with the least amount of access as possible. Please do understand Pod Security Context before implementing any of these solutions.&lt;/p&gt;

&lt;p&gt;Do also read through the eBPF Security Threat Model written by Jack Kelly, James Callaghan, and Andrew Martin. It is a great primer, and really helps you understand eBPF.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is eBPF
&lt;/h3&gt;

&lt;p&gt;eBPF stand for Extended Berkley Packet Filter. It came out as available in the linux kernel 3.18 and basically extended the existing Berkley Packet Filter. The existing BPF implementation was used to only filter and capture network packets. This tool lived in the kernel space making it fast, and not as accessible for the user.&lt;/p&gt;

&lt;p&gt;eBPF made it possible for users to configure small programs to run on a lot of different hooks, such as:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System Calls
Kernel Functions
Network Events 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This basically means that for most events, eBPF can be configured to run a program in the kernel space. These programs can modify the events, or they can simply record the events, which we see often in the observability space.&lt;/p&gt;

&lt;p&gt;eBPF extended the Linux Kernel to the user, allowing us to configure low level programs to collect, record, and alter data.&lt;br&gt;
Why run programs in the kernel space?&lt;/p&gt;

&lt;p&gt;The programs ran here operate in a sandboxed environment where their execution is verified prior to execution. This helps ensure that the program is not going to crash the kernel. These programs are closer to the source that is handling the events, which means handling the events here will provide much better latency and response times. eBPF programs can also be loaded without restarting a node or the kernel, meaning programs can be dynamically added to the kernel space while the system is running.&lt;/p&gt;

&lt;p&gt;eBPF really shines due to it’s low level of execution and it being triggered on tons of hooks into the kernel. This makes it an ideal candidate to provide low level observability into how a system is performing, it’s networking calls, and the security for the system. Some of the core things that eBPF can monitor are:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System Calls
Filesystem Activity
Processes
Security Auditing
Network Traffic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We can think of eBPF as a magical tool that essentially provides us with x-ray vision into the linux host.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why use eBPF?
&lt;/h3&gt;

&lt;p&gt;Well, monitoring of course! Observability, at the lowest level. There is less latency and we can observe events at the lowest level. This is incredible when we are looking at it from a security perspective. We can mitigate and observe filesystem modification, processes, system calls and network traffic as it operates on the host.&lt;/p&gt;

&lt;p&gt;It can provide packet filtering and the ability to proactively drop packets that could otherwise be malicious. Other eBPF programs give us deep application insights all the way to the system layer.&lt;/p&gt;

&lt;p&gt;Tools like Cilium are replacing Kube-Proxy and use eBPF instead of iptables or nftables for super efficient load balancing. Keep in mind though, iptables lives in the userspace and nftables, it’s replacement, also lives in the kernel space. It will be interesting to see some performance tests comparing eBPF to efficient use of nftables for load balancing. Although, I think we will likely always get “more” when using eBPF, just due to how we can monitor it and export the data to other services.&lt;/p&gt;

&lt;p&gt;Tools like &lt;a href="https://www.parca.dev/" rel="noopener noreferrer"&gt;parca&lt;/a&gt; enable us to quickly find out if we are introducing a lot of latency to our application by understanding how our application is using the hosts memory, CPU, and IO. It helps bring to light inefficient system calls, like file.Open(), or maybe we are processing a byte array slowly in memory, and that is causing our latency for an application call to be 100ms higher then it needed to be.&lt;/p&gt;

&lt;p&gt;Within the next couple posts, I will add some tutorials to showcase how to build and run eBPF programs. Below is the Dockerfile that I am using. I’ll re-post it, once I write up the tutorial though!&lt;br&gt;
&lt;code&gt;Dockerfile&lt;/code&gt; for eBPF development&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install -y --no-install-recommends \
    build-essential \
    clang \
    llvm \
    libelf-dev \
    linux-headers-generic \
    pkg-config \
    git \
    curl \
    vim \
    libbpf-dev \
    ca-certificates &amp;amp;&amp;amp; \
    apt-get clean &amp;amp;&amp;amp; \
    rm -rf /var/lib/apt/lists/*

ENV GO_VERSION=1.21.1
RUN curl -LO https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz &amp;amp;&amp;amp; \
    tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz &amp;amp;&amp;amp; \
    rm go${GO_VERSION}.linux-amd64.tar.gz
ENV PATH="/usr/local/go/bin:${PATH}"
ENV GOARCH=arm64

RUN ln -s /usr/include/asm-generic /usr/include/asm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We do have to run this as privileged so it will have access to the necessary system resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build . -t ebpf-dev-container
docker run --privileged --rm -it -v $(pwd):/app -w /app ebpf-dev-container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>linux</category>
      <category>observability</category>
    </item>
    <item>
      <title>Consistent Deployment Strategies for Kubernetes</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Fri, 29 Nov 2024 19:42:13 +0000</pubDate>
      <link>https://dev.to/klip_klop/consistent-deployment-strategies-for-kubernetes-3i9n</link>
      <guid>https://dev.to/klip_klop/consistent-deployment-strategies-for-kubernetes-3i9n</guid>
      <description>&lt;p&gt;There are a few different ways to deploy manifests to Kubernetes. Picking one and sticking with it can be difficult due to lack of support. Some resources support Helm charts, some prefer jsonnet, and then some only support Kustomize. &lt;/p&gt;

&lt;p&gt;Every manifest that is deployed to Kubernetes should be deployed in the same fashion. This will make it massively easier for the Site Reliability Engineering team to manage the infrastructure and have no doubt what to use when deploying any piece of software. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple, is always easier, and often times better.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency over Correctness&lt;/strong&gt;. If I deploy one application with helm, I'd like to deploy everything with helm just to ensure that there is no doubt when deploying anything new. Working over a consistent codebase is always easier, then one that switches back and forth creating more ambiguity. &lt;/p&gt;

&lt;p&gt;This post will explore deploying applications with Kustomize, going over two different examples. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a simple Kubernetes application.&lt;/li&gt;
&lt;li&gt;Using the helm plugin to create an application that uses Helm, with Kustomize.
But first I will cover why I like Kustomize in the first place.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;It is simple and easy with minimal overhead to deploy a single application to a single cluster. &lt;br&gt;
It makes extending an application and applying patches to multiple clusters really simple, no real additional configuration is necessary, aside from a few potentially semi-duplicate manifests in directories prefixed with their cluster-name. It is still possible to deploy helm applications due to the Helm integration, and while doing so, you still have all the benefits from using Kustomize. &lt;/p&gt;
&lt;h2&gt;
  
  
  Deploying an Application with Kustomize
&lt;/h2&gt;

&lt;p&gt;I will walk through two different examples. The first one will include deploying a simple application with Kustomize across multiple clusters, and the second one will include deploying a helm application using Kustomize across multiple clusters.&lt;/p&gt;

&lt;p&gt;From my last blog post, the directory structure in our gitops repository looks similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gitops/
|-birdbox/
|--base/
|  |--kustomization.yaml
|  |--deploy.yaml
|--overlays/
|--|--dev/
|  |---kustomization.yaml
|  |---ingress.yaml
|  |---secrets.yaml
|  |---service-account-patch.yaml
|--|--prd/
|  |---kustomization.yaml
|  |---ingress.yaml
|  |---secrets.yaml
|  |---service-account-patch.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to deploy this application, all we need to do is point ArgoCD's ApplicationSet at the &lt;code&gt;kustomization.yaml&lt;/code&gt; in the &lt;code&gt;{{cluster}}&lt;/code&gt; overlay. It will use that &lt;code&gt;kustomization.yaml&lt;/code&gt; and grab the one from the &lt;code&gt;base&lt;/code&gt; directory and apply all of those manifests. &lt;br&gt;
To give a more concrete example, the &lt;code&gt;kustomization.yaml&lt;/code&gt; in the &lt;code&gt;dev&lt;/code&gt; directory is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
namespace: birdbox
resources:
  - ../../base
  - ./secrets.yaml
  - ./ingress.yaml
patchesStrategicMerge: # this is deprecated
  - ./service-account-patch.yaml
images:
  - name: org/birdbox
    newName: image-repo:birdbox
    newTag: "2AB9Dd4FF"
# add annotation to all resources for 'dev'
commonAnnotations:
  environment: dev
  language: golang
  repo: birdbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is really nice, it shows us exactly what image should be deployed, what resources we are patching, and the annotations that will be applied to the objects that are going to be deployed. This is easy to debug too because Kustomize comes bundled with &lt;code&gt;kubectl&lt;/code&gt; .  This means we can hop in the &lt;code&gt;{{cluster}}&lt;/code&gt; directory, in this case &lt;code&gt;dev&lt;/code&gt; and run &lt;code&gt;kubectl kustomize . &amp;gt; outputs.yaml&lt;/code&gt; This will give us an &lt;code&gt;outputs.yaml&lt;/code&gt; that has all of our manifests from this directory and the subsequent &lt;code&gt;base&lt;/code&gt; directory, that we can verify prior to deployment. &lt;/p&gt;

&lt;p&gt;As of now, for simplicity I prefer updating these manifests via CI/CD PRs updating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;images:
  - name: org/birdbox
    newName: image-repo:birdbox
    newTag: "2AB9Dd4FF"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;code&gt;newTag&lt;/code&gt; field to point to the new image. This makes it so we do not have to worry about versioning and the tags are directly linkable to a commit in our application repository. &lt;/p&gt;

&lt;h2&gt;
  
  
  Kustomize with Helm
&lt;/h2&gt;

&lt;p&gt;In the case of an application like DataDog, or Grafana Loki, it might be a lot simpler to use helm, which seems to be the normal way to deploy most applications that are bundled up from the various vendors. With the Helm Plugin and Kustomize though, we can stick to our consistent approach and use Kustomize for this too.&lt;/p&gt;

&lt;p&gt;In this case our Kustomize manifest will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
namespace: datadog

resources:
  - ../../base
  - ./secrets.yaml

helmCharts:
  - name: datadog
    namespace: datadog  # this sets the namespace for {{ .Relase.Namespace }} in the helm chart
    includeCRDs: true
    valuesFile: datadog-values.yaml
    releaseName: datadog
    version: datadog-3.81.0
    repo: https://helm.datadoghq.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ends up following our previous pattern. Gives us a nice way to deploy our custom &lt;code&gt;values.yaml&lt;/code&gt; and ends up being pretty readable!&lt;/p&gt;

&lt;p&gt;And again, it is really simple to debug with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl kustomize .  --enable-helm &amp;gt; outputs.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to clarify something that has bugged me while writing these blog posts. The &lt;code&gt;secrets.yaml&lt;/code&gt; file that has popped up are not raw secrets. It is an object that references secrets for our cloud provider to download and sync them into our cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By using Kustomize, we can ensure that all of our manifests are deployed in a consistent manner. It gives us the ability to deal with raw kubernetes manifests and provides an easy enough interface to patch objects so that I do not feel like I am missing out when configuring manifests. Of course, we do not get the full benefit of helm templates, but I still prefer simple manifests that can be referenced and then patched when necessary. Kustomize also offers a nice easily debuggable approach that is consistent across all of our applications. &lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>gitops</category>
      <category>cloud</category>
      <category>cicd</category>
    </item>
    <item>
      <title>GitOps Across Clusters — How ArgoCD and Kustomize Makes It Simple</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Sat, 23 Nov 2024 03:07:52 +0000</pubDate>
      <link>https://dev.to/klip_klop/gitops-across-clusters-how-argocd-and-kustomize-makes-it-simple-489j</link>
      <guid>https://dev.to/klip_klop/gitops-across-clusters-how-argocd-and-kustomize-makes-it-simple-489j</guid>
      <description>&lt;p&gt;Working with Kubernetes is fun and rewarding, wait... did I get that right? Overwhelming and complex... Just Kidding, I really do enjoy working with Kubernetes. &lt;/p&gt;

&lt;p&gt;If a Site Reliability Engineer were to manage several clusters and lots of different applications in those clusters, it could quickly become stressful. &lt;/p&gt;

&lt;p&gt;Even just thinking about having to run &lt;code&gt;kubectl apply&lt;/code&gt; manually makes me sweat. &lt;/p&gt;

&lt;p&gt;Instead, everything inside of our various Kubernetes clusters is done automatically via ArgoCD's continuous polling of our GitOps repository. &lt;/p&gt;

&lt;p&gt;To better understand why GitOps is an optimal solution, we should know the four principles that sort of make up the idea of GitOps. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It's Declarative, your end state is defined.&lt;/li&gt;
&lt;li&gt;Application manifests are versioned and their history is stored&lt;/li&gt;
&lt;li&gt;Application manifests are continuously pulled &lt;/li&gt;
&lt;li&gt;State is continuously reconciled&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now to get to the fun part. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is ArgoCD and why use it?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://argo-cd.readthedocs.io/en/stable/#why-argo-cd" rel="noopener noreferrer"&gt;ArgoCD&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why Argo CD?&lt;br&gt;
Application definitions, configurations, and environments should be declarative and version controlled. Application deployment and lifecycle management should be automated, auditable, and easy to understand&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It embodies the principles governing GitOps and becomes a great tool for the job. It automatically polls our gitops repository and continuously reconciles it, making sure that the desired state is the current state in our Kubernetes cluster. This makes it a lot easier for anyone operating within the cluster to understand the desired state. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Kustomize and why use it?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kustomize.io/" rel="noopener noreferrer"&gt;Kustomize&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kustomize introduces a template-free way to customize application configuration that simplifies the use of off-the-shelf applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kustomize makes it simple to define your application manifest in a &lt;code&gt;base&lt;/code&gt; directory and then define either patches or additional components in an &lt;code&gt;overlay&lt;/code&gt; directory.&lt;br&gt;
I'll go over more examples later in this post. &lt;/p&gt;
&lt;h2&gt;
  
  
  Why not helm?
&lt;/h2&gt;

&lt;p&gt;I don't love templating yaml manifests, in fact, I don't think anyone finds it enjoyable! I also do not want to have to account for new fields in kubernetes manifests as they become available. &lt;br&gt;
Applying helm charts is easy enough, but in my experience it becomes frustrating maintaining helm charts. At first, the Helm chart starts as a general-purpose application chart, but over time, more &lt;code&gt;if&lt;/code&gt; statements are added until the entire template becomes difficult to read.&lt;/p&gt;

&lt;p&gt;I have not yet had that experience with Kustomize.&lt;/p&gt;
&lt;h2&gt;
  
  
  How To Effectively use ArgoCD to Deploy Across Multiple Clusters
&lt;/h2&gt;

&lt;p&gt;Argo has two main resources that can be used to deploy applications. One is an &lt;code&gt;Application&lt;/code&gt; and the other is an &lt;code&gt;ApplicationSet&lt;/code&gt;. I tend to prefer the &lt;code&gt;ApplicationSet&lt;/code&gt; resource. Pairing ArgoCD with Kustomize makes it incredibly easy to set up and maintain multiple applications across multiple clusters. &lt;/p&gt;

&lt;p&gt;To go off on an example, say we want to deploy an application called BirdBox in our Kubernetes clusters (dev, uat, and prd). We could:&lt;br&gt;
Create 3 &lt;code&gt;Application&lt;/code&gt; resources and configure ArgoCD to deploy each of them.&lt;br&gt;
or&lt;br&gt;
Make 1 &lt;code&gt;ApplicationSet&lt;/code&gt; and use a few variables to determine the cluster and path to apply the application automatically across the clusters.&lt;/p&gt;

&lt;p&gt;To get into how we define these &lt;code&gt;ApplicationSet&lt;/code&gt; resources it will be easier to describe our gitops repository layout first. &lt;/p&gt;

&lt;p&gt;We use Kustomize for all of the applications we support and the structure typically is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gitops
├── README.md
├── birdbox
│   ├── base
│   │   ├── kustomization.yaml
│   │   ├── deploy.yaml
│   │   ├── service-account.yaml
│   │   └── service.yaml
│   └── overlays
│       ├── dev
│       │   ├── kustomization.yaml
│       │   ├── ingress.yaml
│       │   ├── secrets.yaml
│       │   ├── service-account-patch.yaml
│       │   ├── hpa-deploy.yaml
│       └── uat
│       │   ├── kustomization.yaml
│       │   ├── ingress.yaml
│       │   ├── secrets.yaml
│       │   ├── service-account-patch.yaml
│       │   ├── hpa-deploy.yaml
│       └── prd
│       │   ├── kustomization.yaml
│       │   ├── ingress.yaml
│       │   ├── secrets.yaml
│       │   ├── service-account-patch.yaml
│       │   ├── hpa-deploy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, back to the &lt;code&gt;ApplicationSet&lt;/code&gt; resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: birdbox
  namespace: argocd
spec:
  ignoreApplicationDifferences:
    - jsonPointers:
        - /spec/syncPolicy
  generators:
    - list:
        elements:
          - cluster: dev
            url: https://xxx.xxx.xxx.xxx.xxx.com
          - cluster: uat
            url: https://xxx.xxx.xxx.xxx.xxx.com
          - cluster: prd
            url: https://xxx.xxx.xxx.xxx.xxx.com
  template:
    metadata:
      name: '{{cluster}}-birdbox'
    spec:
      project: default
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true
      source:
        repoURL: https://github.com/${ORG}/gitops.git
        targetRevision: main
        path: birdbox/overlays/{{cluster}}
      destination:
        server: '{{url}}'
        namespace: birdbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ApplicationSet will dynamically create the application across the various clusters: &lt;code&gt;{{cluster}}-birdbox&lt;/code&gt;&lt;br&gt;
We can use the name of the &lt;code&gt;{{cluster}}&lt;/code&gt; to dynamically apply the correct path for the application, which matches our gitops application structure.&lt;/p&gt;

&lt;p&gt;To be more specific. In our &lt;code&gt;dev&lt;/code&gt; cluster, this &lt;code&gt;ApplicationSet&lt;/code&gt; will look in our &lt;code&gt;gitops&lt;/code&gt; repository under the path: &lt;code&gt;birdbox/overlays/dev&lt;/code&gt; and that &lt;code&gt;kustomization.yaml&lt;/code&gt; manifest will reference the &lt;code&gt;kustomization.yaml&lt;/code&gt; manifest located in the base of the application directory. This makes it so we only have to define our app manifests once, and then we can define more cluster specific manifests in their own directories. In the above example, we apply a &lt;code&gt;service-account-patch.yaml&lt;/code&gt; to patch an annotation on our service accounts to link them to the IAM Roles for Service Accounts (IRSA). We also tend to keep &lt;code&gt;ingress.yaml&lt;/code&gt; defined at the environment layer, due to differing Ingress-nginx annotations and the lack of desire to patch everything. &lt;/p&gt;

&lt;p&gt;ApplicationSet's also provide an easy way to ignore certain differences in applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ignoreApplicationDifferences:
    - jsonPointers:
        - /spec/syncPolicy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to quickly disable application auto syncing in the ArgoCD UI in case of an emergency where we need to either patch something, while we work on a more declarative fix. It also helps in the case that ArgoCD might start thrashing if some how the application state does not match what is in the GitOps repository. &lt;/p&gt;

&lt;h2&gt;
  
  
  ApplicationSets to rule Applications
&lt;/h2&gt;

&lt;p&gt;Earlier I mentioned that I never want to have to run &lt;code&gt;kubectl apply&lt;/code&gt;, and while that is true, there is one manifest that still needs applied manually: the &lt;code&gt;Application&lt;/code&gt; that maintains the other &lt;code&gt;ApplicationSets&lt;/code&gt;. This resource is an &lt;code&gt;Application&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: applicationset-controller
  namespace: argocd
spec:
  project: default
  syncPolicy:
    automated:
      prune: false
      selfHeal: true
  destination:
    name: ''
    namespace: argocd
    server: https://kubernetes.default.svc
  source:
    repoURL: https://github.com/${ORG}/gitops.git
    targetRevision: main
    path: argocd/appsets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, with this resource, whenever anyone is to PR a new &lt;code&gt;ApplicationSet&lt;/code&gt; to our gitops repository, it will automatically sync that &lt;code&gt;ApplicationSet&lt;/code&gt; to ArgoCD, and then to the various clusters. This enables us to implement well-scoped Role-Based Access Controls (RBAC) to ensure our compliance with the four principles of GitOps. The only exception is for production related emergencies, which usually involve a breakglass situation.&lt;/p&gt;

&lt;p&gt;In an attempt to keep these short and sweet I will cover how to deploy new application images and go further in depth in to our Kustomize manifests in the next post! &lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>gitops</category>
      <category>cloud</category>
      <category>cicd</category>
    </item>
    <item>
      <title>CI/CD Observability and Why it matters.</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Thu, 22 Feb 2024 02:48:20 +0000</pubDate>
      <link>https://dev.to/klip_klop/cicd-observability-and-why-it-matters-o20</link>
      <guid>https://dev.to/klip_klop/cicd-observability-and-why-it-matters-o20</guid>
      <description>&lt;h2&gt;
  
  
  CI/CD Observability
&lt;/h2&gt;

&lt;p&gt;There are plenty of posts on the importance of Observability. While it is important to have within the applications running the workloads. It is equally important to have it inside the CI/CD pipelines as well.&lt;/p&gt;

&lt;p&gt;Having a deep understanding of your CI/CD pipeline will show when changes happen, how long does it take for that change to become live.&lt;/p&gt;

&lt;p&gt;If an incident happens, how long will it take till the fix is live?&lt;/p&gt;

&lt;p&gt;how many changes result in a failure?&lt;/p&gt;

&lt;p&gt;what is the deployment frequency?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CI/CD Observability is Important
&lt;/h2&gt;

&lt;p&gt;Normally, when we think about Observability, it is in relation to applications and the various endpoints, functions, database calls associated with it.&lt;/p&gt;

&lt;p&gt;I find that one place that lacks observability is often inside of CI/CD Pipelines themselves. This is necessary for us to be able to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how long do builds usually take?&lt;/li&gt;
&lt;li&gt;do we have flaky tests? If so, which ones are they?&lt;/li&gt;
&lt;li&gt;how many apps are within xx compliance?&lt;/li&gt;
&lt;li&gt;how long do deploys take for a given application?&lt;/li&gt;
&lt;li&gt;did this rise or fall within the last week, and if so, why?&lt;/li&gt;
&lt;li&gt;how many times is code pushed for X repository?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Observability Can Help
&lt;/h2&gt;

&lt;p&gt;A lot of these questions are extremely difficult to answer unless we are logging and gathering traces of the CI/CD pipeline throughout its various stages.&lt;/p&gt;

&lt;p&gt;But a lot of these questions are really important.&lt;/p&gt;

&lt;p&gt;For example, if we know an application had been fully deploying within 5 minutes, and it is trending to 7 minutes we can start to inspect other areas of the system that might be the root cause for this. This will also help visually highlight when this trend started.&lt;/p&gt;

&lt;p&gt;In that example we might look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;has application startup time increased?&lt;/li&gt;
&lt;li&gt;are we fighting pod disruption budgets due to startup time increase?&lt;/li&gt;
&lt;li&gt;are we having trouble scheduling our workloads? What does node pressure look like?&lt;/li&gt;
&lt;li&gt;do we need to scale up new nodes preemptively?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;From there, if we are logging and graphing the various metrics we need to make these determinations we can go back and easily see what changed, and when the deployment time increased. This makes it relatively easy to determine the commit it happened on, and start diagnosing the root cause from there. Or diagnose the correct system that is responsible for the new delay.&lt;/p&gt;

&lt;p&gt;Having these metrics and this level of observability within the CI/CD pipeline starts to enable the ability to easily roll back changes, notify relevant developers and helps ensure that the applications remain healthy and happy.&lt;/p&gt;

&lt;p&gt;Embedding observability into the CI/CD pipeline not only helps understand code deployment, but it also really highlights deficiencies in our testing frameworks. We can use observability to identify unreliable / flaky tests. Once we have identified the various tests, we can start to see commonalities between failures and then put those metrics into more visual graphs. This will help identify the test and allow us to either fix it or remove it.&lt;/p&gt;

&lt;p&gt;Follow up to come on how we are implementing observability inside of GitHub actions!&lt;/p&gt;

</description>
      <category>sre</category>
      <category>telemetry</category>
      <category>cicd</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>KubeCon + CloudNativeCon 2023 - NA</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Sun, 12 Nov 2023 04:47:37 +0000</pubDate>
      <link>https://dev.to/klip_klop/kubecon-cloudnativecon-2023-na-1cc5</link>
      <guid>https://dev.to/klip_klop/kubecon-cloudnativecon-2023-na-1cc5</guid>
      <description>&lt;h2&gt;
  
  
  Thoughts
&lt;/h2&gt;

&lt;p&gt;My thoughts on KubeCon + CloudNativeCon&lt;/p&gt;

&lt;p&gt;This year the conference was in the McCormick Place in Chicago. A beautiful city, and a large venue. There was plenty of room for the various talks, which all filled up quite fast. There were a few that I did not make it to because of the amount of people, which is awesome though. I most will follow up and watch those sessions as they come out later!&lt;/p&gt;

&lt;p&gt;There was a cool sticker system for the badges. There were green, yellow and red stickers. Each one indicating your social level. Green -- open to talk, yellow -- hesitant, red -- not interested. That or these served as a level of comfort to social distancing. I found this helpful because I enjoy the networking part of the conference. This made it easy to identify others who enjoyed taking moments to talk about the conference.&lt;/p&gt;

&lt;p&gt;The Kubecrawl on the first day of the conference was a lot of fun. So many vendors helped take part and made it a wonderful event. Some gave out fresh baked cookies, cotton candy, brews and hosted small little carnival style challenges. This made for a really fun night. Also, it was great to see Phippy and a few of their friends out wandering around the event!&lt;/p&gt;

&lt;p&gt;The breakfast and lunch provided had a nice set of healthy options each day. This kept me feeling ready to learn and take part each day.&lt;br&gt;
McCormick Place also provided a coat drop-off and bag-drop area, which was on the lower level and open from before the event started to well after it ended. This made it really nice so that you did not have to carry around coats or swag all day.&lt;/p&gt;

&lt;p&gt;Another thing I found helpful was the staff stationed around the event. They were helpful in directing people towards the various events and talks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Networking and Community
&lt;/h2&gt;

&lt;p&gt;As a Site Reliability Engineer I have a lot of fun doing any number of tasks that I get to work on. A typical day might look like: Improving existing infrastructure, coming up with novel solutions to a problem, or helping out and making sure the developers have what they need from us so that they can continue to be productive.&lt;/p&gt;

&lt;p&gt;At KubeCon there was a good mix of different professions. There were a lot of other developers, product managers, VP's, CTO's, other SRE's and DevOps practitioners. With the different professions that were there it gave me a good chance to get out of my comfort zone and interview so many people. I was able to talk to a lot of the community members that help make up the Cloud Native Computing Foundation (CNCF).&lt;/p&gt;

&lt;p&gt;Being a part of this passionate community is one of my favorite parts of what I get to do. Sometimes during day to day work, it can be isolating, especially with most jobs being remote. I am not sure that anyone enjoys building something by themselves. I know that I value input from my coworkers and the community members. Conferences like this provide a great time to go out and seek that input. Especially from other industry experts.&lt;/p&gt;

&lt;p&gt;A funny example that I can think of is, if I was to build something, isolated, on my own island it might turn out pretty cool. If I could tour hundreds of other islands and receive feedback from other people before building that feature, it will likely turn out to be something great. In this example, sure there is so much googling you can do and researching what is out there. To me, that never compares to going out and talking to other members of the community.&lt;/p&gt;

&lt;p&gt;I also love hearing about the new and exciting things happening within the Cloud Native community. It was also fun getting to celebrate the various projects that the community is now incubating, and especially those that graduated. Getting to see all that hard work become something excellent is wonderful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exposure
&lt;/h2&gt;

&lt;p&gt;Conferences like this also help act as a sort of North Star to me. I will go for months plugging away having fun, but these conferences always help shed new light on things and re-energize my drive to do what I do.&lt;/p&gt;

&lt;p&gt;Conferences like these also help expose us to the new technologies and tools coming out, which helps us do our job better and help enhance our systems' reliability and efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Talks that I enjoyed
&lt;/h2&gt;

&lt;p&gt;There were a lot of good sessions that bring interesting perspectives and novel solutions.&lt;/p&gt;

&lt;p&gt;Specific sessions that I enjoyed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A Tiny Talk on Tiny Containers -- Eric Gregory&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://drive.google.com/file/d/1dJ81z9Gss3K5hcXUcSYbiawD5WxW01N1/view" rel="noopener noreferrer"&gt;slides&lt;/a&gt;
Reducing image size of containers makes them much more efficient, sustainable and easier to secure. This quick talk focuses on these three key things as it demonstrates some best practices when building docker containers and then gives a quick peek at WASM (Web Assembly) and how tiny of a footprint it can take up.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;15,000 Minecraft Players Vs One K8s Cluster. Who Wins? -- Justin Head, Super League Gaming &amp;amp; Cornelia Davis, Spectro Cloud&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://static.sched.com/hosted_files/kccncna2023/ac/15%2C000%20Minecraft%20players%20vs.%20one%20K8s%20cluster-%20SLG%20%26%20SC.pdf" rel="noopener noreferrer"&gt;slides&lt;/a&gt;
In this talk Justin Head and Cornelia Davis demonstrated how much MAAS (metal as a service), and the cAPI (cluster API) has evolved and simplified deploying a kubernetes clusterto an on prem datacenter. By doing this they were able to see 55-60% cost reduction for their machine costs, and 90-100% cost reduction for networking. This did come with some interesting problems though. Due to the nature of physical machines, the boot time for their nodes was upwards of 15 minutes, so there was a lot of work that went into pre-provisioning and having nodes ready to go. This helped make it so that players would not have to wait 15 minutes for new nodes to come online.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;A Practical Guide to Debugging Browser Performance with OpenTelemetry -- Purvi Kanal&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://static.sched.com/hosted_files/kccncna2023/9a/Kubecon%20Web%20Perf%20Talk-1.pdf" rel="noopener noreferrer"&gt;slides&lt;/a&gt;
This talk gave a quick intro to how page load time was and is often times measured. It then dove deeper into how we can instrument Open Telemetry. And use it to gather more effective metrics that come from real users.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I will be adding more to this list as I have time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Swag
&lt;/h2&gt;

&lt;p&gt;I was not planning on mentioning swag when I decided to write this, but anyone that knows me, knows I love reading.&lt;/p&gt;

&lt;p&gt;A lot of vendors this year gave out books as swag. I always appreciate stickers and shirts, but the books are valuable. A few of the books that I received from the various sponsors were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitOps Cookbook, Kubernetes Automation in Practice by Natale Vinto &amp;amp; Alex Soto Bueno&lt;/li&gt;
&lt;li&gt;Observability Engineering, Achieving Production Excellence  by Charity Majors, Liz Fong-Jones &amp;amp; George Miranda&lt;/li&gt;
&lt;li&gt;Kubernetes Up &amp;amp; Running, Dive into the Future of Infrastructure by Brendan Burns, Joe Beda, Kelsey Hightower &amp;amp; Lachlan Evenson&lt;/li&gt;
&lt;li&gt;DevSecOps in Kubernetes, by Wei Lien Dang &amp;amp; Ajmal Kohgadai (Report)&lt;/li&gt;
&lt;li&gt;What is eBPF? An Introduction to a New Generation of Networking, Security and Observability Tools by Liz Rice (Report)&lt;/li&gt;
&lt;li&gt;A Gentle Introduction To OpenSearch by Mitch Seymour&lt;/li&gt;
&lt;li&gt;Phippy's Field Guide to WASM by Matt Butcher &amp;amp; Karen Chu&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Alert Fatigue, and How to Fix it</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Sat, 11 Nov 2023 04:17:13 +0000</pubDate>
      <link>https://dev.to/klip_klop/alert-fatigue-and-how-to-fix-it-34nl</link>
      <guid>https://dev.to/klip_klop/alert-fatigue-and-how-to-fix-it-34nl</guid>
      <description>&lt;h2&gt;
  
  
  What is Alert Fatigue?
&lt;/h2&gt;

&lt;p&gt;For somebody working in tech, especially as a Site Reliability Engineer or in a DevOps role, they are very likely facing a barrage of alerts that show numerous problems with plenty of the services they are supporting.&lt;/p&gt;

&lt;p&gt;Alert fatigue generally happens when alerts are not actionable, or they are so frequent that eventually you end up tuning out the Slack channel because it would be impossible to actually get work done while triaging each alert.&lt;/p&gt;

&lt;p&gt;A good example of alerts that end up causing fatigue are utilization alerts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;disk space is high&lt;/li&gt;
&lt;li&gt;memory for a service is high&lt;/li&gt;
&lt;li&gt;cpu utilization is high&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a service is near a metric threshold, we often get alerted about it, but if that alert is not actionable, it is not actually helpful.&lt;/p&gt;

&lt;p&gt;I find that implementing these utilization alerts with an evaluation period certainly helps reduce the stream of alerts because we are no longer capturing just utilization spikes.For example, if a memory alert is set to alert on &lt;code&gt;max_memory &amp;gt; 85%&lt;/code&gt; the alert could become really noisy. A better alert might look like: &lt;code&gt;avg_memory &amp;gt; 85% for 5 minutes&lt;/code&gt;.&lt;br&gt;
This is still going to capture samples that would help indicate if we were to need to increase request/limit's for a service, but this will be much less noisy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Impacts
&lt;/h2&gt;

&lt;p&gt;Alert fatigue can cause us to overlook or miss the alerts that are actually important. Or the engineer might spend their whole day looking into the alerts, not realizing that they are maybe set to be a bit to sensitive. I have seen this happen numerous times. One engineer will ignore all of them because they are used to them and in the past most have not been actionable, and the next engineer who is on call will spend their entire shift looking into each alert, when the likely culprit is just normal load.&lt;/p&gt;

&lt;p&gt;The actionable item at this point is adjusting the alert, or cpu/memory requests and limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combating Alert Fatigue
&lt;/h2&gt;

&lt;p&gt;The first thing engineers can and should do is try to make the alerts as simple as possible. If there is a noisy alert that is plaguing you today. Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why is this alerting?&lt;/li&gt;
&lt;li&gt;Is this actionable?

&lt;ul&gt;
&lt;li&gt;how do I make this actionable? &lt;strong&gt;this should become the new alert&lt;/strong&gt;
The solution might be to add a longer evaluation period, increase memory/cpu, or remove the alert.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Challenge of Alarms
&lt;/h2&gt;

&lt;p&gt;Often times teams do not get to set up their alerts from the ground up, but even when they do, it is hard to not alert on everything. To get detailed memory and cpu alerts for a new service, we could load test in a production like environment, but not everyone has the time or infrastructure to set that up.&lt;br&gt;
To set up these alerts for a service that has been running, hopefully we have historical metrics that we can look at. As these alerts start to happen, we should be frequently revising these alerts until there is very few of them, or they are actionable when they do happen.&lt;/p&gt;

&lt;p&gt;Another interesting thing we should look at is composite alerts.&lt;/p&gt;

&lt;p&gt;If a service has &amp;gt; 85% memory utilization, how does this affect the service? Are we noticing latency increases? Has our error rate went up?&lt;br&gt;
These might be factors that would provide really actionable alerts, that are not just barraging the Slack channel.&lt;/p&gt;

&lt;p&gt;If we see an increase in: &lt;em&gt;latency&lt;/em&gt;, &lt;em&gt;traffic&lt;/em&gt;, &lt;em&gt;errors&lt;/em&gt; or &lt;em&gt;saturation&lt;/em&gt;.&lt;br&gt;
We likely need to know about this, but it's usually not just one thing that that got us to this point. Which is why it is just as important to have a runbook or dashboard for each alert. This helps ensure that if we are alerted on request latency going up, we can quickly verify that the application has enough memory to handle the request, and then start digging into downstream factors such as the latency of the database, or perhaps we hit a ton of cache-misses from our redis instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Setting up composite alerts can be difficult to get right. I prefer to keep alerts as simple as possible.&lt;/p&gt;

&lt;p&gt;Ideally, I'd like an alert on the &lt;a href="https://sre.google/sre-book/monitoring-distributed-systems/" rel="noopener noreferrer"&gt;four golden signals&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;latency&lt;/em&gt; time it takes to service a request&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;traffic&lt;/em&gt; how much demand is being placed on the system (request per second)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;errors&lt;/em&gt; rate of requests that fail

&lt;ul&gt;
&lt;li&gt;note, requests that succeed, but show the wrong content would be considered errors, they are just much harder to capture&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;em&gt;saturation&lt;/em&gt; measure of utilization of memory, cpu, space available. How much load can the sytem handle?&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;With these alerts, they should only be created when we can link to a dashboard or a runbook along with the alert. This is going to save valuable time for the engineer who is looking into these alerts.&lt;/p&gt;

&lt;p&gt;For example, if we alerted on receiving a high rate of errors, I would expect to see a dashboard or runbook indicating that we should look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what kind of errors are happening and how many errors are there??&lt;/li&gt;
&lt;li&gt;sum of 500 internal server error&lt;/li&gt;
&lt;li&gt;sum of 501 not implemented&lt;/li&gt;
&lt;li&gt;sum of 502 bad gateway&lt;/li&gt;
&lt;li&gt;sum of 503 service unavailable&lt;/li&gt;
&lt;li&gt;sum of 504 gateway timeout's
If we can break up the alerts, that's great, if not, we can aggregate them under &lt;code&gt;http_code &amp;gt; 500 for 5 minutes&lt;/code&gt;
From here I would like to be able to see at a quick glance answers to the following questions:&lt;/li&gt;
&lt;li&gt;Are the various services up?&lt;/li&gt;
&lt;li&gt;When was the last deploy pushed, and what was deployed?

&lt;ul&gt;
&lt;li&gt;Is the service being deployed right now?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;How does saturation and latency look?

&lt;ul&gt;
&lt;li&gt;Are resources saturated?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Is there any downstream system affecting something upstream? In this case, a service map can be really helpful. Especially, if at a glance we can see latency, and saturation of those services.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If anyone has any feedback or suggestions, please let me know!&lt;br&gt;
I would love to have a conversation on how you are handling alerts for your services!&lt;/p&gt;

</description>
      <category>sre</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Navigating Security and Compliance</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Mon, 28 Aug 2023 15:34:28 +0000</pubDate>
      <link>https://dev.to/klip_klop/navigating-security-and-compliance-fd</link>
      <guid>https://dev.to/klip_klop/navigating-security-and-compliance-fd</guid>
      <description>&lt;h2&gt;
  
  
  The Challenge of Silos in Team Collaboration
&lt;/h2&gt;

&lt;p&gt;Teams within companies often operate in specialized areas, focusing on their unique responsibilities. Development teams work on features and maintenance, security teams emphasize compliance, and platform teams build tools for developers. While each team has its part in achieving overarching business objectives, collaboration is key to ensuring that efforts align with the company's goals.&lt;/p&gt;

&lt;p&gt;Even in smaller companies, where teams may share resources like a Jira board, silos can form. It's the responsibility of managers and individual contributors to foster communication and prevent barriers that hinder collaboration.&lt;/p&gt;

&lt;p&gt;Understanding the bigger picture is essential. Developers may not need to know specific IP address ranges, but they should be aware of how things run across various environments. The platform team should understand development efforts that might impact server load.&lt;/p&gt;

&lt;p&gt;Isolation can lead to a lack of holistic understanding, diminishing the value of individual contributions to business goals. Collaboration bridges these gaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bridging the Gap Between Security and Development
&lt;/h2&gt;

&lt;p&gt;Sometimes it feels like there is a war. Security vs the rest of the engineering teams. But this is because these teams are not talking on a daily, or at least weekly basis. There is no list or shared set of priorities. Security is focused on keeping the company within the various compliances and making sure that they do not end up on the news. Developers are focused maintaining the various systems, or are sprinting to create new features. The platform team is usually trying to juggle priorities between the various teams they are supporting. &lt;/p&gt;

&lt;p&gt;But there will come a time that security will create high priority tickets and cite some obscure, but very valid, compliance article that mentions having 30, 60, or 90 days to remediate these tickets or fall out of compliance. Then their tickets will jump to the front of the queue. This then pauses developer's and platform team members work. This is where the frustration comes in. Now the various engineering managers have to make a choice, do we keep all this work in progress and focus on paying down security debt? Or do we finish the work in progress, if it is possible within the time frame, and then tackle the security tickets, hoping they do not take too long, so that we do not fall out of compliance. &lt;/p&gt;

&lt;p&gt;This is why it is important that the Security team, the development team, and the platform team meet to discuss priorities, observe each others work, and determine how to achieve business goals together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aligning Security with Business Goals
&lt;/h2&gt;

&lt;p&gt;Sometimes I have felt that Security teams feel like their only goal is to keep the company within compliance. It is so much more than that. They should be involved in setting business goals and taking a large role in vendor selection. They should be one of the determining forces when a team is trying to decide to build something in house, or to outsource it. Having security involved earlier, is always better. &lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Security and Working as a Team
&lt;/h2&gt;

&lt;p&gt;I've ran into it so many times, that the security team are unaware of what domains the developers are responsible for, or even what the platform team members are responsible for.&lt;br&gt;
This is unacceptable, like it would be unacceptable for a platform team member to not know what the network topology consists of. &lt;/p&gt;

&lt;p&gt;Involving security from the start helps them be aware of when an effort is related to marketing, or if a specific domain needs to be PCI compliant. Too many times I have seen a security team run their automated scans with little insight to how the business is actually ran. They come back with a bunch of tickets, which are likely solved by firewall rules, or network topology. What peeves me the most is when these scans have full access to the system, bypassing many of those security controls. This results in tickets created, that are already mitigated, but from securities prospective, are not. &lt;/p&gt;

&lt;p&gt;This is hard to balance though, and I am not sure the right answer. I agree with security at every layer, but the company still has to run, and we still have to meet business objectives.&lt;/p&gt;

&lt;p&gt;A good security team has established secure development practices for the developers to reduce the amount of vulnerabilities introduced in the system. They will understand the business objectives and be in vendor talks. They will understand the network topology and various controls that are in place to prevent intrusion. And most of all, they will not create a burden for other engineering teams, but try to limit scope of security work to maintain compliance. &lt;/p&gt;

&lt;p&gt;When this happens, other teams work more with the security team and are more happy to invlove them in product discussions sooner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus Checklist
&lt;/h3&gt;

&lt;p&gt;Most people in the engineering department, especially in a smaller company should have a rough idea of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the general business objectives we are working towards achieving?&lt;/li&gt;
&lt;li&gt;How does what I am doing help in achieving those goals?&lt;/li&gt;
&lt;li&gt;At a high level, what systems do we use or support?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By embracing collaboration and breaking down silos, companies can foster a more unified and effective approach to achieving their goals.&lt;/p&gt;

&lt;p&gt;I would love to hear anyone's thoughts on this subject! Please leave a comment and let me know how communication barriers are down at your company!&lt;/p&gt;

</description>
      <category>security</category>
      <category>discuss</category>
      <category>cybersecurity</category>
      <category>community</category>
    </item>
    <item>
      <title>Dive Into Docker part 4: Inspecting Docker Image</title>
      <dc:creator>Kacey Gambill</dc:creator>
      <pubDate>Mon, 21 Aug 2023 19:11:56 +0000</pubDate>
      <link>https://dev.to/klip_klop/dive-into-docker-part-4-inspecting-docker-image-568o</link>
      <guid>https://dev.to/klip_klop/dive-into-docker-part-4-inspecting-docker-image-568o</guid>
      <description>&lt;p&gt;This post is going to be shorter. I'd like to highlight a tool that I really enjoy working with called "&lt;a href="https://github.com/wagoodman/dive" rel="noopener noreferrer"&gt;Dive&lt;/a&gt;" &lt;/p&gt;

&lt;p&gt;Dive is a an essential tool when building or inspecting Dockerfiles. This tool can help pinpoint exactly what is contained in each layer of the Dockerfile. Specifically it &lt;br&gt;
quickly combs through the Dockerfile and tries to show wasted space.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fa9qy4jjq9mjkp9lmwll9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fa9qy4jjq9mjkp9lmwll9.png" alt="dive image wasted space"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Dive
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/wagoodman/dive#installation" rel="noopener noreferrer"&gt;installation-instructions&lt;/a&gt;&lt;br&gt;
My preferred way to install Dive, if using a mac, is to use brew: -- &lt;code&gt;brew install dive&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Dive
&lt;/h2&gt;

&lt;p&gt;I prefer to use dive during local development of Docker containers. To get started I typically just run: &lt;code&gt;dive image-name&lt;/code&gt; if the image is not found locally this will take care of pulling the image from the remote repository. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: tmux keybindings will get in the way, I usually detach from tmux or open another terminal session before using &lt;code&gt;dive&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;dive ruby:3.2.0&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media.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%2Frk49uwm4efb1uqu07oct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Frk49uwm4efb1uqu07oct.png" alt="dive ruby:3.2.0"&gt;&lt;/a&gt;&lt;br&gt;
It first pulls the image if it is not found locally, and then we are presented with "Layers", "Layer Details", "Image Details" and "Current Layer Contents".&lt;/p&gt;

&lt;p&gt;Press  to move between views.&lt;br&gt;
In each view, it presents us with a few more hotkeys that we can use to further inspect this image. &lt;/p&gt;

&lt;p&gt;Looking at the "Layers" tab, it presents us with either "layer changes" or "aggregated changes" on the right-hand side. &lt;br&gt;
You can press either  or  to switch between these two. &lt;/p&gt;

&lt;p&gt;Before moving to the "Layer Contents" view, I like to pick through the various&lt;br&gt;
"Layer Details" right below "Layers"&lt;br&gt;
&lt;a href="https://media.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%2Fpafzpkcklz1yexj94o38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fpafzpkcklz1yexj94o38.png" alt="dive ruby:3.2.0, layer details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here it shows the command that was run to generate that layer. &lt;/p&gt;

&lt;p&gt;On the right-hand side of the screen we can see "Current Layer Contents", this includes the details of the files that were added, removed, permissions on those files and how much space these files are taking up. &lt;br&gt;
If we  over to that view, it presents a few new options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; - collapse single dir&lt;/li&gt;
&lt;li&gt; - collapse all dir's&lt;/li&gt;
&lt;li&gt; Added&lt;/li&gt;
&lt;li&gt; Removed&lt;/li&gt;
&lt;li&gt; modified&lt;/li&gt;
&lt;li&gt; unmodified&lt;/li&gt;
&lt;li&gt; attributes&lt;/li&gt;
&lt;li&gt; wrap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I prefer to start out by collapsing all dir's and then start digging into the layers that are showing the largest increase in file space. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fpq1nnmb3395e87sw6uur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fpq1nnmb3395e87sw6uur.png" alt="dive ruby:3.2.0, current layer details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Dive in a Continuous integration Pipeline
&lt;/h2&gt;

&lt;p&gt;Running Dive with &lt;code&gt;CI=true&lt;/code&gt; is one of the most effective ways to quickly find wasted space.&lt;br&gt;
Example: &lt;code&gt;CI=true dive ruby:3.2.0&lt;/code&gt; &lt;br&gt;
This also is something that could be plugged into a docker image pipeline to ensure that a ridiculous amount of assets or image space is not wasted.&lt;/p&gt;

&lt;p&gt;Full output here: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;CI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true &lt;/span&gt;dive ruby:3.2.0
  Using default CI config
Image Source: docker://ruby:3.2.0
Fetching image... &lt;span class="o"&gt;(&lt;/span&gt;this can take a &lt;span class="k"&gt;while for &lt;/span&gt;large images&lt;span class="o"&gt;)&lt;/span&gt;
Analyzing image...
  efficiency: 98.8316 %
  wastedBytes: 11616315 bytes &lt;span class="o"&gt;(&lt;/span&gt;12 MB&lt;span class="o"&gt;)&lt;/span&gt;
  userWastedPercent: 1.6002 %
Inefficient Files:
Count  Wasted Space  File Path
    6        5.0 MB  /var/cache/debconf/templates.dat
    4        3.2 MB  /var/cache/debconf/templates.dat-old
    6        1.2 MB  /var/lib/dpkg/status
    6        1.2 MB  /var/lib/dpkg/status-old
    5        376 kB  /var/log/dpkg.log
    5        194 kB  /var/log/apt/term.log
    6         95 kB  /etc/ld.so.cache
    6         86 kB  /var/cache/debconf/config.dat
    6         71 kB  /var/lib/apt/extended_states
    5         54 kB  /var/cache/ldconfig/aux-cache
    5         52 kB  /var/log/apt/eipp.log.xz
    4         42 kB  /var/cache/debconf/config.dat-old
    5         36 kB  /var/log/apt/history.log
    4         26 kB  /var/log/alternatives.log
    2         903 B  /etc/group
    2         892 B  /etc/group-
    2         756 B  /etc/gshadow
    2           0 B  /etc/.pwd.lock
    6           0 B  /tmp
    5           0 B  /var/cache/apt/archives/partial
    3           0 B  /var/lib/dpkg/triggers/Unincorp
    6           0 B  /var/lib/dpkg/lock-frontend
    5           0 B  /var/cache/apt/archives/lock
    6           0 B  /var/lib/dpkg/lock
    6           0 B  /var/cache/debconf/passwords.dat
    5           0 B  /var/lib/apt/lists
    2           0 B  /usr/src
    6           0 B  /var/lib/dpkg/triggers/Lock
    6           0 B  /var/lib/dpkg/updates
Results:
  PASS: highestUserWastedPercent
  SKIP: highestWastedBytes: rule disabled
  PASS: lowestEfficiency
Result:PASS &lt;span class="o"&gt;[&lt;/span&gt;Total:3] &lt;span class="o"&gt;[&lt;/span&gt;Passed:2] &lt;span class="o"&gt;[&lt;/span&gt;Failed:0] &lt;span class="o"&gt;[&lt;/span&gt;Warn:0] &lt;span class="o"&gt;[&lt;/span&gt;Skipped:1]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With this particular image we could go through and remove those files, but in this case it does not take up a significant amount of room, so it is  unnecessary.&lt;br&gt;
&lt;a href="https://github.com/wagoodman/dive#ci-integration" rel="noopener noreferrer"&gt;more configuration options&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with Sensitive Data
&lt;/h2&gt;

&lt;p&gt;Do not pass sensitive details through build-arg's and environment variables into Dockerfiles during image creation. Simply inspecting the resulting docker image layers will expose these secrets.&lt;/p&gt;

&lt;p&gt;If a Dockerfile needs sensitive data, pass it using buildx secrets mounts.&lt;/p&gt;

&lt;p&gt;This can be done either with a file, containing the secret value, or an environment variable containing the secret. &lt;/p&gt;

&lt;p&gt;First Create a file, named &lt;code&gt;build_key&lt;/code&gt; with the value &lt;br&gt;
&lt;code&gt;xyz:xyz&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next add this to the Dockerfile to access the secret.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&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;secret,id&lt;span class="o"&gt;=&lt;/span&gt;build_key
&lt;span class="c"&gt;# to access the secret:&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"using build_key: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /run/secrets/build_key&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c"&gt;# note this is an example&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally when running the docker build with buildx we use the secret:&lt;br&gt;
&lt;code&gt;docker buildx build --secret id=build_key,src=build_key .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If we were to use an environment variable containing the secret the command to build would look like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;build_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xyz:xyz
docker buildx build &lt;span class="nt"&gt;--secret&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;build_key,env&lt;span class="o"&gt;=&lt;/span&gt;build_key


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Example of Secrets Leaking
&lt;/h3&gt;

&lt;p&gt;This is a rough example, because we would likely never need to add the db connection string at build time, but there are a few apps that require a build_license when installing packages, or a way to authenticate to a remote  GitHub  server..&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; build_license \&lt;/span&gt;
    postgres_db_string

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; build_license=$build_license \&lt;/span&gt;
    postgres_db_string=$postgres_db_string

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; echo "secret_sauce: $secret_sauce" \&lt;/span&gt;
 &amp;amp;&amp;amp; echo "build_license: $build_license" \
 &amp;amp;&amp;amp; echo "postgres_db_string: $postgres_db_string"



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To see these details in an image, all that is needed is the image to exist locally, then run: &lt;code&gt;docker save &amp;lt;image-name&amp;gt; -o &amp;lt;image.tar&amp;gt;&lt;/code&gt; then from inspecting the tar archive with &lt;code&gt;vim&lt;/code&gt; I can see the layer contents.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

" tar.vim version v32
" Browsing tarfile /Users/kaceygambill/personal/ubuntu-mount/blog/4/test.tar
" Select a file with cursor and press ENTER

444f68a42c829ead4bff4566c6554c761e2075c92d2eef50cbb9152fde8b13cc/
444f68a42c829ead4bff4566c6554c761e2075c92d2eef50cbb9152fde8b13cc/VERSION
444f68a42c829ead4bff4566c6554c761e2075c92d2eef50cbb9152fde8b13cc/json
444f68a42c829ead4bff4566c6554c761e2075c92d2eef50cbb9152fde8b13cc/layer.tar
a93a4c1e4d72d16b55e6aae767bb48e862a4ad8a43ab33107f8d5dfdc749912b.json
ee72d37eae4759eeaadd189b4341c0418faa7662ebc5089ddb528b4640e08c2f/
ee72d37eae4759eeaadd189b4341c0418faa7662ebc5089ddb528b4640e08c2f/VERSION
ee72d37eae4759eeaadd189b4341c0418faa7662ebc5089ddb528b4640e08c2f/json
ee72d37eae4759eeaadd189b4341c0418faa7662ebc5089ddb528b4640e08c2f/layer.tar
manifest.json
repositories


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Looking at any one of those .json files gives us more details about the layer.&lt;br&gt;
Expanding &lt;code&gt;444f68a42c829ead4bff4566c6554c761e2075c92d2eef50cbb9152fde8b13cc/json&lt;/code&gt;&lt;br&gt;
I can see a JSON object that includes the sensitive data.&lt;/p&gt;

&lt;p&gt;If you haven't checked out &lt;a href="https://github.com/wagoodman/dive" rel="noopener noreferrer"&gt;Dive&lt;/a&gt;, I'd highly&lt;br&gt;
suggest checking it out and implementing it as a check in your CI/CD pipelines!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
