<?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[KubeSkills]]></title><description><![CDATA[Learn Kubernetes by doing. Hands-on Kubernetes learning practice and preparation for the CKA and CKAD exams.]]></description><link>https://blog.kubeskills.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1764434634605/898bb97b-11d5-4224-9a38-593e40b75b77.png</url><title>KubeSkills</title><link>https://blog.kubeskills.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 09:28:12 GMT</lastBuildDate><atom:link href="https://blog.kubeskills.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Invisible Load Spike: Why Your Autoscaler Fails When It Matters Most (And How to Fix It)]]></title><description><![CDATA[Your autoscaler is a liar. It promises to scale your workloads when demand spikes, but in production, when revenue is on the line, it chokes. The HorizontalPodAutoscaler (HPA) controller loop runs every 15 seconds, metrics-server takes another 30 sec...]]></description><link>https://blog.kubeskills.com/invisible-load-spike</link><guid isPermaLink="true">https://blog.kubeskills.com/invisible-load-spike</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[kubernetes autoscaling]]></category><category><![CDATA[autoscaling]]></category><category><![CDATA[clusterautoscaler]]></category><category><![CDATA[Horizontal Pod Autoscaler]]></category><dc:creator><![CDATA[Chad M. Crowell]]></dc:creator><pubDate>Sat, 29 Nov 2025 16:40:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764434301656/9ab8831d-f2ac-4720-b4c5-5a1e6c5d5d6e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Your autoscaler is a liar. It promises to scale your workloads when demand spikes, but in production, when revenue is on the line, it chokes. The <a target="_blank" href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/">HorizontalPodAutoscaler (HPA)</a> controller loop runs every 15 seconds, metrics-server takes another 30 seconds to stabilize, and by the time new pods reach <code>Ready</code> your users have already refreshed their browsers and blamed your "slow API" on Twitter.</p>
<p>In dev environments, you can't wait for production traffic to validate autoscaling behavior. You need synthetic, deterministic load that exercises the entire control loop: HPA decision-making, scheduler placement, kubelet startup latency, and metrics collection. The <code>polinux/stress</code> image provides precisely this: a maintained, security-compliant CPU and memory workload generator that exposes every weakness in your autoscaling configuration before customers do.</p>
<h2 id="heading-why-polinuxstress-is-the-right-tool">Why <code>polinux/stress</code> Is the Right Tool</h2>
<p>The <code>polinux/stress</code> image is an actively maintained fork of the Linux stress utility with modern base images that pass CVE scanning. It accepts <code>--cpu N</code> arguments to spawn N CPU-intensive workers and <code>--vm</code> with <code>--vm-bytes</code> for memory pressure. Unlike HTTP load generators (wrk, ab, locust), it isolates resource consumption from network I/O, making it <a target="_blank" href="https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/#specify-a-memory-request-and-a-memory-limit">ideal for validating:</a></p>
<ul>
<li><strong>HPA controller calculations</strong>: The controller queries metrics-server for pod-level CPU utilization, computes <code>currentMetricValue / desiredMetricValue</code>, and scales when the ratio exceeds thresholds​</li>
</ul>
<ul>
<li><p><strong>Metrics-server scraping latency</strong>: The default scraping interval and CPU initialization period (5 minutes) can delay scaling decisions​</p>
</li>
<li><p><strong>CFS throttling behavior</strong>: Containers requesting more CPU than their limit experience throttling via <code>cpu.cfs_quota_us</code>, visible in <code>container_cpu_cfs_throttled_periods_total</code> metrics​</p>
</li>
<li><p><strong>Scheduler and kubelet latency</strong>: Measures time from HPA scale-up decision to pod <code>Ready</code> status, including image pulls and CNI setup</p>
</li>
</ul>
<p>Compared to the unmaintained <code>vish/stress</code>, <code>polinux/stress</code> provides the same functionality while meeting modern security compliance requirements.</p>
<h2 id="heading-hands-on-demo-hpa-scale-up-and-scale-down">Hands-On Demo: HPA Scale-Up and Scale-Down</h2>
<p>Use this <a target="_blank" href="https://killercoda.com/chadmcrowell/scenario/metrics-server">Killercoda scenario</a> to follow along!</p>
<h2 id="heading-setup-deploy-the-workload-with-zero-load-baseline">Setup: Deploy the Workload with Zero-Load Baseline</h2>
<p>Create a namespace and deployment starting in an idle state. This establishes a performance baseline before triggering load:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># stress-deployment.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Namespace</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">autoscale-demo</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">cpu-stress</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">autoscale-demo</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">cpu-stress</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">app:</span> <span class="hljs-string">cpu-stress</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">stress-ctr</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">polinux/stress</span>
        <span class="hljs-attr">resources:</span>
          <span class="hljs-attr">limits:</span>
            <span class="hljs-attr">cpu:</span> <span class="hljs-string">"1"</span>
            <span class="hljs-attr">memory:</span> <span class="hljs-string">"512Mi"</span>
          <span class="hljs-attr">requests:</span>
            <span class="hljs-attr">cpu:</span> <span class="hljs-string">"500m"</span>
            <span class="hljs-attr">memory:</span> <span class="hljs-string">"256Mi"</span>
        <span class="hljs-attr">command:</span> [<span class="hljs-string">"/bin/sh"</span>, <span class="hljs-string">"-c"</span>]
        <span class="hljs-attr">args:</span> [<span class="hljs-string">"sleep infinity"</span>]
</code></pre>
<p>Deploy it:</p>
<pre><code class="lang-bash">kubectl apply -f stress-deployment.yaml

<span class="hljs-comment"># Wait for pod to be ready</span>
kubectl <span class="hljs-built_in">wait</span> --<span class="hljs-keyword">for</span>=condition=ready pod -l app=cpu-stress -n autoscale-demo --timeout=60s

<span class="hljs-comment"># Verify zero-load state</span>
kubectl top pod -n autoscale-demo
<span class="hljs-comment"># Expected: cpu-stress-xxxxx   ~1m   ~10Mi (near-zero CPU usage)</span>
</code></pre>
<h2 id="heading-configure-hpa-with-cpu-target">Configure HPA with CPU Target</h2>
<p>Create an HPA targeting 50% CPU utilization:​</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># hpa.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">autoscaling/v2</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">HorizontalPodAutoscaler</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">cpu-stress-hpa</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">autoscale-demo</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">scaleTargetRef:</span>
    <span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
    <span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">cpu-stress</span>
  <span class="hljs-attr">minReplicas:</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">maxReplicas:</span> <span class="hljs-number">6</span>
  <span class="hljs-attr">metrics:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">Resource</span>
    <span class="hljs-attr">resource:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">cpu</span>
      <span class="hljs-attr">target:</span>
        <span class="hljs-attr">type:</span> <span class="hljs-string">Utilization</span>
        <span class="hljs-attr">averageUtilization:</span> <span class="hljs-number">50</span>
  <span class="hljs-attr">behavior:</span>
    <span class="hljs-attr">scaleDown:</span>
      <span class="hljs-attr">stabilizationWindowSeconds:</span> <span class="hljs-number">60</span>   <span class="hljs-comment"># Faster scale-down for demo</span>
    <span class="hljs-attr">scaleUp:</span>
      <span class="hljs-attr">stabilizationWindowSeconds:</span> <span class="hljs-number">0</span>    <span class="hljs-comment"># Immediate scale-up</span>
</code></pre>
<p>Apply and verify:</p>
<pre><code class="lang-bash">kubectl apply -f hpa.yaml

<span class="hljs-comment"># Wait for metrics to populate (15-30 seconds)</span>
sleep 30

<span class="hljs-comment"># Check HPA baseline</span>
kubectl get hpa -n autoscale-demo -w
</code></pre>
<h2 id="heading-establish-baseline-metrics">Establish Baseline Metrics</h2>
<p>Before triggering load, validate that metrics-server is functioning and HPA recognizes the idle state:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Describe HPA to see events and current status</span>
kubectl describe hpa cpu-stress-hpa -n autoscale-demo

<span class="hljs-comment"># Expected output includes:</span>
<span class="hljs-comment"># Metrics:</span>
<span class="hljs-comment">#   Resource cpu on pods (as a percentage of request):  0% (0m) / 50%</span>
<span class="hljs-comment"># Current number of replicas: 1</span>
<span class="hljs-comment"># ScalingActive condition: True</span>
</code></pre>
<p>This confirms the HPA control loop is active and baseline CPU is near zero.​</p>
<h2 id="heading-trigger-scale-up-with-high-cpu-load">Trigger Scale-Up with High CPU Load</h2>
<p>Patch the deployment to generate CPU load:​</p>
<pre><code class="lang-bash">kubectl patch deployment cpu-stress -n autoscale-demo --<span class="hljs-built_in">type</span>=<span class="hljs-string">'json'</span> \
  -p=<span class="hljs-string">'[
    {"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value": "100m"},
    {"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/memory", "value": "128Mi"},
    {"op": "replace", "path": "/spec/template/spec/containers/0/resources/limits/cpu", "value": "500m"},
    {"op": "replace", "path": "/spec/template/spec/containers/0/resources/limits/memory", "value": "256Mi"},
    {"op": "replace", "path": "/spec/template/spec/containers/0/command", "value": ["stress"]},
    {"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": ["--cpu", "2", "--verbose"]}
  ]'</span>


<span class="hljs-comment"># Wait for rollout</span>
kubectl rollout status deployment/cpu-stress -n autoscale-demo
</code></pre>
<p>This combined patch accomplishes multiple objectives:</p>
<p><strong>Resource Optimization for Single-Node</strong>:</p>
<ul>
<li><p><strong>CPU request</strong>: 500m → 100m (allows up to 6 pods on a node with ~1 CPU available)</p>
</li>
<li><p><strong>CPU limit</strong>: 1000m → 500m (prevents individual pods from consuming entire node CPU)</p>
</li>
<li><p><strong>Memory request</strong>: 256Mi → 128Mi (reduces memory pressure)</p>
</li>
<li><p><strong>Memory limit</strong>: 512Mi → 256Mi (prevents OOM issues on small nodes)</p>
</li>
</ul>
<p><strong>Load Generation</strong>:</p>
<ul>
<li><p><strong>Command change</strong>: <code>["/bin/sh", "-c"]</code> → <code>["stress"]</code></p>
</li>
<li><p><strong>2 CPU workers</strong>: Spawns 2 stress processes attempting to consume CPU continuously</p>
</li>
<li><p><strong>No timeout</strong>: Runs indefinitely until patched back to sleep</p>
</li>
</ul>
<p>With the new configuration, each pod creates:​</p>
<ul>
<li><p><strong>Actual usage</strong>: ~200m per pod (2 workers generating load)</p>
</li>
<li><p><strong>Utilization</strong>: 200m / 100m request = 200%</p>
</li>
<li><p><strong>HPA action</strong>: Current utilization (200%) exceeds target (50%), triggers scale-up</p>
</li>
</ul>
<p>Monitor scale-up with timestamps:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Watch HPA in real-time (updates every 15s)</span>
kubectl get hpa cpu-stress-hpa -n autoscale-demo -w

<span class="hljs-comment"># In another terminal, watch pods scaling</span>
kubectl get pods -n autoscale-demo -w
</code></pre>
<p>Expected timeline:​</p>
<ul>
<li><p><strong>T+15-30s</strong>: Metrics-server scrapes kubelet, updates cache</p>
</li>
<li><p><strong>T+30-45s</strong>: HPA polls metrics-server, sees 200% utilization</p>
</li>
<li><p><strong>T+45s</strong>: HPA updates deployment replicas (calculated as <code>ceil(1 * (200/50)) = 4</code>)</p>
</li>
<li><p><strong>T+60-90s</strong>: New pods reach <code>Running</code> and <code>Ready</code> state</p>
</li>
<li><p><strong>T+90-120s</strong>: Metrics stabilize across all pods</p>
</li>
</ul>
<p>Expected HPA output after scale-up:</p>
<pre><code class="lang-bash">NAME              REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS
cpu-stress-hpa    Deployment/cpu-stress   200%/50%   1         6         4
<span class="hljs-comment"># After pods stabilize and share 1 CPU on single node:</span>
cpu-stress-hpa    Deployment/cpu-stress   166%/50%   1         6         6
</code></pre>
<p>The HPA will scale to maximum replicas (6) because each pod with 2 CPU workers generates approximately 200m CPU load, creating 200% utilization (200m actual / 100m request). After scaling to 6 pods on a single-node cluster with 1 total CPU, each pod receives ~166m average, maintaining 166% utilization and keeping HPA at maxReplicas.</p>
<h2 id="heading-verify-scaling-behavior-and-resource-distribution">Verify Scaling Behavior and Resource Distribution</h2>
<pre><code class="lang-bash"><span class="hljs-comment"># Check final pod count</span>
kubectl get pods -n autoscale-demo -l app=cpu-stress

<span class="hljs-comment"># Check per-pod CPU usage (wait 60s for metrics stability)</span>
sleep 60
kubectl top pod -n autoscale-demo
<span class="hljs-comment"># Expected: Each pod consuming ~166m (1000m node capacity / 6 pods)</span>

<span class="hljs-comment"># View HPA events showing scale decisions</span>
kubectl describe hpa cpu-stress-hpa -n autoscale-demo | grep -A 10 <span class="hljs-string">"Events:"</span>
<span class="hljs-comment"># Expected events:</span>
<span class="hljs-comment"># - ScalingReplicaSet: New size: 4; reason: cpu resource utilization above target</span>
<span class="hljs-comment"># - ScalingReplicaSet: New size: 6; reason: cpu resource utilization above target</span>

<span class="hljs-comment"># Verify updated resource configuration</span>
kubectl get deployment cpu-stress -n autoscale-demo -o jsonpath=<span class="hljs-string">'{.spec.template.spec.containers[0].resources}'</span> | jq
<span class="hljs-comment"># Expected:</span>
<span class="hljs-comment"># {</span>
<span class="hljs-comment">#   "limits": {"cpu": "500m", "memory": "256Mi"},</span>
<span class="hljs-comment">#   "requests": {"cpu": "100m", "memory": "128Mi"}</span>
<span class="hljs-comment"># }</span>

<span class="hljs-comment"># Check node allocation</span>
kubectl describe node &lt;worker-node&gt; | grep -A 5 <span class="hljs-string">"Allocated resources:"</span>
<span class="hljs-comment"># Expected: cpu ~825m (225m system + 600m from 6 pods @ 100m each)</span>
</code></pre>
<p>If you have Prometheus installed, validate CPU throttling:​</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Throttling periods per pod (indicates hitting CPU limits)</span>
rate(container_cpu_cfs_throttled_periods_total{namespace=<span class="hljs-string">"autoscale-demo"</span>}[5m])
</code></pre>
<h2 id="heading-test-scale-down-with-stabilization-window">Test Scale-Down with Stabilization Window</h2>
<p>Return to zero-load baseline and observe scale-down behavior:​</p>
<pre><code class="lang-bash">kubectl patch deployment cpu-stress -n autoscale-demo --<span class="hljs-built_in">type</span>=<span class="hljs-string">'json'</span> \
  -p=<span class="hljs-string">'[
    {"op": "replace", "path": "/spec/template/spec/containers/0/command", "value": ["/bin/sh", "-c"]},
    {"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": ["sleep infinity"]}
  ]'</span>

<span class="hljs-comment"># Wait for rollout</span>
kubectl rollout status deployment/cpu-stress -n autoscale-demo
</code></pre>
<p>We set the HPA to have a 60-second stabilization window for scale-down to increase speed. Monitor the behavior:​</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Watch HPA - note TARGETS drop but REPLICAS remain at 6</span>
kubectl get hpa cpu-stress-hpa -n autoscale-demo -w

<span class="hljs-comment"># Expected:</span>
<span class="hljs-comment"># T+0s:   cpu-stress-hpa   Deployment/cpu-stress   0%/50%   1   6   6</span>
<span class="hljs-comment"># T+300s: cpu-stress-hpa   Deployment/cpu-stress   0%/50%   1   6   1</span>
</code></pre>
<p>After 60 seconds, replicas scale down to 1. This delay prevents rapid scaling oscillations during temporary load drops.​</p>
<h2 id="heading-advanced-multi-metric-autoscaling-with-memory">Advanced: Multi-Metric Autoscaling with Memory</h2>
<p>HPA supports scaling on multiple metrics simultaneously, selecting the maximum scale recommendation:​</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># hpa-multi-metric.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">autoscaling/v2</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">HorizontalPodAutoscaler</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">stress-multi-hpa</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">autoscale-demo</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">scaleTargetRef:</span>
    <span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
    <span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">cpu-stress</span>
  <span class="hljs-attr">minReplicas:</span> <span class="hljs-number">2</span>
  <span class="hljs-attr">maxReplicas:</span> <span class="hljs-number">15</span>
  <span class="hljs-attr">metrics:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">Resource</span>
    <span class="hljs-attr">resource:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">cpu</span>
      <span class="hljs-attr">target:</span>
        <span class="hljs-attr">type:</span> <span class="hljs-string">Utilization</span>
        <span class="hljs-attr">averageUtilization:</span> <span class="hljs-number">60</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">Resource</span>
    <span class="hljs-attr">resource:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">memory</span>
      <span class="hljs-attr">target:</span>
        <span class="hljs-attr">type:</span> <span class="hljs-string">Utilization</span>
        <span class="hljs-attr">averageUtilization:</span> <span class="hljs-number">70</span>
  <span class="hljs-attr">behavior:</span>
    <span class="hljs-attr">scaleDown:</span>
      <span class="hljs-attr">stabilizationWindowSeconds:</span> <span class="hljs-number">120</span>        <span class="hljs-comment"># Faster scale-down for testing</span>
      <span class="hljs-attr">policies:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">Percent</span>
        <span class="hljs-attr">value:</span> <span class="hljs-number">50</span>                             <span class="hljs-comment"># Remove max 50% of pods</span>
        <span class="hljs-attr">periodSeconds:</span> <span class="hljs-number">60</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">Pods</span>
        <span class="hljs-attr">value:</span> <span class="hljs-number">2</span>                              <span class="hljs-comment"># Or max 2 pods</span>
        <span class="hljs-attr">periodSeconds:</span> <span class="hljs-number">60</span>
      <span class="hljs-attr">selectPolicy:</span> <span class="hljs-string">Min</span>                       <span class="hljs-comment"># Use most conservative policy</span>
    <span class="hljs-attr">scaleUp:</span>
      <span class="hljs-attr">stabilizationWindowSeconds:</span> <span class="hljs-number">0</span>           <span class="hljs-comment"># Immediate scale-up</span>
      <span class="hljs-attr">policies:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">Percent</span>
        <span class="hljs-attr">value:</span> <span class="hljs-number">100</span>                            <span class="hljs-comment"># Double pods</span>
        <span class="hljs-attr">periodSeconds:</span> <span class="hljs-number">15</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">Pods</span>
        <span class="hljs-attr">value:</span> <span class="hljs-number">4</span>                              <span class="hljs-comment"># Or add 4 pods</span>
        <span class="hljs-attr">periodSeconds:</span> <span class="hljs-number">15</span>
      <span class="hljs-attr">selectPolicy:</span> <span class="hljs-string">Max</span>                       <span class="hljs-comment"># Use most aggressive policy</span>
</code></pre>
<p>Update the deployment to stress both CPU and memory:​</p>
<pre><code class="lang-bash">kubectl patch deployment cpu-stress -n autoscale-demo --<span class="hljs-built_in">type</span>=<span class="hljs-string">'json'</span> \
  -p=<span class="hljs-string">'[
    {"op": "replace", "path": "/spec/template/spec/containers/0/command", "value": ["stress"]},
    {"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": ["--cpu", "2", "--vm", "1", "--vm-bytes", "100M", "--verbose"]}
  ]'</span>

<span class="hljs-comment"># Apply multi-metric HPA</span>
kubectl apply -f hpa-multi-metric.yaml

<span class="hljs-comment"># Wait for metrics to stabilize (60 seconds)</span>
sleep 60

<span class="hljs-comment"># Check multi-metric status</span>
kubectl get hpa stress-multi-hpa -n autoscale-demo
</code></pre>
<p>Expected behavior:​</p>
<ul>
<li><p><strong>CPU</strong>: 1000m / 500m = 200% utilization → recommends ~7 replicas</p>
</li>
<li><p><strong>Memory</strong>: 200Mi / 256Mi = 78% utilization → recommends ~3 replicas</p>
</li>
<li><p><strong>HPA decision</strong>: Selects maximum (7 replicas)</p>
</li>
</ul>
<h2 id="heading-validating-scale-up-latency-and-metrics-pipeline">Validating Scale-Up Latency and Metrics Pipeline</h2>
<p>Measure end-to-end latency from load spike to pod readiness:​</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Reset to baseline</span>
kubectl patch deployment cpu-stress -n autoscale-demo --<span class="hljs-built_in">type</span>=<span class="hljs-string">'json'</span> \
  -p=<span class="hljs-string">'[
    {"op": "replace", "path": "/spec/template/spec/containers/0/command", "value": ["/bin/sh", "-c"]},
    {"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": ["sleep infinity"]}
  ]'</span>

<span class="hljs-comment"># Wait for scale-down to minReplicas</span>
sleep 180

<span class="hljs-comment"># Trigger load spike at T=0 and record timestamp</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Load spike triggered at: <span class="hljs-subst">$(date +%H:%M:%S)</span>"</span>
kubectl patch deployment cpu-stress -n autoscale-demo --<span class="hljs-built_in">type</span>=<span class="hljs-string">'json'</span> \
  -p=<span class="hljs-string">'[
    {"op": "replace", "path": "/spec/template/spec/containers/0/command", "value": ["stress"]},
    {"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": ["--cpu", "30", "--verbose"]}
  ]'</span>

<span class="hljs-comment"># Monitor with timestamps every 10 seconds</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> {1..12}; <span class="hljs-keyword">do</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"--- T+<span class="hljs-subst">$((i*10)</span>)s at <span class="hljs-subst">$(date +%H:%M:%S)</span> ---"</span>
  kubectl get hpa stress-multi-hpa -n autoscale-demo --no-headers
  kubectl get pods -n autoscale-demo -l app=cpu-stress --no-headers | wc -l
  sleep 10
<span class="hljs-keyword">done</span>
</code></pre>
<p>Typical latency breakdown:​</p>
<ul>
<li><p><strong>T+0-30s</strong>: Metrics-server CPU initialization delay (default 30s via <code>--horizontal-pod-autoscaler-initial-readiness-delay</code>)​</p>
</li>
<li><p><strong>T+30-45s</strong>: HPA controller detects high utilization</p>
</li>
<li><p><strong>T+45-60s</strong>: Scheduler places new pods, image pull (if not cached)</p>
</li>
<li><p><strong>T+60-90s</strong>: Pods reach <code>Ready</code>, CNI initialization complete</p>
</li>
<li><p><strong>T+90-120s</strong>: Metrics include new pods, utilization stabilizes</p>
</li>
</ul>
<p>This exposes real control-plane latencies that mirror production behavior.​</p>
<h2 id="heading-promql-queries-for-observability">PromQL Queries for Observability</h2>
<p>Monitor HPA and kubelet behavior with Prometheus:​</p>
<pre><code class="lang-bash"><span class="hljs-comment"># HPA decision latency (controller reconciliation time)</span>
rate(hpa_controller_reconciliation_duration_seconds_sum[5m]) 
  / rate(hpa_controller_reconciliation_duration_seconds_count[5m])

<span class="hljs-comment"># CPU throttling per pod (indicates hitting limits)</span>
rate(container_cpu_cfs_throttled_periods_total{namespace=<span class="hljs-string">"autoscale-demo"</span>}[5m])

<span class="hljs-comment"># Metrics-server scrape latency</span>
histogram_quantile(0.99, 
  rate(metrics_server_kubelet_request_duration_seconds_bucket[5m]))

<span class="hljs-comment"># Pod startup time (requires kube-state-metrics)</span>
kube_pod_start_time - kube_pod_created
</code></pre>
<h2 id="heading-production-ready-configuration-patterns">Production-Ready Configuration Patterns</h2>
<p><strong>Approach A: Conservative (Avoid Flapping)</strong></p>
<ul>
<li><p><code>scaleDown.stabilizationWindowSeconds: 300</code> (5 min)</p>
</li>
<li><p><code>scaleUp.stabilizationWindowSeconds: 60</code></p>
</li>
<li><p>Target utilization: 70-80%</p>
</li>
</ul>
<p><strong>Pros</strong>: Minimal pod churn, predictable costs, cache warmth preserved<br /><strong>Cons</strong>: Slower response to traffic drops, potential over-provisioning<br /><strong>When</strong>: Steady workloads with gradual changes, stateful apps with warm caches​</p>
<p><strong>Approach B: Aggressive (Low Latency)</strong></p>
<ul>
<li><p><code>scaleDown.stabilizationWindowSeconds: 60</code></p>
</li>
<li><p><code>scaleUp.stabilizationWindowSeconds: 0</code></p>
</li>
<li><p>Target utilization: 40-50%</p>
</li>
</ul>
<p><strong>Pros</strong>: Fast scale-up, headroom for bursts, responsive to spikes<br /><strong>Cons</strong>: Higher pod churn, wasted capacity, cold cache restarts<br /><strong>When</strong>: Latency-sensitive APIs, unpredictable spikes, stateless workloads​</p>
<p><strong>Approach C: Custom Metrics (Advanced)</strong><br />Use custom metrics (requests/sec, queue depth) instead of CPU for application-aware scaling. Requires Prometheus Adapter or KEDA.​</p>
<p><strong>Pros</strong>: Application semantics, not resource proxies; accounts for P99 latency<br /><strong>Cons</strong>: Complexity, external dependencies, custom instrumentation<br /><strong>When</strong>: RPS-based workloads, async job queues, SLA-driven scaling​</p>
<p>The <code>polinux/stress</code> image removes the guesswork from autoscaling validation while meeting modern security requirements. By establishing a zero-load baseline and then generating deterministic CPU and memory load, you validate HPA calculations, expose metrics-server latency, measure scheduler performance, and identify throttling issues—all before production traffic exercises these code paths. Starting small and scaling gradually reveals configuration problems early, ensuring your autoscaler actually works when it matters most.</p>
<h1 id="heading-next-steps">Next Steps</h1>
<h2 id="heading-expand-autoscaling-scope">Expand Autoscaling Scope</h2>
<p><strong>Vertical Pod Autoscaler (VPA)</strong><br />Move beyond horizontal scaling to automatically adjust CPU and memory requests/limits based on actual usage patterns. <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/autoscaling/vertical-pod-autoscale/">VPA</a> analyzes historical consumption, peak usage, and OOM events to calculate optimal resource recommendations.​</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install VPA (separate project, not part of core Kubernetes)</span>
git <span class="hljs-built_in">clone</span> https://github.com/kubernetes/autoscaler.git
<span class="hljs-built_in">cd</span> autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh

<span class="hljs-comment"># Create VPA for your stress workload</span>
cat &lt;&lt;EOF | kubectl apply -f -
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: stress-vpa
  namespace: autoscale-demo
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: cpu-stress
  updatePolicy:
    updateMode: <span class="hljs-string">"Auto"</span>      <span class="hljs-comment"># Auto applies recommendations</span>
  resourcePolicy:
    containerPolicies:
    - containerName: stress-ctr
      minAllowed:
        cpu: <span class="hljs-string">"100m"</span>
        memory: <span class="hljs-string">"128Mi"</span>
      maxAllowed:
        cpu: <span class="hljs-string">"2"</span>
        memory: <span class="hljs-string">"1Gi"</span>
EOF
</code></pre>
<p>VPA recommends target, lower bound, and upper bound resource values based on actual consumption trends.​</p>
<p><strong>Cluster Autoscaler /</strong> <a target="_blank" href="https://karpenter.sh/"><strong>Karpenter</strong></a><br />Scale the node layer to ensure sufficient capacity for your autoscaling pods. <a target="_blank" href="https://kubernetes.io/docs/concepts/cluster-administration/node-autoscaling/">Cluster Autoscaler</a> adds/removes nodes based on pending pods and node utilization.​</p>
<p><strong>KEDA (Event-Driven Autoscaling)</strong><br />Move beyond resource-based metrics to scale on application events like queue depth, Kafka lag, HTTP requests/sec. <a target="_blank" href="https://keda.sh/">KEDA</a> is a CNCF-graduated project supporting 60+ scalers.​</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install KEDA</span>
kubectl apply -f https://github.com/kedacore/keda/releases/latest/download/keda-2.13.0.yaml

<span class="hljs-comment"># Example: Scale based on Prometheus metrics</span>
cat &lt;&lt;EOF | kubectl apply -f -
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: prometheus-scaler
spec:
  scaleTargetRef:
    name: cpu-stress
  triggers:
  - <span class="hljs-built_in">type</span>: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      metricName: http_requests_total
      threshold: <span class="hljs-string">'100'</span>
      query: sum(rate(http_requests_total[2m]))
EOF
</code></pre>
<p>This scales based on actual application semantics rather than CPU/memory proxies.​</p>
<h2 id="heading-advanced-hpa-configuration">Advanced HPA Configuration</h2>
<p><strong>Custom Metrics with Prometheus Adapter</strong><br />Integrate Prometheus metrics into HPA for application-aware autoscaling:​</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install Prometheus Adapter</span>
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus-adapter prometheus-community/prometheus-adapter

<span class="hljs-comment"># Configure HPA with custom metric</span>
cat &lt;&lt;EOF | kubectl apply -f -
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: custom-metrics-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: cpu-stress
  metrics:
  - <span class="hljs-built_in">type</span>: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        <span class="hljs-built_in">type</span>: AverageValue
        averageValue: <span class="hljs-string">"1000"</span>
EOF
</code></pre>
<p><strong>Scheduled Autoscaling</strong><br />Pre-scale workloads for predictable traffic patterns using CronJobs that patch HPA min/max replicas:​</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">batch/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">CronJob</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">scale-up-business-hours</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">schedule:</span> <span class="hljs-string">"0 8 * * 1-5"</span>  <span class="hljs-comment"># 8 AM weekdays</span>
  <span class="hljs-attr">jobTemplate:</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">template:</span>
        <span class="hljs-attr">spec:</span>
          <span class="hljs-attr">containers:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">kubectl</span>
            <span class="hljs-attr">image:</span> <span class="hljs-string">bitnami/kubectl</span>
            <span class="hljs-attr">command:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">/bin/sh</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">-c</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">patch</span> <span class="hljs-string">hpa</span> <span class="hljs-string">cpu-stress-hpa</span> <span class="hljs-string">-n</span> <span class="hljs-string">autoscale-demo</span> <span class="hljs-string">--patch</span> <span class="hljs-string">'{"spec":{"minReplicas":5}}'</span>
          <span class="hljs-attr">restartPolicy:</span> <span class="hljs-string">OnFailure</span>
</code></pre>
<p>This proactively scales before demand surges, eliminating cold-start latency.​</p>
<h2 id="heading-production-observability">Production Observability</h2>
<p><strong>Integrate Grafana Dashboards</strong><br />Visualize HPA metrics, pod lifecycle events, and resource utilization:​</p>
<ul>
<li><p><strong>HPA metrics</strong>: <code>kube_horizontalpodautoscaler_status_current_replicas</code>, <code>kube_horizontalpodautoscaler_status_desired_replicas</code></p>
</li>
<li><p><strong>Scaling events</strong>: Query Kubernetes events for <code>ScalingReplicaSet</code> reasons</p>
</li>
<li><p><strong>Pod startup latency</strong>: <code>kube_pod_start_time - kube_pod_created</code></p>
</li>
</ul>
<p><strong>Alert on Autoscaling Issues</strong><br />Set up Prometheus alerts for scaling failures:​</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">HPAMaxedOut</span>
  <span class="hljs-attr">expr:</span> <span class="hljs-string">kube_horizontalpodautoscaler_status_current_replicas</span> <span class="hljs-string">==</span> <span class="hljs-string">kube_horizontalpodautoscaler_spec_max_replicas</span>
  <span class="hljs-attr">for:</span> <span class="hljs-string">15m</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-attr">summary:</span> <span class="hljs-string">"HPA <span class="hljs-template-variable">{{ $labels.horizontalpodautoscaler }}</span> has been at max replicas for 15+ minutes"</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">HPAScalingDisabled</span>
  <span class="hljs-attr">expr:</span> <span class="hljs-string">kube_horizontalpodautoscaler_status_condition{condition="ScalingActive",</span> <span class="hljs-string">status="false"}</span> <span class="hljs-string">==</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-attr">summary:</span> <span class="hljs-string">"HPA <span class="hljs-template-variable">{{ $labels.horizontalpodautoscaler }}</span> scaling is disabled"</span>
</code></pre>
<h2 id="heading-cost-and-performance-optimization">Cost and Performance Optimization</h2>
<p><strong>Manual Resource Request Tuning</strong><br />After observing HPA behavior, adjust resource requests to improve efficiency:</p>
<ul>
<li><p><strong>Over-provisioning</strong>: If HPA rarely scales and CPU stays at 20-30%, reduce requests​</p>
</li>
<li><p><strong>Under-provisioning</strong>: If HPA constantly maxes out and pods throttle, increase requests​</p>
</li>
<li><p><strong>Right-sizing</strong>: Match requests to P95 usage, not peak​</p>
</li>
</ul>
<p><strong>Load Testing in CI/CD</strong><br />Integrate autoscaling validation into your pipeline using k6 or Locust:​</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># .gitlab-ci.yml example</span>
<span class="hljs-attr">autoscaling-test:</span>
  <span class="hljs-attr">stage:</span> <span class="hljs-string">test</span>
  <span class="hljs-attr">script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">apply</span> <span class="hljs-string">-f</span> <span class="hljs-string">hpa.yaml</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">k6</span> <span class="hljs-string">run</span> <span class="hljs-string">--vus</span> <span class="hljs-number">100</span> <span class="hljs-string">--duration</span> <span class="hljs-string">5m</span> <span class="hljs-string">load-test.js</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">get</span> <span class="hljs-string">hpa</span> <span class="hljs-string">cpu-stress-hpa</span> <span class="hljs-string">-o</span> <span class="hljs-string">jsonpath='{.status.currentReplicas}'</span> <span class="hljs-string">|</span> <span class="hljs-string">grep</span> <span class="hljs-string">-v</span> <span class="hljs-string">"^1$"</span>  <span class="hljs-comment"># Verify scale-up</span>
</code></pre>
<p>This catches autoscaling regressions before production.​</p>
<h2 id="heading-stormforge-resources-for-ml-powered-optimization">StormForge Resources for ML-Powered Optimization</h2>
<p>StormForge provides machine learning-driven Kubernetes optimization that goes beyond manual tuning. Their platform automates resource rightsizing, HPA configuration, and cost optimization using <a target="_blank" href="https://www.cloudbolt.io/kubernetes-cost-optimization/kubernetes-optimization/">observability data and experimentation</a>.​​</p>
<h2 id="heading-stormforge-optimize-live">StormForge Optimize Live</h2>
<p><a target="_blank" href="https://aws.amazon.com/blogs/apn/best-practices-for-optimizing-kubernetes-costs-on-aws-with-stormforge-and-karpenter/"><strong>Automated Resource Recommendations</strong></a><br />StormForge Optimize Live continuously analyzes production workloads and generates ML-based recommendations for CPU/memory requests, limits, and HPA target utilization.​</p>
<p>Key features:​</p>
<ul>
<li><p><strong>Continuous optimization</strong>: Monitors resource usage and application behavior to identify cost-saving configurations automatically​</p>
</li>
<li><p><strong>HPA target tuning</strong>: Recommends optimal HPA target utilization percentages (not just static 50%)​</p>
</li>
<li><p><strong>OOM protection</strong>: Configures temporary memory bump-ups in response to OOM events​</p>
</li>
<li><p><strong>One-click apply</strong>: Directly applies recommendations to your cluster via the StormForge controller​</p>
</li>
</ul>
<p><strong>Getting Started with StormForge</strong><br />StormForge provides a <a target="_blank" href="https://dzone.com/articles/automating-kubernetes-workload-rightsizing-with-stormforge">comprehensive tutorial</a> for integrating their platform:​</p>
<ol>
<li><strong>Install the StormForge agent</strong>:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># Add Helm repo</span>
helm repo add stormforge https://registry.stormforge.io/chartrepo/library
helm repo update

<span class="hljs-comment"># Install agent with your API token</span>
helm install stormforge-agent stormforge/stormforge-agent \
  --namespace stormforge-system \
  --create-namespace \
  --<span class="hljs-built_in">set</span> authorization.token=YOUR_API_TOKEN
</code></pre>
<ol start="2">
<li><strong>Deploy an optimization experiment</strong>:​</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># Create optimization resource</span>
stormforge optimize create nginx-optimization \
  --application=nginx \
  --namespace=autoscale-demo
</code></pre>
<ol start="3">
<li><strong>Review recommendations</strong>:​</li>
</ol>
<pre><code class="lang-bash">stormforge optimize recommendations nginx-optimization
</code></pre>
<ol start="4">
<li><strong>Apply optimizations</strong>:​<br /> Visit the StormForge web UI at <a target="_blank" href="https://app.stormforge.io"><code>https://app.stormforge.io</code></a> and click "Apply Recommendations" to deploy optimized resource configurations directly to your cluster.​</li>
</ol>
<h2 id="heading-stormforge-and-karpenter-integration">StormForge and Karpenter Integration</h2>
<p>For AWS EKS clusters, StormForge integrates with Karpenter for full-stack optimization:​</p>
<ul>
<li><p><strong>StormForge optimizes workload requests</strong>: ML analyzes usage patterns and adjusts CPU/memory requests​</p>
</li>
<li><p><strong>Karpenter provisions nodes</strong>: Observes incoming pod requests and provisions right-sized nodes​</p>
</li>
<li><p><strong>Continuous feedback loop</strong>: As StormForge reduces requests, Karpenter consolidates nodes, reducing costs​</p>
</li>
</ul>
<p>AWS provides a <a target="_blank" href="https://aws.amazon.com/blogs/apn/best-practices-for-optimizing-kubernetes-costs-on-aws-with-stormforge-and-karpenter/">detailed walkthrough</a> showing a 30-40% cost reduction using this combination.​</p>
<h2 id="heading-stormforge-documentation-and-tutorials">StormForge Documentation and Tutorials</h2>
<p><strong>Official Documentation</strong></p>
<ul>
<li><p><a target="_blank" href="https://docs.stormforge.io/optimize-live/configure/settings/"><strong>Settings guide</strong>:</a> Configure CPU/memory optimization, HPA target ranges, and OOM handling​</p>
</li>
<li><p><a target="_blank" href="https://dzone.com/articles/automating-kubernetes-workload-rightsizing-with-stormforge"><strong>Optimization tutorial</strong>:</a> Step-by-step guide for workload rightsizing​</p>
</li>
</ul>
<p><strong>Video Resources</strong></p>
<ul>
<li><p><strong>Platform overview</strong>: <a target="_blank" href="https://youtu.be/fbwC32kPQWs?si=toLFLnabYOI8nkth">"Solving the Kubernetes Efficiency Problem with StormForge"​</a></p>
</li>
<li><p><strong>Product demo</strong>: <a target="_blank" href="https://youtu.be/8uVm73GHbfQ?si=9BulidgIhzM950lv">"StormForge Optimize Live Product Demo"</a> showing top-down visibility and recommendation workflows​</p>
</li>
<li><p><strong>HPA/VPA deep dive</strong>: "<a target="_blank" href="https://youtu.be/i-yROWwsdjI?si=_zsDxQ6p7afmEDyH">HPA and VPA For Pods With StormForge</a>" comparing horizontal vs vertical scaling with automated optimization​</p>
</li>
</ul>
<p><strong>Key Advantage Over Manual Tuning</strong><br />StormForge uses ML to analyze thousands of containers simultaneously, identifying optimization opportunities invisible to manual analysis. It automates the tedious process of profiling workloads, calculating percentile-based resource needs, and updating configurations—achieving enterprise-scale optimization with minimal manual intervention.​</p>
<h2 id="heading-continuous-optimization-in-cicd">Continuous Optimization in CI/CD</h2>
<p>StormForge supports automated optimization schedules via CI/CD pipelines:​</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Example GitLab CI integration</span>
<span class="hljs-attr">stormforge-optimize:</span>
  <span class="hljs-attr">stage:</span> <span class="hljs-string">optimize</span>
  <span class="hljs-attr">schedule:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">"0 2 * * 0"</span>  <span class="hljs-comment"># Weekly optimization run</span>
  <span class="hljs-attr">script:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">stormforge</span> <span class="hljs-string">optimize</span> <span class="hljs-string">run</span> <span class="hljs-string">nginx-optimization</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">stormforge</span> <span class="hljs-string">optimize</span> <span class="hljs-string">recommendations</span> <span class="hljs-string">nginx-optimization</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">recommendations.yaml</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">apply</span> <span class="hljs-string">-f</span> <span class="hljs-string">recommendations.yaml</span>
</code></pre>
<p>This ensures resource configurations evolve with changing workload patterns.​</p>
<p>The progression from basic HPA demos with <code>polinux/stress</code> to production-grade autoscaling with VPA, KEDA, custom metrics, and ML-powered optimization platforms like StormForge provides a complete path from learning fundamentals to achieving enterprise-scale efficiency.</p>
]]></content:encoded></item><item><title><![CDATA[VictoriaMetrics: A Guide, Comparing It to Prometheus, and Implementing Kubernetes Monitoring]]></title><description><![CDATA[Originally written by: Seif Rajhi
Original article: VictoriaMetrics: A Guide, Comparing It to Prometheus...Republished with permission

💬 Introduction
VictoriaMetrics is a time-series database designed for high-performance monitoring and analytics. ...]]></description><link>https://blog.kubeskills.com/victoriametrics-vs-prometheus</link><guid isPermaLink="true">https://blog.kubeskills.com/victoriametrics-vs-prometheus</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[kubernetes monitoring]]></category><category><![CDATA[#Prometheus #Grafana #DevOps #MLOps #Observability #Monitoring #Kubernetes]]></category><category><![CDATA[VictoriaMetrics]]></category><dc:creator><![CDATA[KubeSkills]]></dc:creator><pubDate>Wed, 19 Nov 2025 11:13:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763551246096/d7349bf0-c77b-458e-a6ea-c1fe0bc9ff41.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h2 id="heading-originally-written-by-seif-rajhihttpswwwlinkedincominrajhi-saif"><strong>Originally written by:</strong> <a target="_blank" href="https://www.linkedin.com/in/rajhi-saif/">Seif Rajhi</a></h2>
<p><strong>Original article:</strong> <a target="_blank" href="https://seifrajhi.github.io/blog/victoriametrics-time-series-db-prometheus-k8s/">VictoriaMetrics: A Guide, Comparing It to Prometheus...</a><br /><strong>Republished with permission</strong></p>
<hr />
<h2 id="heading-introduction"><strong>💬 Introduction</strong></h2>
<p><a target="_blank" href="https://victoriametrics.com">VictoriaMetrics</a> is a time-series database designed for high-performance monitoring and analytics. It is similar to Prometheus in many ways, but it offers several advantages, including better performance, scalability, and data compression. VictoriaMetrics is also open-source and free to use.</p>
<p>VictoriaMetrics can monitor a wide range of systems, including Kubernetes clusters, servers, applications, infrastructure components, and even IoT devices.</p>
<p>In this blog post, we will provide a comprehensive overview of VictoriaMetrics, covering the following topics:</p>
<ul>
<li><p>What is VictoriaMetrics, and how does it work?</p>
</li>
<li><p>How does VictoriaMetrics compare to Prometheus?</p>
</li>
<li><p>How to implement Kubernetes monitoring with VictoriaMetrics</p>
</li>
</ul>
<p>This blog post is for anyone who wants to learn more about VictoriaMetrics or use it to improve their system monitoring capabilities. It is also a good resource for anyone considering Prometheus and wanting to compare the two solutions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763550112435/db944460-e2ca-4a7f-adc6-4781833ff803.png" alt class="image--center mx-auto" /></p>
<p><strong>TL;DR: VictoriaMetrics and Prometheus</strong></p>
<p><strong>VictoriaMetrics</strong> and <strong>Prometheus</strong> are both time-series databases used for monitoring and analytics, but they have some key differences:</p>
<p><strong>Main features of VictoriaMetrics Compared to Prometheus</strong></p>
<ol>
<li><p><strong>Performance and Scalability</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Higher performance, better scalability, and more efficient data compression.</p>
</li>
<li><p><strong>Prometheus</strong>: Good performance but can struggle with high cardinality metrics and large-scale environments.</p>
</li>
</ul>
</li>
<li><p><strong>Resource Usage</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Lower CPU, RAM, and disk IO usage, especially with <a target="_blank" href="https://docs.victoriametrics.com/vmagent/">vmagent</a>.</p>
</li>
<li><p><strong>Prometheus</strong>: Higher resource consumption, especially with high cardinality metrics.</p>
</li>
</ul>
</li>
<li><p><strong>Data Ingestion</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Supports both pull and push models natively.</p>
</li>
<li><p><strong>Prometheus</strong>: Primarily pull-based; requires Pushgateway for push model.</p>
</li>
</ul>
</li>
<li><p><strong>High Availability</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Built-in support for high availability.</p>
</li>
<li><p><strong>Prometheus</strong>: No native high availability; requires duplication and sharding.</p>
</li>
</ul>
</li>
<li><p><strong>Long-Term Storage</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Designed for long-term storage with efficient data retention.</p>
</li>
<li><p><strong>Prometheus</strong>: Not intended for long-term storage; relies on external solutions.</p>
</li>
</ul>
</li>
<li><p><strong>Anomaly Detection</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Includes built-in anomaly detection features.</p>
</li>
<li><p><strong>Prometheus</strong>: Does not have built-in anomaly detection.</p>
</li>
</ul>
</li>
<li><p><strong>Buffering</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Independent disk-backed buffers for each remote storage.</p>
</li>
<li><p><strong>Prometheus</strong>: Single shared buffer for all remote storage systems.</p>
</li>
</ul>
</li>
<li><p><strong>Query Language</strong>:</p>
<ul>
<li><p><strong>VictoriaMetrics</strong>: Uses MetricsQL, which extends PromQL with additional features.</p>
</li>
<li><p><strong>Prometheus</strong>: Uses PromQL.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-victoriametrics-vs-prometheus-system-properties-comparison"><strong>📊 VictoriaMetrics vs Prometheus: System Properties Comparison</strong></h2>
<p>VictoriaMetrics is a monitoring system that is fully compatible with Prometheus. It offers many of the same features as Prometheus, but with some additional benefits, such as higher performance and scalability.</p>
<p>One key difference between VictoriaMetrics and Prometheus is that VictoriaMetrics includes an anomaly detection feature. This feature can be used to identify unusual changes in metrics data, which can be helpful for troubleshooting and identifying potential problems.</p>
<p>While both <code>vmagent</code> and Prometheus may scrape Prometheus targets (aka <code>/metrics</code> pages) according to the provided Prometheus-compatible scrape configs and send data to multiple remote storage systems, <code>vmagent</code> has the following additional features:</p>
<ul>
<li><p><code>vmagent</code> usually requires lower amounts of CPU, RAM, and disk IO compared to Prometheus when scraping an enormous number of targets (more than 1000) or targets with a great number of exposed metrics.</p>
</li>
<li><p><code>vmagent</code> provides independent disk-backed buffers for each configured remote storage (see <code>-remoteWrite.url</code>). This means that slow or temporarily unavailable storage doesn't prevent it from sending data to healthy storage in parallel. Prometheus uses a single shared buffer for all the configured remote storage systems (see <code>remote_write-&gt;url</code>) with a hardcoded retention of 2 hours.</p>
</li>
<li><p><code>vmagent</code> may accept, relabel, and filter data obtained via multiple data ingestion protocols in addition to data scraped from Prometheus targets. That means it supports both pull and push protocols for data ingestion. <a target="_blank" href="https://docs.victoriametrics.com/vmagent.html#features">See these docs for details</a>.</p>
</li>
</ul>
<p>Prometheus does not have a native High Availability mode: to have high availability, we had to duplicate our Prometheus instances. This implies that our targets were "scraped" by all our Prometheus instances (same for our rules and records). To avoid this, we had to use sharding, but this made the infrastructure more complex. More information on this subject in <a target="_blank" href="https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/high-availability.md">this documentation</a> from the Prometheus operator.</p>
<p>Prometheus is not designed to store metrics on a long-term basis, as mentioned in <a target="_blank" href="https://prometheus.io/docs/prometheus/latest/storage/#operational-aspects">the documentation</a>:</p>
<blockquote>
<p><em>Prometheus's local storage is not intended to be durable long-term storage; external solutions offer extended retention and data durability.</em></p>
</blockquote>
<p>We worked around this limitation by using VictoriaMetrics (VMCluster) as a LongTermStorage via the <code>remote_write</code> protocol.</p>
<p>All processes (scraping, ingest, storage, etc.) were, until now, managed in the same Prometheus instance, which implied a less flexible and vertical scaling only (since recently a <a target="_blank" href="https://prometheus.io/blog/2021/11/16/agent/">Prometheus agent</a> is available for the "scraping" part).</p>
<p>The RAM and CPU usage of a Prometheus instance is correlated to the number of metrics (and their cardinality) it has to manage. In our case, several Prometheus instances consumed more than 64 GB of RAM and 26 CPUs each, in order to absorb our peak loads. In a Kubernetes cluster, this high resource consumption can cause problems, especially for scheduling.</p>
<p>The Write-Ahead Log (WAL) system can cause rather slow restarts if the Prometheus instance runs out of RAM and can cause the Prometheus instance to hang for varying lengths of time. During the replay of the WAL, Prometheus doesn't scrape anything, thus there is no alerting and no way of knowing if something is going on.</p>
<h2 id="heading-the-cardinality-of-metrics"><strong>📈 The Cardinality of Metrics</strong></h2>
<p>When our Kubernetes clusters manage a large number of pods, a constraint quickly appears: cardinality.</p>
<blockquote>
<p><em>The cardinality of a metric is the number of TimeSeries of that metric with single-valued labels.</em></p>
</blockquote>
<p><img src="https://seifrajhi.github.io/static/203edc96f235ef0a301901fae893b443/c5bb3/labels.png" alt="Cardinality Example" /></p>
<p>In the example above, the <code>status_code</code> label has a cardinality of 5, <code>app</code> has a cardinality of 2, and the overall cardinality of the <code>server_responses</code> metric is 10. In this example, any Prometheus instance can handle this cardinality, but if you add, for example, the label <code>pod_name</code> or <code>client_IP</code> (or both) to the <code>server_responses</code> metric, the cardinality increases for each different client's calls and for each pod.</p>
<p>You should read the excellent <a target="_blank" href="https://www.robustperception.io/cardinality-is-key">article on cardinality</a> from "Robust Perception" for more details on this subject.</p>
<p>At Bedrock, the high cardinality metrics come from our HAProxy ingress. For our needs, we retrieve several labels like the name of the ingress pod as well as its IP address, but more importantly, the name and IP address of the destination pod. In a cluster that can grow to more than 15,000 pods, the combination of unique labels (cardinality) is very significant for some of our ingress metrics.</p>
<p>We found that Prometheus performed poorly when we had multiple metrics with high cardinalities (&gt; 100,000), resulting in over-consumption of RAM. During a high load event, Prometheus could consume up to 200 GB of RAM before being OOMKilled. When this happened, we would go completely blind as we had no metrics or alerting. This also impacts scalability in our Kubernetes clusters, as we use <a target="_blank" href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#scaling-on-custom-metrics">Custom Metrics</a> very heavily in HPAs to scale the number of pods in our applications.</p>
<p>There are many comparisons available online; here is a summary:</p>
<ul>
<li><p><a target="_blank" href="https://db-engines.com/en/system/Prometheus%3BVictoriaMetrics">System Properties Comparison: Prometheus vs. VictoriaMetrics</a> - General information on both systems.</p>
</li>
<li><p><a target="_blank" href="https://valyala.medium.com/prometheus-vs-victoriametrics-benchmark-on-node-exporter-metrics-4ca29c75590f">Prometheus vs VictoriaMetrics Benchmark on Node Exporter Metrics</a> - VictoriaMetrics uses much less disk and memory.</p>
</li>
<li><p><a target="_blank" href="https://docs.victoriametrics.com/FAQ.html#what-is-the-difference-between-vmagent-and-prometheus">FAQ: Differences Between vmagent and Prometheus</a> - FAQ from VictoriaMetrics.</p>
</li>
<li><p><a target="_blank" href="https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#prominent-features">Prominent Features of VictoriaMetrics</a> - Documentation from VictoriaMetrics about its capabilities.</p>
</li>
</ul>
<p>In short, some of VictoriaMetrics' abilities include:</p>
<ul>
<li><p>Supports both Pull and Push models (unlike Prometheus, which requires Pushgateway for push).</p>
</li>
<li><p>You can configure Prometheus with remote write to VictoriaMetrics, i.e., write data to VictoriaMetrics from Prometheus.</p>
</li>
<li><p>VictoriaMetrics has a concept of "namespaces" - you can have isolated environments for metrics, see <a target="_blank" href="https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#multitenancy">Multitenancy</a>.</p>
</li>
<li><p>Has its own <a target="_blank" href="https://docs.victoriametrics.com/MetricsQL.html">MetricsQL</a> with wider capabilities than PromQL.</p>
</li>
<li><p>For acquaintance, there is a <a target="_blank" href="https://play.victoriametrics.com/select/accounting/1/6a716b0f-38bc-4856-90ce-448fd713e3fe/prometheus/graph/#/">VictoriaMetrics playground</a>.</p>
</li>
<li><p>For AWS, there is <a target="_blank" href="https://aws.amazon.com/marketplace/pp/prodview-4tbfq5icmbmyc">Managed VictoriaMetrics</a>.</p>
</li>
</ul>
<h2 id="heading-victoriametrics-cluster-architecture"><strong>🏗️ VictoriaMetrics Cluster Architecture</strong></h2>
<p>VictoriaMetrics can be deployed as a single server or as a cluster version. I chose to <a target="_blank" href="https://docs.victoriametrics.com/guides/k8s-monitoring-via-vm-cluster.html">deploy the VictoriaMetrics-cluster on k8s</a> using Helm charts.</p>
<p><img src="https://seifrajhi.github.io/static/dafaa456ba23d8e20569aaaea250fa74/c5bb3/components.png" alt="Components" /></p>
<p><img src="https://seifrajhi.github.io/static/2290739ff77986c0b4ec581ad6e07f29/c5bb3/vm-k8s.png" alt="VM on K8s" /></p>
<ul>
<li><p><strong>vmstorage</strong>: Stores the raw data and returns the queried data on the given time range for the given label filters. This is the only stateful component in the cluster.</p>
</li>
<li><p><strong>vminsert</strong>: Accepts the ingested data and spreads it among vmstorage nodes according to consistent hashing over metric name and all its labels.</p>
</li>
<li><p><strong>vmselect</strong>: Performs incoming queries by fetching the needed data from all the configured vmstorage nodes.</p>
</li>
<li><p><strong>vmauth</strong>: A simple auth proxy and router for the cluster. It reads auth credentials from the Authorization HTTP header (Basic Auth, Bearer token, and <a target="_blank" href="https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1897">InfluxDB authorization</a> is supported), matches them against configs, and proxies incoming HTTP requests to the configured targets.</p>
</li>
<li><p><strong>vmagent</strong>: A tiny but mighty agent that helps you collect metrics from various sources and store them in VictoriaMetrics or any other Prometheus-compatible storage systems that support the remote_write protocol.</p>
</li>
<li><p><strong>vmalert</strong>: Executes a list of the given alerting or recording rules against configured data sources. Sending alerting notifications, vmalert relies on configured <a target="_blank" href="https://github.com/prometheus/alertmanager">Alertmanager</a>. Recording rules results are persisted via <a target="_blank" href="https://prometheus.io/docs/prometheus/latest/storage/#remote-storage-integrations">remote write</a> protocol. vmalert is heavily inspired by Prometheus implementation and aims to be compatible with its syntax.</p>
</li>
<li><p><strong>promxy</strong>: Used for querying the data from multiple clusters. It's a Prometheus proxy that makes many shards of Prometheus appear as a single API endpoint to the user.</p>
</li>
</ul>
<h2 id="heading-cluster-resizing-and-scalability"><strong>Cluster Resizing and Scalability</strong></h2>
<p>Cluster performance and capacity can be scaled up in two ways:</p>
<ol>
<li><p><strong>Vertical Scalability</strong>: By adding more resources (CPU, RAM, disk IO, disk space, etc.).</p>
</li>
<li><p><strong>Horizontal Scalability</strong>: By adding more of each component to the cluster.</p>
</li>
</ol>
<p>The components can all be scaled individually, with the only stateful component being the <code>vmstorage</code> component. This makes it easier to maintain and scale clusters. Adding new components and updating <code>vminsert</code> configurations is all it takes to scale the storage layer. Nothing else is needed.</p>
<p><img src="https://seifrajhi.github.io/static/7ae9f27c556f6fa8346d55dc998d79db/c5bb3/scalability.png" alt="Scalability" /></p>
<h2 id="heading-implementation-of-victoriametrics"><strong>🛠️ Implementation of VictoriaMetrics</strong></h2>
<p>VictoriaMetrics has charts for each component to deploy in Kubernetes. See <a target="_blank" href="https://github.com/VictoriaMetrics/helm-charts/tree/master">Victoria Metrics Helm Charts</a>. There are also charts to run <a target="_blank" href="https://github.com/VictoriaMetrics/operator">VictoriaMetrics Operator</a> and <a target="_blank" href="https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-k8s-stack/README.md">victoria-metrics-k8s-stack</a> – an analog of the Kubernetes Prometheus Stack.</p>
<p>We will use the <a target="_blank" href="https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-k8s-stack/README.md">victoria-metrics-k8s-stack</a>, which "under the hood" will launch VictoriaMetrics Operator, Grafana, and kube-state-metrics. See its <a target="_blank" href="https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-k8s-stack/Chart.yaml#L10C1-L10C13">dependencies</a>.</p>
<p>A VMCluster (Insert, Select, Storage) is deployed to manage access to metrics. The collection of metrics (push/pull) from exporters in Prometheus format is handled by the <code>vmagent</code>. Its configuration is done in the form of a Prometheus configuration file. It is able to:</p>
<ul>
<li><p>Manage the relabeling of metrics.</p>
</li>
<li><p>Temporarily store the metrics it has collected if the VMCluster is unavailable or not able to send the metrics to the VMCluster.</p>
</li>
<li><p>Limit the cardinality of metrics.</p>
</li>
</ul>
<p>One of the advantages of using this Helm chart is that it will deploy essential components to properly monitor a Kubernetes cluster such as <code>kube-state-metrics</code> or <code>prometheus-node-exporter</code>, but also scraping configurations for services such as <code>Kubelet</code>, <code>KubeApiServer</code>, <code>KubeControllerManager</code>, <code>KubeDNS</code>, <code>KubeEtcd</code>, <code>KubeScheduler</code>, <code>KubeProxy</code>.</p>
<p>Alerting is also managed via a <code>VMAlert</code> component, which will execute the alerting and recording rules set by VictoriaMetrics. Notifications are managed by an <code>Alertmanager</code>, which is also deployable via this chart.</p>
<p>This is what the monitoring and alerting stack based on this Helm chart looks like:</p>
<p><img src="https://seifrajhi.github.io/static/bc578fff8aec6b31f92918d32737886d/c5bb3/vm-eks.png" alt="VM on EKS" /></p>
<p>If you want to keep historical metrics of your Kubernetes clusters, VictoriaMetrics provides a tool to manage the export and import of data from different TSDB: <a target="_blank" href="https://docs.victoriametrics.com/vmctl.html">vmctl</a>.</p>
<p>Let's go. Let's start by checking the chart itself: <code>victoria-metrics-k8s-stack</code>.</p>
<h3 id="heading-victoriametrics-stack-helm-chart-installation"><strong>📦 VictoriaMetrics Stack Helm Chart Installation</strong></h3>
<p>Add repositories with dependencies:</p>
<pre><code class="lang-shell">helm repo add grafana https://grafana.github.io/helm-charts
"grafana" has been added to your repositories
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
"prometheus-community" has been added to your repositories
</code></pre>
<p>And VictoriaMetrics itself:</p>
<pre><code class="lang-shell">helm repo add vm https://victoriametrics.github.io/helm-charts/
"vm" has been added to your repositories
helm repo update
</code></pre>
<p>All values can be taken as follows:</p>
<pre><code class="lang-shell">helm show values vm/victoria-metrics-k8s-stack &gt; default-values.yaml
</code></pre>
<p>Or just from the repository — <a target="_blank" href="https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-k8s-stack/values.yaml">values.yaml</a>.</p>
<p>VictoriaMetrics has very good documentation, so during the process, we will often use the <a target="_blank" href="https://docs.victoriametrics.com/operator/api.html">API Docs</a>.</p>
<h3 id="heading-create-a-configuration"><strong>Create a Configuration</strong></h3>
<pre><code class="lang-shell">victoria-metrics-operator:
    serviceAccount:
        create: false

alertmanager:
    enabled: true

vmalert:
    annotations: {}
    enabled: true

vmagent:
    enabled: true

grafana:
    enabled: true
    ingress:
        enabled: true
        annotations:
            kubernetes.io/ingress.class: alb
            alb.ingress.kubernetes.io/target-type: ip
            alb.ingress.kubernetes.io/scheme: internet-facing
        hosts:
            - monitoring.dev.example.com
</code></pre>
<h3 id="heading-deploy-to-a-new-namespace"><strong>🚀 Deploy to a New Namespace</strong></h3>
<pre><code class="lang-shell">helm upgrade --install victoria-metrics-k8s-stack -n monitoring --create-namespace vm/victoria-metrics-k8s-stack -f monitoring-values.yaml
</code></pre>
<p>Get the pods lists by running these commands:</p>
<pre><code class="lang-shell">kubectl get pods -A | grep 'victoria-metrics'
# or list all resources of victoria-metrics
kubectl get all -n monitoring | grep victoria
</code></pre>
<p>Get the application by running these commands:</p>
<pre><code class="lang-shell">helm list -f victoria-metrics -n monitoring
</code></pre>
<p>See the history of versions of victoria-metrics application with command:</p>
<pre><code class="lang-shell">helm history victoria-metrics -n monitoring
</code></pre>
<h2 id="heading-summarizing"><strong>📋 Summarizing</strong></h2>
<p>In this post, VictoriaMetrics is a high-performance time-series database that is well-suited for Kubernetes monitoring and analytics. It offers several advantages over Prometheus, including:</p>
<ul>
<li><p>Superior scalability and performance</p>
</li>
<li><p>Long-term storage capabilities</p>
</li>
<li><p>Seamless integration with Kubernetes</p>
</li>
<li><p>Anomaly detection</p>
</li>
</ul>
<p>VictoriaMetrics can help organizations to improve their monitoring and analytics efforts, leading to more informed decision-making and improved system reliability.</p>
<p><strong><em>Until next time, つづく 🎉</em></strong></p>
<blockquote>
<p><em>💡 Thank you for Reading !! 🙌🏻😁📃, see you in the next blog.🤘</em> <strong><em>Until next time 🎉</em></strong></p>
</blockquote>
<p>🚀 Thank you for sticking up till the end. If you have any questions/feedback regarding this blog feel free to connect with me:</p>
<p><strong>♻️ LinkedIn:</strong> <a target="_blank" href="https://www.linkedin.com/in/rajhi-saif/">https://www.linkedin.com/in/rajhi-saif/</a></p>
<p><strong>♻️ X/Twitter:</strong> <a target="_blank" href="https://x.com/rajhisaifeddine">https://x.com/rajhisaifeddine</a></p>
<p><strong>The end ✌🏻</strong></p>
<h1 id="heading-keep-learning-keep-sharing">🔰 Keep Learning !! Keep Sharing !! 🔰</h1>
]]></content:encoded></item><item><title><![CDATA[10 Ways to Supercharge Your GitHub Profile (With Real Examples)]]></title><description><![CDATA[If you’re a DevOps Engineer, Platform Engineer, or Developer aiming to catch an employer’s eye, your GitHub profile can be much more than code storage. It can be your showcase, your brand, your story. Below are 10 practical strategies, paired with re...]]></description><link>https://blog.kubeskills.com/supercharge-github</link><guid isPermaLink="true">https://blog.kubeskills.com/supercharge-github</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Platform Engineering ]]></category><dc:creator><![CDATA[Chad M. Crowell]]></dc:creator><pubDate>Mon, 29 Sep 2025 10:25:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759141375674/e48f55cb-bea4-47ad-95ec-7e8da0f689bb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’re a DevOps Engineer, Platform Engineer, or Developer aiming to catch an employer’s eye, your GitHub profile can be much more than code storage. It can be your showcase, your brand, your story. Below are 10 practical strategies, paired with real examples, that illustrate how to level up your <a target="_blank" href="https://github.com">GitHub</a> profile.</p>
<p>Let’s be honest, recruiters and hiring managers don’t just look at your resume anymore; they often check your GitHub profile first.</p>
<blockquote>
<p>In this <a target="_blank" href="https://opensourcefundingsurvey2024.com/">2024 Open Source Software Funding Report</a>, recommendations include encouraging employees to publicise their contributions to GitHub projects.</p>
</blockquote>
<p>The impression they get can decide whether you move forward in the hiring process. The good news? You can control that impression. Let’s look at ways of doing just that, with examples from <a target="_blank" href="https://github.com/iximiuz">Ivan Velichko</a>, <a target="_blank" href="https://github.com/strowk">Timur Sultanaev</a>, <a target="_blank" href="https://github.com/thockin">Tim Hockin</a>, <a target="_blank" href="https://github.com/katcosgrove">Kat Cosgrove</a>, <a target="_blank" href="https://github.com/dims">Davanum Srinivas (dims)</a>, <a target="_blank" href="https://github.com/bentheelder">Benjamin Elder</a>, and the community-driven <a target="_blank" href="https://github.com/kubeskills/student-notebook">KubeSkills GROW project</a>.</p>
<h2 id="heading-pin-your-best-repositories">Pin Your Best Repositories</h2>
<p><strong>Why it matters:</strong> It directs attention to your strongest work</p>
<p><strong>Example:</strong> <a target="_blank" href="https://github.com/thockin">Tim Hockin’s profile</a> highlights pinned repos like Kubernetes-related tools, design proposals, and code samples. This makes it easy for visitors to see high-value projects at a glance.</p>
<p><strong>What you can do:</strong> Pin 3 to 6 repositories that reflect your strengths, whether that’s Go controllers, Kubernetes operators, or DevOps automation.</p>
<h2 id="heading-write-polished-readme-files">Write Polished README Files</h2>
<p><strong>Why it matters:</strong> Your README is the landing page of your project</p>
<p><strong>Example:</strong> Ivan’s <a target="_blank" href="https://github.com/iximiuz/client-go-examples">client-go-examples repo</a> has clear, self-contained examples showing how to use Kubernetes client-go APIs. Each example includes its own README and context, making it approachable.</p>
<p><strong>What you can do:</strong> Write READMEs that explain the problem, solution, tech stack, usage instructions, and examples. Add visuals like screenshots or GIFs to make them pop.</p>
<h2 id="heading-contribute-to-open-source">Contribute to Open Source</h2>
<p><strong>Why it matters:</strong> Shows you can collaborate and add value outside of personal projects.</p>
<p><strong>Example:</strong> <a target="_blank" href="https://github.com/katcosgrove">Kat Cosgrove</a> is a developer advocate and open source contributor known for their work in the Kubernetes and cloud native ecosystem. Their contributions, ranging from documentation to community projects, demonstrate that open source isn’t only about code, but also about improving accessibility and education.</p>
<p><strong>What you can do:</strong> Contribute small fixes, improve docs, or add features to projects you care about. Even modest contributions demonstrate collaboration and community impact.</p>
<h2 id="heading-show-variety-in-your-projects">Show Variety in Your Projects</h2>
<p><strong>Why it matters:</strong> Employers want to see breadth, not just another CRUD app.</p>
<p><strong>Example:</strong> The <a target="_blank" href="https://github.com/strowk/mcp-k8s-go">mcp-k8s-go repo</a> by Timur is a real-world tool that interacts with Kubernetes resources. It demonstrates complexity and problem-solving, not just tutorials.</p>
<p><strong>What you can do:</strong> Balance utilities, tutorials, experiments, and production-grade projects in your profile.</p>
<h2 id="heading-use-github-actions-automation">Use GitHub Actions / Automation</h2>
<p><strong>Why it matters:</strong> Demonstrates knowledge of modern workflows (CI/CD, testing, automation).</p>
<p><strong>Example:</strong> Many Kubernetes projects (including those maintained by <a target="_blank" href="https://github.com/bentheelder">Benjamin Elder</a> and others in the Kubernetes org) use GitHub Actions or other CI pipelines for testing and validation, keeping quality high.</p>
<p><strong>What you can do:</strong> Add workflows for testing, linting, formatting, or automatically updating parts of your README.</p>
<h2 id="heading-commit-consistently">Commit Consistently</h2>
<p><strong>Why it matters:</strong> A steady contribution graph signals continuous growth.</p>
<p><strong>Example:</strong> <a target="_blank" href="https://github.com/dims">Davanum Srinivas (dims)</a> is one of the most prolific Kubernetes contributors. His GitHub history reflects years of steady, high-impact activity across Kubernetes, CNCF projects, and related tooling. That level of consistency signals both expertise and long-term commitment to the ecosystem.</p>
<p><strong>What you can do:</strong> Don’t wait for big projects, make small, steady improvements. Fix a bug, add a test, and improve the documentation. Consistency matters more than volume.</p>
<h2 id="heading-document-your-learning">Document Your Learning</h2>
<p><strong>Why it matters:</strong> Public learning shows curiosity and persistence.</p>
<p><strong>Example:</strong> The <a target="_blank" href="https://github.com/iximiuz/client-go-examples">client-go-examples</a> repo is itself a public learning exercise, with bite-sized code samples for Kubernetes developers.</p>
<p><strong>Community-driven Example:</strong> The <a target="_blank" href="https://github.com/kubeskills/student-notebook">KubeSkills Student Notebook</a> is part of the KubeSkills GROW initiative. Students fork the repo, add reflections via PRs, and track their growth. This demonstrates technical growth and collaboration in a public way.</p>
<p><strong>What you can do:</strong> Create your own learning repo, or contribute to a community-driven one. Over time, it becomes a testament to your persistence and growth.</p>
<h2 id="heading-use-professional-workflows-in-your-repos">Use Professional Workflows in Your Repos</h2>
<p><strong>Why it matters:</strong> Employers want to see that you can work like a team.</p>
<p><strong>Example:</strong> In <a target="_blank" href="https://github.com/strowk/mcp-k8s-go">mcp-k8s-go</a> , issues, documentation, and structure make it look like a professional project, not just code thrown together.</p>
<p><strong>What you can do:</strong> Use Issues, Pull Requests, and project boards (even in personal repos). It signals that you understand real workflows.</p>
<h2 id="heading-add-a-profile-readme">Add a Profile Readme</h2>
<p><strong>Why it matters:</strong> Your GitHub profile is your homepage.</p>
<p><strong>Example:</strong> <a target="_blank" href="https://github.com/Nancy-chauhan">Nancy Chauhan’s GitHub profile</a> is a strong example. She uses her profile README to highlight who she is, what she’s working on, and how to connect with her. It’s simple, straightforward, and professional. This is precisely what recruiters look for.</p>
<p><strong>What you can do:</strong> Create a repo named after your GitHub username and add a README with your skills, current projects, and ways to connect.</p>
<h2 id="heading-highlight-quality-testing-and-security">Highlight Quality, Testing, and Security</h2>
<p><strong>Why it matters:</strong> Employers value reliable, secure code.</p>
<p><strong>Example:</strong> The <a target="_blank" href="https://github.com/strowk/mcp-k8s-go">mcp-k8s-go</a> repo utilizes structured, tested code, signaling that it’s production-ready.</p>
<p><strong>What you can do:</strong> Add unit tests, coverage reports, linting, and security checks (Dependabot, Trivy). Even in small projects, this signals you think like a professional.</p>
<h2 id="heading-conclusion-amp-next-steps">Conclusion &amp; Next Steps</h2>
<p>By applying these 10 steps, you’ll do more than improve your GitHub profile; you’ll give employers an apparent reason to say yes. A polished, active, and well-documented profile speaks volumes about your skills and work style.</p>
<p>Start today by forking the <a target="_blank" href="https://github.com/kubeskills/student-notebook">KubeSkills Student Notebook</a>, documenting your progress, and building a portfolio that proves your growth. Share your updated GitHub profile with the community and inspire others to grow alongside you. Employers notice developers who learn, share, and collaborate. Make sure you’re one of them!</p>
<p><strong>Bonus Call to Action:</strong> If you want to take your GitHub journey even further, consider exploring the <a target="_blank" href="https://lfx.linuxfoundation.org/tools/mentorship">LFX Mentorship Program</a>. It connects developers with open source projects under the Linux Foundation, giving you real-world experience and a public record of contributions. Nearly half of mentees report that the program <a target="_blank" href="https://navendu.me/posts/how-the-lfx-mentorship-program-helped-me-level-up-my-career">helped them secure new jobs</a>, proof that visible contributions can open doors to career opportunities.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Kubernetes API Objects and How They Work]]></title><description><![CDATA[This article was originally written by Ehis Iribhogbe
Kubernetes is an open-source container orchestration platform that allows developers to automate the deployment, scaling, and management of containerized applications. One of the key features of K...]]></description><link>https://blog.kubeskills.com/understanding-kubernetes-api-objects</link><guid isPermaLink="true">https://blog.kubeskills.com/understanding-kubernetes-api-objects</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[cloud native]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Cloud Computing]]></category><dc:creator><![CDATA[Divine Odazie]]></dc:creator><pubDate>Tue, 05 Aug 2025 20:18:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754379853706/3c1dee29-790b-4f88-99e5-62374bc79123.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article was originally written by <a target="_blank" href="https://www.everythingdevops.dev/blog/understanding-the-kubernetes-api-objects-and-how-they-work"><strong>Ehis Iribhogbe</strong></a></p>
<p>Kubernetes is an open-source container orchestration platform that allows developers to automate the deployment, scaling, and management of containerized applications. One of the key features of Kubernetes is its API, which provides a uniform way to interact with the platform and perform tasks such as deploying and managing applications, monitoring the status of the cluster, and updating configuration settings.</p>
<p>This article will teach you about the Kubernetes API and its various objects, such as Pod, Service, Controller, Deployment, and Storage. You will also learn what each object does and see examples that will help you understand its functionality.</p>
<h2 id="heading-what-is-the-kubernetes-api">What is the Kubernetes API?</h2>
<p>The Kubernetes API is the primary interface for interacting with a Kubernetes cluster. It is exposed by the kube-apiserver, which serves as the central control plane component handling all REST operations for creating, modifying, and retrieving the state of cluster resources.</p>
<p>The API provides endpoints to manage core and custom resources, such as Pods, Deployments, Services, ReplicaSets, and Namespaces, using <a target="_blank" href="https://restfulapi.net/">RESTful</a> principles over HTTPS and commonly returns data in JSON format.</p>
<p>The Kubernetes API consists of a set of basic API objects that represent the system’s current state. These API objects enable the configuration of the system’s state, which can be done either declaratively or imperatively. Declarative configuration involves describing the desired implementation, such as specifying the deployment and how we want the system to appear. On the other hand, imperative configuration involves executing a sequence of commands on the command line to achieve the desired system state.</p>
<h2 id="heading-some-of-the-kubernetes-api-objects">Some of the Kubernetes API Objects</h2>
<p>In this section, you will explore some of the essential Kubernetes API objects and their functionalities. Understanding these objects is crucial for effectively harnessing the power of Kubernetes and maximizing the efficiency of your containerized infrastructure. Let's dive in and discover the key Kubernetes API objects that form the backbone of this powerful platform.</p>
<h3 id="heading-pods">Pods</h3>
<p><em>“Pods</em> are the smallest deployable units of computing that you can create and manage in Kubernetes” — <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/pods/">The Kubernetes documentation</a>. To create a Pod, create a manifest (YAML or JSON) file with a specification. The specification will contain the Pod name and the Pod's container(s) image. When you apply the manifest, Kubernetes schedules the Pod on a <a target="_blank" href="https://everythingdevops.dev/kubernetes-architecture-explained-worker-nodes-in-a-cluster/">worker node</a> in the cluster.</p>
<p>Below is an example YAML manifest that defines a Pod object:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Pod</span>
<span class="hljs-attr">metadata:</span>
 <span class="hljs-attr">name:</span> <span class="hljs-string">nginx-pod</span>
 <span class="hljs-attr">labels:</span>
   <span class="hljs-attr">env:</span> <span class="hljs-string">dev</span>
<span class="hljs-attr">spec:</span>
 <span class="hljs-attr">containers:</span>
   <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">nginx</span>
     <span class="hljs-attr">image:</span> <span class="hljs-string">nginx</span>
</code></pre>
<p>The above YAML file describes a Kubernetes Pod running a single container of the nginx image. Let's break down the different fields:</p>
<ul>
<li><p><code>apiVersion: v1</code><strong>:</strong> This specifies the Kubernetes API version used for this Pod, in this case, v1.</p>
</li>
<li><p><code>kind: Pod</code>: This specifies the type of Kubernetes resource being described, in this case, a Pod.</p>
</li>
<li><p><code>metadata</code>: This section contains metadata about the Pod, such as its name and labels.</p>
</li>
<li><p><code>name: nginx-pod</code>: This is the name of the Pod.</p>
</li>
<li><p><code>labels</code>: This is a set of key-value pairs that can be used to identify and group related resources. In this case, the label <code>env: dev</code> is applied to the Pod.</p>
</li>
<li><p><code>spec</code>: This section describes the specification for the Pod.</p>
</li>
<li><p><code>containers</code>: This is an array of containers to be run in the Pod. In this case, there is a single container.</p>
</li>
<li><p><code>name</code>: nginx: This is the name of the container.</p>
</li>
<li><p><code>image: nginx</code>: This specifies the Docker image to use for the container. In this case, it will use the official <code>nginx</code> image from Docker Hub.</p>
</li>
</ul>
<p>Pods are considered ephemeral, meaning they are not redeployed if they die. For instance, if we deploy an application as a Pod based on a container image and that Pod dies, Kubernetes will automatically deploy another Pod based on the same container image. There is no state maintained between these two pods, and they are considered independent of each other.</p>
<p>Pods are also considered atomic, meaning they either exist or do not exist. For example, in a single container Pod, if the application running inside that Pod dies, the Pod also dies. Similarly, in a multi-container Pod where multiple applications run, the entire Pod becomes unavailable if one of those applications dies. Therefore, having only one container-based application inside a Pod is recommended to avoid any unwanted dependencies between applications.</p>
<h3 id="heading-controllers">Controllers</h3>
<p>Controllers are responsible for defining and maintaining the desired state of a cluster. The controller managers ensure that the system remains in the desired state. For controllers to define and manage the desired state of deployed applications, they monitor and respond to the state and health of the Pods, ensuring that the desired number of pods are up and running and healthy. If the state or health changes, the controller will respond accordingly, ensuring the system stays in the desired state.</p>
<p>Kubernetes utilizes controller managers to monitor the state of a pod and ensure that it remains operational. There are different types of controller managers; the following are some of them:</p>
<ul>
<li><p><strong>ReplicaSet</strong> <strong>Controlle</strong>r <strong>Manager</strong>: It allows you to define the number of replicas for a particular Pod you want up and running at all times. Suppose one of those Pods becomes unhealthy and unavailable for any reason. In that case, it's the job of the ReplicaSet controller to delete that unhealthy Pod and deploy a new Pod to return the system to its desired healthy state.</p>
</li>
<li><p><strong>Deployment set Controller Manager:</strong> When deploying applications in Kubernetes, you do not create ReplicaSet(s) directly. Instead, you create a deployment, which then creates a ReplicaSet based on what is specified in the Deployment manifest file. The Deployment manages the state of the replica set, such as the number of Pods to create and which container image to run. Additionally, the Deployment set manages the transition between two ReplicaSets, such as when updating an application with new changes or transitioning from one version of an application to another.</p>
</li>
</ul>
<p>To learn about other Controllers, check out this <a target="_blank" href="https://kubernetes.io/docs/concepts/architecture/controller/">Kubernetes documentation on controllers</a>.</p>
<h3 id="heading-services">Services</h3>
<p>Services in Kubernetes provide a persistent access point to the applications deployed as Pods. They add persistence to the ephemeral nature of Pods. A Service is an abstraction that defines a set of Pods and a policy for accessing them. It offers reliable and stable network connections to the Pods, allowing you to expose your application to the outside world or other parts of your cluster.</p>
<p>Services can automatically distribute incoming traffic among the Pods in a Deployment, providing load-balancing features and allowing you to scale your application as needed.</p>
<p>There are different types of Services in Kubernetes, each with its own set of features and use cases. Some of the most common types are:</p>
<ul>
<li><p><strong>ClusterIP:</strong> This is a type of service that exposes the pods within the cluster only. It creates a virtual IP address that is accessible only within the cluster.</p>
</li>
<li><p><strong>NodePort:</strong> This type of service exposes the pods to the network by opening a port on each node in the cluster. The port can be used to access the service from outside the cluster.</p>
</li>
<li><p><strong>LoadBalancer:</strong> This service is similar to <strong>NodePort</strong> but also creates an external load balancer to distribute incoming traffic to the pods. Load balancers are typically used in cloud-hosted clusters where the cloud provider can create and manage the load balancer for you.</p>
</li>
</ul>
<p>The following is a YAML manifest that defines a NodePort service:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
 <span class="hljs-attr">name:</span> <span class="hljs-string">nginx-service</span>
<span class="hljs-attr">spec:</span>
 <span class="hljs-attr">type:</span> <span class="hljs-string">NodePort</span>
 <span class="hljs-attr">ports:</span>
   <span class="hljs-bullet">-</span> <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
     <span class="hljs-attr">targetPort:</span> <span class="hljs-number">80</span>
     <span class="hljs-attr">nodePort:</span> <span class="hljs-number">30008</span>
 <span class="hljs-attr">selector:</span>
   <span class="hljs-attr">env:</span> <span class="hljs-string">dev</span>
</code></pre>
<p>The above YAML file describes a NodePort Service that will expose the Pod running the <code>nginx</code> image on port <code>80</code>. Let's break down the different fields:</p>
<ul>
<li><p><code>apiVersion: v1</code>: This specifies the Kubernetes API version used for this Service, in this case, v1.</p>
</li>
<li><p><code>kind: Service</code>: This specifies the type of Kubernetes resource being described, in this case a Service.</p>
</li>
<li><p><code>metadata</code>: This section contains metadata about the Service, such as its name.</p>
</li>
<li><p><code>name: nginx-service</code>: This is the name of the Service.</p>
</li>
<li><p><code>spec</code>: This section describes the specification for the Service.</p>
</li>
<li><p><code>type: NodePort</code>: This specifies the type of the Service, in this case <strong>NodePort</strong>. This type exposes the Service on a static port on each Node in the cluster.</p>
</li>
<li><p><code>ports</code>: This is an array of ports to be exposed by the Service.</p>
</li>
<li><p><code>port: 80</code>: This is the port number on which the Service will listen.</p>
</li>
<li><p><code>targetPort: 80</code>: This is the port number of the Pod to which the traffic will be forwarded.</p>
</li>
<li><p><code>nodePort: 30008</code>: This is the static port number on each Node in the cluster on which the Service will be exposed.</p>
</li>
<li><p><code>selector</code>: This is a set of key-value pairs that will be used to match the Service to the Pod to which it will forward traffic.</p>
</li>
<li><p><code>env: dev</code>: This specifies the label to use for matching the Service to the Pod. In this case, the Service will match any Pod with the label <code>env: dev</code>.</p>
</li>
</ul>
<p>In Kubernetes clusters, services provide network connectivity, load balancing, and service discovery for your applications. They help you build scalable and highly available applications that can run on a cluster of machines.</p>
<h3 id="heading-storage">Storage</h3>
<p>In Kubernetes, there are storage options that provide persistent storage for your applications. Storage refers to the different storage solutions used to store data for our applications. These storage solutions can be local to a single node or distributed across multiple nodes. They can be used to store application data, configuration data, or log data.</p>
<p>In Kubernetes, Persistent Volume (PV), Persistent Volume Claim (PVC), and StorageClass are Kubernetes resources used for managing storage in a cluster.</p>
<ul>
<li><strong>Persistent Volume (PV)</strong> is a Kubernetes resource that represents a piece of storage that can be dynamically provisioned when a claim for storage is made, or they can be manually created and managed by an administrator.</li>
</ul>
<p>Below is a yaml template that defines a PV object.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">PersistentVolume</span>
<span class="hljs-attr">metadata:</span>
 <span class="hljs-attr">name:</span> <span class="hljs-string">my-pv</span>
<span class="hljs-attr">spec:</span>
 <span class="hljs-attr">accessModes:</span>
 <span class="hljs-bullet">-</span> <span class="hljs-string">ReadWriteOnce</span>
 <span class="hljs-attr">capacity:</span>
   <span class="hljs-attr">storage:</span> <span class="hljs-string">500Mi</span>
</code></pre>
<p><code>‍</code>The above YAML manifest describes a Kubernetes PV that can be used to store data persistently in the cluster. Let's break down the different fields:</p>
<ul>
<li><p><code>apiVersion: v1</code>: This specifies the Kubernetes API version used for this PV, in this case v1.</p>
</li>
<li><p><code>kind: PersistentVolume</code>: This specifies the type of Kubernetes resource being described, in this case a Persistent Volume.</p>
</li>
<li><p><code>metadata</code>: This section contains metadata about the PV, such as its name.</p>
</li>
<li><p><code>name: my-pv</code>: This is the name of the PV.</p>
</li>
<li><p><code>spec</code>: This section describes the specification for the PV.</p>
</li>
<li><p><code>accessModes</code>: This is an array of access modes that the PV supports.</p>
</li>
<li><p><code>- ReadWriteOnce</code>: This access mode specifies that the PV can be mounted as read-write by a single node.</p>
</li>
<li><p><code>capacity</code>: This section specifies the capacity of the PV.</p>
</li>
<li><p><code>storage: 500Mi</code>: This specifies the storage capacity of the PV, in this case 500MiB.</p>
</li>
</ul>
<p>The YAML file describes a Persistent Volume that can be used to store data persistently in the cluster, with a storage capacity of 500MiB, and can be mounted by a single node as read-write. However, this PV is not bound to any specific Persistent Volume Claim (PVC) yet. To make it usable by a specific application, a matching PVC should be created that requests storage with the same access mode and capacity as the PV. Then, the PV should be bound to the PVC to make it available for use by the application.</p>
<ul>
<li><strong>Persistent Volume Claims (PVCs)</strong> in Kubernetes are requests made by pods in your cluster for storage. When a PVC is created, it will bind to a Persistent Volume (PV) and make the storage available to the pod. In other words, a PVC is a way for pods to request a specific amount of storage without having to know the underlying details of where that storage is coming from.</li>
</ul>
<p>Below is a YAML template that defines a PVC object :</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">PersistentVolumeClaim</span>
<span class="hljs-attr">metadata:</span>
 <span class="hljs-attr">name:</span> <span class="hljs-string">my-claim</span>
<span class="hljs-attr">spec:</span>
 <span class="hljs-attr">accessModes:</span>
 <span class="hljs-bullet">-</span> <span class="hljs-string">ReadWriteOnce</span>
 <span class="hljs-attr">storageClassName:</span> <span class="hljs-string">google-storage</span>
 <span class="hljs-attr">resources:</span>
   <span class="hljs-attr">requests:</span>
     <span class="hljs-attr">storage:</span> <span class="hljs-string">300Mi</span>
</code></pre>
<p><code>‍</code> This is a YAML file that describes a Kubernetes Persistent Volume Claim (PVC) that requests storage from a Persistent Volume (PV) with specific characteristics. Let's break down the different fields:</p>
<ul>
<li><p><code>apiVersion: v1</code>: This specifies the Kubernetes API version used for this PVC, in this case v1.</p>
</li>
<li><p><code>kind: PersistentVolumeClaim</code>: This specifies the type of Kubernetes resource being described, in this case, a Persistent Volume Claim.</p>
</li>
<li><p><code>metadata</code>: This section contains metadata about the PVC, such as its name.</p>
</li>
<li><p><code>name: my-claim</code>: This is the name of the PVC.</p>
</li>
<li><p><code>spec</code>: This section describes the specification for the PVC.</p>
</li>
<li><p><code>accessModes</code>: This is an array of access modes that the PVC requires.</p>
</li>
<li><p><code>- ReadWriteOnce</code>: This access mode specifies that the PVC requires read-write access to the storage.</p>
</li>
<li><p><code>storageClassName: google-storage</code>: This specifies the name of the StorageClass to use for creating the PV. The StorageClass provides a way to specify the underlying storage provider and its characteristics.</p>
</li>
<li><p><code>resources</code>: This section specifies the resource requirements for the PVC.</p>
</li>
<li><p><code>requests</code>: This section specifies the minimum amount of storage that the PVC requires.</p>
</li>
<li><p><code>storage: 300Mi</code>: This specifies the minimum amount of storage capacity that the PVC requires, in this case 300MiB.</p>
</li>
</ul>
<p>The YAML file describes a Persistent Volume Claim that requests 300MiB of storage with read-write access from a PV with a StorageClass of <code>google-storage</code>. If a PV with matching characteristics is available in the cluster, the PVC will bind to it and make it available for use by the application. If a suitable PV is not available, a new PV will be dynamically provisioned according to the StorageClass definition.</p>
<ul>
<li><strong>Storage Classes</strong> are used to define the type of storage that will be dynamically provisioned when a Persistent Volume Claim (PVC) is created. A Storage Class represents a set of parameters for dynamic provisioning of Persistent Volumes. These parameters can include the type of storage (e.g., block or file), the performance characteristics (e.g., SSD or HDD), and the location of the storage (e.g., on-premises or in the cloud). When a PVC is created and the StorageClass is specified, the Kubernetes cluster will automatically provision a Persistent Volume that meets the criteria defined in the Storage Class.</li>
</ul>
<p>Below is a yaml template that defines a StorageClass object :</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">storage,k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">StorageClass</span>
<span class="hljs-attr">metadata:</span>
 <span class="hljs-attr">name:</span> <span class="hljs-string">my-google-storage</span>
<span class="hljs-attr">provisioner:</span> <span class="hljs-string">Kubernetes.io/gce-pd</span>
<span class="hljs-attr">parameters:</span>
 <span class="hljs-attr">type:</span> <span class="hljs-string">pd-standard</span>
 <span class="hljs-attr">replication-type:</span> <span class="hljs-string">none</span>
</code></pre>
<p>This is a YAML file that describes a Kubernetes StorageClass resource, which is used to define different classes of storage with specific characteristics. Storage classes allow users to request storage resources without having to know the underlying details of the storage infrastructure.</p>
<p>Let's break down the different fields:</p>
<ul>
<li><p><code>apiVersion: storage.k8s.io/v1</code>: This specifies the Kubernetes API version used for this StorageClass, in this case storage.k8s.io/v1.</p>
</li>
<li><p><code>kind: StorageClass</code>: This specifies the type of Kubernetes resource being described, in this case, a StorageClass.</p>
</li>
<li><p><code>metadata</code>: This section contains metadata about the StorageClass, such as its name.</p>
</li>
<li><p><code>name: my-google-storage</code>: This is the name of the StorageClass.</p>
</li>
<li><p><code>provisioner: Kubernetes.io/gce-pd</code>: This specifies the name of the storage provider that will be used to provision the underlying storage resources. In this case, it's using the GCE-PD provisioner, which provisions Google Compute Engine persistent disks.</p>
</li>
<li><p><code>parameters</code>: This section specifies additional parameters for the storage provider.</p>
</li>
<li><p><code>type: pd-standard</code>: This parameter specifies the type of disk to use for the persistent disk, in this case, pd-standard.</p>
</li>
<li><p><code>replication-type: none</code>: This parameter specifies that replication is not required for this storage class.</p>
</li>
</ul>
<p>The YAML file describes a StorageClass named <code>my-google-storage</code> that uses the <code>GCE-PD</code> provisioner to dynamically provision persistent disks of type pd-standard without replication. This StorageClass can be used to dynamically provision Persistent Volumes when requested by Persistent Volume Claims that request the same StorageClass.</p>
<p>Kubernetes storage allows your applications to store data persistently, even if the pods or containers that use the data are deleted or recreated. It also enables you to manage the various types of storage available in your cluster and provision new storage dynamically as required. By using Kubernetes storage, you can ensure that your data is safe and available whenever your application needs it.</p>
<h3 id="heading-deployment">Deployment</h3>
<p>A Deployment manages a ReplicaSet, which in turn manages the deployment and scaling of a set of Pods. By using a Deployment object, you can define a desired state for the ReplicaSet, such as the number of replicas to be created, the container images to be used, and the configuration options to be set. The Deployment object then ensures that the desired state is achieved by updating or rolling back the ReplicaSet as necessary.<br />Deployments enable you to perform rolling updates and rollbacks, which are done by creating a new ReplicaSet and slowly replacing the old Pods with the new ones. This ensures that there is no downtime and that the latest version of the application is rolled out gradually.</p>
<p>The following YAML template defines a deployment object:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
 <span class="hljs-attr">name:</span> <span class="hljs-string">my-app-deployment</span>
<span class="hljs-attr">spec:</span>
 <span class="hljs-attr">replicas:</span> <span class="hljs-number">3</span>
 <span class="hljs-attr">selector:</span>
   <span class="hljs-attr">matchLabels:</span>
     <span class="hljs-attr">app:</span> <span class="hljs-string">my-app</span>
 <span class="hljs-attr">template:</span>
   <span class="hljs-attr">metadata:</span>
     <span class="hljs-attr">labels:</span>
       <span class="hljs-attr">app:</span> <span class="hljs-string">my-app</span>
   <span class="hljs-attr">spec:</span>
     <span class="hljs-attr">containers:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">my-app-container</span>
         <span class="hljs-attr">image:</span> <span class="hljs-string">my-app-image:latest</span>
         <span class="hljs-attr">ports:</span>
           <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">8080</span>
         <span class="hljs-attr">volumeMounts:</span>
           <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">my-app-pvc</span>
             <span class="hljs-attr">mountPath:</span> <span class="hljs-string">/data</span>
     <span class="hljs-attr">volumes:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">my-app-pvc</span>
         <span class="hljs-attr">persistentVolumeClaim:</span>
           <span class="hljs-attr">claimName:</span> <span class="hljs-string">my-pvc</span>
</code></pre>
<p>The above YAML file describes a Kubernetes Deployment resource, which is used to manage the lifecycle of a set of replicated Pods. This Deployment creates and manages a set of replicas of a containerized application, as well as the associated resources, such as a Persistent Volume Claim and a Volume to store the application's data. Let's break down the different fields:</p>
<ul>
<li><p><code>apiVersion: apps/v1</code>: This specifies the Kubernetes API version used for this Deployment, in this case, apps/v1.</p>
</li>
<li><p><code>kind: Deployment</code>: This specifies the type of Kubernetes resource being described, in this case,e a Deployment.</p>
</li>
<li><p><code>metadata</code>: This section contains metadata about the Deployment, such as its name.</p>
</li>
<li><p><code>name: my-app-deployment</code>: This is the name of the Deployment.</p>
</li>
<li><p><code>spec</code>: This section describes the specification for the Deployment.</p>
</li>
<li><p><code>replicas: 3</code>: This specifies the number of replicas of the application to create.</p>
</li>
<li><p><code>selector</code>: This specifies the labels used to select the Pods managed by the Deployment.</p>
</li>
<li><p><code>matchLabels</code>: This specifies the labels used to match the Pods managed by the Deployment.</p>
</li>
<li><p><code>app: my-app</code>: This label selects the Pods that have the label app set to my-app.</p>
</li>
<li><p><code>template</code>: This specifies the Pod template used to create the replicas.</p>
</li>
<li><p><code>metadata</code>: This section contains metadata about the Pod template.</p>
</li>
<li><p><code>labels</code>: This specifies the labels used to select the Pods created from the template.</p>
</li>
<li><p><code>app: my-app</code>: This label is applied to the Pods created from the template.</p>
</li>
<li><p><code>spec</code>: This section specifies the specification for the Pod template.</p>
</li>
<li><p><code>containers</code>: This specifies the containers to be run in the Pod.</p>
</li>
<li><p><code>name: my-app-container</code>: This specifies the name of the container.</p>
</li>
<li><p><code>image: my-app-image:latest</code>: This specifies the Docker image to use for the container, with a tag of latest.</p>
</li>
<li><p><code>ports</code>: This specifies the ports to be exposed by the container.</p>
</li>
<li><p><code>containerPort: 8080</code>: This specifies that the container will listen on port 8080.</p>
</li>
<li><p><code>volumeMounts</code>: This specifies the volumes to be mounted by the container.</p>
</li>
<li><p><code>name: my-app-pvc</code>: This specifies the name of the volume to be mounted.</p>
</li>
<li><p><code>mountPath: /data</code>: This specifies the mount path for the volume in the container.</p>
</li>
<li><p><code>volumes</code>: This specifies the volumes to be created for the Pod.</p>
</li>
<li><p><code>name: my-app-pvc</code>: This specifies the name of the volume.</p>
</li>
<li><p><code>persistentVolumeClaim</code>: This specifies that the volume is backed by a Persistent Volume Claim.</p>
</li>
<li><p><code>claimName: my-pvc</code>: This specifies the name of the Persistent Volume Claim that the volume is backed by.</p>
</li>
</ul>
<p>The YAML file describes a Deployment named <code>my-app-deployment</code> that manages three replicas of an application containerized in <code>my-app-image:latest</code>. The Pods created by the Deployment have a volume <code>my-app-pvc</code> mounted at <code>/data</code>, which is backed by a Persistent Volume Claim named <code>my-pvc</code>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned about the Kubernetes API and some of its various objects. Other API objects in Kubernetes can be used to define the desired state of a cluster. To learn more about them, check out the <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/">Kubernetes documentation</a>.</p>
<p>‍</p>
]]></content:encoded></item><item><title><![CDATA[Become a Kubernetes Rockstar: Your GitHub Portfolio Starts with GROW]]></title><description><![CDATA[🎸 WANTED: Devs & DevOps Who want to rock the cloud-native stage 🎸
(Yes, we’re talking to you.)
What if learning Kubernetes wasn’t just about passing a course……but building your GitHub portfolio, proving your skills, and leveling up your career?
Int...]]></description><link>https://blog.kubeskills.com/github-repository-of-work</link><guid isPermaLink="true">https://blog.kubeskills.com/github-repository-of-work</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[#kubernetes #container ]]></category><category><![CDATA[kubernetes architecture]]></category><category><![CDATA[tech careers]]></category><category><![CDATA[#Tech career road map]]></category><dc:creator><![CDATA[Gerardo Lopez]]></dc:creator><pubDate>Thu, 03 Jul 2025 10:33:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751533417216/6edc06d4-7b69-4e60-a9e1-2ba407a1a62b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-wanted-devs-amp-devops-who-want-to-rock-the-cloud-native-stage">🎸 <strong>WANTED: Devs &amp; DevOps Who want to rock the cloud-native stage</strong> 🎸</h3>
<p>(<em>Yes, we’re talking to you.</em>)</p>
<p>What if learning Kubernetes wasn’t just about passing a course…<br />…but building your <strong>GitHub portfolio</strong>, proving your skills, and leveling up your career?</p>
<h2 id="heading-introducing-grow-github-repository-of-work"><strong>Introducing GROW</strong> 🌱 - <em>GitHub Repository of Work</em></h2>
<p>From the crew at <a target="_blank" href="https://kubeskills.com"><strong>KubeSkills</strong></a>, GROW is where your Kubernetes journey turns into a <strong>living, breathing portfolio</strong> of YAML-powered awesomeness.</p>
<h3 id="heading-how-does-it-work">🚀 <strong>How does it work?</strong></h3>
<p>With GROW, you:</p>
<p>✅ Fork a <a target="_blank" href="https://github.com/kubeskills/grow">ready-to-rock GitHub repo</a> template<br />✅ Document your labs, reflections, configs, and tools<br />✅ Show the world what you're made of (hint: containers and grit)<br />✅ Level up with badges (Starter → Bronze → Silver → Gold)</p>
<p>This isn’t homework, it’s your <strong>future resume!</strong></p>
<h3 id="heading-what-youll-gain"><strong>🪴 What You’ll Gain</strong></h3>
<p><strong>Employers</strong> want to <em>see</em> what you can do!</p>
<p>With <strong>GROW</strong>, they can:</p>
<ul>
<li><p>Browse your real-world Kubernetes portfolio (YAML, GitOps templates, security configs…)</p>
</li>
<li><p>See your actual Git history and progress towards learning and growing</p>
</li>
<li><p>Gain confidence in your knowledge before the interview</p>
</li>
</ul>
<h3 id="heading-learning-that-scales"><strong>📈 Learning That Scales</strong></h3>
<p>Whether you’re:<br />✔ Creating your first pod<br />✔ Securing clusters with Network Policies<br />✔ Automating deployments with FluxCD<br />✔ Or launching your portfolio site on GitHub Pages.</p>
<p><strong>GROW</strong> has everything you need to show your work! Entirely yours and entirely open source!</p>
<h3 id="heading-have-questions-submit-a-pr">❓Have questions? Submit a PR!</h3>
<p>If you hit a roadblock or you’re unsure of something, this is where the <strong>KubeSkills</strong> community comes in!</p>
<ul>
<li><p>Create a file like <code>99-reflections/weekX.md</code> or <code>questions/question.md</code></p>
</li>
<li><p>Add your question and context (what you tried, what you expected, and any doubts)</p>
</li>
<li><p>Submit a Pull Request titled: <code>question: [Your Topic]</code></p>
</li>
</ul>
<h3 id="heading-lets-grow-together">🙌 <strong>Let’s GROW Together</strong></h3>
<p>Start for FREE. <strong>No gatekeeping</strong>. <strong>No fluff</strong>. <strong>Just skills</strong>.</p>
<p><strong>Are you ready</strong> to fork your future?</p>
<p>📂 Grab the notebook template here: <a target="_blank" href="https://github.com/kubeskills/grow">https://github.com/kubeskills/grow</a><br />📢 Share your progress on socials with <code>#KubeSkillsGROW</code><br />📬 Email us your notebook to get featured: <a target="_blank" href="mailto:notebooks@kubeskills.com">notebooks@kubeskills.com</a></p>
<p>🌍 At <a target="_blank" href="https://kubeskills.com">KubeSkills</a>, we don’t just teach Kubernetes, we help <strong>build</strong> cloud native careers!</p>
<p>Let’s do this. 💪</p>
<h2 id="heading-want-even-more">🌐 Want Even More?</h2>
<h3 id="heading-coming-soon-grow"><strong>Coming Soon: GROW+</strong></h3>
<p>Yeah, we’re taking it further:</p>
<ul>
<li><p>1:1 reviews with instructors</p>
</li>
<li><p>Verified badges for your LinkedIn profile</p>
</li>
<li><p>Community spotlight on our site</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Hands-On with FluxCD: A Practical Guide to GitOps for Beginners]]></title><description><![CDATA[Whether you're a developer, DevOps engineer, sysadmin, or platform engineer, you've heard of GitOps. GitOps is a methodology that extends the CI/CD model, allowing teams to manage infrastructure and application deployments using Git as a single sourc...]]></description><link>https://blog.kubeskills.com/hands-on-with-fluxcd</link><guid isPermaLink="true">https://blog.kubeskills.com/hands-on-with-fluxcd</guid><category><![CDATA[gitops-and-fluxcd-complete-hands-on-project]]></category><category><![CDATA[FluxcD]]></category><category><![CDATA[gitops]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[KubeSkills]]></dc:creator><pubDate>Wed, 30 Apr 2025 11:05:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746011002197/bfedad54-5d2f-4561-b8b0-136697c299a3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whether you're a developer, DevOps engineer, sysadmin, or platform engineer, you've heard of GitOps. <a target="_blank" href="https://about.gitlab.com/topics/gitops/">GitOps</a> is a methodology that extends the CI/CD model, allowing teams to manage infrastructure and application deployments using <a target="_blank" href="https://git-scm.com/">Git</a> as a single source of truth. Using GitOps, however, might not be as straightforward as it seems. Some would even argue that its hidden complexity is not worth the hassle. GitOps with <a target="_blank" href="https://fluxcd.io/">FluxCD</a> can help navigate these complexities, as FluxCD simplifies <a target="_blank" href="https://martinfowler.com/books/continuousDelivery.html">continuous delivery</a> through its built-in reconciliation engine and more.</p>
<p>In this beginner's guide, I aim to break down some of the complexity and deliver some <a target="_blank" href="https://helpjuice.com/blog/tacit-knowledge">tacit knowledge</a>, allowing you to get hands-on with FluxCD. I'll show you the benefits of <a target="_blank" href="https://github.com/fluxcd/flux">FluxCD</a>, so you feel confident getting up and running. Also, you'll learn by doing an actual project!</p>
<h2 id="heading-what-is-fluxcd">What is FluxCD?</h2>
<p>FluxCD is an open-source continuous delivery tool designed for Kubernetes. It works by continuously monitoring your Git repository and applying any changes to your Kubernetes cluster. With FluxCD, you can automate updates and rollbacks and even monitor your deployments.</p>
<h4 id="heading-key-features-of-fluxcd">Key Features of FluxCD</h4>
<ul>
<li><p><strong>GitOps</strong>: FluxCD leverages Git as the single source of truth, enabling declarative management of infrastructure and application deployments.</p>
</li>
<li><p><strong>Automated Deployments</strong>: FluxCD continuously monitors your Git repository and automatically updates your Kubernetes cluster with the desired state.</p>
</li>
<li><p><strong>Syncing and Reconciliation</strong>: FluxCD ensures that the live state of your cluster matches the state defined in your Git repository.</p>
</li>
<li><p><strong>Multi-Tenancy</strong>: FluxCD supports managing multiple environments, allowing you to use the same Git repository for staging, production, and more.</p>
</li>
<li><p><strong>Integrations</strong>: FluxCD integrates well with tools like Helm, Prometheus, and others to provide a comprehensive solution for GitOps.</p>
</li>
</ul>
<h3 id="heading-core-components-of-fluxcd">Core Components of FluxCD</h3>
<p>Before we dive into the hands-on part, let's briefly discuss the core components of FluxCD:</p>
<ol>
<li><p><strong>Flux</strong> is the primary operator (control plane), continuously monitoring the Git repository and applying changes to the Kubernetes cluster.</p>
</li>
<li><p>The <strong>Helm Controller</strong> is a component of FluxCD that allows you to manage Helm charts in a GitOps fashion.</p>
</li>
<li><p>The <strong>Kustomize Controller</strong> supports managing Kubernetes manifests using Kustomize, enabling you to customize your deployments.</p>
</li>
<li><p>The <strong>Notification Controller</strong> handles notifications and alerts for your deployments.</p>
</li>
<li><p>The <strong>Source Controller</strong> monitors the source of the Kubernetes manifests (Git, Helm repositories, etc.) and makes them available for the other controllers.</p>
</li>
</ol>
<h3 id="heading-creating-a-github-personal-access-token-pat">Creating a GitHub Personal Access Token (PAT)</h3>
<p>Since FluxCD uses Git as the single source of truth for deployments, the apparent prerequisite is a Git hosting service. Flux CLI creates a new GitHub repository for you, but it needs a personal access token (PAT) to do so.</p>
<p>Create a new PAT by going to the following GitHub link: <a target="_blank" href="https://github.com/settings/tokens/new">https://github.com/settings/tokens/new</a></p>
<p>Select the checkmark box next to "repo," as shown below, then click "Generate Token." <strong>Copy the PAT</strong>, as you will use it for the next step!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724434309458/46b3a0f0-818e-48ee-9e9e-50e6b9dfb5fe.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-installing-fluxcd">Installing FluxCD</h2>
<p>FluxCD can be installed using the <code>flux</code> CLI tool. Here's how you can set it up on your Kubernetes cluster. For free access to a cluster, head to <a target="_blank" href="https://killercoda.com/chadmcrowell/course/cka/single-node">Killercoda.com</a> and follow along!</p>
<ol>
<li><p><strong>Install the Flux CLI:</strong></p>
<pre><code class="lang-bash"> curl -s https://fluxcd.io/install.sh | sudo bash
</code></pre>
</li>
<li><p><strong>Bootstrap FluxCD:</strong></p>
<p> The bootstrap command installs the FluxCD components and configures them to reconcile your cluster state with a Git repository (replace <code>&lt;github-username&gt;</code> with your <a target="_blank" href="https://github.com">GitHub</a> username).</p>
<pre><code class="lang-bash"> flux bootstrap github \
   --owner=&lt;github-username&gt; \
   --repository=my-flux-repo \
   --branch=main \
   --path=./clusters/my-cluster \
   --personal=<span class="hljs-literal">true</span> \
   --private=<span class="hljs-literal">false</span>
</code></pre>
</li>
<li><p><strong>Verify the Installation:</strong></p>
<p> After bootstrapping, you can verify that FluxCD is running correctly using the command <code>flux check --pre</code> which will check the health of the Flux components in your Kubernetes cluster.</p>
<pre><code class="lang-bash"> flux check --pre
</code></pre>
</li>
<li><p><strong>Clone the Repo:</strong><br /> After running the <code>flux bootstrap github</code> command, you should clone the GitHub repository that Flux created during the bootstrap process. This allows you to add your application files (e.g., Kubernetes manifests, Helm charts, or Kustomize files) to the repository. These files define the desired state of your applications, which Flux will then monitor and apply to your Kubernetes cluster (replace <code>&lt;github-username&gt;</code> with your <a target="_blank" href="https://github.com">GitHub</a> username).</p>
<pre><code class="lang-bash"> git <span class="hljs-built_in">clone</span> https://github.com/&lt;github-username&gt;/my-flux-repo.git
</code></pre>
</li>
<li><p><strong>Create your Application Directory</strong><br /> Inside the cloned repository, you will see the directory structure created by Flux. Typically, a specific directory is created to store the application manifests, helm charts or Kustomize configurations (e.g. <code>apps/my-app</code>). Create the directory where your application files will go.</p>
<pre><code class="lang-bash"> mkdir -p my-flux-repo/apps/my-app
</code></pre>
</li>
<li><p><strong>(Optional) Organize Your Repository</strong><br /> For larger projects, you can structure your repository into separate directories for staging, production, and other environments. The following is an example of this organizational pattern, which allows you to define shared configurations in the base directory and customize them for each specific environment in the overlays directory, without duplicating code.</p>
<pre><code class="lang-plaintext"> apps/
 ├── my-app/
 │   ├── base/
 │   │   ├── deployment.yaml
 │   │   └── service.yaml
 │   ├── overlays/
 │       ├── staging/
 │       └── production/
 clusters/
 ├── staging/
 │   └── kustomization.yaml
 └── production/
     └── kustomization.yaml
</code></pre>
</li>
</ol>
<h2 id="heading-building-a-sample-microservices-application">Building a Sample Microservices Application</h2>
<p>In this example, we'll create a simple microservices-based application consisting of two services:</p>
<ol>
<li><p><strong>Frontend Service</strong>: A simple web server built using Node.js that serves static content.</p>
</li>
<li><p><strong>Backend Service</strong>: A Python-based API service that provides some data to the frontend.</p>
</li>
</ol>
<p>For most Kubernetes-based setups using FluxCD, the best practice is to store application code and deployment manifests in separate repositories. This adheres to GitOps principles, where your Git repository serves as the single source of truth for your cluster's desired state. Therefore, we’ll create a new application repository that contains our application code.</p>
<pre><code class="lang-bash">mkdir src &amp;&amp; <span class="hljs-built_in">cd</span> src
</code></pre>
<h4 id="heading-frontend-service"><strong>Frontend Service</strong></h4>
<p>The frontend service will be a basic Node.js application that serves an HTML page. Here's the code:</p>
<pre><code class="lang-bash">cat &lt;&lt; EOF &gt; index.js
// index.js
const express = require(<span class="hljs-string">'express'</span>);
const app = express();
const port = 3000;

app.get(<span class="hljs-string">'/'</span>, (req, res) =&gt; {
  res.send(<span class="hljs-string">'&lt;h1&gt;Welcome to the Frontend Service&lt;/h1&gt;'</span>);
});

app.listen(port, () =&gt; {
  console.log(<span class="hljs-string">'Frontend service is running on http://localhost:${port}'</span>);
});
EOF
</code></pre>
<p>Create a Dockerfile for the frontend service:</p>
<pre><code class="lang-bash">cat &lt;&lt; EOF &gt; JS-Dockerfile
<span class="hljs-comment"># JS-Dockerfile</span>
FROM node:14-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000
CMD [<span class="hljs-string">"node"</span>, <span class="hljs-string">"index.js"</span>]
EOF
</code></pre>
<h4 id="heading-backend-service">Backend Service</h4>
<p>The backend service will be a simple Python Flask application that returns some JSON data. Here's the code:</p>
<pre><code class="lang-bash">cat &lt;&lt; EOF &gt; app.py
<span class="hljs-comment"># app.py</span>
from flask import Flask, jsonify

app = Flask(__name__)

@app.route(<span class="hljs-string">'/api/data'</span>, methods=[<span class="hljs-string">'GET'</span>])
def get_data():
    data = {
        <span class="hljs-string">'message'</span>: <span class="hljs-string">'Hello from the Backend Service!'</span>
    }
    <span class="hljs-built_in">return</span> jsonify(data)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(host=<span class="hljs-string">'0.0.0.0'</span>, port=5000)
EOF
</code></pre>
<p>Create a Dockerfile for the backend service:</p>
<pre><code class="lang-bash">cat &lt;&lt; EOF &gt; Py-Dockerfile
<span class="hljs-comment"># Dockerfile</span>
FROM python:3.8-slim

WORKDIR /app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000
CMD [<span class="hljs-string">"python"</span>, <span class="hljs-string">"app.py"</span>]
EOF
</code></pre>
<p>Create the <code>requirements.txt</code> file:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"flask"</span> &gt; requirements.txt
</code></pre>
<p>create a <code>package.json</code> file:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># package.json</span>
cat &lt;&lt; EOF &gt; package.json
{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"flux-project"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"express"</span>: <span class="hljs-string">"^4.17.1"</span>
  },
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">""</span>
  },
  <span class="hljs-string">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"license"</span>: <span class="hljs-string">"ISC"</span>
}
EOF
</code></pre>
<h4 id="heading-build-the-container-images"><strong>Build the Container Images</strong></h4>
<p>We'll build the container images for both the front and backend apps using the Docker CLI. Use the following commands to build and tag the images using the two separate <code>Dockerfile</code> files named <code>JS-Dockerfile</code> and <code>Py-Dockerfile</code>:</p>
<pre><code class="lang-bash">docker build -f JS-Dockerfile -t localhost:5000/my-frontend .
</code></pre>
<pre><code class="lang-bash">docker build -f Py-Dockerfile -t localhost:5000/my-backend .
</code></pre>
<p>Create a container registry locally:</p>
<pre><code class="lang-bash">docker run --name local-registry -d -p 5000:5000 registry
</code></pre>
<p>Push the container images to the local registry:</p>
<pre><code class="lang-bash">docker push localhost:5000/my-backend
docker push localhost:5000/my-frontend
</code></pre>
<h2 id="heading-creating-kubernetes-manifests">Creating Kubernetes Manifests</h2>
<p>Next, we'll create Kubernetes manifests for deploying these two services, placing them in the repo that we created and cloned at the beginning, in <code>my-flux-repo/apps/my-app</code>. Use your favorite text editor to create these files in the <code>my-app</code> directory.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> <span class="hljs-variable">$HOME</span>/my-flux-repo/apps/my-app
</code></pre>
<h4 id="heading-frontend-deployment-manifest">Frontend Deployment Manifest</h4>
<pre><code class="lang-yaml"><span class="hljs-comment"># frontend-deployment.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">frontend</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">frontend</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">2</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">frontend</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">app:</span> <span class="hljs-string">frontend</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">frontend</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">localhost:5000/my-frontend:latest</span>
        <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">3000</span>
</code></pre>
<h4 id="heading-frontend-service-manifest">Frontend Service Manifest</h4>
<pre><code class="lang-yaml"><span class="hljs-comment"># frontend-service.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">frontend-service</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">frontend</span>
  <span class="hljs-attr">ports:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
      <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
      <span class="hljs-attr">targetPort:</span> <span class="hljs-number">3000</span>
</code></pre>
<h4 id="heading-backend-deployment-manifest">Backend Deployment Manifest</h4>
<pre><code class="lang-yaml"><span class="hljs-comment"># backend-deployment.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">backend</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">backend</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">replicas:</span> <span class="hljs-number">2</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">backend</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">metadata:</span>
      <span class="hljs-attr">labels:</span>
        <span class="hljs-attr">app:</span> <span class="hljs-string">backend</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">backend</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">localhost:5000/my-backend:latest</span>
        <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">5000</span>
</code></pre>
<h4 id="heading-backend-service-manifest">Backend Service Manifest</h4>
<pre><code class="lang-yaml"><span class="hljs-comment"># backend-service.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">backend-service</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">backend</span>
  <span class="hljs-attr">ports:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
      <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
      <span class="hljs-attr">targetPort:</span> <span class="hljs-number">5000</span>
</code></pre>
<h2 id="heading-setting-up-fluxcd-to-deploy-the-application">Setting Up FluxCD to Deploy the Application</h2>
<p>Now that we have our application and Kubernetes manifests ready, let's set up FluxCD to deploy them.</p>
<h4 id="heading-step-1-create-a-kustomization-file">Step 1: Create a Kustomization File</h4>
<p>Also in the <code>my-app</code> directory, create a <code>kustomization.yaml</code> file. This file tells FluxCD to apply the resources defined in the specified YAML files.</p>
<p>The <code>kustomization.yaml</code> file serves as a configuration file for <a target="_blank" href="https://github.com/kubernetes-sigs/kustomize"><strong>Kustomize</strong></a>, a Kubernetes-native configuration management tool. It defines how Kubernetes manifests in that directory should be aggregated, customized, or patched before being applied to your cluster.</p>
<p>In a GitOps setup, such as with FluxCD, this file helps manage and deploy the application's resources by describing how the various Kubernetes YAML files in the <code>my-app</code> directory (like <code>frontend-deployment.yaml</code>, <code>frontend-service.yaml</code>, etc.) should be combined and customized.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># kustomization.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">kustomize.config.k8s.io/v1beta1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Kustomization</span>
<span class="hljs-attr">resources:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">frontend-deployment.yaml</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">frontend-service.yaml</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">backend-deployment.yaml</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">backend-service.yaml</span>
</code></pre>
<ol start="2">
<li><strong>Link the Application Directory to FluxCD</strong><br /> In the <code>clusters/my-cluster/flux-system/kustomization.yaml</code> file (already created from the bootstrap process), add a reference to your application's <code>kustomization.yaml</code> file. This tells FluxCD to apply the resources defined in <code>apps/my-app</code>. Edit the <code>clusters/my-cluster/flux-system/kustomization.yaml</code> file and add the <code>path</code> to your application directory.</li>
</ol>
<pre><code class="lang-yaml"><span class="hljs-string">cd</span> <span class="hljs-string">$HOME/my-flux-repo/clusters/my-cluster/flux-system</span>
</code></pre>
<pre><code class="lang-yaml"><span class="hljs-comment"># kustomization.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">kustomize.config.k8s.io/v1beta1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Kustomization</span>
<span class="hljs-attr">resources:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">gotk-components.yaml</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">gotk-sync.yaml</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">../../../apps/my-app/</span> <span class="hljs-comment"># add this line</span>
</code></pre>
<h3 id="heading-what-happens-when-fluxcd-reconciles-it"><strong>What Happens When FluxCD Reconciles It?</strong></h3>
<ol>
<li><p><strong>FluxCD Detects Changes</strong>:</p>
<ul>
<li>If you make a change in the Git repository (e.g., update <code>kustomization.yaml</code> or a resource file), FluxCD detects the change.</li>
</ul>
</li>
<li><p><strong>FluxCD Applies the Kustomization</strong>:</p>
<ul>
<li><p>FluxCD reads the <code>kustomization.yaml</code> file in the <code>apps/my-app</code> directory.</p>
</li>
<li><p>It processes the listed resources, applies the customizations (e.g., patches, labels), and reconciles the desired state with the cluster.</p>
</li>
</ul>
</li>
<li><p><strong>Resources Are Deployed</strong>:</p>
<ul>
<li>The aggregated and customized manifests are applied to the cluster, ensuring the application is deployed in the desired configuration.</li>
</ul>
</li>
</ol>
<h3 id="heading-commit-and-push-changes">Commit and Push Changes</h3>
<p>After updating the <code>kustomization.yaml</code>, commit and push the changes to your Git repository.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> <span class="hljs-variable">$HOME</span>/my-flux-repo

git config --global user.email <span class="hljs-string">"you@example.com"</span>

git config --global user.name <span class="hljs-string">"Your Name"</span>

git add .; git commit -m <span class="hljs-string">"add my-app to cluster configuration"</span>; git push origin main
</code></pre>
<p><strong>NOTE:</strong> When prompted for your GitHub password, paste in your GitHub PAT (the one we generated at the beginning).</p>
<h3 id="heading-verify-fluxcd-reconciliation">Verify FluxCD Reconciliation</h3>
<p>Wait for FluxCD to reconcile the changes or manually trigger it. Check the logs for updates:</p>
<ul>
<li><p><strong>Trigger Reconciliation</strong>:</p>
<pre><code class="lang-bash">  flux reconcile kustomization flux-system -n flux-system
</code></pre>
</li>
<li><p><strong>Check Logs</strong>:</p>
<pre><code class="lang-bash">  kubectl logs -n flux-system deploy/kustomize-controller
</code></pre>
</li>
<li><p><strong>Check Kustomization Status</strong>:</p>
<pre><code class="lang-bash">  flux get kustomizations -n flux-system
</code></pre>
</li>
<li><p>Check that the app was created:</p>
<pre><code class="lang-bash">  kubectl get all
</code></pre>
</li>
</ul>
<h2 id="heading-summary">Summary</h2>
<p>In this guide, we walked through the end-to-end process of setting up a GitOps workflow using <a target="_blank" href="https://fluxcd.io/"><strong>FluxCD</strong></a><strong>,</strong> from bootstrapping a Flux-enabled cluster to deploying a sample microservices application. Along the way, you learned how FluxCD simplifies the continuous delivery process through reconciliation, Git-based change tracking, and modular infrastructure design.</p>
<h3 id="heading-key-takeaways">Key Takeaways</h3>
<ul>
<li><p><strong>Git as the Source of Truth</strong>: With FluxCD, your Git repository drives all changes in your Kubernetes cluster, ensuring consistency and auditability.</p>
</li>
<li><p><strong>Modular Design</strong>: You can organize your manifests using <code>Kustomize</code>, separating base configurations from overlays and manage multiple environments efficiently.</p>
</li>
<li><p><strong>Declarative Deployment</strong>: All resources, from Deployments to Services, are declaratively described, version-controlled, and automatically applied via FluxCD.</p>
</li>
<li><p><strong>End-to-End Automation</strong>: FluxCD monitors changes in Git and continuously reconciles your desired state with the actual state of your cluster, eliminating manual drift correction.</p>
</li>
<li><p><strong>Hands-On Value</strong>: By deploying a working microservices application using Node.js and Flask, you’ve applied GitOps principles in a real-world scenario.</p>
</li>
</ul>
<p>While GitOps can initially seem overwhelming, especially with the many moving parts of Kubernetes, CI/CD pipelines, and declarative tooling, <strong>FluxCD</strong> makes it approachable, scalable, and production-ready. The hands-on walkthrough you completed today is just the beginning.</p>
<p>Whether you’re just getting started or expanding GitOps across multiple environments, FluxCD provides a robust and secure foundation to manage your workloads the GitOps way.</p>
<p>If this guide helped demystify FluxCD, share it with your team or community! And if you’re ready for more advanced topics, like multi-tenancy, pull-based secrets management, and progressive delivery, stay tuned for our next post!</p>
]]></content:encoded></item><item><title><![CDATA[From Zero to Kubernetes Hero: Start Your Journey in 2025]]></title><description><![CDATA[Kubernetes has become the cornerstone of modern application deployment and management, but for newcomers, its complexity can feel overwhelming. If you're ready to dive into the world of containers and orchestration but aren't sure where to start, thi...]]></description><link>https://blog.kubeskills.com/from-zero-to-kubernetes-hero-2025</link><guid isPermaLink="true">https://blog.kubeskills.com/from-zero-to-kubernetes-hero-2025</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[#kubernetes #container ]]></category><category><![CDATA[container orchestration]]></category><category><![CDATA[LearningKubernetes]]></category><dc:creator><![CDATA[Gerardo Lopez]]></dc:creator><pubDate>Fri, 06 Dec 2024 14:20:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/qlheiI2e_ec/upload/e26e5558c4daae103ac1268d4f39484d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kubernetes has become the cornerstone of modern application deployment and management, but for newcomers, its complexity can feel overwhelming. If you're ready to dive into the world of containers and orchestration but aren't sure where to start, this blog post is your roadmap. By the end, you'll have actionable steps to navigate Kubernetes and unlock its potential with confidence.</p>
<h2 id="heading-1-understand-the-basics-before-diving-deep">1. Understand the Basics Before Diving Deep</h2>
<p>Kubernetes operates on foundational concepts, and mastering these basics sets the stage for your learning journey:</p>
<ul>
<li><p><strong>Containers</strong>: Understand how containers work and why they revolutionized software delivery. Tools like Docker are excellent starting points to grasp the concept of lightweight, isolated environments that package your applications and their dependencies.</p>
</li>
<li><p><strong>Networking, Storage, and Virtualization Basics</strong>: Kubernetes abstracts these components, but knowing their principles ensures you aren't lost when troubleshooting or scaling your clusters. Learn how containers communicate (networking), persist data (storage), and run across virtualized environments.</p>
</li>
<li><p><strong>YAML Files</strong>: Kubernetes configurations are declared in YAML. Start with simple files to define a Pod or Service, then progress to more complex ones like Deployments. Practicing with YAML will also enhance your understanding of Kubernetes resources and their relationships.</p>
</li>
</ul>
<h2 id="heading-2-start-with-practical-tools">2. Start with practical tools</h2>
<p>The hands-on approach is the fastest way to learn Kubernetes. Instead of diving headfirst into production, experiment in controlled environments:</p>
<ul>
<li><p>Killercoda: Perfect for browser-based, guided Kubernetes scenarios. It eliminates the setup overhead so you can focus on learning. Minikube or Kind: These tools allow you to run Kubernetes clusters locally.</p>
</li>
<li><p>Minikube is beginner-friendly, while Kind (Kubernetes IN Docker) is lightweight and great for testing CI/CD pipelines. Both provide safe sandboxes to experiment with Kubernetes concepts.</p>
</li>
</ul>
<h2 id="heading-3-focus-on-core-kubernetes-components">3. Focus on core Kubernetes components</h2>
<p>Mastering Kubernetes means understanding its building blocks. Start with these essential components:</p>
<ul>
<li><p>Pods: The smallest deployable units in Kubernetes, containing your application containers. Learn their lifecycle and management.</p>
</li>
<li><p>Services: Abstracts access to Pods, enabling communication and load balancing. Dive into ClusterIP, NodePort, and LoadBalancer types.</p>
</li>
<li><p>ConfigMaps and Secrets: Understand how to decouple your configuration data from application code while managing sensitive information securely.</p>
</li>
<li><p>Deployments: Learn how they automate the management of Pods, handle scaling, and facilitate rolling updates with zero downtime.</p>
</li>
</ul>
<h2 id="heading-4-automate-early-with-gitops">4. Automate early with GitOps</h2>
<p>GitOps isn't just a buzzword; it's a game-changer for Kubernetes management: Tools like ArgoCD and Flux integrate version control with your Kubernetes cluster, turning your Git repository into a single source of truth. Start small by deploying simple workloads using GitOps workflows. As you progress, leverage automation to handle scaling, monitoring, and application updates seamlessly.</p>
<h2 id="heading-5-explore-diverse-environments">5. Explore diverse environments</h2>
<p>Kubernetes behaves differently across platforms, and gaining exposure to various environments helps build well-rounded expertise:</p>
<ul>
<li><p>Local Environments: Tools like Minikube and Kind let you experiment without cost.</p>
</li>
<li><p>Cloud Platforms: Explore managed Kubernetes services like AWS EKS, Azure AKS, Google GKE, or Civo. They abstract the infrastructure, allowing you to focus on applications.</p>
</li>
<li><p>On-Premises: Try lightweight distributions like k3s or orchestration tools like Rancher to simulate edge or hybrid environments.</p>
</li>
</ul>
<h2 id="heading-6-leverage-modern-kubernetes-tools">6. Leverage modern kubernetes tools</h2>
<p>Simplify and enhance your Kubernetes experience with modern tools:</p>
<ul>
<li><p>Helm: Package and deploy applications easily using Helm charts.</p>
</li>
<li><p>Kustomize: Customize Kubernetes configurations without duplication. It's particularly handy when managing multiple environments.</p>
</li>
<li><p>OpenTelemetry: Implement observability to trace, monitor, and debug your applications seamlessly across your Kubernetes clusters.</p>
</li>
</ul>
<h2 id="heading-7-engage-with-the-kubernetes-community">7. Engage with the kubernetes community</h2>
<p>The Kubernetes ecosystem thrives on collaboration. Joining the community accelerates learning and provides invaluable networking opportunities:</p>
<ul>
<li><p>Meetups and Events: Participate in local Kubernetes groups, KubeCon, or Kubernetes Community Days (KCDs) to learn from and connect with experts.</p>
</li>
<li><p>CNCF Slack: Join channels dedicated to Kubernetes discussions for real-time support and insights.</p>
</li>
<li><p>Open-Source Contributions: Start small, like fixing documentation or testing features. Contributing not only deepens your knowledge but also connects you to experienced practitioners.</p>
</li>
</ul>
<h2 id="heading-8-get-certified-to-validate-your-skills">8. Get Certified to validate your skills</h2>
<p>Certifications provide structured learning and validate your Kubernetes expertise: Start with the KCNA (Kubernetes and Cloud Native Associate) for foundational knowledge. Progress to role-specific certifications like CKAD (Certified Kubernetes Application Developer) or CKA (Certified Kubernetes Administrator) to solidify your skills.</p>
<h2 id="heading-9-prioritize-security-from-the-start">9. Prioritize security from the start</h2>
<p>Security is a critical aspect of Kubernetes. Adopt secure practices early:</p>
<ul>
<li><p>NetworkPolicies: Restrict traffic between Pods and external services to prevent unauthorized access.</p>
</li>
<li><p>Trivy: Scan container images for vulnerabilities before deploying them.</p>
</li>
<li><p>RBAC (Role-Based Access Control): Implement granular permissions to control who can perform specific actions within your cluster.</p>
</li>
</ul>
<h2 id="heading-10-learn-at-your-own-pace">10. Learn at your own pace</h2>
<p>Kubernetes is a vast and constantly evolving ecosystem. It's easy to feel overwhelmed, but the key is consistency:</p>
<ul>
<li><p>Set achievable goals for daily or weekly learning. Embrace new features and trends as they emerge in the ecosystem.</p>
</li>
<li><p>Remember, it's not about mastering Kubernetes overnight—it's about building a strong foundation and growing from there.</p>
</li>
</ul>
<h3 id="heading-call-to-action">Call to Action</h3>
<p>Ready to begin your Kubernetes journey? Start today by picking one tip and taking that first step. Whether it's setting up your first cluster, experimenting with tools like Helm, or exploring Kubernetes concepts, every action moves you closer to mastery. Share your progress or questions in the comments below—we'd love to hear from you! Don't forget to connect with the broader Kubernetes community and join us at <a target="_blank" href="https://kubeskills.com/">KubeSkills.com</a>. Together, we'll navigate the exciting world of Kubernetes and unlock the full potential of cloud native technology.</p>
]]></content:encoded></item><item><title><![CDATA[Kubernetes Trends and Skills to Watch in 2025]]></title><description><![CDATA[Fresh from KubeCon in Salt Lake City this November, I’ve been reflecting on the incredible journey of the Cloud Native ecosystem in 2024. From the trends showcased at KubeCon to the broader shifts across the industry this year, it’s clear that Kubern...]]></description><link>https://blog.kubeskills.com/kubernetes-trends-and-skills-to-watch-in-2025</link><guid isPermaLink="true">https://blog.kubeskills.com/kubernetes-trends-and-skills-to-watch-in-2025</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[cloud native]]></category><category><![CDATA[#kubernetes #container ]]></category><category><![CDATA[kubernetes architecture]]></category><category><![CDATA[wasm]]></category><dc:creator><![CDATA[KubeSkills]]></dc:creator><pubDate>Wed, 04 Dec 2024 22:52:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733352608913/c8d571c0-a3c5-4eea-9b30-58baabebcaa5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Fresh from <a target="_blank" href="https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/">KubeCon</a> in Salt Lake City this November, I’ve been reflecting on the incredible journey of the Cloud Native ecosystem in 2024. From the trends showcased at KubeCon to the broader shifts across the industry this year, it’s clear that Kubernetes and its surrounding technologies continue to evolve at a breakneck pace.</p>
<p>As we head into 2025, I want to share some key takeaways and actionable advice to help you refine your skills and stay ahead of the curve, positioning yourself for even greater success in the cloud-native world.</p>
<h3 id="heading-1-kubernetes-is-maturing-but-simplification-is-key"><strong>1️⃣ Kubernetes Is Maturing, But Simplification Is Key</strong></h3>
<p>While Kubernetes adoption continues to soar, the focus is shifting toward making the platform more user-friendly. Tools like <a target="_blank" href="https://www.kubeflow.org/">KubeFlow</a>, <a target="_blank" href="https://k8slens.dev/">Lens</a>, and the <a target="_blank" href="https://gateway-api.sigs.k8s.io/">Gateway API</a> are evolving to abstract away complexity and enhance developer productivity.</p>
<p><strong>Key takeaway for learners:</strong> Start with the <a target="_blank" href="https://community.kubeskills.com/c/101-course">basics of Kubernetes</a>, but also explore tools that simplify management to stay ahead in the ecosystem.</p>
<p><strong>Recorded talks from KubeCon that focused on this:</strong></p>
<ul>
<li><p><a target="_blank" href="https://youtu.be/reGxuaM7XBs?si=X5Xp9an6wu4qtOUf">Gateway API: What's new, What's Next</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/asbtOWQosxI?si=C6Vr9YlmI37AZAxB">Tutorial: Live with Gateway API V1.2</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/xfv6AT7om4s?si=l55p1FS_JtPrDmz5">One Gateway API to Rule Them All</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/_nR1cHhBth8?si=u5INSEtpveB-SXnh">Inspektor Gadget: eBPF for Observability, Made Easy and Approachable</a></p>
</li>
</ul>
<hr />
<h3 id="heading-2-security-is-everyones-responsibility"><strong>2️⃣ Security Is Everyone’s Responsibility</strong></h3>
<p>The conference emphasized the importance of security, with several sessions dedicated to securing clusters, managing workloads, and protecting data. Tools like <a target="_blank" href="https://falco.org/">Falco</a>, <a target="_blank" href="https://kyverno.io/">Kyverno</a>, and <a target="_blank" href="https://www.openpolicyagent.org/">Open Policy Agent (OPA)</a> are becoming standard.</p>
<p><strong>Key takeaway for learners:</strong> Begin integrating security into your workflows early, and don’t wait until you’re deploying in production to start thinking about it.</p>
<p><strong>Recorded talks from KubeCon that focused on this:</strong></p>
<ul>
<li><p><a target="_blank" href="https://youtu.be/tqvjzsNmJZ8?si=gnDPd-ILfB0akxkh">Keynote: Open Source Security Is Not A Spectator Sport</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/e2wO3lxzjEA?si=VGk2XXmqMeKfmBYv">Falco: Evolution of Real Time Cloud Security with Falco</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/D3J8YTNfT1c?si=t4oyxTsG20MqDF_s">Kyverno: Level Up Your Cluster - 5 Kyverno Policies You Need Now!</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/f-NJptXlp5I?si=f0uJuPSTXn0w7c57">Working Together to Improve Security Visibility in Kubernetes</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/QuotLxFb2f4?si=PhDy_RuiRMwGegTk">Open Policy Agent (OPA) Intro, Deep Dive &amp; V1.0 Update</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/TMZA4y9hslU?si=d-6kO3MboPCJ1j0O">Why Perfect Compliance Is the Enemy of Good Kubernetes Security</a></p>
</li>
</ul>
<hr />
<h3 id="heading-3-multi-cloud-and-hybrid-cloud-are-the-future"><strong>3️⃣ Multi-Cloud and Hybrid Cloud Are the Future</strong></h3>
<p>Organizations are embracing multi-cloud setups, and Kubernetes is a critical enabler of this strategy. Projects like <a target="_blank" href="https://submariner.io/">Submariner</a> and service meshes are making it easier to manage workloads across diverse environments.</p>
<p><strong>Key takeaway for learners:</strong> Understanding how Kubernetes fits into multi-cloud and hybrid cloud setups will make you a valuable asset to your team.</p>
<p><strong>Recorded talks from KubeCon that focused on this:</strong></p>
<ul>
<li><p><a target="_blank" href="https://youtu.be/xJ9RH0AE7zE?si=WYIWbKYyE4BUVTwa">Meshery: Visualizing Kubernetes Resource Relationships with Meshery</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/wJGKVQmeDns?si=MJxJ2kenMUJ81OUu">Mish-Mesh: Abusing the Service Mesh to Compromise Kubernetes Environments</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/6Q35q0dlJoc?si=40p2AvCFMBXf1NbZ">Linkerd Update: Ingress, Egress, IPv6, Enhanced Multicluster, Rust, and More</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/boU_yVSLrbY?si=fY-6wHeWjgjZ8GBJ">Istio: Why Choose Istio in 2025</a></p>
</li>
</ul>
<hr />
<h3 id="heading-4-aiml-meets-kubernetes"><strong>4️⃣ AI/ML Meets Kubernetes</strong></h3>
<p>There’s growing interest in deploying AI and ML workloads on Kubernetes. Projects like <a target="_blank" href="https://www.kubeflow.org/">Kubeflow</a> and <a target="_blank" href="https://wasmedge.org/">WasmEdge</a> are helping bridge the gap between data science and scalable infrastructure.</p>
<p><strong>Key takeaway for learners:</strong> Kubernetes is becoming a must-have skill for data engineers and AI practitioners. Learn how it supports these specialized workloads.</p>
<p><strong>Recorded talks from KubeCon that focused on this:</strong></p>
<ul>
<li><p><a target="_blank" href="https://youtu.be/wYzsPNfMF7A?si=cT_BpW6JKuj8jzBN">Building Massive-Scale Generative AI Services with Kubernetes and Open Source</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/Lgy4ir1AhYw?si=IT_FdkqodzGLsxpw">Democratizing AI Model Training on Kubernetes with KubeFlow</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/JSF66UrnaR8?si=zl-RHQYVwg58tFYE">WasmEdge: Cross-Platform, High-Performance, Lightweight, Embeddable Multi-Modal LLM Runtime</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/Tt6Smg2wYnQ?si=2oyP6nFz1xyHPsQt">WasmCloud: Declarative WebAssembly Orchestration for Cloud Native Applications</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/URqbMZJ9UEQ?si=rKgLkztAYNlhZ3qS">Reproducible AI with Kubeflow, lakeFS and Langchain</a></p>
</li>
</ul>
<hr />
<h3 id="heading-5-community-and-certifications-matter"><strong>5️⃣ Community and Certifications Matter</strong></h3>
<p>Networking with other professionals confirmed how valuable certifications like the <a target="_blank" href="https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/">Certified Kubernetes Administrator (CKA)</a> and <a target="_blank" href="https://training.linuxfoundation.org/certification/certified-kubernetes-application-developer-ckad/">Certified Kubernetes Application Developer (CKAD)</a> are for career advancement (<a target="_blank" href="https://training.linuxfoundation.org/cyber-monday-2024">see exam discounts here</a>). The conference also highlighted how the Kubernetes community supports continuous learning through meetups, forums, and open-source projects.</p>
<p><strong>Key takeaway for learners:</strong> Engaging with the Kubernetes community and earning certifications can accelerate your journey.</p>
<p><strong>Recorded talks from KubeCon that focused on this:</strong></p>
<ul>
<li><p><a target="_blank" href="https://youtu.be/p7J0lAU3AWo?si=tG9IVl7C0_OD4dvO">Keynote: Awards Ceremony</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/yGNFK1cV_o0?si=CJKTUky0e69bDLBJ">Keynote: Four Cloud Native Technology Areas to Watch For</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/BOjXyD_kTfw?si=XPe7suuwsP_bhsZ6">Keynote: A Decade of Kubernetes and Cloud Native – Are We There Yet?</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/9IhV67Xwy0M?si=siFUnGUMaxl16N3H">Open Source 2.0: The Maintainers' Perspective</a></p>
</li>
</ul>
<hr />
<p>At <a target="_blank" href="https://kubeskills.com">KubeSkills</a>, we’re committed to helping you navigate these trends and build expertise in Kubernetes and containers. Stay tuned for <a target="_blank" href="https://community.kubeskills.com/courses">upcoming courses</a>, live workshops, and community events tailored to these evolving needs.</p>
]]></content:encoded></item><item><title><![CDATA[Civo's Developer-Centric Cloud: Simplifying Kubernetes for All]]></title><description><![CDATA[What is Civo?
Civo is a cloud computing platform that provides fast and easy-to-use Kubernetes services. Its main offering, Civo Kubernetes, uses K3s, a lightweight and optimized version of Kubernetes developed by Rancher Labs. K3s is ideal for small...]]></description><link>https://blog.kubeskills.com/civo-k8s-for-all</link><guid isPermaLink="true">https://blog.kubeskills.com/civo-k8s-for-all</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[civo]]></category><category><![CDATA[#kubernetes #container ]]></category><category><![CDATA[civo-kubernetes-cluster]]></category><category><![CDATA[kubernetes civo]]></category><dc:creator><![CDATA[Gerardo Lopez]]></dc:creator><pubDate>Wed, 16 Oct 2024 21:16:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GSiEeoHcNTQ/upload/4a3b7b3757f3cfbe9de0bf76ff24dde1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>What is Civo?</strong></p>
<p>Civo is a cloud computing platform that provides fast and easy-to-use Kubernetes services. Its main offering, Civo Kubernetes, uses K3s, a lightweight and optimized version of Kubernetes developed by Rancher Labs. K3s is ideal for small to medium-sized cloud applications and environments. Civo allows developers to set up a functional Kubernetes cluster in under 90 seconds, making it perfect for those just starting.</p>
<h3 id="heading-why-use-civo">Why Use Civo?</h3>
<ol>
<li><p><strong>Speed and Simplicity</strong>: For beginners, Civo provides a quick way to create a Kubernetes cluster, allowing you to start experimenting without getting bogged down in complicated configurations.</p>
</li>
<li><p><strong>Utilizing K3s</strong>: Civo runs on <strong>K3s</strong>, which consumes fewer resources than a standard Kubernetes installation. This makes it an excellent choice for projects that don't require the full capabilities of Kubernetes, ensuring you can deploy applications swiftly and efficiently.</p>
</li>
<li><p><strong>User-Friendly Interface</strong>: Civo offers an intuitive web platform, CLI, and API, simplifying cluster deployment, management, and removal without requiring deep Kubernetes expertise.</p>
</li>
<li><p><strong>Competitive Pricing</strong>: With affordable pricing and transparent billing, Civo is an attractive option for developers who want to leverage Kubernetes without incurring high costs associated with larger cloud providers.</p>
</li>
<li><p><strong>Community and Support</strong>: Civo has an active community that shares resources and knowledge. Their support team is known for being responsive, helping you resolve issues while you learn Kubernetes.</p>
</li>
<li><p><strong>Developer-Centric Approach</strong>: Designed with developers in mind, Civo provides features that enable rapid experimentation and development, making it easier for newcomers to grasp Kubernetes concepts.</p>
</li>
</ol>
<h3 id="heading-benefits-of-using-civo">Benefits of Using Civo:</h3>
<ul>
<li><p><strong>Rapid Cluster Creation</strong>: You can have a fully operational Kubernetes cluster up and running in less than 90 seconds, which is invaluable when you're eager to start learning and experimenting.</p>
</li>
<li><p><strong>Lightweight K3s</strong>: By leveraging K3s, your cluster will use fewer resources, reducing costs and optimizing infrastructure utilization.</p>
</li>
<li><p><strong>Ease of Use</strong>: Both the platform and CLI/API are designed to simplify the Kubernetes experience, making it accessible even for those who are not experts.</p>
</li>
<li><p><strong>Low Cost</strong>: As you familiarize yourself with Kubernetes, you won’t need to worry about high expenses, allowing for budget-friendly experimentation.</p>
</li>
<li><p><strong>Scalability</strong>: Although Civo is lightweight, it still supports Kubernetes, so you can scale your applications as needed, providing a balance between simplicity and growth potential.</p>
</li>
</ul>
<h3 id="heading-marketplace-features">Marketplace Features</h3>
<p>One of Civo's standout features is its <strong>Marketplace</strong>, which allows you to add additional components to your Kubernetes cluster easily. This is especially beneficial for beginners who want to integrate popular tools without dealing with complex configurations.</p>
<ul>
<li><p><strong>Easy Integration</strong>: The Marketplace offers a selection of preconfigured applications like <strong>Prometheus</strong> for monitoring, <strong>Grafana</strong> for visualization, <strong>Linkerd</strong> for service mesh management, and <strong>Traefik</strong> for ingress control. You can deploy these tools with just a few clicks.</p>
</li>
<li><p><strong>Optimized Deployments</strong>: The applications in the Marketplace are optimized to work seamlessly with K3s, ensuring a smooth integration process without compatibility issues.</p>
</li>
<li><p><strong>Quick Access</strong>: You can quickly implement essential tools in your cluster, enabling rapid experimentation and helping you focus more on application development rather than installation procedures.</p>
</li>
<li><p><strong>Learning Opportunities</strong>: The Marketplace allows you to explore commonly used tools in the Kubernetes ecosystem without needing to install them manually, which is helpful as you learn how to utilize these tools effectively.</p>
</li>
</ul>
<h3 id="heading-personal-experience">Personal Experience</h3>
<p>Having taught Kubernetes to many developers and tested various cloud providers, I can confidently say that very few have impressed me, except <strong>Google Kubernetes Engine (GKE)</strong>. However, after trying Civo, it has quickly become one of my top two choices alongside GKE. Civo stands out for its simplicity, comprehensive documentation, and its contribution to the cloud-native landscape, making it an excellent option for developers looking to learn and grow with Kubernetes.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In summary, <strong>Civo</strong> is an ideal choice for developers new to Kubernetes. It enables rapid and straightforward deployment of Kubernetes clusters using K3s, offers an easy-to-use interface, and provides quick access to essential tools through its Marketplace. With competitive pricing and strong community support, Civo makes it easy to dive into the world of Kubernetes, allowing you to focus on building and deploying applications without the hassle of complex configurations. Its place in my top two alongside GKE speaks volumes about its value for developers seeking a cloud-native solution.</p>
<p>To see for yourself, you can now get $250.00 of free credit when you sign up at <a target="_blank" href="https://civo.com">https://civo.com</a></p>
]]></content:encoded></item><item><title><![CDATA[Unlocking Kubernetes Security: The Risks of Privileged Pods]]></title><description><![CDATA[In Kubernetes, security should always be a top priority. One common pitfall that can lead to serious vulnerabilities is running pods in privileged mode. Understanding why this is dangerous and how to avoid it can significantly enhance the security po...]]></description><link>https://blog.kubeskills.com/unlocking-kubernetes-security-the-risks-of-privileged-pods</link><guid isPermaLink="true">https://blog.kubeskills.com/unlocking-kubernetes-security-the-risks-of-privileged-pods</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[kubernetes-pods]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[containersecurity]]></category><dc:creator><![CDATA[Gerardo Lopez]]></dc:creator><pubDate>Fri, 23 Aug 2024 15:35:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724427257548/0098c060-1e17-4587-88b8-abb942ba9da3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In Kubernetes, security should always be a top priority. One common pitfall that can lead to serious vulnerabilities is running pods in privileged mode. Understanding why this is dangerous and how to avoid it can significantly enhance the security posture of your Kubernetes clusters.</p>
<p><strong>What is Privileged Mode?</strong></p>
<p>Running a pod in privileged mode means giving the container elevated permissions that allow it to perform operations that would normally be restricted. In essence, a privileged container has almost the same level of access to the host as root. This can be dangerous because it opens up the possibility of the container escaping its isolation, leading to potential control over the host system.</p>
<p><img src="https://assets-v2.circle.so/1vc8w4f9gq2e8yddqtmk7o2e1uy5" alt class="image--center mx-auto" /></p>
<p><strong>Why is Running Privileged Pods a Bad Idea?</strong></p>
<ol>
<li><p><strong>Increased Attack Surface:</strong> Privileged containers can interact with the host’s kernel, modify system files, and access sensitive data. If a container running in privileged mode is compromised, the attacker could gain control over the host machine.</p>
</li>
<li><p><strong>Escalation of Privileges:</strong> Privileged containers can bypass many security restrictions, leading to an escalation of privileges. This could allow an attacker to move laterally within your infrastructure, causing widespread damage.</p>
</li>
<li><p><strong>Breakdown of Isolation:</strong> Kubernetes relies on the isolation between containers to maintain security. Running containers in privileged mode undermines this isolation, potentially allowing one compromised container to affect others.</p>
</li>
<li><p><strong>Violation of Least Privilege Principle:</strong> One of the fundamental principles of security is the principle of least privilege. Privileged containers violate this principle by granting more permissions than are necessary for the container to perform its intended function.</p>
</li>
</ol>
<p><strong>Basic Example: Avoiding Privileged Mode</strong></p>
<p>Let’s look at an example of how to define a pod without using privileged mode.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Pod</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">non-privileged-pod</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">containers:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">app-container</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx</span>
    <span class="hljs-attr">securityContext:</span>
      <span class="hljs-attr">privileged:</span> <span class="hljs-literal">false</span>
</code></pre>
<p>In this example, the securityContext specifies that the container should not run in privileged mode (privileged: false). This is the default behavior in Kubernetes, but it's important to explicitly set this to ensure that no containers inadvertently run with elevated permissions.</p>
<p><strong>Best Practices:</strong></p>
<ul>
<li><p><strong>Use Security Context:</strong> Always define a securityContext for your pods and containers to explicitly state that they should not run in privileged mode.</p>
</li>
<li><p><strong>Audit Your Cluster:</strong> Regularly audit your Kubernetes cluster to identify any pods that are running in privileged mode. This can help you catch misconfigurations before they lead to a security incident.</p>
</li>
<li><p><strong>Implement Pod Security Admission:</strong> It is a feature introduced in Kubernetes to enforce clear and consistent isolation levels for Pods. It builds upon the Kubernetes Pod Security Standards, guidelines that govern how Pods behave and interact with other resources.</p>
</li>
<li><p><strong>Educate Your Team:</strong> Ensure that everyone involved in deploying applications to your Kubernetes cluster understands the risks associated with privileged containers and how to avoid them.</p>
</li>
</ul>
<p>By avoiding privileged mode, you can significantly reduce the risk of container escapes and other security breaches in your Kubernetes environment. Always prioritize security and follow best practices to keep your applications and infrastructure safe.</p>
]]></content:encoded></item><item><title><![CDATA[Applying the 80/20 Rule to Kubernetes]]></title><description><![CDATA[Kubernetes is a vast and complex topic; knowing where to start can be overwhelming. Learning everything about Kubernetes all at once is a large undertaking that requires significant and sometimes overwhelming effort. When learning a new technology su...]]></description><link>https://blog.kubeskills.com/applying-the-8020-rule-to-kubernetes</link><guid isPermaLink="true">https://blog.kubeskills.com/applying-the-8020-rule-to-kubernetes</guid><category><![CDATA[#prometheus]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Helm]]></category><category><![CDATA[cloud native]]></category><category><![CDATA[kubernetes architecture]]></category><category><![CDATA[#kubernetes #container ]]></category><category><![CDATA[kubernetes-persistent-volumes]]></category><category><![CDATA[kubernetes-pods]]></category><dc:creator><![CDATA[KubeSkills]]></dc:creator><pubDate>Fri, 09 Aug 2024 22:07:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723131755001/4c99a45f-d46b-42a7-be17-3e948c170a7d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://kubernetes.io">Kubernetes</a> is a vast and complex topic; knowing where to start can be overwhelming. Learning everything about Kubernetes all at once is a large undertaking that requires significant and sometimes overwhelming effort. When learning a new technology such as Kubernetes, it can be easier to identify the fundamental topics, establish a solid foundation, and dive deeper.</p>
<p>In this article, we're doing just that, using the <a target="_blank" href="https://en.wikipedia.org/wiki/Pareto_principle">80/20 rule</a>. Applying the <a target="_blank" href="https://en.wikipedia.org/wiki/Pareto_principle">Pareto Principle (the 80/20 rule)</a> to learning a new subject like Kubernetes means focusing on the 20% of concepts and skills that will provide you with 80% of the value or understanding. Instead of trying to master every detail from the start, you concentrate on the core areas—like container orchestration, deploying applications, and basic networking—that will allow you to be productive and effective quickly. Once you’ve grasped these fundamentals, you can gradually explore more advanced topics as needed. This approach helps you learn efficiently, avoid being overwhelmed, and quickly gain practical knowledge.</p>
<h3 id="heading-heres-how-you-can-do-it"><strong>Here’s how you can do it</strong></h3>
<p>1. <strong>Identify Key Concepts and Components:</strong></p>
<ul>
<li>Focus on 20% of the foundational Kubernetes concepts, giving you a solid understanding of the system. This includes understanding pods, nodes, clusters, namespaces, services, and the Kubernetes control plane. Scroll down to the next section to dive into the 20%.</li>
</ul>
<p>2. <strong>Leverage Top Resources:</strong></p>
<ul>
<li>Utilize the most authoritative and comprehensive resources covering essential information. See this list of <a target="_blank" href="https://kodekloud.com/blog/best-kubernetes-books/">The Best Kubernetes Books of All Time</a>.</li>
</ul>
<p>3. <strong>Focus on High-Impact Tools and Practices:</strong></p>
<ul>
<li>Learn and practice the tools and workflows widely adopted in the Kubernetes ecosystem and contribute to most practical use cases, such as <a target="_blank" href="https://helm.sh/">Helm</a> for package management and <a target="_blank" href="https://prometheus.io/">Prometheus</a> for monitoring. See the paragraphs below for getting started with these tools.</li>
</ul>
<p>4. <strong>Engage with the Community:</strong></p>
<ul>
<li><p>Participate in community events, forums, and meetups where you can interact with experts and peers. Platforms like the Kubernetes Slack channel, CNCF events, or local Kubernetes meetups (like KCD Texas and the Austin Kubernetes meetup) can provide concentrated and valuable insights.</p>
</li>
<li><p>Watch <a target="_blank" href="https://www.youtube.com/live/v8nme1bSwCQ">this video</a> about <a target="_blank" href="https://x.com/kaslinfields">Kaslin's</a> experience in the Kubernetes community:</p>
</li>
</ul>
<p><a target="_blank" href="https://www.youtube.com/live/v8nme1bSwCQ"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722990258919/67ae180f-7db6-4fcf-aac0-8c29bcd01cbb.png" alt class="image--center mx-auto" /></a></p>
<h3 id="heading-key-concepts-and-components">Key Concepts and Components</h3>
<p>1. <strong>Kubernetes Architecture</strong></p>
<ul>
<li><p><strong>Nodes and Clusters:</strong> To understand the basic building blocks, one must consider the roles of a control plane node and a worker node. The control plane is a critical component in Kubernetes because it maintains all the parts of the Kubernetes system. You can authenticate to the Kubernetes <a target="_blank" href="https://livebook.manning.com/book/acing-the-certified-kubernetes-administrator-exam/chapter-1/r-3/point-18994-45-45-0">RESTful API</a>. Often, Kubernetes administrators use a <a target="_blank" href="https://kubernetes.io/docs/reference/kubectl/">kubeconfig with the kubectl command line</a> to interact with their cluster and perform <a target="_blank" href="https://www.codecademy.com/article/what-is-crud">create, read, update, and delete (CRUD)</a> operations on the API. Worker nodes run workloads running inside of pods. Also, additional components that run both on the control plan and worker node are <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-proxy">kube-proxy</a>, the <a target="_blank" href="https://github.com/containernetworking/cni">CNI</a>, <a target="_blank" href="https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/">kubelet</a>, and a <a target="_blank" href="https://kubernetes.io/docs/setup/production-environment/container-runtimes/">container runtime</a> like <a target="_blank" href="https://github.com/containerd/containerd">containerd</a>. The <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kubelet">kubelet</a> usually runs as a <a target="_blank" href="https://man7.org/linux/man-pages/man7/daemon.7.html">daemon</a> on the Linux host. It communicates with the Kubernetes API server to receive instructions and report the status of the node and the workloads running on it. The <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-proxy">kube-proxy</a> component handles network communication for services, including forwarding traffic to the correct Pods, load balancing, and implementing network policies. The <a target="_blank" href="https://kubernetes.io/docs/setup/production-environment/container-runtimes/">container runtime</a> pulls container images, starts and stops containers, and manages container storage and networking. The <a target="_blank" href="https://www.cni.dev/">Container Networking Interface (CNI)</a> is a plugin in Kubernetes that allows pod-to-pod communication across nodes.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722457425936/2ee187ce-1838-4fbb-8c70-c35888af85ac.png" alt="Kubernetes Architecture" class="image--center mx-auto" /></p>
<p>  <strong>Control Plane Components:</strong> Includes <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#etcd">etcd</a> (for cluster state), <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-apiserver">API Server</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-controller-manager">Controller Manager</a>, and <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-scheduler">Scheduler</a>. These all run as <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/pods/">pods</a> in the Kubernetes cluster in a namespace named <code>kube-system</code> (Different namespaces can be used to separate environments such as development, staging, and production). The <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-apiserver">API server</a> is the front end for the Kubernetes control plane. It exposes the Kubernetes API and serves as the hub for communication between other components. The <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#etcd">etcd datastore</a> is a consistent and highly available key-value store used as Kubernetes’ backing store for all cluster data. Every state change and configuration in the cluster is stored in etcd. The <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-scheduler">scheduler</a> assigns workloads (<a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/pods/">pods</a>) to specific nodes in the cluster based on resource availability, policy constraints, and <a target="_blank" href="https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/">affinity</a> specifications. The <a target="_blank" href="https://kubernetes.io/docs/concepts/overview/components/#kube-controller-manager">controller manager</a> runs the controllers and regulates the system's state. The controllers include the <a target="_blank" href="https://kubernetes.io/docs/concepts/architecture/nodes/#node-controller">Node Controller</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/">Replication Controller</a>, and <a target="_blank" href="https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#serviceaccount-controller">Service Account Controller</a>.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722458310928/e6652928-c5a8-43bb-a54a-c94cd6d03dfd.png" alt="Kubernetes system pods" class="image--center mx-auto" /></p>
</li>
</ul>
<p>2. <strong>Pods</strong></p>
<ul>
<li>A pod is the smallest deployable unit in Kubernetes and can contain one or more containers. Check out this <a target="_blank" href="https://killercoda.com/chadmcrowell/course/cka/declarative-pod">FREE lab environment</a>, where you can deploy a pod to a Kubernetes cluster (with step-by-step instructions). 😃</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722460942987/6bd873f8-5fcc-4b6d-a1f5-fab59e2bcc45.png" alt="multi-container pod in Kubernetes" class="image--center mx-auto" /></p>
<p>3. <strong>Services</strong></p>
<ul>
<li>The Types of <a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/service/">Services</a> in Kubernetes are <a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/cluster-ip-allocation/">ClusterIP</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport">NodePort</a>, and <a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer">LoadBalancer</a>. A primary purpose of Services in Kubernetes is to avoid modifying your existing application to use an unfamiliar service discovery mechanism. You can run code in Pods, whether this is code designed for a cloud-native world or an older app you've containerized. Then, you use a service to make that set of pods available on the network so clients can interact with them.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722530662708/a0fbb4a8-f111-4d40-ac80-1f47891f8039.png" alt="Kubernetes Service" class="image--center mx-auto" /></p>
<p>4. <strong>Deployments</strong></p>
<ul>
<li><p>A <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">deployment</a> is a higher-level abstraction that manages a group of identical Pods, ensuring they are running and up-to-date. Deployments provide declarative updates for Pods and <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/">ReplicaSets</a>, enabling automated <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment">rollout and rollback</a> of applications.</p>
</li>
<li><p>Check out this <a target="_blank" href="https://killercoda.com/chadmcrowell/course/cka/rollback-deployment">FREE guided Kubernetes Lab</a> to try it out for yourself!</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722530758821/58fcaed1-4b7a-43f9-b5d1-ad721a3018bd.png" alt="Kubernetes Deployment" class="image--center mx-auto" /></p>
<p>5. <strong>ConfigMaps and Secrets</strong></p>
<ul>
<li><p><a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/configmap/">ConfigMaps</a> decouples configuration artifacts from image content to keep containerized applications portable. ConfigMaps allow you to store configuration data as key-value pairs that your application pods can consume.</p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/concepts/configuration/secret/">Secrets</a> are objects that store and manage sensitive information, such as passwords, OAuth tokens, SSH keys, and other data you want to keep out of plain text in your configuration files. Secrets allow you to securely inject sensitive data into your application pods.</p>
</li>
<li><p>Create <code>configMaps</code> and use then with pods in this <a target="_blank" href="https://killercoda.com/chadmcrowell/course/cka/configmaps">FREE Kubernetes Lab</a> environment!</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722531491494/c2bce4e3-cb4e-43c2-82da-12544d0abbfe.png" alt="Kubernetes ConfigMap and Secret" class="image--center mx-auto" /></p>
<p>6. <strong>Volumes and Persistent Storage</strong></p>
<ul>
<li><p>In Kubernetes, <a target="_blank" href="https://kubernetes.io/docs/concepts/storage/volumes/">volumes</a> are used to manage and persist data for containers running in Pods. Unlike ephemeral container storage, which is lost when a container crashes, volumes allow data to be preserved, shared between containers within a Pod, and made persistent across Pod restarts. If you require to store data, you can use different types, such as <a target="_blank" href="https://kubernetes.io/docs/concepts/storage/volumes/#emptydir">emptyDir</a>, <a target="_blank" href="https://kubernetes.io/docs/concepts/storage/volumes/#hostpath">hostPath</a>, and <a target="_blank" href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/">Persistent Volumes (PVs)</a>.</p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims">Persistent Volume Claims (PVCs)</a> request storage resources defined by a Persistent Volume. PVCs provide an abstraction for requesting and using storage without knowing the underlying details. Get hands-on with PVs and PVCs in this <a target="_blank" href="https://killercoda.com/chadmcrowell/course/cka/persistent-volumes">FREE Kubernetes lab environment</a>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722555762522/f6b6bafe-fb8a-432d-a55f-8688a4b1ae99.png" alt="Kubernetes PersistentVolume" class="image--center mx-auto" /></p>
<p>9. <strong>Ingress</strong></p>
<ul>
<li>An <a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/ingress/">Ingress</a> is an API object that manages external access to services within a cluster, typically HTTP and HTTPS. Ingress can provide load balancing, SSL termination, and name-based virtual hosting, making it a powerful way to expose services to external users.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722556339797/54bd5622-9257-43dc-9fe2-705aae5284c8.png" alt="Kubernetes Ingress" class="image--center mx-auto" /></p>
<p>10. <strong>RBAC (Role-Based Access Control)</strong></p>
<ul>
<li><p><a target="_blank" href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/">Role-Based Access Control (RBAC)</a> in Kubernetes regulates access to the Kubernetes API and resources within a cluster. RBAC allows administrators to define roles with specific permissions and then assign those roles to users or groups, ensuring that only authorized individuals can perform certain actions.</p>
</li>
<li><p>A <a target="_blank" href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole">Role</a> contains a set of permissions (rules) that apply within a specific namespace. It defines what actions can be performed on which resources. A <a target="_blank" href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding">RoleBinding</a> grants the permissions defined in a Role to a user, group, or service account within a specific namespace.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722557888638/6a3f4fd2-05f1-4f7b-9379-c65be6d14209.png" alt="Kubernetes RBAC" class="image--center mx-auto" /></p>
<p>14. <strong>Autoscaling</strong></p>
<ul>
<li><p>A <a target="_blank" href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/">Horizontal Pod Autoscaler</a> adjusts the number of Pods in a Deployment, Replica Set, or Stateful Set based on observed CPU utilization, memory usage, or other custom metrics.</p>
</li>
<li><p>A <a target="_blank" href="https://kubernetes.io/docs/concepts/cluster-administration/cluster-autoscaling/">Cluster Autoscaler</a> scales the cluster size up or down by adding or removing nodes to match the resource requirements of the running Pods.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722558376649/10eba278-bab2-43e5-bf29-5462df48037b.png" alt="Kubernetes Autoscaling" class="image--center mx-auto" /></p>
<p>17. <strong>StatefulSets</strong></p>
<ul>
<li><p>A <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/">StatefulSet</a> is a controller that manages deploying and scaling a set of Pods and guarantees their ordering and uniqueness. StatefulSets are used for applications that require stable, unique network identifiers, persistent storage, and ordered deployment and scaling, like a database.</p>
</li>
<li><p>Create and manage a <code>statefulSet</code> in this <a target="_blank" href="https://killercoda.com/chadmcrowell/scenario/kubernetes-statefulset">FREE Kubernetes lab environment</a>!</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722991944479/a6fdd8c3-b9f3-4b16-a452-6c8dbc29381f.png" alt="Kubernetes StatefulSet" class="image--center mx-auto" /></p>
<p>18. <strong>DaemonSets</strong></p>
<ul>
<li>a <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/">DaemonSet</a> is a type of controller that ensures a copy of a specific Pod runs on each node in a cluster. DaemonSets are particularly useful for deploying system-level or cluster-wide services that need to run on every node, such as log collectors, monitoring agents, and network plugins</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722992495913/0bfe0f84-b46f-420b-a5ed-91ced16ad507.png" alt="Kubernetes DaemonSet" class="image--center mx-auto" /></p>
<p>19. <strong>Jobs and CronJobs</strong></p>
<ul>
<li><p>a <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/job/">Job</a> is a controller that ensures a specified number of Pods successfully terminate. Jobs are used to run tasks that have a clear start and end, such as batch processing, data analysis, or one-time scripts. Once the tasks specified by the Job are completed successfully, the Job itself is considered complete</p>
</li>
<li><p>a <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/">CronJob</a> is a specialized type of Job that runs on a schedule. CronJobs perform tasks regularly, much like the cron utility in Unix-like operating systems. They are suitable for recurring tasks such as backups, report generation, and periodic maintenance.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723068838879/7d1da7db-fc69-4b4a-bcf9-1e5feffc6470.png" alt="Kubernetes CronJob" class="image--center mx-auto" /></p>
<p>20. <strong>Security</strong></p>
<ul>
<li><p><a target="_blank" href="https://kubernetes.io/docs/concepts/security/pod-security-standards/">Pod Security Standards (PSS)</a> in Kubernetes are predefined security policies that outline best practices for running Pods securely. These standards help Pods adhere to specific security guidelines, reducing the risk of vulnerabilities and security breaches. The PSS are typically enforced using Pod Security Admission (PSA), an admission controller that applies these standards at the namespace level. Get hands-on with PSS in this <a target="_blank" href="https://killercoda.com/chadmcrowell/scenario/kubernetes-pss">FREE hands-on lab</a>!</p>
</li>
<li><p><a target="_blank" href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">Network Policies</a> in Kubernetes are a way to define rules for controlling the traffic flow between Pods, and between Pods and external endpoints. They allow you to specify how Pods are allowed to communicate with each other and other network endpoints, enhancing security by isolating different parts of your applications and services. Create your first Network Policy in this <a target="_blank" href="https://killercoda.com/chadmcrowell/scenario/kubernetes-netpol">FREE Kubernetes Lab</a>!</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723131450953/868a09dd-976f-4e20-9543-c96b6efea01c.png" alt="Kubernetes Network Policies" class="image--center mx-auto" /></p>
<p>Focusing on these areas will provide a solid foundation in Kubernetes and cover the core aspects you need to understand and effectively use the platform. For deeper learning, you can dive into each of these topics with detailed resources and hands-on practice.</p>
<h3 id="heading-high-impact-tools-and-practices-helmhttpshelmsh">High-Impact Tools and Practices: <a target="_blank" href="https://helm.sh">Helm</a></h3>
<p>Learning and practicing with <a target="_blank" href="https://helm.sh/">Helm</a> can significantly enhance your understanding of Kubernetes by simplifying the management and deployment of applications. Helm is a package manager for Kubernetes that helps you define, install, and upgrade complex Kubernetes applications. Here’s a step-by-step guide to learning and practicing with Helm.</p>
<p>To understand the verbiage used in Helm, here are the three <a target="_blank" href="https://helm.sh/docs/topics/architecture/">Helm Components</a>:</p>
<ol>
<li><p><strong>Helm Client</strong>: The command-line tool used to interact with Helm.</p>
</li>
<li><p><strong>Helm Chart</strong>: A package that contains all the necessary Kubernetes manifest files to deploy an application.</p>
</li>
<li><p><strong>Release</strong>: An instance of a Helm chart running in a Kubernetes cluster.</p>
</li>
</ol>
<p><strong>Install Helm on your local machine:</strong></p>
<p>• <strong>Helm Installation</strong>: Follow the official installation guide for Helm.</p>
<p>• <a target="_blank" href="https://helm.sh/docs/intro/install/">Helm Installation Guide</a></p>
<p>Example for installing Helm on macOS using Homebrew:</p>
<pre><code class="lang-bash">brew install helm
</code></pre>
<p>Example for installing Helm on Linux:</p>
<pre><code class="lang-bash">curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
</code></pre>
<p>Access a <strong>FREE</strong> Kubernetes Lab environment on <a target="_blank" href="https://killercoda.com/playgrounds/scenario/kubernetes">Killercoda.com</a>.</p>
<p>Familiarize yourself with basic Helm commands:</p>
<p>• <strong>helm search</strong>: Search for Helm charts.</p>
<p>• <strong>helm repo add</strong>: Add Helm chart repositories.</p>
<p>• <strong>helm install</strong>: Install a Helm chart.</p>
<p>• <strong>helm list</strong>: List installed Helm releases.</p>
<p>• <strong>helm upgrade</strong>: Upgrade an existing Helm release.</p>
<p>• <strong>helm uninstall</strong>: Uninstall a Helm release.</p>
<p>Example:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Add the official stable repository</span>
helm repo add stable https://charts.helm.sh/stable

<span class="hljs-comment"># Update the repository</span>
helm repo update

<span class="hljs-comment"># Search for a chart</span>
helm search repo stable

<span class="hljs-comment"># Install a chart</span>
helm install my-release stable/nginx

<span class="hljs-comment"># List releases</span>
helm list

<span class="hljs-comment"># Upgrade a release</span>
helm upgrade my-release stable/nginx

<span class="hljs-comment"># Uninstall a release</span>
helm uninstall my-release
</code></pre>
<p><strong>Learn how to create your own Helm charts:</strong></p>
<p>This command creates a directory structure for your chart, including default templates and values:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># create a new chart</span>
helm create mychart
</code></pre>
<p><strong>Understanding Chart Structure</strong>:</p>
<ul>
<li><p><a target="_blank" href="https://helm.sh/docs/glossary/#chartyaml">Chart.yaml</a>: Contains metadata about the chart (name, version, description).</p>
</li>
<li><p><a target="_blank" href="https://helm.sh/docs/chart_best_practices/values/#document-valuesyaml">values.yaml</a>: Default configuration values for the chart.</p>
</li>
<li><p><a target="_blank" href="https://helm.sh/docs/chart_best_practices/templates/#structure-of-templates">templates/</a>: Contains Kubernetes manifest templates.</p>
</li>
</ul>
<p><strong>Customize the Chart</strong>:</p>
<p>Modify the values.yaml and templates to suit your application’s needs.</p>
<p><strong>Install the Chart</strong>:</p>
<pre><code class="lang-bash">helm install my-release ./mychart
</code></pre>
<p><strong>Upgrade the Chart:</strong></p>
<pre><code class="lang-bash">helm upgrade my-release ./mychart
</code></pre>
<p><strong>Uninstall the Chart:</strong></p>
<pre><code class="lang-bash">helm upgrade my-release ./mychart
</code></pre>
<p><strong>Helm Community and Resources</strong></p>
<p>Engage with the Helm community and utilize available resources:</p>
<ul>
<li><p><a target="_blank" href="https://helm.sh/docs/"><strong>Helm Documentation</strong></a>: The official documentation provides comprehensive guides and references.</p>
</li>
<li><p><a target="_blank" href="https://github.com/helm/helm"><strong>Helm GitHub Repository</strong></a>: Explore the source code and contribute.</p>
</li>
<li><p><a target="_blank" href="https://communityinviter.com/apps/kubernetes/community"><strong>Community Forums and Slack</strong></a>: Join discussions and seek help from the community.</p>
</li>
</ul>
<h3 id="heading-high-impact-tools-and-practices-prometheushttpsprometheusio">High-Impact Tools and Practices: <a target="_blank" href="https://prometheus.io">Prometheus</a></h3>
<p>Learning and practicing with Prometheus in the context of Kubernetes is a great way to understand the fundamentals of monitoring and observability in cloud-native environments. Prometheus is widely used for monitoring and alerting in Kubernetes clusters and plays a key role in the Kubernetes ecosystem. Here’s a step-by-step guide to help you learn and practice with Prometheus to understand Kubernetes better.</p>
<p>Key components of Prometheus:</p>
<ol>
<li><p><strong>Prometheus Server:</strong> Responsible for scraping and storing metrics data.</p>
</li>
<li><p><strong>Prometheus Query Language (PromQL):</strong> A flexible query language for querying metrics data.</p>
</li>
<li><p><strong>Alertmanager:</strong> Manages alerts generated by Prometheus.</p>
</li>
<li><p><strong>Exporters:</strong> Applications that expose metrics in a format that Prometheus can scrape (e.g., Node Exporter for hardware metrics).</p>
</li>
</ol>
<p>Access Prometheus using the instructions in <a target="_blank" href="https://killercoda.com/chadmcrowell/scenario/prometheus">this FREE hand-on lab</a>.</p>
<p><strong>Once Prometheus is running, start exploring its features.</strong></p>
<p><strong>Run Basic PromQL Queries</strong>, like this one, to get the CPU usage percentage per node:</p>
<pre><code class="lang-plaintext">100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) * 100)
</code></pre>
<p>This is the expected output from the above PromQL query:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723237308078/4e7e34a2-3cf3-4478-a465-cf18a758e766.png" alt class="image--center mx-auto" /></p>
<p>Or this one, to monitor memory usage:</p>
<pre><code class="lang-plaintext">sum(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) by (instance) / sum(node_memory_MemTotal_bytes) by (instance) * 100
</code></pre>
<p>This is the expected output from the above PromQL query:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723237378123/49101ef5-ec4c-42a5-ab0a-801a03729aef.png" alt class="image--center mx-auto" /></p>
<p>Or this one to count the number of running pods</p>
<pre><code class="lang-plaintext">count(kube_pod_info)
</code></pre>
<p>This is the expected output from the above PromQL query:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723237474462/c4e63f02-b58b-474e-9cdf-6d3da685b69f.png" alt class="image--center mx-auto" /></p>
<p><strong>Engage with the Prometheus Community</strong></p>
<ul>
<li><p><a target="_blank" href="https://prometheus.io/community/"><strong>Join the Prometheus Community</strong></a>: participate in discussions, ask questions, and learn from others in the community.</p>
</li>
<li><p><a target="_blank" href="https://github.com/prometheus/prometheus"><strong>Contribute to Prometheus</strong>:</a> Explore the Prometheus GitHub repository and contribute to the project.</p>
</li>
<li><p><a target="_blank" href="https://prometheus.io/docs/introduction/overview/"><strong>Explore Prometheus Documentation</strong></a>: The official Prometheus documentation is an excellent resource for in-depth learning.</p>
</li>
</ul>
<h3 id="heading-summary">Summary</h3>
<p><strong>Now that you have the 20%, what’s next?</strong> Each topic we've touched on has countless avenues to explore further. I recommend joining a learning community where you can connect with others who share your passion for technology. At <a target="_blank" href="https://community.kubeskills.com">KubeSkills</a>, we offer a friendly and supportive environment where you can dive deeper and continue your journey. If you found this guide helpful, share it on social media and use it as you see fit. We have more guides like this and more in the <a target="_blank" href="https://community.kubeskills.com">KubeSkills community</a>, which you can join for <strong>FREE</strong>! Thank you for your time and attention if you've read this far.  </p>
<p>I look forward to seeing you in the KubeSkills community soon! 😃</p>
<p>-Chad</p>
]]></content:encoded></item></channel></rss>