<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Gursimar Singh - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Gursimar Singh - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 12 Oct 2026 12:33:36 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/gursimar/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Diagnose and Fix AI Inference Latency on Kubernetes ]]>
                </title>
                <description>
                    <![CDATA[ It's Thursday, around quarter past two. Your team shipped an internal assistant two weeks ago. The demo went well enough that someone in finance asked whether it could read contracts. Word spread. Tod ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-diagnose-and-fix-ai-inference-latency-on-kubernetes/</link>
                <guid isPermaLink="false">6abca2f9f944d026311c7f7b</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ infrastructure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ llm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gursimar Singh ]]>
                </dc:creator>
                <pubDate>Wed, 30 Sep 2026 05:49:45 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/4ab24802-80a3-43bb-a432-28f18d1f777e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>It's Thursday, around quarter past two. Your team shipped an internal assistant two weeks ago. The demo went well enough that someone in finance asked whether it could read contracts. Word spread. Today, for the first time, everyone is using it at once.</p>
<p>The support channel has the same complaint arriving in six different tones. Is it down? Mine is just spinning. It worked this morning. Somebody has posted a screenshot of a loading indicator with no caption, which you suspect they're enjoying.</p>
<p>So you open the dashboard.</p>
<p>Nodes ready. Pods running. CPU at 20%. No restarts, nothing in CrashLoopBackOff, no alert fired. By every signal Kubernetes gives you, the system is healthy.</p>
<p>It is not healthy. Somebody is eleven seconds into waiting for the first word of an answer, and they're about to go back to doing it the old way, and they're not coming back.</p>
<p>That is the failure this piece is about. Not the outage. The quiet one, where everything is technically up and the product is still unusable.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ul>
<li><p><a href="#heading-your-first-instinct-is-wrong">Your First Instinct is Wrong</a></p>
</li>
<li><p><a href="#heading-you-are-not-the-only-one">You Are Not the Only One</a></p>
</li>
<li><p><a href="#heading-the-thing-nobody-told-you-when-you-deployed-it">The Thing Nobody Told You When You Deployed It</a></p>
</li>
<li><p><a href="#heading-where-the-eleven-seconds-went">Where the Eleven Seconds Went</a></p>
<ul>
<li><p><a href="#heading-stage-one-routing-your-load-balancer-is-guessing">Stage One, Routing: Your Load Balancer is Guessing</a></p>
</li>
<li><p><a href="#heading-stage-two-the-queue-nothing-is-coming-to-help">Stage Two, The Queue: Nothing is Coming to Help</a></p>
</li>
<li><p><a href="#heading-stage-three-prefill-the-gpus-are-there-and-useless">Stage Three, Prefill: The GPUs Are There, and Useless</a></p>
</li>
<li><p><a href="#heading-stage-four-decode-your-ingress-is-cutting-people-off">Stage Four, Decode: Your Ingress is Cutting People Off</a></p>
</li>
<li><p><a href="#heading-and-underneath-all-four-bursty-traffic-and-nobodys-name-on-the-problem">And Underneath All Four: Bursty Traffic and Nobody's Name on the Problem</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-meanwhile-the-platform-did-not-stand-still">Meanwhile, the Platform Did Not Stand Still</a></p>
</li>
<li><p><a href="#heading-how-this-got-here-in-the-first-place">How This Got Here in the First Place</a></p>
</li>
<li><p><a href="#heading-what-to-do-once-the-fire-is-out">What To Do Once the Fire is Out</a></p>
<ul>
<li><p><a href="#heading-capacity">Capacity</a></p>
</li>
<li><p><a href="#heading-performance">Performance</a></p>
</li>
<li><p><a href="#heading-placement">Placement</a></p>
</li>
<li><p><a href="#heading-resilience">Resilience</a></p>
</li>
<li><p><a href="#heading-ownership">Ownership</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-four-things-your-monitoring-still-isnt-telling-you">Four Things Your Monitoring Still Isn't Telling You</a></p>
</li>
<li><p><a href="#heading-the-thing-that-is-still-unsettled">The Thing That is Still Unsettled</a></p>
</li>
<li><p><a href="#heading-monday-morning">Monday Morning</a></p>
</li>
<li><p><a href="#heading-back-to-thursday">Back to Thursday</a></p>
</li>
</ul>
<h2 id="heading-your-first-instinct-is-wrong">Your First Instinct is Wrong</h2>
<p>The instinct at that moment is to suspect the model. Wrong version, bad quantization, context too long, or that someone changed the system prompt.</p>
<p>It is almost never the model.</p>
<p>Walk one request end to end and you find four stages. It gets routed to a replica. It waits in a queue. The model reads the prompt. The model streams an answer. Only the last two involve the model doing anything you are paying for. The first two are queueing and routing, which is to say infrastructure.</p>
<p>When people say their model is slow, the model is usually fine. The wait is somewhere else.</p>
<h2 id="heading-you-are-not-the-only-one">You Are Not the Only One</h2>
<p>It's worth knowing before you go hunting that this is the most common complaint in the field, not an unlucky configuration on your part.</p>
<p>A <a href="https://www.akamai.com/lp/the-state-of-ai-inference">practitioner survey</a> of 200 people running AI in production found that nearly half, 49.5%, named latency at peak load as their single hardest scaling problem. Not accuracy. Not hallucination. Not cost per token. Latency, at the exact moment people are trying to use the thing.</p>
<p>Two more figures from the same research are worth holding alongside it. 59.5% said running inference closer to users or decision points is critical or very important. 45.5% still serve from a single cloud region. People know proximity matters and have not managed to act on it, which tells you something about what multi-region GPU capacity costs to stand up.</p>
<p>The same research mentions organizations mandating sub-250ms response times alongside 99.9% availability. Read that carefully, because taken literally it is impossible. No meaningful LLM response completes in a quarter of a second. It has to mean time to first token (how long before the first word of the answer appears), and that is the right thing to hold yourself to anyway. Once tokens are flowing at a readable pace, people stop counting. The silence before the first one is what loses them.</p>
<h2 id="heading-the-thing-nobody-told-you-when-you-deployed-it">The Thing Nobody Told You When You Deployed It</h2>
<p>Here's the part that explains everything else.</p>
<p>A normal web request is short, small, and costs roughly what the last one cost. Kubernetes scheduling assumes that. Service load balancing assumes it. The Horizontal Pod Autoscaler assumes it. Your ingress controller's default timeout assumes it. Nobody wrote the assumption down, because for fifteen years it was simply true.</p>
<p>An LLM request breaks it in three places.</p>
<p>It runs in two phases with completely different profiles. Prefill: the model reads the entire prompt in one pass. Compute-bound, bursty, and this is what decides how long your user stares at nothing. Then decode: one token at a time, each needing the accumulated state of every token before it. That state is the KV cache. It lives in GPU memory next to the weights, and it grows as the answer grows.</p>
<p>So requests are not short, they can run for a minute. They do not cost the same, since a prompt with a document pasted into it can cost fifty times what a one-liner costs. And the genuinely scarce resource is GPU memory, which does not appear on a single dashboard you inherited.</p>
<p>That is why your monitoring said everything was fine. It was measuring the wrong machine.</p>
<h2 id="heading-where-the-eleven-seconds-went">Where the Eleven Seconds Went</h2>
<p>Follow the request through the four stages and the failure modes fall out in order. These six are the ones practitioners name most often, and they map neatly onto the path.</p>
<h3 id="heading-stage-one-routing-your-load-balancer-is-guessing">Stage One, Routing: Your Load Balancer is Guessing</h3>
<p>Round-robin stops being fair the moment request costs diverge. Three heavy prompts land on one pod while its neighbour handles one-liners. The loaded pod's queue grows, its tail latency climbs, and the fleet average still looks completely reasonable, which is why nobody noticed before today.</p>
<p>Long-lived connections make it worse. With HTTP/2 or keepalive, a client opens one connection and sends everything down it, and a Kubernetes Service balances per connection rather than per request. All that traffic pins to a single backend and stays there.</p>
<p>Then there is the cost most teams have never considered. If a replica already holds the prefix of this prompt in its KV cache, routing there skips real prefill work. Since most production prompts share a long system preamble, that is not an edge case, it is most of your traffic. Round-robin throws the benefit away at random, every time.</p>
<h3 id="heading-stage-two-the-queue-nothing-is-coming-to-help">Stage Two, The Queue: Nothing is Coming to Help</h3>
<p>Your autoscaler could add capacity. It will be late, and the reason is unglamorous: a new replica has to pull a multi-gigabyte serving image, fetch 20GB to 70GB of weights over the network, and load them into GPU memory. Minutes, not seconds, and that assumes a node with a free card already exists. If it does not, add provisioning time, and add whether your provider has stock in that zone today.</p>
<p>There is a second problem stacked on the first. The signal is usually wrong. CPU tells you nothing here, because the CPU is idle while the GPU works. GPU utilization is barely better: it reports that a kernel was executing during the sample window, and a server handling one request and a server handling sixty both read 100%. It cannot tell you whether anyone is waiting.</p>
<p>Queue depth can. vLLM already exposes running and waiting request counts as Prometheus metrics. Scale on those:</p>
<pre><code class="language-yaml">apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: llm-server
spec:
  scaleTargetRef:
    name: llm-server
  minReplicaCount: 2
  maxReplicaCount: 8
  cooldownPeriod: 600
  triggers:
    - type: prometheus
      metadata:
        serverAddress: http://prometheus.monitoring:9090
        query: sum(vllm:num_requests_waiting{app="llm-server"})
        threshold: "5"
</code></pre>
<p>Check the metric names against your vLLM version. Several have been renamed across releases, and the failure is silent.</p>
<p>Two values there are deliberate. The minimum of 2, because a cold start means you cannot sit at zero and expect to serve. The ten minute cooldown, because scaling down eagerly means paying that cold start again shortly afterwards.</p>
<p>Which leads to the uncomfortable conclusion about autoscaling inference. Reactive scaling is permanently late by however long your cold start is, and no trigger fixes that. The fix is to keep more spare capacity than feels comfortable. Run extra replicas at all times, scale up earlier than you think you need to, and scale down more slowly. This also means scale to zero isn't a good fit for user-facing inference. Save it for batch jobs, where nobody is sitting there waiting for a response.</p>
<h3 id="heading-stage-three-prefill-the-gpus-are-there-and-useless">Stage Three, Prefill: The GPUs Are There, and Useless</h3>
<p>Kubernetes hands out CPU in millicores and GPUs whole. A pod asks for one card and gets the entire card, whether it needs 10% of it or all of it.</p>
<p>The waste is the obvious problem. Fragmentation is the one that ruins a Thursday. A 70B model in 16-bit needs roughly 140GB of weights, so a replica needs several GPUs on one node. You can have six free GPUs spread two-two-one-one across four nodes, and the replica sits in Pending indefinitely. Capacity on paper, none of it usable, and no alert, because nothing is broken.</p>
<p>Sharing a card gives three options, each with a catch you should know before choosing. Time-slicing is easy to enable and gives no memory isolation, so one greedy pod can take down its neighbour. Fine for development, not for anything customer-facing. MIG gives real hardware isolation but fixed slice geometry, which means predicting your workload mix before you have one. Dynamic Resource Allocation is the structurally correct answer and brings accelerator requests properly into the core Kubernetes API.</p>
<p>None of these are on by default. Each needs a deliberate decision from somebody who understands the workload, who is usually not in the room when the cluster gets built.</p>
<h3 id="heading-stage-four-decode-your-ingress-is-cutting-people-off">Stage Four, Decode: Your Ingress is Cutting People Off</h3>
<p>Many ingress controllers ship with a 60 second read timeout and response buffering enabled.</p>
<p>The timeout terminates long generations mid-sentence. Users report that as a crash, and you cannot reproduce it, because your test prompt is short. The buffering holds tokens and releases them in clumps, which destroys the feel of streaming while the model is behaving perfectly.</p>
<p>Two config lines, written for a workload that no longer exists.</p>
<h3 id="heading-and-underneath-all-four-bursty-traffic-and-nobodys-name-on-the-problem">And Underneath All four: Bursty Traffic and Nobody's Name on the Problem</h3>
<p>Internal AI tools don't get steady traffic. They get sudden spikes: when everyone starts work at 9am, in the hour after a company all-hands meeting, or when someone shares the link in a busy Slack channel and says it's actually quite good. A fixed replica count handles exactly one of those. Most teams set it once during a quiet week and never revisit it, so they get both waste and collapse on the same day.</p>
<p>Then the sixth failure mode, which is not technical at all, and which is the reason the other five survive for quarters.</p>
<p>Platform engineering owns the cluster. The cluster is green. From where they sit, the job is done and done well. Application developers can see latency is bad and cannot see why, because every cause sits in scheduling, scaling and routing that they neither control nor observe. MLOps owns the model artifact and almost nothing that determines how it performs at quarter past two on a Thursday.</p>
<p>Three teams, all telling the truth, and the problem living in the gap between their on-call rotas, where no alert is configured and no dashboard points.</p>
<h2 id="heading-meanwhile-the-platform-did-not-stand-still">Meanwhile, the Platform Did Not Stand Still</h2>
<p>The encouraging part of this story is that the gaps above are known, and the fixes have been shipping.</p>
<p>Dynamic Resource Allocation brings accelerator hardware requests into the core Kubernetes API, so the scheduler can reason about the device rather than counting opaque units. Kueue adds job queueing and multi-tenant GPU quota alongside CPU and memory, which is how you stop a research job starving the endpoint your users depend on. Gateway API Inference Extension and llm-d add model-aware routing: request criticality, dynamic balancing from live model metrics, and awareness of cache state. That last one is the direct answer to the guessing load balancer in stage one.</p>
<p>Published benchmarks give a sense of scale: Kueue reducing multi-stage workload makespan by up to 15%, dynamic accelerator slicing cutting mean job completion time by 36%, and Gateway API plus llm-d improving tail time to first token by up to 90% under heavy load.</p>
<p>Treat those as headroom rather than forecast. Up to 90% is measured on a configuration chosen to demonstrate the improvement, and your gain depends entirely on how poor your baseline is. If you already run least-outstanding-requests balancing with a warm cache, expect far less. If you are on stock round-robin behind a default ingress, possibly something dramatic, because that baseline is genuinely bad.</p>
<p>The direction is what matters. The biggest published gain is in tail time to first token, which is precisely what half the surveyed practitioners named as their worst problem. Somebody built the fix for the thing people were complaining about.</p>
<h2 id="heading-how-this-got-here-in-the-first-place">How This Got Here in the First Place</h2>
<p>Worth a short detour, because it explains why the tooling arrived late.</p>
<p>When generative AI landed in enterprise planning documents, the confident position was that Kubernetes could not hold it. Container orchestration was built for small fungible units of CPU and memory, cheap restarts, interchangeable replicas. AI needed scheduled specialized silicon carrying enormous state that takes minutes to place. A purpose-built platform was coming.</p>
<p>It never arrived. AI went into the microservices stack and Kubernetes absorbed it.</p>
<p>The <a href="https://www.cncf.io/reports/the-cncf-annual-cloud-native-survey/">survey data</a> explains why. More than half of enterprises do not train models at all, and only 7% deploy a model on any given day. Meanwhile 82% of container users run Kubernetes in production, and 66% of organizations hosting generative AI already serve it there. The industry spent years designing for the workload almost nobody has, while everybody else quietly downloaded weights and put them behind an endpoint.</p>
<p>What actually converged was not a place to run AI. It was a standard way to run it, with the location left negotiable. Which is exactly why your problems today are placement, routing and capacity rather than anything model-shaped.</p>
<h2 id="heading-what-to-do-once-the-fire-is-out">What To Do Once the Fire is Out</h2>
<p>The path from working to reliable comes down to five things: capacity, performance, placement, resilience and ownership.</p>
<h3 id="heading-capacity">Capacity</h3>
<p>Requests per second is meaningless when one request is 50 tokens and the next is 8,000. Plan in tokens per second and track prompt and completion separately, because they stress different parts of the system. Prompt tokens are a compute burst during prefill. Completion tokens are a sustained drip during decode that holds GPU memory for the life of the response.</p>
<p>Load test with your worst realistic prompt at your worst realistic concurrency, and plan from that number. A benchmark built on short prompts gives a reassuring figure that evaporates in week one.</p>
<p>On supply, treat GPUs as something you reserve ahead of time rather than request when needed. Keep a committed baseline and burst on top. Find out your provider's quota and regional stock position before the evening you need it, and use Kueue so one team cannot quietly consume the pool.</p>
<h3 id="heading-performance">Performance</h3>
<p>Two numbers matter most. Time to first token (TTFT) is how long a user waits between sending a prompt and seeing the first word of the answer. It decides whether people trust the product. Inter-token latency is the gap between each word after that, and it decides whether the answer feels smooth to read.</p>
<p>Track both at p95 and p99, not the average. These are percentiles. p95 is the time that 95% of requests come in under, so it shows what your slowest 1 in 20 users experience. p99 does the same for the slowest 1 in 100. An average can look healthy while those users wait far too long, and they're the ones who give up.</p>
<p>Next, tune the serving layer. This is the software that loads the model and handles requests, such as vLLM. It's where you'll get the biggest improvements for the least effort and cost. Continuous batching keeps the GPU busy without making early requests wait for a batch to fill. Quantization roughly halves memory footprint where the quality tradeoff is acceptable, and freed memory becomes concurrent requests. Set maximum context length to what your product actually needs rather than what the model supports. If the model handles 128K and your longest genuine prompt is 6K, you are reserving KV cache for a scenario that never occurs. One config line, and it can substantially raise effective concurrency.</p>
<h3 id="heading-placement">Placement</h3>
<p>Taint GPU nodes so general workloads cannot land on them and only inference pods with matching tolerations schedule there. A logging sidecar should never be the reason a model replica cannot place.</p>
<p>Keep weights close. Node-local NVMe or a zone-local cache turns a 40GB network pull into a fast local read, which feeds directly into cold start, autoscaling lag, and the peak-hour latency you spent Thursday afternoon on. This is the highest-leverage unglamorous fix on the list.</p>
<p>Respect topology. Cards connected by NVLink behave very differently from cards that merely share a PCIe bus, and for a sharded model that interconnect sits on the critical path of every token generated.</p>
<p>Then be honest about geography. If your users are in London and your GPUs are in Virginia, every token crosses an ocean, and a well-tuned model behind a long network path is still a slow product.</p>
<h3 id="heading-resilience">Resilience</h3>
<p>Readiness should pass only when the model is loaded and genuinely able to serve. Use a startup probe with a generous failure threshold, otherwise liveness kills the pod partway through loading weights and you get a restart loop that presents as a mystery and costs an hour.</p>
<p>Set a PodDisruptionBudget so a routine node upgrade cannot remove half your replicas at once.</p>
<p>Raise the termination grace period past the 30 second default and add a preStop hook. A generation can easily run longer than that, so otherwise every rollout severs in-flight streams and your users experience deployments as random failure.</p>
<p>Shed load deliberately. Past a queue depth threshold, return a fast busy-try-again rather than accepting a request that will hang for two minutes. This feels wrong to engineers and is right for users. People forgive a quick honest retry. Nobody forgives a frozen screen.</p>
<p>Have somewhere to fall back to: a second region, a smaller model covering the common cases, or an external API at the edge of disaster. Given that 45.5% of practitioners run from a single region, this is the most commonly skipped item on the list, which makes it the most likely candidate for your next incident.</p>
<h3 id="heading-ownership">Ownership</h3>
<p>Agree on the numbers and write them down: time to first token, inter-token latency, error rate, queue time. Put them on one dashboard showing cluster and model metrics side by side, and make sure both teams open the same link rather than maintaining separate versions of reality.</p>
<p>Split responsibility explicitly. Platform owns the ability to hit the target: capacity, scheduling, routing, scaling, placement. Application owns how the model is configured and called: context length, batching parameters, prompt size, retry behaviour. When the number slips, both show up, and the conversation starts from the same graph instead of two that disagree.</p>
<h2 id="heading-four-things-your-monitoring-still-isnt-telling-you">Four Things Your Monitoring Still Isn't Telling You</h2>
<p>Latency, traffic, errors and saturation are still necessary and no longer sufficient. Four more belong on the board.</p>
<p>Token consumption rate, split prompt and completion, because that is your real unit of capacity. Cost per request by tenant and query type, because we run eight GPUs is not an answer to what a feature costs per user. Output quality, tracking hallucination rate and guardrail drift, because latency work that degrades quality is not a win. Model attribution, recording which checkpoint and which prompt version produced a response, because when quality moves you need to know what changed.</p>
<p>That last one connects to a shift worth noticing. Model registries have become peers to container registries, and prompts and agent configurations are increasingly versioned as GitOps artifacts in the same delivery pipelines as everything else.</p>
<p>The prompt is code now. It changes production behaviour, it can break things, and it should go through review, versioning and rollback like anything else that does. Plenty of teams are still editing prompts in a web console and wondering why quality shifted on a Tuesday.</p>
<h2 id="heading-the-thing-that-is-still-unsettled">The Thing That is Still Unsettled</h2>
<p>The substrate has converged, and the speed of it is the evidence. A Kubernetes AI conformance programme launched in late 2025 with 18 platforms. Within roughly four months it had grown to 31 and extended to agentic workloads, covering the major hyperscalers, the enterprise and private cloud distributions, GPU neoclouds and edge networks. Companies that agree on almost nothing agreed on this.</p>
<p>The layer above has not converged at all. AI gateways, evaluation platforms, agent control planes, agent observability. All advancing faster in commercial products than in any standard body, and all sitting exactly where the interesting business logic is heading.</p>
<p>The risk is worth naming plainly. You can be perfectly portable at the Kubernetes layer and completely locked in at the layer where you actually build. Your pods will migrate between clouds beautifully while your agent definitions, eval suites and gateway policies stay exactly where they are, because there is nowhere standard to move them to.</p>
<p>That is not a reason to avoid those tools. They solve real problems today. It is a reason to know which of your components has an exit and which does not, and to make that a decision you wrote down rather than one you discover during a renewal negotiation.</p>
<h2 id="heading-monday-morning">Monday Morning</h2>
<p>Start with one measurement. Time a cold start end to end, from pod created to first token served, and write the number down. That figure is your autoscaling floor, and your minimum replica count falls directly out of it.</p>
<p>Put time to first token and queue depth on your main dashboard at p99. Replace CPU-based autoscaling with a queue-depth trigger and minimums that respect the cold start. Check your ingress read timeout and buffering against a real long streaming response rather than a test prompt. Fix the termination grace period so deployments stop cutting people off.</p>
<p>Then, over the next few weeks: taint your GPU nodes, move weights to node-local or zone-local storage, set maximum context length to what you actually use, and find out whether you are still on round-robin. You probably are.</p>
<p>And before the quarter ends, decide who owns the end-to-end latency number, and say it out loud in a room with the other team present.</p>
<h2 id="heading-back-to-thursday">Back to Thursday</h2>
<p>The dashboard was never lying. It was answering a different question.</p>
<p>It was telling you whether the containers were alive, which they were. It could not tell you that requests were queueing behind a badly routed batch, that no new replica was coming for four minutes, that six GPUs were free and unusable, or that the ingress was buffering tokens it should have been streaming. Nothing in the standard toolkit is pointed at any of that.</p>
<p>Getting a model to answer on Kubernetes takes an afternoon. Getting it to answer well when everyone logs in at once is a different discipline, and it looks far more like ordinary infrastructure engineering than the current conversation suggests. Scheduling, routing, capacity, ownership. We have been solving those since long before any of this carried the AI label. The skills are already in the building. They need pointing at the right metric.</p>
<p>A green cluster is where the work starts. What counts is what the person typing the prompt sees.</p>
<p>I hope you’ve enjoyed this and learned something new. I’m always open to suggestions and discussions on <a href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>. Hit me up with direct messages.</p>
<p>If you’ve enjoyed my writing and want to keep me motivated, consider leaving stars on <a href="https://github.com/gursimarsm">GitHub</a> and endorsing me for relevant skills on <a href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>.</p>
<p>Till the next one, happy exploring!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Automate Alert Provisioning with the SigNoz Terraform Provider ]]>
                </title>
                <description>
                    <![CDATA[ Modern infrastructure requires continuous monitoring and rapid incident response. However, manually configuring and managing alerts is not only labor-intensive but also susceptible to human error. Automating alert provisioning allows you to enforce c... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/automate-alert-provisioning-with-the-signoz-terraform-provider/</link>
                <guid isPermaLink="false">67d87353b13a6fd9fb559ada</guid>
                
                    <category>
                        <![CDATA[ observability ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Terraform ]]>
                    </category>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ signoz ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gursimar Singh ]]>
                </dc:creator>
                <pubDate>Mon, 17 Mar 2025 19:09:07 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742237716002/3e7d07f8-39f7-45ba-aac3-d421f61a8785.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Modern infrastructure requires continuous monitoring and rapid incident response. However, manually configuring and managing alerts is not only labor-intensive but also susceptible to human error.</p>
<p>Automating alert provisioning allows you to enforce consistency, secure sensitive credentials, and integrate monitoring into your deployment pipelines.</p>
<p>This guide dives deep into how you can use the SigNoz Terraform Provider to define and manage alert configurations as code, making your observability setup resilient and adaptable.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-why-automate-alert-provisioning">Why Automate Alert Provisioning?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-signoz-and-terraform">What are SigNoz and Terraform?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-overview-of-the-setup">Overview of the Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-steps-to-setup-the-project">Steps to Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-and-security-considerations">Best Practices and Security Considerations</a></p>
</li>
<li><p><a class="post-section-overview" href="#integrating-with-cicd-pipelines">Integrating with CI/CD Pipelines</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-advanced-customizations-and-troubleshooting">Advanced Customizations and Troubleshooting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-why-automate-alert-provisioning">Why Automate Alert Provisioning?</h2>
<p>It’s a good idea to automate your alert provisioning for various reasons.</p>
<p>First of all, configuring things manually often leads to discrepancies between environments (development, staging, production). Automating alerts ensures that all environments adhere to the same monitoring standards, reducing the likelihood of configuration drift and improving consistency and uniformity.</p>
<p>Also, when alerts are defined as code, every change is tracked in your version control system. This audit trail makes it easier to trace and review changes, collaborate with team members, and roll back configurations if issues arise.</p>
<p>Something else to consider is that as your infrastructure grows, manually managing alerts becomes unsustainable. Automation allows you to quickly and efficiently update your alerting rules across multiple services without the need for repetitive manual intervention.</p>
<p>Automation also helps improve security. Storing sensitive information like API tokens as environment variables or in secret management systems helps maintain security. Automating the process also minimizes human exposure to critical credentials.</p>
<p>And finally, defining alerts as code enables you to integrate monitoring configurations into your CI/CD pipelines. This leads to continuous testing, validation, and deployment of alert rules alongside application updates.</p>
<p>So as you can see, there are many compelling reasons to go the automation route. Now let’s see how you can do this in practice.</p>
<h2 id="heading-what-are-signoz-and-terraform">What Are SigNoz and Terraform?</h2>
<p>SigNoz is an open-source observability platform designed to collect, analyze, and visualize metrics, logs, and traces from your applications. Its most helpful features include:</p>
<ul>
<li><p>It has comprehensive monitoring abilities: Provides detailed insights into system performance, error rates, and user behaviors.</p>
</li>
<li><p>It comes equipped with real-time analytics: Enables proactive issue detection and performance optimization.</p>
</li>
<li><p>It’s community-driven: As an open-source solution, it benefits from community contributions, transparency, and customization.</p>
</li>
<li><p>It’s cost-effective: Offers powerful observability capabilities without the hefty licensing fees of proprietary solutions.</p>
</li>
</ul>
<p>Terraform is an Infrastructure as Code (IaC) tool developed by HashiCorp. It allows you to define and provision infrastructure using declarative configuration files. Terraform’s core advantages include:</p>
<ul>
<li><p>Its declarative syntax: You specify the desired state of your infrastructure, and Terraform handles the implementation.</p>
</li>
<li><p>Its version Control: Configuration files can be managed in Git repositories, enabling traceability and rollback of changes.</p>
</li>
<li><p>Powerful automation: Facilitates automated provisioning and updates, reducing manual effort and errors.</p>
</li>
<li><p>Multi-cloud support: Manages resources across different cloud providers with a consistent workflow.</p>
</li>
</ul>
<p>So you might be wondering: why should you use Terraform with SigNoz?</p>
<p>First of all, Terraform ensures that your infrastructure is managed consistently across different environments, reducing the risk of configuration drift. It also simplifies managing multiple alerts and resources, making it easier to scale your observability setup.</p>
<p>Beyond this, automating the provisioning process reduces manual setup efforts and minimizes the potential for human error.</p>
<p>And finally, Terraform configurations can be version-controlled, allowing teams to track changes over time and collaborate more effectively.</p>
<h2 id="heading-overview-of-the-setup">Overview of the Setup</h2>
<p>This setup utilizes the SigNoz Terraform Provider to manage alerts and notification channels within SigNoz Cloud. The configuration includes:</p>
<ul>
<li><p><strong>Provider configuration:</strong> Establishes the connection to SigNoz using the API endpoint and a securely provided API token.</p>
</li>
<li><p><strong>Notification channels:</strong> Defines where alerts are sent (for example, via email) to ensure the right teams are notified.</p>
</li>
<li><p><strong>Alert rules:</strong> Specifies the conditions under which alerts are triggered, including thresholds and evaluation windows.</p>
</li>
<li><p><strong>External variables:</strong> Enhances flexibility by allowing critical values (like CPU thresholds and email addresses) to be managed externally.</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into the setup, make sure you have the following:</p>
<ol>
<li><p><strong>SigNoz Cloud account</strong>: If you don't have one, sign up for SigNoz Cloud to host your observability data and configure alerts.</p>
</li>
<li><p><strong>Terraform installed</strong>: Install Terraform on your machine. Terraform is the tool you'll use to manage your infrastructure as code.</p>
</li>
<li><p><strong>SigNoz API token</strong>:</p>
<ul>
<li><p>Log in to your SigNoz Cloud dashboard.</p>
</li>
<li><p>Navigate to Settings &gt; API Tokens.</p>
</li>
<li><p>Click Generate API Token.</p>
</li>
<li><p>Copy the token, as you'll need it to authenticate Terraform with SigNoz.</p>
</li>
</ul>
</li>
<li><p><strong>Basic knowledge of Terraform</strong>: Familiarity with Terraform's syntax and concepts, including writing configuration files and running Terraform commands, is essential.</p>
</li>
<li><p><strong>Text editor</strong>: Use any code editor like Visual Studio Code or Sublime Text to write your Terraform configuration files.</p>
</li>
</ol>
<h2 id="heading-steps-to-set-up-the-project">Steps to Set Up the Project</h2>
<h3 id="heading-1-understand-the-signozalert-resource">1. Understand the <code>signoz_alert</code> Resource</h3>
<p>The <code>signoz_alert</code> resource allows you to create and manage alert rules in SigNoz via Terraform. It supports various alert types, conditions, and configurations. Understanding this resource is crucial as it forms the basis of your alert configuration.</p>
<h3 id="heading-2-set-up-your-terraform-configuration">2. Set Up Your Terraform Configuration</h3>
<p>Create a new directory for your Terraform configuration:</p>
<pre><code class="lang-bash">mkdir signoz-terraform
<span class="hljs-built_in">cd</span> signoz-terraform
</code></pre>
<p>Create a <a target="_blank" href="http://main.tf"><code>main.tf</code></a> file with the following content:</p>
<pre><code class="lang-json">terraform {
  required_providers {
    signoz = {
      source  = <span class="hljs-attr">"SigNoz/signoz"</span>
      version = <span class="hljs-attr">"0.1.3"</span> # Use the latest version from the Terraform Registry
    }
  }
}

provider <span class="hljs-string">"signoz"</span> {
  endpoint  = <span class="hljs-attr">"https://api.us.signoz.cloud"</span> # Replace with your SigNoz Cloud API endpoint
  api_token = var.signoz_api_token
}

variable <span class="hljs-string">"signoz_api_token"</span> {}
</code></pre>
<p>The <code>provider</code> block configures the SigNoz provider, where <code>endpoint</code> specifies the API endpoint and <code>api_token</code> is passed through a variable for security.</p>
<h3 id="heading-3-define-a-notification-channel-optional">3. Define a Notification Channel (Optional)</h3>
<p>If you plan to send alerts to specific channels, define them using <code>signoz_notification_channel</code>. For example, create a <a target="_blank" href="http://channels.tf"><code>channels.tf</code></a> file:</p>
<pre><code class="lang-json">resource <span class="hljs-string">"signoz_notification_channel"</span> <span class="hljs-string">"email_channel"</span> {
  name = <span class="hljs-attr">"Email Channel"</span>
  type = <span class="hljs-attr">"email"</span>

  receivers {
    email_config {
      to = [<span class="hljs-attr">"alerts@example.com"</span>]
    }
  }
}
</code></pre>
<p>Defining a notification channel ensures that alerts are sent to the correct recipients, enhancing the utility of your alerting system.</p>
<h3 id="heading-4-create-an-alert-using-the-signozalert-resource">4. Create an Alert Using the <code>signoz_alert</code> Resource</h3>
<p>Create an <a target="_blank" href="http://alerts.tf"><code>alerts.tf</code></a> file to define your alert:</p>
<pre><code class="lang-json">resource <span class="hljs-string">"signoz_alert"</span> <span class="hljs-string">"cpu_high_usage"</span> {
  alert            = <span class="hljs-attr">"High CPU Usage Alert"</span>
  alert_type       = <span class="hljs-attr">"METRIC_BASED_ALERT"</span>
  severity         = <span class="hljs-attr">"critical"</span>
  description      = <span class="hljs-attr">"Alert when CPU usage exceeds 80% over 5 minutes"</span>
  rule_type        = <span class="hljs-attr">"threshold_rule"</span>
  broadcast_to_all = false
  disabled         = false
  eval_window      = <span class="hljs-attr">"5m0s"</span>
  frequency        = <span class="hljs-attr">"1m0s"</span>
  version          = <span class="hljs-attr">"v4"</span>

  condition = jsonencode({
    compositeQuery = {
      builderQueries = {
        A = {
          aggregateOperator = <span class="hljs-attr">"avg"</span>
          dataSource        = <span class="hljs-attr">"metrics"</span>
          metricName        = <span class="hljs-attr">"cpu_usage_user"</span>
          reduceTo          = <span class="hljs-attr">"avg"</span>
          filters           = {
            items = []
            op    = <span class="hljs-attr">"AND"</span>
          }
          groupBy = []
        }
      }
      queryType = <span class="hljs-string">"builder"</span>
      panelType = <span class="hljs-string">"graph"</span>
      unit      = <span class="hljs-string">"%"</span>
    }
    op                = <span class="hljs-string">"&gt;"</span>
    target            = <span class="hljs-number">80</span>
    matchType         = <span class="hljs-string">"EQUALS"</span>
    selectedQueryName = <span class="hljs-string">"A"</span>
    targetUnit        = <span class="hljs-string">"%"</span>
  })

  preferred_channels = [signoz_notification_channel.email_channel.name]

  labels = {
    severity = <span class="hljs-attr">"critical"</span>
    team     = <span class="hljs-attr">"DevOps"</span>
  }
}
</code></pre>
<p>This configuration creates a high CPU usage alert with specific conditions and notifications. The <code>condition</code> parameter is crucial as it defines the alert triggering logic.</p>
<h3 id="heading-5-provide-the-api-token">5. Provide the API Token</h3>
<p>Set the <code>signoz_api_token</code> as an environment variable:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> TF_VAR_signoz_api_token=<span class="hljs-string">"YOUR_SIGNOZ_API_TOKEN"</span>
</code></pre>
<p>This ensures that your API token is securely used by Terraform without hardcoding it in your configuration files.</p>
<h3 id="heading-6-initialize-terraform">6. Initialize Terraform</h3>
<p>Run:</p>
<pre><code class="lang-bash">terraform init
</code></pre>
<p>This command initializes your Terraform working directory, downloading necessary plugins, and preparing the environment.</p>
<h3 id="heading-7-review-the-execution-plan">7. Review the Execution Plan</h3>
<p>Generate the execution plan:</p>
<pre><code class="lang-bash">terraform plan
</code></pre>
<p>This step previews the changes Terraform will make, allowing you to verify the configuration before applying it.</p>
<h3 id="heading-8-apply-the-configuration">8. Apply the Configuration</h3>
<p>Apply the changes:</p>
<pre><code class="lang-bash">terraform apply
</code></pre>
<p>Type <code>yes</code> when prompted. This command applies the configuration, creating or updating resources as specified.</p>
<h3 id="heading-9-verify-the-alert-in-signoz-cloud">9. Verify the Alert in SigNoz Cloud</h3>
<p>To do this, follow these steps:</p>
<ul>
<li><p>Log in to your SigNoz Cloud dashboard.</p>
</li>
<li><p>Navigate to Alerts.</p>
</li>
<li><p>Confirm that the "High CPU Usage Alert" is listed.</p>
</li>
<li><p>Click on the alert to view its details and ensure it matches your configuration.</p>
</li>
</ul>
<h3 id="heading-10-modify-the-alert-optional">10. Modify the Alert (Optional)</h3>
<p>To change the CPU usage threshold to 75%, follow these steps:</p>
<ul>
<li><p>Update the target in <a target="_blank" href="http://alerts.tf"><code>alerts.tf</code></a>:</p>
<pre><code class="lang-json">  target = <span class="hljs-number">75</span>
</code></pre>
</li>
<li><p>Apply the changes:</p>
<pre><code class="lang-bash">  terraform apply
</code></pre>
</li>
</ul>
<h3 id="heading-11-destroy-the-resources-optional">11. Destroy the Resources (Optional)</h3>
<p>To remove the alert and notification channel:</p>
<pre><code class="lang-bash">terraform destroy
</code></pre>
<p>Type <code>yes</code> to confirm. This command will delete the resources created by Terraform.</p>
<h2 id="heading-best-practices-and-security-considerations">Best Practices and Security Considerations</h2>
<p>In modern infrastructure automation, robust best practices and security measures are paramount.</p>
<h3 id="heading-use-version-pinning">Use version pinning</h3>
<p>To ensure your alert provisioning remains reliable and maintainable, start with strict version control. Avoid using the latest tag and instead specify an exact version number. This ensures your infrastructure configuration remains consistent and predictable.</p>
<p>By pinning your provider version (for example, use version = "0.1.3" instead of version = "&gt;= 0.1.3".), you eliminate unexpected behavior that can arise from upstream changes. This practice is critical for long-term stability, especially when your infrastructure scales across multiple environments.</p>
<h3 id="heading-externalize-credentials"><strong>Externalize Credentials</strong></h3>
<p>Security is non-negotiable. Instead of embedding sensitive details like API tokens in your codebase, leverage environment variables or dedicated secret management tools such as HashiCorp Vault or AWS Secrets Manager.</p>
<p>For instance, storing your SigNoz API token as an environment variable (TF_VAR_signoz_api_token) not only mitigates the risk of credential exposure but also simplifies the process of credential rotation. Also, enforce access control policies around your configuration repositories and CI/CD pipelines to further secure these secrets.</p>
<h3 id="heading-use-version-control"><strong>Use Version Control</strong></h3>
<p>A mature setup also demands rigorous infrastructure version control. Hosting your Terraform configuration in a Git repository with branch protection and code review policies allows you to track changes meticulously, roll back problematic updates, and maintain an audit trail. This traceability is essential when troubleshooting issues or validating compliance during audits.</p>
<p>You should also document your configuration decisions extensively—explain why a particular CPU threshold was chosen or why specific labels (like severity and team) are used. Such documentation becomes invaluable for onboarding new team members or when revisiting configurations months later.</p>
<h2 id="heading-integrating-with-cicd-pipelines">Integrating with CI/CD Pipelines</h2>
<p>Integrating Terraform with your CI/CD pipeline is a cornerstone of a modern, automated deployment strategy. A well-architected pipeline not only validates your infrastructure changes but also ensures that your alerting rules remain in sync with your evolving application environment.</p>
<p>Continuous Integration (CI) involves automatically merging code changes into a shared repository and running automated tests on each commit. In practice, embedding Terraform plan into your pull request workflow provides early feedback, catching misconfigurations before they reach production. For instance, a GitHub Actions workflow can automatically check your changes:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Terraform</span> <span class="hljs-string">CI/CD</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">main</span>]
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">main</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">terraform:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">Repository</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Terraform</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">hashicorp/setup-terraform@v2</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Terraform</span> <span class="hljs-string">Init</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">terraform</span> <span class="hljs-string">init</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Terraform</span> <span class="hljs-string">Plan</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">terraform</span> <span class="hljs-string">plan</span> <span class="hljs-string">-no-color</span>
        <span class="hljs-attr">env:</span>
          <span class="hljs-attr">TF_VAR_signoz_api_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.SIGNOZ_API_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<p>This workflow uses GitHub secrets to securely manage your API tokens while validating the configuration changes. Continuous Delivery (CD) takes this further by automating deployments. Once your plan is approved, an automated Terraform apply step (often scheduled during off-peak hours or coordinated with application deployments) ensures smooth, coordinated rollouts.</p>
<p>Advanced pipelines can also include automated rollback mechanisms. For example, if a deployment triggers an anomaly, scripts can automatically revert to a previous version using your version control history—minimizing downtime and reinforcing the feedback loop between application performance and infrastructure configuration.</p>
<h2 id="heading-advanced-customizations-and-troubleshooting">Advanced Customizations and Troubleshooting</h2>
<p>As your observability requirements evolve, you may need to implement advanced customizations. One powerful approach is using multi-metric composite alerts. Instead of triggering an alert on a single threshold, you can design rules that combine multiple conditions—for example, firing only when both CPU usage and memory consumption exceed critical levels. This nuanced alerting minimizes false positives and ensures alerts are issued only during genuine performance issues.</p>
<p>Terraform’s modular design is especially useful here. By creating reusable modules that encapsulate your alert configurations, you can parameterize key variables—such as thresholds, evaluation windows, and notification channels—across a microservices architecture. This modularity enforces consistency while simplifying management and scaling.</p>
<p>Troubleshooting advanced configurations starts with reviewing your <code>terraform plan</code> output to ensure every change aligns with expectations. If an alert isn’t triggering as expected, inspect the JSON structure generated by the <code>jsonencode</code> function. Even minor syntax errors can cause significant issues.</p>
<p>When integrating with incident management tools like PagerDuty or Opsgenie, run comprehensive end-to-end tests in a staging environment. For example, deploy a test alert to a dedicated channel to verify that the complete alerting pipeline—from condition detection to incident escalation—is functioning correctly.</p>
<p>In one real-world scenario, a misconfigured composite query in an alert’s JSON payload led to intermittent failures. By enabling detailed provider logs and iteratively validating the JSON output, the issue was rapidly isolated and resolved. Such experiences underscore the importance of rigorous logging, validation, and testing in production-grade setups.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Automating alert provisioning is a transformative approach to managing observability in modern infrastructures.</p>
<p>By defining alerts and notification channels as code, you make your systems more consistent, scalable, secure, and easily integratabtle with CI/CD. You can set up uniform alert rules across all environments, quickly update and deploy monitoring configs, easily handle secure credentials, and automate CI/CD workflows that stay in sync with application changes. They also become easier to integrate with CI/CD workflows.</p>
<p>I hope you’ve enjoyed this tutorial and have learned something new. I’m always open to suggestions and discussions on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>. Hit me up with direct messages.</p>
<p>If you’ve enjoyed my writing and want to keep me motivated, consider leaving starts on <a target="_blank" href="https://github.com/gursimarsm">GitHub</a> and endorsing me for relevant skills on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>.</p>
<p>Till the next one, happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Choose a Cloud Development Environment – Harness CDE, Gitpod, and Coder Compared ]]>
                </title>
                <description>
                    <![CDATA[ Cloud Development Environments (CDEs) have become essential tools in modern software development, offering enhanced productivity and streamlined workflows. This article compares three leading CDEs: Harness CDE, Gitpod, and Coder. My goal here is to o... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-choose-a-cloud-development-environment/</link>
                <guid isPermaLink="false">67a22fc0b7eb4acc424cb220</guid>
                
                    <category>
                        <![CDATA[ Cloud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Gitpod ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Harness ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Development  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Environment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ coder ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gursimar Singh ]]>
                </dc:creator>
                <pubDate>Tue, 04 Feb 2025 15:18:24 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738612280310/a3e39db8-66e9-45f5-9bc1-60cfa426a001.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Cloud Development Environments (CDEs) have become essential tools in modern software development, offering enhanced productivity and streamlined workflows.</p>
<p>This article compares three leading CDEs: Harness CDE, Gitpod, and Coder. My goal here is to offer an objective analysis to help you make informed decisions based on your specific needs.</p>
<h2 id="heading-what-is-a-cloud-development-environment-cde">What is a Cloud Development Environment (CDE)?</h2>
<p>A <strong>Cloud Development Environment (CDE)</strong> is a cloud-hosted workspace where developers can write, test, and deploy code without relying on local machines. Unlike traditional setups, CDEs provide pre-configured environments accessible via a browser or IDE, eliminating the "it works on my machine" problem.</p>
<p>How CDEs differ from traditional development environments</p>
<ul>
<li><p>CDEs are more consistent and help standardize tools, dependencies, and configurations across teams.</p>
</li>
<li><p>They’re also accessible from anywhere, enabling remote collaboration.</p>
</li>
<li><p>They’re more scalable, as resources (CPU, memory) scale dynamically based on workload.</p>
</li>
<li><p>And they’re secure, with centralized security controls and compliance adherence (for example, SOC 2, GDPR).</p>
</li>
</ul>
<h3 id="heading-common-cde-features"><strong>Common CDE Features</strong></h3>
<p>Most CDEs come with a variety of helpful features. They typically have pre-built environment templates (for example, Python, Node.js) and integrate easily with Git repositories and CI/CD pipelines. They also have various real-time collaboration tools, as well as the ability to automate backups and recovery.</p>
<p>You’ll learn more about specific features when we discuss each of our CDE options below.</p>
<h2 id="heading-the-case-for-cloud-based-development"><strong>The Case for Cloud-Based Development</strong></h2>
<p>CDEs can help you and your team solve some critical pain points:</p>
<h3 id="heading-cdes-make-setup-easier">CDEs make setup easier</h3>
<p>When using a CDE, you don’t have the hassle of setting up local machines. Instead, you have a pre-configured development environment that’s ready to go in minutes. With a traditional setup, you have to install dependencies, configure environments, and resolve compatibility issues – and this can take hours or even days. CDEs make this process much easier.</p>
<p>Let’s say a new developer joins your project that requires a complex stack – it needs a specific Python version, multiple frameworks, and environment variables. Instead of spending hours configuring their local machine, they can just launch a cloud-based workspace (like one of the tools we’ll discuss here), which comes pre-loaded with everything they need.</p>
<h3 id="heading-cdes-help-reduce-costs">CDEs help reduce costs</h3>
<p>CDEs can reduce your costs by making sure that development resources are allocated only when they’re needed. Unlike local machines, which require upfront investment in high-performance hardware, cloud environments help you scale resources dynamically and pay only for the compute power you and your team use.</p>
<p>Perhaps your team is developing a resource-intensive AI application. If you’re using a CDE, you’ll no longer need to provide every developer with an expensive workstation. Instead, you can just provision high-performance cloud instances when needed and shut them down when idle. This cuts down on unnecessary spending.</p>
<h3 id="heading-cdes-enhance-security">CDEs enhance security</h3>
<p>With cloud-based environments, code and sensitive data remain on secure, centralized servers rather than being stored on individual developer machines. This helps reduce the risk of data loss or theft. CDEs also provide audit logs, identity management, and automated backups, all of which help make things more security.</p>
<p>Let’s say a financial services company requires strict security controls over customer data. By using a CDE, the developers on the team can access code via secure connections without storing sensitive files locally. This helps ensure compliance with industry regulations like SOC 2 or GDPR.</p>
<h3 id="heading-cdes-enable-global-collaboration">CDEs enable global collaboration</h3>
<p>CDEs make collaboration among distributed teams much easier by allowing multiple developers to work in the same environment with shared configurations. Remote developers can contribute from anywhere without worrying about compatibility issues or inconsistent setups.</p>
<p>For example, perhaps your global development team is working on a SaaS product. They can use a CDE to collaborate in real time. A member of your dev team in India can start debugging an issue, and then a teammate in the US can pick up where they left off hours later without needing to set up the same environment locally.</p>
<h2 id="heading-methodology"><strong>Methodology</strong></h2>
<p>This analysis is based on official documentation, user reviews, and independent testing. All information is current as of the last update date. The article is focused on key aspects such as features, deployment options, security, pricing, and use cases.</p>
<h2 id="heading-overview-of-each-tool"><strong>Overview of Each Tool</strong></h2>
<h3 id="heading-harness-cde">Harness CDE</h3>
<p>Harness CDE is part of the broader Harness platform, designed to streamline software delivery with integrated CI/CD pipelines, feature flags, and cloud cost management. It provides enterprise-grade security, a user-friendly interface, and robust integration capabilities, making it ideal for large-scale applications.</p>
<p>With its comprehensive suite of tools and advanced cost management, Harness CDE helps enterprises efficiently manage their entire development lifecycle. Harness CDE's intuitive interface and detailed documentation further enhance its suitability for large-scale applications.</p>
<h4 id="heading-drawbacks"><strong>Drawbacks</strong></h4>
<p>Despite its many strengths, Harness CDE is relatively new to the market, meaning its features and capabilities are still evolving. Deep integration with the Harness platform could make switching challenging.</p>
<h3 id="heading-gitpod">Gitpod</h3>
<p>Gitpod is a SaaS solution that provides automated, ready-to-code development environments. It integrates seamlessly with popular version control systems like GitHub, GitLab, and Bitbucket, offering fast and consistent setups.</p>
<p>Gitpod is known for its user-friendly web interface and quick onboarding process, which significantly reduces setup times and lets devs focus on coding rather than environment configuration. This makes it ideal for agile development teams and startups.</p>
<h4 id="heading-drawbacks-1"><strong>Drawbacks</strong></h4>
<p>Gitpod's SaaS model offers limited control over infrastructure, which can be a disadvantage for teams needing more customization and control. Also, dedicated instances can be more costly, potentially offsetting some of the benefits of its free plan.</p>
<h3 id="heading-coder">Coder</h3>
<p>Coder is an open-source platform offering both free and self-managed (paid) options. It provides highly customizable, secure, and scalable development environments that you can host on your infrastructure. This makes it suitable for organizations needing tailored solutions.</p>
<p>Coder excels in environments where stringent security and compliance requirements are paramount, offering extensive control and customization.</p>
<h4 id="heading-drawbacks-2"><strong>Drawbacks</strong></h4>
<p>Coder requires more setup time and maintenance compared to Gitpod and Harness CDE. Its reliance on self-managed infrastructure can also increase complexity and cost, particularly for smaller teams or startups without dedicated DevOps resources.</p>
<h2 id="heading-detailed-feature-comparison">Detailed Feature Comparison</h2>
<p>Now let’s compare some basic features to see how these three tools stack up against each other.</p>
<h3 id="heading-deployment-and-scalability">Deployment and Scalability</h3>
<ul>
<li><p><strong>Harness CDE</strong>: Integrated with the Harness &amp; Gitness platforms, offering high scalability within the Harness ecosystem.</p>
</li>
<li><p><strong>Gitpod</strong>: SaaS model with easy scalability and options for managed dedicated instances.</p>
</li>
<li><p><strong>Coder</strong>: Self-managed deployment with full control over infrastructure, providing high scalability for tailored environments.</p>
</li>
</ul>
<h3 id="heading-integration-and-user-experience">Integration and User Experience</h3>
<ul>
<li><p><strong>Harness CDE</strong>: Comprehensive suite of development tools, intuitive interface, and detailed documentation.</p>
</li>
<li><p><strong>Gitpod</strong>: Seamless integration with GitHub, GitLab, and Bitbucket, featuring automated setups and excellent documentation.</p>
</li>
<li><p><strong>Coder</strong>: Integrates with existing infrastructure and various tech stacks, providing detailed documentation and customizable configurations.</p>
</li>
</ul>
<h3 id="heading-security-and-compliance">Security and Compliance</h3>
<ul>
<li><p><strong>Harness CDE</strong>: Enterprise-grade security features, including SOC 2 compliance, role-based access control, and advanced secrets management. Offers comprehensive audit logging and governance with policy-as-code support.</p>
</li>
<li><p><strong>Gitpod</strong>: Secure environments with data encryption, SOC 2 compliant.</p>
</li>
<li><p><strong>Coder</strong>: Focuses on security and compliance, supporting various standards like HIPAA and GDPR.</p>
</li>
</ul>
<h3 id="heading-costpricing">Cost/Pricing</h3>
<ul>
<li><p><strong>Harness CDE</strong>: Competitive pricing with integrated platform features. A lot of features are free to use. Pricing varies based on scale and needs – contact Harness for details.</p>
</li>
<li><p><strong>Gitpod</strong>: Varies with free and paid plans, limited customization based on SaaS offerings. The free plan includes 50 hours/month, while paid plans offer unlimited hours.</p>
</li>
<li><p><strong>Coder</strong>: Costs depend on self-managed infrastructure, offering high customization and control over environment setup. The tool is free for open-source use, and paid for self-managed deployments.</p>
</li>
</ul>
<h3 id="heading-setup-time-and-user-interface">Setup Time and User Interface</h3>
<ul>
<li><p><strong>Harness CDE</strong>: Fast setup with integrated CI/CD pipeline and modern, intuitive interface.</p>
</li>
<li><p><strong>Gitpod</strong>: Quick setup in minutes with a user-friendly, web-based interface.</p>
</li>
<li><p><strong>Coder</strong>: Setup time varies based on custom configurations, offering a flexible and customizable interface.</p>
</li>
</ul>
<h3 id="heading-availability">Availability</h3>
<ul>
<li><p><strong>Harness CDE</strong>: Part of the Harness platform, typically targeted at enterprise users.</p>
</li>
<li><p><strong>Gitpod</strong>: SaaS model with both free and paid plans.</p>
</li>
<li><p><strong>Coder</strong>: Open-source with both free and self-managed (paid) options.</p>
</li>
</ul>
<h3 id="heading-specs">Specs</h3>
<ul>
<li><p><strong>Harness CDE</strong>: Integrated CI/CD, feature flags, cloud cost management, enterprise-grade security, and so on.</p>
</li>
<li><p><strong>Gitpod</strong>: Automated setups, seamless integration with VCS, user-friendly interface.</p>
</li>
<li><p><strong>Coder</strong>: Highly customizable, secure, scalable, extensive control.</p>
</li>
</ul>
<h3 id="heading-additional-features"><strong>Additional Features</strong></h3>
<p>Here’s a detailed table that includes info on a bunch of other features that might help you make your decision as to which tool is best for you.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Feature</td><td>Harness CDE</td><td>Gitpod</td><td>Coder</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Data Storage</strong></td><td>Integrated with Harness</td><td>External, cloud-based storage</td><td>On-premises, cloud options available</td></tr>
<tr>
<td><strong>Resource Management</strong></td><td>Automated scaling</td><td>Easy resource allocation</td><td>Customizable resource allocation</td></tr>
<tr>
<td><strong>Monitoring and Logging</strong></td><td>Integrated monitoring tools</td><td>External tools (e.g., Grafana)</td><td>Integrated and external options</td></tr>
<tr>
<td><strong>Performance</strong></td><td>High, optimized for enterprise use</td><td>High, optimized for cloud</td><td>High, depends on infrastructure</td></tr>
<tr>
<td><strong>Updates and Maintenance</strong></td><td>Automated updates</td><td>Regular updates, easy maintenance</td><td>Manual updates, customizable maintenance</td></tr>
<tr>
<td><strong>Community Support</strong></td><td>Growing community, active forums</td><td>Active community, strong documentation</td><td>Large community, extensive documentation</td></tr>
<tr>
<td><strong>Learning Curve</strong></td><td>Moderate, user-friendly</td><td>Low, easy to start</td><td>Moderate, flexible setup</td></tr>
<tr>
<td><strong>CI/CD Integration</strong></td><td>Built-in CI/CD pipelines</td><td>Supports CI/CD via third-party integrations</td><td>Requires custom setup for CI/CD</td></tr>
<tr>
<td><strong>Collaboration Features</strong></td><td>Integrated collaboration tools</td><td>Collaboration through VCS integrations</td><td>Customizable collaboration tools</td></tr>
<tr>
<td><strong>Container Support</strong></td><td>Native Docker support</td><td>Supports containerized environments</td><td>Full containerization support</td></tr>
<tr>
<td><strong>Cost Management</strong></td><td>Integrated cost management</td><td>No built-in cost management</td><td>Requires external tools for cost management</td></tr>
<tr>
<td><strong>Workflow Automation</strong></td><td>Extensive automation features</td><td>Basic automation through scripts</td><td>High customizability for automation</td></tr>
<tr>
<td><strong>Version Control Support</strong></td><td>Seamless VCS integration</td><td>Native support for Git-based VCS</td><td>Customizable VCS integration</td></tr>
<tr>
<td><strong>API Access</strong></td><td>Comprehensive API access</td><td>Robust API for integration</td><td>Full API support for custom integration</td></tr>
<tr>
<td><strong>Code Reviews</strong></td><td>Built-in code review tools</td><td>Code reviews through VCS integrations</td><td>Customizable code review processes</td></tr>
<tr>
<td><strong>Branch Management</strong></td><td>Advanced branch management</td><td>Supports branch management through VCS</td><td>Customizable branch management</td></tr>
<tr>
<td><strong>Testing Tools</strong></td><td>Integrated testing tools</td><td>Requires third-party testing tools</td><td>Full integration with various testing tools</td></tr>
<tr>
<td><strong>Data Backup and Recovery</strong></td><td>Automated backup and recovery</td><td>Limited backup options</td><td>Requires custom setup for backup and recovery</td></tr>
<tr>
<td><strong>Cloud Provider Compatibility</strong></td><td>Supports multiple cloud providers</td><td>Primarily cloud-agnostic</td><td>Fully compatible with various cloud providers</td></tr>
<tr>
<td><strong>Onboarding Time</strong></td><td>Fast, guided onboarding</td><td>Quick, automated onboarding</td><td>Varies, depending on custom configurations</td></tr>
<tr>
<td><strong>Multi-language Support</strong></td><td>Extensive support for multiple languages</td><td>Supports many languages</td><td>Full support for various programming languages</td></tr>
<tr>
<td><strong>User Authentication</strong></td><td>Integrated authentication options</td><td>Basic authentication options</td><td>Comprehensive, customizable authentication</td></tr>
<tr>
<td><strong>Secrets Management</strong></td><td>Built-in secrets management</td><td>Requires third-party tools</td><td>Full support for secrets management</td></tr>
<tr>
<td><strong>Pipeline Visualization</strong></td><td>Advanced, intuitive pipeline visualization</td><td>Basic pipeline visualization</td><td>Customizable pipeline visualization</td></tr>
<tr>
<td><strong>Environment Provisioning</strong></td><td>Automated, scalable environment provisioning</td><td>Fast, on-demand environment provisioning</td><td>Flexible environment provisioning</td></tr>
<tr>
<td><strong>License Model</strong></td><td>Open-source and commercial licenses</td><td>Open-source and commercial licenses</td><td>Open-source and commercial licenses</td></tr>
<tr>
<td><strong>Network Isolation</strong></td><td>Built-in network isolation features</td><td>Limited network isolation</td><td>Advanced network isolation options</td></tr>
<tr>
<td><strong>Role-based Access Control</strong></td><td>Comprehensive RBAC</td><td>Basic RBAC</td><td>Advanced RBAC</td></tr>
<tr>
<td><strong>Audit Logging</strong></td><td>Detailed audit logging</td><td>Basic audit logging</td><td>Extensive audit logging</td></tr>
<tr>
<td><strong>Governance with Policy as Code</strong></td><td>Supports OPA-based policies</td><td>Limited</td><td>Advanced governance features</td></tr>
<tr>
<td><strong>Feature Flags</strong></td><td>Integrated, robust feature flag management</td><td>Requires third-party tools</td><td>Full support for feature flag management</td></tr>
<tr>
<td><strong>Internal Developer Portal</strong></td><td>Comprehensive internal developer portal</td><td>Limited</td><td>Advanced portal capabilities</td></tr>
<tr>
<td><strong>Software Supply Chain Management</strong></td><td>Integrated, secure supply chain features</td><td>Limited</td><td>Requires custom setup</td></tr>
<tr>
<td><strong>Service Reliability Management</strong></td><td>Real-time insights and reliability</td><td>Limited</td><td>Requires third-party tools</td></tr>
<tr>
<td><strong>Chaos Engineering</strong></td><td>Built-in chaos engineering tools</td><td>Requires third-party tools</td><td>Full support for chaos engineering</td></tr>
<tr>
<td><strong>Self-Managed Options</strong></td><td>Available for enterprise</td><td>Not available</td><td>Available</td></tr>
<tr>
<td><strong>Code Repository Integration</strong></td><td>Seamless integration with Git-based repositories</td><td>Limited</td><td>Full support for various repositories</td></tr>
<tr>
<td><strong>APM Integration</strong></td><td>Comprehensive APM integration</td><td>Requires third-party tools</td><td>Full support for APM integration</td></tr>
<tr>
<td><strong>Artifact Management</strong></td><td>Integrated artifact management</td><td>Limited</td><td>Full support for artifact management</td></tr>
<tr>
<td><strong>Cloud Cost Management</strong></td><td>Advanced cloud cost management features</td><td>No built-in cost management</td><td>Requires third-party tools</td></tr>
<tr>
<td><strong>AI and ML Support</strong></td><td>Built-in tools for AI/ML workflows</td><td>Requires third-party tools</td><td>Extensive support for AI/ML</td></tr>
</tbody>
</table>
</div><h3 id="heading-how-to-choose-the-right-tool"><strong>How to Choose the Right Tool</strong></h3>
<p>As you can see, each of these cloud development environments has its strengths. It’s up to you to analyze them and decide which tool is right for you. Here’s a quick summary:</p>
<ul>
<li><p>Harness CDE offers the fastest startup times and a straightforward, performance-focused approach.</p>
</li>
<li><p>Gitpod provides the widest language support and a large community, with competitive pricing.</p>
</li>
<li><p>Coder excels in security, compliance, and customization.</p>
</li>
</ul>
<p>When choosing a CDE, consider the following factors:</p>
<ul>
<li><p>Team size and structure</p>
</li>
<li><p>Existing technology stack</p>
</li>
<li><p>Security and compliance requirements</p>
</li>
<li><p>Budget constraints</p>
</li>
<li><p>Customization needs</p>
</li>
<li><p>Scalability requirements</p>
</li>
<li><p>Integration with existing tools and workflows</p>
</li>
</ul>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this guide, you learned about three CDE tools and their main features. Which of these tools you choose will largely depend on your specific needs.</p>
<p>Ultimately, I recommend that you take advantage of any free trials or demos offered by these platforms to get hands-on experience before making a decision. Consider your team's specific workflows, the technologies you use, and your scalability needs when choosing a cloud development environment.</p>
<h3 id="heading-references"><strong>References</strong></h3>
<ul>
<li><p><a target="_blank" href="https://developer.harness.io/docs/">Harness Docs</a></p>
</li>
<li><p><a target="_blank" href="https://www.gitpod.io/docs/introduction">Gitpod Docs</a></p>
</li>
<li><p><a target="_blank" href="https://coder.com/docs">Coder Docs</a></p>
</li>
</ul>
<p>Note: This article is for informational purposes only. Everyone should conduct their own thorough evaluation based on their specific requirements before making a decision.</p>
<p>I hope you’ve enjoyed it and have learned something new. I’m always open to suggestions and discussions on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>. Hit me up with direct messages.</p>
<p>If you’ve enjoyed my writing and want to keep me motivated, consider leaving starts on <a target="_blank" href="https://github.com/gursimarsm">GitHub</a> and endorsing me for relevant skills on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>.</p>
<p>Till the next one, happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an EKS Cluster Across AWS Local Zones using the AWS CDK ]]>
                </title>
                <description>
                    <![CDATA[ AWS Local Zones are a new type of infrastructure that enables you to build and run applications closer to end-users, providing low latency and improved performance.  They are designed to provide the same high availability and reliability as an AWS Re... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-an-eks-cluster-using-aws-local-zones-with-aws-cdk/</link>
                <guid isPermaLink="false">66c4c5a3d788a9c53d88d2d9</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gursimar Singh ]]>
                </dc:creator>
                <pubDate>Tue, 28 May 2024 14:34:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/pexels-pixabay-357742.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>AWS Local Zones are a new type of infrastructure that enables you to build and run applications closer to end-users, providing low latency and improved performance. </p>
<p>They are designed to provide the same high availability and reliability as an AWS Region, but with the added benefit of low-latency connections for applications that require it.</p>
<p>Using Local Zones can be particularly helpful if you have end users located in specific geographic areas and want to provide them with low-latency access to their applications. This can be especially important for applications that require real-time data processing or have strict performance requirements.</p>
<p>Local Zones can also minimize network expenses, which is an additional advantage. By executing applications in a Local Zone closer to end users, you can limit the quantity of data that must be transferred over long distances, which reduces network costs.</p>
<p>In this tutorial, we will see how to build a hybrid edge EKS cluster that spans across the AWS Regions and AWS Local Zones using both AWS Management Console and AWS Cloud Development Kit (CDK).</p>
<p>Before getting started, it's important to note that AWS Local Zones are physically separate locations that are connected to the main AWS region through high-speed links. They allow you to run certain services closer to your customers and reduce latency.</p>
<p>To build your EKS cluster across Local Zones, you will need to:</p>
<ol>
<li>Create an EKS cluster in the main region</li>
<li>Create a VPC and associated resources in the Local Zones</li>
<li>Connect the Local Zone VPCs to the main region VPC</li>
<li>Launch worker nodes in the Local Zone VPCs</li>
</ol>
<p>We'll walk through these steps in this guide.</p>
<p><img src="https://lh3.googleusercontent.com/-kdtf6vkPfxVY3aLcGpqQI5wczBZXfcScdCz2z1bhNSuawjGEJyLEznPfB5mqnupfuVsPCNybRHJViCjLTxKmF5F2zq82LdHvRmnItjDFTrPDtTRhAzAgr7ToL8bhuymqSkCpVei2VcPyFdjz7YQC_w" alt="Image" width="860" height="640" loading="lazy">
<em>Architecture Diagram</em></p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>Before we begin, you need to have the following:</p>
<ol>
<li>An AWS account with permissions to create resources in AWS Wavelength and AWS Local Zones.</li>
<li>AWS CDK installed on your local machine. If you don't have it installed, you can follow the instructions in the AWS CDK documentation to install it.</li>
<li>AWS CLI installed on your local machine. If you don't have it installed, you can follow the instructions in the AWS CLI documentation to install it.</li>
</ol>
<p>Finally, let’s get started.</p>
<h2 id="heading-step-1-create-an-aws-local-zone">Step 1: Create an AWS Local Zone</h2>
<p>The first step is to opt-in to AWS Local Zones in the region of your choice. You can follow the instructions in the <a target="_blank" href="https://docs.aws.amazon.com/local-zones/latest/ug/getting-started.html">AWS Local Zones documentation</a> to opt-in to these zones.</p>
<h2 id="heading-step-2-create-a-cdk-project">Step 2: Create a CDK Project</h2>
<p>To start, we need to create a new CDK project using the following command:</p>
<pre><code>cdk init --language=javascript
</code></pre><p>This will create a new directory with the required files and directories for a CDK project.</p>
<p>Next, install the required dependencies using the following command:</p>
<pre><code>npm install
</code></pre><p>Now, let's create a new file called local-zone-eks.js in the lib directory and add the following code:</p>
<pre><code><span class="hljs-keyword">const</span> cdk = <span class="hljs-built_in">require</span>(<span class="hljs-string">'aws-cdk-lib'</span>);
<span class="hljs-keyword">const</span> ec2 = <span class="hljs-built_in">require</span>(<span class="hljs-string">'aws-cdk-lib/aws-ec2'</span>);
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> autoscaling <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-cdk/aws-autoscaling'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> ecs <span class="hljs-keyword">from</span> <span class="hljs-string">'@aws-cdk/aws-eks'</span>;

<span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-keyword">const</span> config = {
  <span class="hljs-attr">env</span>: {
    <span class="hljs-attr">account</span>: process.env.AWS_ACCOUNT_NUMBER,
    <span class="hljs-attr">region</span>: process.env.AWS_REGION,
  },
};


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VPCStack</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">cdk</span>.<span class="hljs-title">Stack</span> </span>{
  <span class="hljs-keyword">constructor</span>(scope, id, props) {
    <span class="hljs-built_in">super</span>(scope, id, props);

    <span class="hljs-comment">// Create a VPC </span>
    <span class="hljs-keyword">const</span> vpc = <span class="hljs-keyword">new</span> ec2.Vpc(<span class="hljs-built_in">this</span>, <span class="hljs-string">'VPC'</span>, {
      <span class="hljs-attr">cidr</span>: <span class="hljs-string">'10.0.0.0/16'</span>,
      <span class="hljs-attr">maxAzs</span>: <span class="hljs-number">2</span>,
      <span class="hljs-attr">subnetConfiguration</span>: [
        {
          <span class="hljs-attr">cidrMask</span>: <span class="hljs-number">24</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Public'</span>,
          <span class="hljs-attr">subnetType</span>: ec2.SubnetType.PRIVATE,
        },
        {
          <span class="hljs-attr">cidrMask</span>: <span class="hljs-number">24</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Private'</span>,
          <span class="hljs-attr">subnetType</span>: ec2.SubnetType.PRIVATE,
        },
      ],
    });
  }
}

<span class="hljs-built_in">module</span>.exports = { VPCStack };
</code></pre><p>This code creates a new VPC with a CIDR block of 10.0.0.0/16, which spans across two private subnets. </p>
<p>Next, let’s export the environment variable for our AWS Local Zone, which we will use to create the only public subnet in our VPC. In this example, we have selected the Las Vegas Local Zone and have configured the subnet accordingly.</p>
<pre><code><span class="hljs-keyword">const</span> localZone: string = <span class="hljs-string">'us-west-2-las-1a’

 // Create Local Zone Public Subnet
    const LocalZoneSubnet = new ec2.PublicSubnet(this, '</span>localzone-public-subnet<span class="hljs-string">', {
      availabilityZone: localZone,
      cidrBlock: '</span><span class="hljs-number">10.0</span><span class="hljs-number">.3</span><span class="hljs-number">.0</span>/<span class="hljs-number">26</span><span class="hljs-string">',
      vpcId: vpc.vpcId,
      mapPublicIpOnLaunch: true,
    });

    // Add Local Zone Subnet to VPC
    vpc.publicSubnets.push(LocalZoneSubnet);</span>
</code></pre><h2 id="heading-step-3-create-an-amazon-eks-cluster">Step 3: Create an Amazon EKS Cluster</h2>
<p>Now that we have a VPC, we can create an Amazon Elastic Container Service for Kubernetes (Amazon EKS) cluster.</p>
<p>Add the following code to the local-zone-eks.js file:</p>
<pre><code><span class="hljs-keyword">const</span> eks = <span class="hljs-built_in">require</span>(<span class="hljs-string">'aws-cdk-lib/aws-eks'</span>);

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EKSStack</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">cdk</span>.<span class="hljs-title">Stack</span> </span>{
  <span class="hljs-keyword">constructor</span>(scope, id, props) {
    <span class="hljs-built_in">super</span>(scope, id, props);
    <span class="hljs-comment">// Create the EKS cluster</span>
    <span class="hljs-keyword">const</span> cluster = <span class="hljs-keyword">new</span> eks.Cluster(<span class="hljs-built_in">this</span>, <span class="hljs-string">'EKSCluster'</span>, {
      <span class="hljs-attr">vpc</span>: vpc,
      <span class="hljs-attr">defaultCapacity</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">version</span>: <span class="hljs-string">'1.21'</span>,
      <span class="hljs-attr">clusterName</span>: <span class="hljs-string">'local-zone-eks-demo-cluster'</span>,
    });
  }
}
<span class="hljs-built_in">module</span>.exports = { EKSStack };
</code></pre><p>This code creates a new EKS cluster using the VPC we created earlier. It also specifies the Kubernetes version to use and the name of the cluster.</p>
<h2 id="heading-step-4-create-worker-nodes">Step 4: Create Worker Nodes</h2>
<p>Next, we need to create worker nodes to run our applications on the EKS cluster.</p>
<p>Add the following code to the local-zone-eks.js file:</p>
<pre><code><span class="hljs-comment">// Define EKS-optimized image for Launch Template</span>
    <span class="hljs-keyword">const</span> image = <span class="hljs-keyword">new</span> ecs.EksOptimizedAmi();

    <span class="hljs-comment">// Create Launch Template for Auto Scaling group to reference</span>
    <span class="hljs-keyword">const</span> lzLaunchTemplate = <span class="hljs-keyword">new</span> ec2.CfnLaunchTemplate(
      <span class="hljs-built_in">this</span>,
      <span class="hljs-string">'eks-launch-template'</span>,
      {
        <span class="hljs-attr">launchTemplateName</span>: <span class="hljs-string">'lz-launch-template'</span>,
        <span class="hljs-attr">launchTemplateData</span>: {
          <span class="hljs-attr">networkInterfaces</span>: [
            {
              <span class="hljs-attr">deviceIndex</span>: <span class="hljs-number">0</span>,
              <span class="hljs-attr">associatePublicIpAddress</span>: <span class="hljs-literal">true</span>,
              <span class="hljs-attr">deleteOnTermination</span>: <span class="hljs-literal">true</span>,
              <span class="hljs-attr">subnetId</span>: LocalZoneSubnet.subnetId!,
            },
          ],
          <span class="hljs-attr">imageId</span>: image.getImage(<span class="hljs-built_in">this</span>).imageId,
          <span class="hljs-attr">instanceType</span>: <span class="hljs-string">'t3.medium'</span>,
          <span class="hljs-attr">userData</span>: cdk.Fn.base64(
            <span class="hljs-string">`#!/bin/bash -xe
          set -o xtrace
          /etc/eks/bootstrap.sh ‘local-zone-eks-demo-cluster’}
            )
        },
      }
    );

 // Create Auto Scaling Group
    const lz_asg = new autoscaling.AutoScalingGroup(this, 'LocalZoneWorkerNodes', {
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
      machineImage: new ecs.EksOptimizedAmi(),
      updateType: autoscaling.UpdateType.REPLACING_UPDATE,
      desiredCapacity: 1,
      vpc: vpc,
    launchTemplate: lzLaunchTemplate
    });</span>
</code></pre><p>This code creates a new auto-scaling group to manage the worker nodes, and adds the worker nodes to the EKS cluster using the instance bootstrap script.</p>
<h2 id="heading-step-5-deploy-the-cdk-app">Step 5: Deploy the CDK App</h2>
<p>Now that we have all the required code, we can deploy it using the following command:</p>
<pre><code>cdk deploy
</code></pre><p>With your EKS cluster up and running, you can start deploying your applications. You can use Kubernetes manifests or Helm charts to deploy your applications to the cluster.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>AWS Local Zones provide a robust mechanism for providing high-performance applications to end users, independent of their location. They also give end users a better experience and deliver great performance.</p>
<p>I’m always open to suggestions and discussions on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>. Hit me up with direct messages.</p>
<p>If you’ve enjoyed my writing and want to keep me motivated, consider leaving stars on <a target="_blank" href="https://github.com/gursimarsm">GitHub</a> and endorse me for relevant skills on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>.</p>
<p>Till the next one, stay safe and keep learning.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is RAM? How to Access Your Computer's RAM and Read the Contents ]]>
                </title>
                <description>
                    <![CDATA[ This article is a comprehensive guide on how to read the contents of your computer's RAM.  Random Access Memory (RAM) is a crucial component of any computer system, and it is responsible for temporarily storing data that is required by the system to ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-access-and-read-ram-contents/</link>
                <guid isPermaLink="false">66c4c5a926a77d9936ef0a61</guid>
                
                    <category>
                        <![CDATA[ Computer Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hardware ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gursimar Singh ]]>
                </dc:creator>
                <pubDate>Mon, 24 Apr 2023 19:31:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/ram-article.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This article is a comprehensive guide on how to read the contents of your computer's RAM. </p>
<p>Random Access Memory (RAM) is a crucial component of any computer system, and it is responsible for temporarily storing data that is required by the system to carry out its functions. But the contents of RAM can be quite volatile, and they are usually lost when the system is shut down.</p>
<p>One way to preserve the contents of RAM is by performing a RAM dump, which is a process of copying the contents of RAM onto a storage device, such as a hard drive. You can analyze the RAM dump, and the data contained within it can provide valuable insights into the system's state at the time the dump was taken.</p>
<p>In this article, I will walk you through the process of reading the contents of RAM, as well as explain what a RAM dump is and how it can be useful in analyzing a computer system. I will also provide you with step-by-step instructions on how to perform a RAM dump and how to analyze the resulting data.</p>
<h2 id="heading-why-read-ram-data">Why Read RAM Data?</h2>
<p>Reading data from the disc is something you might be familiar with doing. But can we also read data straight from the RAM, where the most essential information is stored?</p>
<p>As developers, we can investigate the space complexity and delve further into the RAM to understand what is going on.</p>
<p>Accessing and reading the contents of RAM can be useful in a variety of scenarios. One common use case is for troubleshooting and diagnosing issues with a computer system. By examining the contents of RAM, you can gain insights into the state of the system at a particular point in time. </p>
<p>For example, if your computer suddenly crashes, examining the contents of RAM can help you identify the cause of the crash.</p>
<p>Another use case is for forensic analysis. When investigating a computer system for evidence of wrongdoing, examining the contents of RAM can provide valuable insights into the activities that were being carried out on the system. </p>
<p>For example, a security professional may use RAM analysis to determine whether a particular process was running on the system or to identify files that were recently accessed.</p>
<p>In addition, accessing and reading the contents of RAM can also be useful for software developers and researchers. By analyzing the data stored in RAM, developers can gain insights into the performance of their software and identify potential issues or bottlenecks. Researchers can also use RAM analysis to study the behavior of malware or to develop new security tools and techniques.</p>
<p>Overall, accessing and reading the contents of RAM can be useful for troubleshooting, forensic analysis, software development, and research. It provides a valuable way to gain insights into the inner workings of a computer system and can help identify issues and potential security threats.</p>
<p>Before we move further into the specifics, let's take a short look at the nomenclature. This may be common knowledge, but you'll need to understand the terminology as you go through this guide, so it's worth a review.</p>
<h2 id="heading-what-is-ram">What is RAM?</h2>
<p>There's a physical hardware device called RAM (which stands for Random Access Memory): the physical memory, a CPU, a hard disk, and other physical components.</p>
<p>On top of this, we have the operating system. The operating system is always in conversation with the piece of hardware known as the "kernel" – and this is one of the most critical aspects of this software.</p>
<p>If we consider things from the user's point of view, we initially log in to the operating system so that we can carry out our tasks, the majority of which include executing applications.</p>
<h3 id="heading-what-is-the-kernel">What is the Kernel?</h3>
<p>A kernel is a fundamental portion of an operating system that accepts the instructions from the user with the aid of the program we run behind the scenes. This may happen regardless of the program that we run behind the scenes.</p>
<p>Everything that has to be computed is handled by the central processing unit (CPU), but whatever we do and however we manage the services provided by the CPU, the data, instructions, code, and program must all go via the random access memory (RAM).</p>
<p>This implies that the results of anything we do with the data at any given moment in time will be available on top of the memory. If you are a programmer and you're constructing some kind of data structure, this indicates that all of the data will live on top of the RAM.</p>
<p>We can directly go to the RAM and see how the data structures have been created and how they align, and we can see how the space complexity works there.</p>
<p>For instance, if we are discussing any web browser, such as Chrome, there may have been security flaws generated in an application. So the most effective method is to navigate to the RAM and investigate how the data has been operating.</p>
<p>Let's say you open any secure website in Chrome (or any browser), like gmail.com. Any information you enter into Gmail, including your username and password, is sent over the internet to a server run by Google. That data has been fully encrypted, and it will be challenging, if not impossible, to crack the password.</p>
<p>But in order to enter your password, you likely use a computer with a keyboard attached to it. After that, some programs will encrypt the data and send it to the internet. This means that initially, your data was present in the RAM.</p>
<p>First, the password is standard data, and the password goes and lands on the top of the RAM. Then, some programs will encrypt the data and send it to the internet. If you can access the RAM, you can examine it to determine whether or not your password has been encrypted. And this process is pretty straightforward.</p>
<p>Let's look at an example to see how this works. We'll pretend that "a" is a variable and "9" is the data. When we execute the program, this data loads onto the RAM. When the program ends, the data from the RAM will be gone, although nobody has proven it yet. But this is the case, and we can prove it with a little investigation.</p>
<p>So how can we check whether or not this data is still present in the RAM after the application has finished running if it was loaded at the very top of the memory?</p>
<p>Well, the RAM will be cleared of these contents shortly. A "RAM dump" is the process of capturing all of the RAM. This demonstrates the actual form in which the entire data set is made accessible and loaded onto the RAM for the first time. And you'll learn how to capture or extract the data from memory next.</p>
<p>In order to accomplish this, you'll need some form of software. As a result, the goal of this program is to travel further into the memory. It will go into memory and retrieve all of the stored data from memory before continuing.</p>
<h3 id="heading-what-is-lime">What is LiME?</h3>
<p>The Linux memory extractor, sometimes referred to as LiME, is a powerful piece of software. It's what you use to extract the memory from Linux. This piece of software is also known as the driver, also referred to as the module. This is because RAM is a device, which complicates things further.</p>
<p>We need some form of driver to access the device so we can try to read the contents of it. LiME is an example of a driver, and if you're familiar with Linux you may know that in order to make any driver function, you need to load that driver with the assistance of the kernel.</p>
<p>Within the context of Linux, a driver is also referred to as a module. So LiME is a Linux kernel module. We have access to what is known as a kernel loadable module, which allows us to install the module on the operating system.</p>
<p>We have covered enough background. Now, let's look at how we can extract the contents of the RAM. We'll go through the process step-by-step in a hands-on way.</p>
<h2 id="heading-setup-and-installations"><strong>Setup</strong> and <strong>Installations</strong></h2>
<p>So, the only thing we need is the LiME driver. Here's the link to download this particular module: <a target="_blank" href="https://github.com/gursimarsm/LiME">https://github.com/gursimarsm/LiME</a>.</p>
<p>Now, boot up your Linux system (I use RedHat Enterprise Linux). You can use the <strong><code>free -h</code></strong> command to check the amount of RAM memory that's being used, that's available, and other details. Mine looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-186.png" alt="Image" width="600" height="400" loading="lazy">
<em>Output from running the <code>free -m</code> command</em></p>
<p>To access RAM, we need some software where the kernel can load some extra modules. In our case, the module name is LiME. So, the software we install are called “<strong>kernel-devel</strong>”, and “<strong>kernel-headers</strong>”. These two pieces of software are what we need to install in order to perform our subsequent actions, that is to use the LiME module.</p>
<p>If you want to install the software, you should have "yum" configured. For context, <strong>yum</strong> is a command you can use to install the software in the RedHat Linux operating system. I'll demo how to configure it in the appendix for reference.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-187.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installation</em></p>
<p>So, now that you've installed that software, you need one more piece of software because you have to download some drivers from GitHub. So, now you need to install Git if you don't already have it. You can do this using the command <strong><code>yum install git</code></strong>. You also need to configure your account so that you can work with it.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># git config --global user.name "Your Name" </span>

<span class="hljs-comment"># git config --global user.email "you@example.com"</span>
</code></pre>
<p>I shared the repository above. It's a loadable kernel module (LKM). It lets you acquire the entire memory from your Linux operating system or any kind of language operating system (including Android devices because Android is based on Linux as well).</p>
<p>You can download the module using the <code>**# g**it clone**** [**https://github.com/gursimar**sm**/LiME**](https://github.com/gursimarsm/LiME)</code> command.</p>
<p>After downloading that, you need to move into the directory of the software. You'll find multiple folders there. But, to run the main code, you need to move to the "src" directory.</p>
<p>In this directory, you'll find multiple programs based on the C language. So, in order to make use of the files, you'll need to compile them. To do that, you can use the <strong><code>make</code></strong> command. Install that like this:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># yum install make </span>

<span class="hljs-comment"># yum install gcc</span>
</code></pre>
<p>In the directory /LiME/src/, run the <strong><code>make</code></strong> command to compile the entire code.</p>
<p>If you encounter an error, it might be because we are using the latest version of LiME, and it comes with a new feature called orc metadata generate. To implement this feature, you have to install one more thing that's part of LiME called <strong><code>elfutils-libelf-devel</code></strong>. You can do that using yum like you can see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-188.png" alt="Image" width="600" height="400" loading="lazy">
<em>How to install <strong><code>elfutils-libelf-devel</code></strong></em></p>
<p>After that's done, if we now run the <code>make</code> command it will ask the GCC compiler to compile the entire code. After the compilation, it will create one final object file called the kernel object file, and that is the final module in LiME.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-189.png" alt="Image" width="600" height="400" loading="lazy">
<em>Output</em></p>
<p>You can find this file in the same directory by using the <strong><code>ls</code></strong> command.</p>
<h2 id="heading-how-to-use-the-module"><strong>How to Use the Module</strong></h2>
<p>With this module, the kernel now has the capability to capture or read the entire RAM. By default, we can't read the entire RAM in one go, but now because of the LiME module, we can.</p>
<p>To learn more about the LiME module, you can use the <strong><code>modinfo</code></strong> command. Type <code>modinfo</code> along with <code>lime</code>. This will show you some more details like where the file is available, and it also displays all the modules or drivers that come with some kind of extra parameters. Every parameter has some benefits.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-190.png" alt="Image" width="600" height="400" loading="lazy">
<em>modinfo</em></p>
<p>Here we are going to use two parameters which are very important: <code>path</code> and <code>format</code>.</p>
<p><code>path</code> means when we read the entire RAM, we have to store the data of the RAM in some file. So, to specify the destination file we would like to create, we have to give that particular information over here.</p>
<p>The next parameter, <code>format</code>, specifies the format in which we want to read the RAM data. So, in this case, we want to read the format of the RAM as it is. The data stored in the RAM is mostly in binary, and we want to read the entire data in that binary format only and capture it in its raw form.</p>
<p>So, the format will be raw and stored in the file wherever we give the path.</p>
<p>Finally, it's time to read the data from the RAM. So, let's come to the main command that will help us start reading the entire RAM.</p>
<h3 id="heading-demonstration">Demonstration</h3>
<p>Type in your password for your Gmail account in Chrome for this demonstration. This will help you learn how to capture the data from the RAM and also if your password is encrypted.</p>
<p>To verify these two things, move to the command prompt and check if the data is still on the RAM. You'll have to load a particular module using the command <strong><code>insmod</code></strong>. This will help you insert the module.</p>
<p>Copy the complete path of the module and paste it along with the <code>insmod</code> command.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-191.png" alt="Image" width="600" height="400" loading="lazy">
<em><code>insmod</code> command</em></p>
<p>This module will get loaded with the help of the kernel. The module will start capturing the entire data from the RAM and it'll store it in a file, for example, myram.data</p>
<p>It will also load the entire memory dump or RAM dump into this file and which format we want to capture. So, the format will be the raw format.</p>
<p>We'll use these two parameters (don't worry about this for now). We need only two parameters to perform, and now as soon as we hit this command, whatever data we have will be captured and stored in this particular file. This command typically takes a few seconds, depending on the CPU speed and the amount of data we have in the RAM.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-192.png" alt="Image" width="600" height="400" loading="lazy">
<em>Command</em></p>
<h3 id="heading-how-to-read-the-data">How to read the data</h3>
<p>Now, we have this file myram.data and the entire data of the RAM is stored in this file. Because we captured this data in the raw format, the data is going to be in binary. If we try to read this data from this file directly, as human beings, we can't read it even if we try it with the initial lines using the head command to read some of the top 10 lines.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-193.png" alt="Image" width="600" height="400" loading="lazy">
<em>Output</em></p>
<p>So, we can use the “cat” command, which will read the entire data. But, again, the same thing is going to happen – it will read the entire data, but the data will be displayed in the binary format. Then we need to use the pipe function with this command and combine it with another new command called <code>strings</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-194.png" alt="Image" width="600" height="400" loading="lazy">
<em>Command</em></p>
<p>String is a command that will convert the data into regular text in a human-readable format.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-195.png" alt="Image" width="600" height="400" loading="lazy">
<em>Output</em></p>
<p>The list will go on and on. You can interrupt it using <strong>Ctl+C</strong>.</p>
<p>Right now, it won't mean much seeing and reading the entire data. We know some data that are there on the RAM is the password called mywebpasswordgmail. So, just to confirm that this data is available on the RAM we can use one more pipe along with the <code>grep</code> command. The grep command helps us sort the data.</p>
<pre><code class="lang-bash">cat /myram.data | strings | grep mywebpasswordgmail
</code></pre>
<p>Now, we are searching for this string in the entire data. It will convert the data into regular text, and wherever that particular string shows up, grep will grab that line and let us start searching, then show us this data.</p>
<p>So, as you can see from this simple example, whatever you type on your keyboard can also go into the RAM – even if it's your password or any kind of secure site you are surfing, your data is there on the RAM. It doesn't matter what program you run. If you type using the keyboard everything will load on the RAM and can be extracted. This is called the memory dump.</p>
<p>LiME provides us with many other powerful capabilities. Right now, we are capturing the data directly from the system where we perform the actions. But we can also run LiME on the system and it can capture the data in real-time and send the data over the network to another computer.</p>
<p>What does this mean? Think of it this way: for example, somebody opens a website and they're typing something in real-time. This entire message is being transmitted in real-time to another computer.</p>
<p>We're not talking about key loggers, we are just talking about the RAM. Whatever is happening when any program is running, the database is storing some data. Programs are reading data from other parts of the hard disk. And whatever is happening on the RAM can be captured in real-time by the system and sent over the network to other computers.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>We’ve finally come to the end of this article. I hope you've enjoyed it and have learned something new.</p>
<p>I’m always open to suggestions and discussions on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>. Hit me up with direct messages.</p>
<p>If you’ve enjoyed my writing and want to keep me motivated, consider leaving starts on <a target="_blank" href="https://github.com/gursimarsm">GitHub</a> and endorse me for relevant skills on <a target="_blank" href="https://www.linkedin.com/in/gursimarsm">LinkedIn</a>.</p>
<p>Till the next one, stay safe and keep learning.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Docker Engine-like Custom Container without Any Software ]]>
                </title>
                <description>
                    <![CDATA[ This article will discuss every aspect of containers, including how they operate in the background and their various component elements. We will also discover why Docker is so lightning-fast. By the end, you'll be able to create your own custom conta... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-your-on-custom-container-without-docker/</link>
                <guid isPermaLink="false">66c4c5a6e7521bfd6862b3a9</guid>
                
                    <category>
                        <![CDATA[ containerization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ containers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gursimar Singh ]]>
                </dc:creator>
                <pubDate>Wed, 10 Aug 2022 16:45:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/image-12-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This article will discuss every aspect of containers, including how they operate in the background and their various component elements. We will also discover why Docker is so lightning-fast.</p>
<p>By the end, you'll be able to create your own custom container. We'll also examine why Kubernetes deprecated Docker and embraced CRI-O, as well as how to configure a multi-node Kubernetes cluster using CRI-O.</p>
<p>In the end, we will look at the list of available container runtimes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-11.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-are-containers">What are containers</a>?</li>
<li><a class="post-section-overview" href="#heading-why-do-we-need-containers">Why do we need containers</a>?</li>
<li><a class="post-section-overview" href="#heading-whats-the-difference-between-containers-and-virtualization">What's the difference between containers and virtualization</a>?</li>
<li><a class="post-section-overview" href="#heading-is-there-a-standard-format-for-containers">Is there a standard format for containers</a>?</li>
<li><a class="post-section-overview" href="#heading-types-of-container-platforms">Types of container platforms</a></li>
<li><a class="post-section-overview" href="#heading-how-to-launch-a-container">How to launch a container</a></li>
<li><a class="post-section-overview" href="#heading-why-did-kubernetes-depreciate-docker">Why did Kubernetes deprecate Docker</a>?</li>
<li><a class="post-section-overview" href="#heading-challenges-of-using-docker">Challenges of using Docker</a></li>
<li><a class="post-section-overview" href="#heading-what-is-a-cri-container-runtime-interface">What is a CRI (Container Runtime Interface)</a>?</li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-multi-node-cluster-using-cri-o">How to build a multi-node cluster using CRI-O</a></li>
</ol>
<p>Alright, let's dive in.</p>
<h2 id="heading-what-are-containers">What Are Containers?</h2>
<p>Containers allow you to reliably move software from one computing environment to another.  </p>
<p>The technology behind containers is nearly as old as that behind virtual machines. But the information technology industry didn't begin using containers until around 2013–14, when Docker, Kubernetes, and other innovations that disrupted the sector became popular. </p>
<p>Containers have emerged as a critical tool in the process of developing software. They can serve either as a replacement for Virtual Machines or as a supplement to them. </p>
<p>Containerisation helps developers construct apps more rapidly and securely while also deploying them more easily.</p>
<h2 id="heading-why-do-we-need-containers">Why Do We Need Containers?</h2>
<p>As we learned above, containers provide a solution to the problem of transporting software from one computer environment to another in a reliable manner. This can be just from a developer's workstation to a test environment, from a staging environment to production, or even from a real system in a data center to a private or public cloud virtual machine. </p>
<p>Containerization makes possible all of these transformations. And these are just some of the viewpoint alterations that can happen.</p>
<p>This quote gives a little perspective on why containers are helpful:</p>
<blockquote>
<p>"You’re going to test using Python 2.7, and then it’s going to run on Python 3 in production and something weird will happen.   </p>
<p>Or you’ll rely on the behavior of a certain version of an SSL library and another one will be installed.   </p>
<p>You’ll run your tests on Debian and production is on Red Hat and all sorts of weird things happen.   </p>
<p>The network topology might be different, or the security policies and storage might be different but the software has to run on it." – Solomon Hykes</p>
</blockquote>
<h2 id="heading-how-do-containers-solve-this-issue">How Do Containers Solve This Issue?</h2>
<p>A more straightforward interpretation is that a container is an all-encompassing runtime environment. </p>
<p>This means that a piece of software, together with all of its dependencies, libraries, other binaries, and configuration files, is packed and distributed to customers as a single package. </p>
<p>The application platform and its dependencies can be protected from the consequences of changes in operating system distribution and underlying infrastructure if they are bundled within containers.</p>
<h2 id="heading-whats-the-difference-between-containers-and-virtualization">What’s the Difference Between Containers and Virtualization?</h2>
<p>A virtual machine is a package that may be shared when employing virtualization technology. This package includes both the program and the operating system being used. </p>
<p>On top of a physical server running three virtual machines, you'd have an installation of a hypervisor, as well as three distinct operating systems.</p>
<p>On the other hand, a Docker server that hosts three containerized programs only needs to run a single operating system because all of the containers share the same kernel. The standard components of the operating system can only be read, but each container has its own mount or access mechanism, which allows it to store and retrieve data. </p>
<p>This hints that containers are far lighter than virtual machines and make considerably less use of their resources.</p>
<h2 id="heading-is-there-a-standard-format-for-containers">Is There a Standard Format for Containers?</h2>
<p>When CoreOS published its own App Container Image (ACI) specification in 2015, some people worried that the rapidly growing container movement might splinter into different Linux container formats. This was because ACI stood for "App Container Image."</p>
<p>In contrast, the Open Container Project, which would subsequently become the Open Container Initiative (OCI), was not made public until the latter half of the same year.</p>
<p>The <a target="_blank" href="https://opencontainers.org/">Open Container Initiative</a>, which the Linux Foundation leads, aims to establish an industry standard for container formats as well as container runtime software that is compatible with all operating systems (OCI).</p>
<p>Docker technology was used to develop the Open Container Project (OCP) guidelines, and Docker gave around 5 percent of their software to help get the effort off the ground.</p>
<h3 id="heading-what-is-open-container-initiative">What is Open Container Initiative?</h3>
<p>The Open Container Initiative (OCI) is an organization whose mission is to ensure that the fundamental aspects of container technology, such as the container's format, are standardized so that anyone can use them.</p>
<p>As a result, companies can concentrate their efforts on developing the supplementary software they need in order to use standardized containers in an enterprise or cloud environment (instead of developing competing technologies for containers). </p>
<p>Software components called container orchestration and management solutions, as well as container security systems, are essential components.</p>
<h2 id="heading-types-of-container-platforms">Types of Container Platforms</h2>
<p>As a result of the development and expansion of container technology, a number of different choices are currently available. </p>
<p>Docker is, without a doubt, the most common and widely used container platform available. </p>
<p>On the other hand, the landscape of container technologies includes other technologies, each of which has its own use cases and benefits.</p>
<p>We will look at the two most famous ones, i.e., Docker and Podman.</p>
<h3 id="heading-docker">Docker</h3>
<p>Docker is the container platform that's currently the most popular and is used the most widely. It allows you to develop and use Linux containers. </p>
<p>Docker is a piece of software that, by using containers, simplifies the processes of creating, deploying, and operating software applications. It does this by minimising the number of steps in each process. </p>
<p>Docker has gained support not just from the most major Linux distributions, such as Red Hat and Canonical, but also from large organisations, such as Microsoft, Amazon, and Oracle. </p>
<p>Virtually all businesses concerned with information technology and cloud computing use Docker.</p>
<h5 id="heading-docker-architecture-and-components">Docker Architecture and Components</h5>
<p>Docker is built on a client-server architecture. The Docker daemon enables the creation, operation, and distribution of Docker containers. </p>
<p>The Docker client and Docker daemon can interact through a REST application programming interface (API), UNIX sockets, or network interface.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-34.png" alt="Image" width="600" height="400" loading="lazy">
<em>Source: docs.docker.com</em></p>
<p>Docker's architecture is comprised of the following five primary components:</p>
<ol>
<li><strong>Docker Daemon</strong> manages Docker objects like images, containers, networks, and volumes. It also responds to Docker API inquiries.</li>
<li><strong>Docker Clients</strong> enables users to interact with Docker by allowing the user to connect with Docker. Docker client supplies a CLI interface that allows users to send application commands to a Docker daemon and start and halt such operations.</li>
<li><strong>Docker Host</strong> provides a complete software program execution and operation environment. This system comprises the Docker daemon, Images, Containers, Networks, and Storage components.</li>
<li><strong>Docker Registry</strong> maintains Docker Images. Docker Hub is a public registry, and by default, Docker is configured to use images saved on Docker Hub. You can use it to administer your own register.</li>
<li><strong>Docker Images</strong> are templates that can only be read and produced by following a Dockerfile's set of instructions. Images specify the appearance we want for our packaged program, its dependencies, and the processes that should run when the application is launched.</li>
</ol>
<h4 id="heading-resource-isolation-components-in-docker">Resource Isolation components in Docker</h4>
<h5 id="heading-namespaces">Namespaces:</h5>
<ul>
<li>PID namespace for process isolation.</li>
<li>NET namespace for managing network interfaces.</li>
<li>IPC namespace for managing access to IPC resources.</li>
<li>MNT namespace for managing filesystem mount points.</li>
<li>UTS namespace for isolating kernel and version identifiers.</li>
</ul>
<h5 id="heading-control-groups">Control groups</h5>
<ul>
<li>Memory cgroup that oversees accounting as well as restrictions and alerts</li>
<li>HugeTBL is a cgroup that keeps track of each process group's use of huge pages.</li>
<li>CPU group is responsible for regulating the time users and the system spend using CPU.</li>
<li>CPUSet cgroup lets you associate a group with a certain CPU. Utilized for real-time workloads and NUMA systems with localised memory for each CPU.</li>
<li>BlkIO cgroup for measuring and limiting the amount of blkIO each group produces.</li>
<li>the net cls and net prio cgroups are utilised for traffic control tagging.</li>
<li>Devices cgroup for accessing devices that can both read and write data.</li>
<li>Cgroup for the freezing of a group referred to as the freezer. It is useful for scheduling cluster batches, relocating processes, and troubleshooting.</li>
</ul>
<h5 id="heading-union-filesystem">Union Filesystem</h5>
<ul>
<li>Docker images are composed of layered filesystems, allowing them to be extremely lightweight and speedy. Union file systems are layering-based file systems.</li>
<li>Docker Engine has the ability to use several different versions of UnionFS, such as AUFS, btrfs, vfs, and devicemapper.</li>
<li>For executing five 250MB image containers, we would require 1.25GB of disc space if we didn't have UnionFS.</li>
</ul>
<p>The Docker interface may appear to be a mysterious black box holding a variety of unknown technologies when seen from the outside. Despite their relative obscurity, these technologies are both highly intriguing and useful.  </p>
<p>Despite the fact that we do not need to grasp these technologies in order to utilise Docker effectively, it is still beneficial to learn about and have an awareness of these technologies.   </p>
<p>If we have a deeper understanding of the instrument, it will be much easier for us to make the proper decisions, such as those regarding performance optimization or security implications.   </p>
<p>In addition, this facilitates the discovery of innovative new technologies, which may have many more uses for the organisation than initially thought.</p>
<h3 id="heading-just-a-note">Just a note:</h3>
<p>Docker does not require cgroupfs as the control group driver. The cgroup can be changed to systemd. </p>
<p>Docker's own control group manager is cgroupfs. Nevertheless, for most Linux distributions, systemd is the default init system, and systemd has tight interaction with Linux control groups. </p>
<p>For Kubernetes, it is recommended to use systemd, as utilising cgroupfs in conjunction with systemd appears to be suboptimal.</p>
<p>So systemd is preferable for cgroup management. kubelet is set to utilise systemd by default. Therefore, Docker should be modified to utilise the systemd driver. </p>
<h5 id="heading-docker-engine-sparked-the-containerization-movement">Docker Engine Sparked the Containerization Movement</h5>
<p>The Docker Engine is the de-facto container runtime for Linux and Windows Server platforms. </p>
<p>Docker develops simple tools and a uniform packaging strategy that encapsulates all application requirements into a container, which is then executed by Docker Engine. </p>
<p>The Docker Engine enables containerized apps to operate anywhere reliably on any infrastructure, resolving "dependency hell" for developers and operations teams and removing the "it works on my laptop!" issue.</p>
<h3 id="heading-podman">Podman</h3>
<p>Podman is RedHat's product. Docker and Podman are fairly comparable to one another in many ways. </p>
<p>Podman provides a Docker-compatible command-line interface that you can alias to the Docker command-line interface with the <code>$ alias docker = podman</code>. Also, Podman provides a socket-activated REST API service that makes it possible for remote apps to launch containers whenever they want. </p>
<p>Users of docker-py and docker-compose are able to connect with Podman as a service because this REST API also supports the Docker API.</p>
<p>By using the libpod library, Podman is able to handle the entirety of the container ecosystem, which includes pods, containers, container images, and container volumes. </p>
<p>Podman is distinct from Docker in that it does not require a server and has a lightweight and Daemon-less design. This means that it makes direct contact with runC to start containers, which eliminates the need for an overhead server.</p>
<p>Containers managed by Podman can either be operated by the root user or by a user with fewer privileges than root. </p>
<p>While working with Docker, the Docker Command Line Interface is how we interface with the daemon that Docker runs in the background. The daemon, which operates on containers and produces pictures, is where the majority of the program's functionality can be found. </p>
<p>This daemon runs with the permissions of the root user. This also suggests that a Docker container may have access to the file system of the host computer if the configuration is not done appropriately. </p>
<p>In contrast, the architecture of Podman makes it possible for us to collaborate with the user who is responsible for running the container, and this user does not need to have root access in order to execute the application. </p>
<p>When compared to containers that run with root capabilities, non-privileged containers provide a substantial advantage. This is because if an intruder breaks into a non-privileged container and flees, the intruder will still be an unprivileged host user. Using this approach provides an additional safeguard for our data.</p>
<p>Just replace Docker with Podman in the instructions to use it. It has the same commands as Docker.</p>
<pre><code>$ alias docker=podman
</code></pre><h5 id="heading-what-other-advantages-does-podman-have">What other advantages does Podman have?</h5>
<ul>
<li>Integrated support for systemd makes it possible to run container processes in the background without the need for a separate daemon process.</li>
<li>Provides us with the ability to build and manage Podami, a collection consisting of one or more functional containers. Because of this, future workload migration to Kubernetes and the orchestration of Podman containers is now possible.</li>
<li>It is possible to implement UID separation using namespaces, providing an additional layer of security isolation while containers are being executed.</li>
<li>Can create a YAML file for Kubernetes from a container that is currently operating (with the command <code>$ podman generate kube</code>).</li>
</ul>
<h2 id="heading-how-to-launch-a-container">How to Launch a Container</h2>
<p>To launch any container we need two things: Image and RunTime.</p>
<p>Container engines such as Docker and Podman are only an additional software layer that sits on top of the runtimes. They are not responsible for actually launching the containers themselves. </p>
<p>They also initiate interaction with the runtimes in the background to start the container processes.</p>
<p>A Container Runtime is a software that runs and manages the components required to run containers.</p>
<p>Runtime is actually a program/software which launches, deletes, and removes containers.</p>
<p>runC is a very famous Runtime, but we have many other Runtimes like gvisor and kata.</p>
<p>Docker connects to this runtime behind the scenes.</p>
<p>The runtime spec file is a configuration file where we give all the important things for the container to be launch like CMD, folder, network, and so on. It is the file that the container runtime uses to launch the container.</p>
<p>We can verify that Docker is using runC as its default runtime engine like this:</p>
<pre><code>$ docker info
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-35.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-use-runc-the-universal-container-runtime">How to use runC – the universal container runtime</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-36.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Because "containers" are a collection of complex and occasionally obscure system elements, they are combined into a single low-level component. This is runC.<br>As a standalone tool, infrastructure plumbers all around the world utilise runC as plumbing.</p>
<p>runC is a lightweight, portable runtime for containers. It is a command-line tool for creating and running containers according to the Open Container Initiative (OCI) specification. It has libcontainer, which is the original lower-layer library interface that the Docker engine used to set up what we call an operating system container.</p>
<p>runC is designed with the principles of security, usability at large scale, and no dependency on Docker in mind.</p>
<p>Whenever we launch a container, it starts within a second. It looks like a new OS has launched because it has all the things an OS would have (like all the commands, network card, and more). It looks like an independent OS.</p>
<h4 id="heading-how-can-a-container-be-launched-in-one-second">How can a container be launched in one second?</h4>
<p>As you may know, when you run any program, it becomes a process. So even here, every running container is a process in the host system. So whenever we launch a container, it means we have started some process.</p>
<p>It looks like that container is a different OS with its own file system, network, and so on, as I mentioned above. But the kernel runs this entire setup inside a process by using the concept of namespaces. We'll discuss namespaces further in a minute.</p>
<p>So, as the container is a process, it launches quickly.</p>
<p>A container is just a process running in the RAM. This process looks like it is running a full-flash OS inside an OS. Typically, the process (container) runs the bash command, which has an infinite lifetime till someone gives an exit command.</p>
<p>If we inspect the container, we can find the PID of the /bin/bash command running in the base OS. Now, if we kill the process of the /bin/bash, the container will also be terminated.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-37.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-what-is-a-namespace">What is a namespace?</h4>
<p>Again, running a container is also a process. But with Docker, a container is given with its own principal user, network configuration, mount folders, filesystem, and so on which they get as a common component of the baseOS. As a result, the container now has its own isolated environment, known as a namespace.</p>
<pre><code>$ lsns

# To list down all the namespace <span class="hljs-keyword">in</span> the baseOS
</code></pre><p>To launch a container, Docker Creates a Runtime Spec file for runC, and then runC uses that to launch the container. runC creates Namespaces for the container process.</p>
<p>The Image works as a Hard Drive – that is, it contains the entire file system for the container. A Container Image bundles all the data which is mounted on a storage namespace (that is, mount namespace).</p>
<p>The Image creates the entire bundle in the "/" directory of the containers. We have to unbundle it by untaring it.</p>
<p>Note that runC will not download, unzip, or untar the images for us. It can launch the container and mount the files for us to the container. For the images, we need some image management tools.</p>
<p>Also, runC only provides us with a network namespace, but Docker has to manage the network (that is, specify the IP range, provide IPs, and so on).</p>
<p>Docker can download, unzip, or unbundle the images. It can also do the required networking setup. It can also connect to the storage for us, and many such features are provided by Docker. Typically, Docker can do almost all the stuff provided by Kubernetes via its commands.</p>
<p>In Docker, we have a client-server architecture in which we have Docker CLI working as the client program and the container as the server. The server will now connect to the runtime and launch the container for us.</p>
<p>If we want to launch the container directly, we can do so with the help of runC. </p>
<p>First, we need to install runC using yum.</p>
<pre><code>$ runc list 

# This will list the available containers.
</code></pre><pre><code>$ runc spec

# To create a runtime spec file <span class="hljs-keyword">in</span> current directory.
</code></pre><p>runC is written in the Go language. So, generally it supports Go programs (images are also written in the Go language).</p>
<p><code>$ go build -o name</code> is the command to compile a Go program.</p>
<h3 id="heading-runc-commands">runC Commands:</h3>
<pre><code>$ runc create &lt;cont_name&gt;

# To launch a container (This will take config file <span class="hljs-keyword">from</span> current directory).
</code></pre><pre><code>$ runc start &lt;cont_name&gt;

# This command will run and give the output <span class="hljs-keyword">of</span> the program that we’ve specified <span class="hljs-keyword">in</span> container.
</code></pre><p>In the workspace we use the following:</p>
<pre><code>$ runc spec

# This will create a config.json file <span class="hljs-keyword">for</span> the runC configuration.
</code></pre><p>In the congif.json file, we must change the parameters-values according to our requirements. </p>
<p>For example, if we don’t want the terminal, we need to make it false. For that we can give the command to run in the arg, we can set the hostname, and so on.</p>
<p>We can connect to this container namespace by doing the following:</p>
<pre><code>$ nsenter -u -t -n &lt;pid_of_container&gt;

# To enter user and network namespace <span class="hljs-keyword">of</span> specific process ID.
</code></pre><h4 id="heading-to-create-a-container-just-by-using-runc">To create a container just by using runC:</h4>
<ol>
<li>Install runC.</li>
<li>Create config.json by running the runC spec command.</li>
<li>Mention all the important things in the above file. We also have to give process by writing its code in the Go language.</li>
<li>Create a rootfs folder in the current workspace and move the compiled Go code into this folder.</li>
<li>Now, to launch the container:</li>
</ol>
<pre><code>$ start runc create &lt;container_name&gt;
</code></pre><p>To start the container and print on the console whatever is there in the go file, run this command:</p>
<pre><code>$ runc start &lt;container_name&gt;
</code></pre><h3 id="heading-how-to-generate-an-example-specification-with-runc">How to generate an example specification with runC:</h3>
<pre><code>&gt; runc spec
&gt; cat config.json
{
  <span class="hljs-string">"ociVersion"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"process"</span>: {
    <span class="hljs-string">"terminal"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-string">"user"</span>: { <span class="hljs-string">"uid"</span>: <span class="hljs-number">0</span>, <span class="hljs-string">"gid"</span>: <span class="hljs-number">0</span> },
    <span class="hljs-string">"args"</span>: [<span class="hljs-string">"sh"</span>],
    <span class="hljs-string">"env"</span>: [
      <span class="hljs-string">"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"</span>,
      <span class="hljs-string">"TERM=xterm"</span>
    ],
    <span class="hljs-string">"cwd"</span>: <span class="hljs-string">"/"</span>,
    <span class="hljs-string">"capabilities"</span>: {
      <span class="hljs-string">"bounding"</span>: [<span class="hljs-string">"CAP_AUDIT_WRITE"</span>, <span class="hljs-string">"CAP_KILL"</span>, <span class="hljs-string">"CAP_NET_BIND_SERVICE"</span>],
      [...]
    },
    <span class="hljs-string">"rlimits"</span>: [ { <span class="hljs-string">"type"</span>: <span class="hljs-string">"RLIMIT_NOFILE"</span>, <span class="hljs-string">"hard"</span>: <span class="hljs-number">1024</span>, <span class="hljs-string">"soft"</span>: <span class="hljs-number">1024</span> } ],
    <span class="hljs-string">"noNewPrivileges"</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-string">"root"</span>: { <span class="hljs-string">"path"</span>: <span class="hljs-string">"rootfs"</span>, <span class="hljs-string">"readonly"</span>: <span class="hljs-literal">true</span> },
  <span class="hljs-string">"hostname"</span>: <span class="hljs-string">"runc"</span>,
  <span class="hljs-string">"mounts"</span>: [
    {
      <span class="hljs-string">"destination"</span>: <span class="hljs-string">"/proc"</span>,
      <span class="hljs-string">"type"</span>: <span class="hljs-string">"proc"</span>,
      <span class="hljs-string">"source"</span>: <span class="hljs-string">"proc"</span>
    },
    [...]
  ],
  <span class="hljs-string">"linux"</span>: {
    <span class="hljs-string">"resources"</span>: { <span class="hljs-string">"devices"</span>: [ { <span class="hljs-string">"allow"</span>: <span class="hljs-literal">false</span>, <span class="hljs-string">"access"</span>: <span class="hljs-string">"rwm"</span> } ] },
    <span class="hljs-string">"namespaces"</span>: [
      { <span class="hljs-string">"type"</span>: <span class="hljs-string">"pid"</span> },
      { <span class="hljs-string">"type"</span>: <span class="hljs-string">"network"</span> },
      { <span class="hljs-string">"type"</span>: <span class="hljs-string">"ipc"</span> },
      { <span class="hljs-string">"type"</span>: <span class="hljs-string">"uts"</span> },
      { <span class="hljs-string">"type"</span>: <span class="hljs-string">"mount"</span> }
    ],
    <span class="hljs-string">"maskedPaths"</span>: [
      <span class="hljs-string">"/proc/kcore"</span>,
      [...]
    ],
    <span class="hljs-string">"readonlyPaths"</span>: [
      <span class="hljs-string">"/proc/asound"</span>,
      [...]
    ]
  }
}
</code></pre><h2 id="heading-why-did-kubernetes-depreciate-docker">Why Did Kubernetes Depreciate Docker?</h2>
<p>Docker is often the first choice when it comes to managing and creating containers and images. It is extremely fast – so you might be wondering why Kubernetes dropped Docker and went on to use the CRI-O container engine? Let’s explore.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/0_jh4jUOjPPNS-bfU0.png" alt="Image" width="600" height="400" loading="lazy">
<em>Source: https://www.sumologic.com/blog/kubernetes-vs-docker/</em></p>
<p>We can check the Docker container engine like this:</p>
<pre><code>$ systemctl status docker
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-41.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here it shows Docker Application Container Engine but conntainerD is the actual engine running.</p>
<p>In Docker, when kubelet needs to connect to the ContainerD it has to go through an API Docker shim to contact runC. This acts as an interface between Docker and Kubernetes. This makes the whole process fairly complex.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-40.png" alt="Image" width="600" height="400" loading="lazy">
<em>Source: Tutorial Works</em></p>
<h3 id="heading-what-is-conatinerd">What is ConatinerD?</h3>
<p>ContainerD is an industry standard container runtime that emphasises simplicity, durability, and portability.</p>
<p>You can find a daemon-based implementation of containerD on both Linux and Windows. It is responsible for managing the whole container lifecycle of the system that it is hosted on, which includes image transfer and storage, container execution and monitoring, low-level storage, and network attachments.</p>
<h4 id="heading-features-of-containerd">Features of ContainerD:</h4>
<ul>
<li>OCI Image Spec support</li>
<li>Image push and pull support</li>
<li>Network primitives for creation, modification, and deletion of interfaces</li>
<li>Multi-tenant supported with CAS storage for global images</li>
<li>OCI Runtime Spec support (aka runC)</li>
<li>Container runtime and lifecycle support</li>
<li>Management of network namespaces containers to join existing namespaces</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-42.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-what-is-dockerd">What is dockerd?</h3>
<p>Docker's daemon may be kicked off with the help of dockerd (so you can command the daemon to manage images, containers, and so on). Dockerd is a server that runs in the background as a daemon.</p>
<p>To run the Docker daemon we can specify dockerd. After the dockerd keyword, you should supply the daemon parameters you want to use. </p>
<p>dockerd (Docker Daemon) can listen for Docker Engine API requests via three different types of Sockets: <code>unix</code>, <code>tcp</code>, and <code>fd</code>.</p>
<h3 id="heading-challenges-of-using-docker">Challenges of Using Docker</h3>
<h4 id="heading-overhead">Overhead</h4>
<p>Docker is a fairly developed platform in the container market. Along with container management, it offers many other capabilities like storage, security, and network infrastructure, among other things.</p>
<p>When compared to Cri-O and Podman, Docker's performance suffers as a direct result of the overhead caused by these additional functionalities. </p>
<p>But Kubernetes and OpenShift come equipped with all of these functions. Therefore, they want only one thing from the container engine: the ability to launch and manage the containers. In other words, they do not need any other functions.</p>
<h4 id="heading-dockershim">Dockershim</h4>
<p>In Kubernetes, the process of launching containers begins when kubelet communicates with containerD, which then contacts runC.</p>
<p>Because separate businesses are responsible for the production of containerD and kubelet, kubelet must have an additional layer in order to contact containerD (an API like layer). And inside the Docker ecosystem, this layer is referred to as Dockershim.</p>
<p>Kubernetes had depreciated dockershim because of the complexities and burden created by Docker updates.</p>
<h4 id="heading-whats-the-issue-with-dockershim">What's the issue with dockershim?</h4>
<p>Kubernetes suggested a temporary solution to include support for Docker so that it could serve as its container runtime. Dockershim's deprecation just signifies that Dockershim's code will no longer be maintained in the Kubernetes source repository. </p>
<p>Dockershim has become a significant problem for Kubernetes developers. Following this change, the Kubernetes community will only be permitted to maintain the Kubernetes Container Runtime Interface (CRI). </p>
<p>Kubernetes supports all CRI-compliant runtimes, such as containerD and CRI-O.</p>
<p>Kubernetes has come up with CRI-O as its interface to contact with runC. Kubelet will now be contacting CRI-O. Further, it will contact the runC, and the container will be launched.</p>
<p>However, like CRI-O and Docker, there are many container engines present. So, the Kubernetes community decided to create an abstraction layer on top of all container engines. So, a client can use any container engine according to their requirements.</p>
<p>This abstraction layer is called CRI (container runtime interface).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-44.png" alt="Image" width="600" height="400" loading="lazy">
<em>Kubernetes using Docker vs Kubernetes using CRI-O</em></p>
<h3 id="heading-what-is-a-cri-container-runtime-interface">What is a CRI (Container Runtime Interface)?</h3>
<p>The Kubelet program abstracts the underlying container engines. The Container Runtime Interface (CRI) is a plugin interface that lets kubelet use several container runtimes without recompilation. </p>
<p>In addition to protocol buffers, the gRPC API, and libraries, other specifications and tools are in active development for CRI.</p>
<p>Kubelet establishes a connection with CRI over the gRPC Protocol.</p>
<h3 id="heading-what-is-cri-o">What is CRI-O?</h3>
<p>CRI-OCI is an abbreviation that stands for the Container Runtime Interface and OCI, which stands for the Open Container Initiative.</p>
<p>The term CRI-O was chosen after taking into account references made by members of the CRI and CIO communities.</p>
<p>CRI-O is another container engine, but it is more lightweight than Docker since it does not include the additional capabilities that Docker has, such as networking, storage, and so on.</p>
<p>CRI-O provides a foundation that is more secure, stable, and performant for the execution of runtimes that are compatible with the Open Container Initiative (OCI). Runtimes that are OCI-compliant can be used in conjunction with the CRI-O container engine to launch containers and pods. </p>
<p>Examples of such runtimes include runC, which is the default OCI runtime, and Kata Containers. But you can use any OCI-conformant runtime in its place. </p>
<p>The goal of the CRI-O project is to replace Docker as the container engine that implements the Kubernetes Container Runtime Interface (CRI) for OpenShift Container Platform and Kubernetes.</p>
<p>The stability of CRI-O may be attributed to the fact that it is developed, tested, and distributed in tandem with major and minor versions of Kubernetes and complies with OCI standards. </p>
<p>The O's in CRI-scope are reliant on the Container Runtime Interface (CRI). The actual container engine specifications of a Kubernetes service (kubelet) were compiled and specified by CRI. </p>
<p>In light of the fact that several container engines were being developed, the CRI team decided to take this measure in order to settle Kubernetes' requirements for container engines.</p>
<p>According to the OpenShift Docs, the tools that help replace and extend what the Docker command and service provided are:</p>
<ul>
<li>crictl: For working directly with CRI-O container engines &amp; troubleshooting</li>
<li>runc: For running container images</li>
<li>podman: For managing pods and container images (run, stop, start, ps, attach, exec, and so on) outside of the container engine</li>
<li>buildah: For building, pushing and signing container images</li>
<li>skopeo: For copying, inspecting, deleting, and signing images</li>
</ul>
<h3 id="heading-cri-o-architecture">CRI-O Architecture</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-49.png" alt="Image" width="600" height="400" loading="lazy">
<em>Source: cri-o.io</em></p>
<h2 id="heading-how-to-build-a-multi-node-cluster-using-cri-o">How to Build a Multi-Node Cluster using CRI-O</h2>
<p>Following are the commands you'd use to create a multi-node Kubernetes cluster using CRI-O in Ubuntu 20.04.</p>
<p>Here's the repository that contains the set of commands: </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/gursimarh/Kubernetes-CRIO/blob/main/commands">https://github.com/gursimarh/Kubernetes-CRIO/blob/main/commands</a></div>
<pre><code>OS=xUbuntu_20<span class="hljs-number">.04</span>
VERSION=<span class="hljs-number">1.20</span>

cat &gt;&gt;<span class="hljs-regexp">/etc/</span>apt/sources.list.d/devel:kubic:libcontainers:stable.list&lt;&lt;EOF
deb https:<span class="hljs-comment">//download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /</span>
EOF

cat &gt;&gt;<span class="hljs-regexp">/etc/</span>apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list&lt;&lt;EOF
deb http:<span class="hljs-comment">//download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /</span>
EOF

curl -L https:<span class="hljs-comment">//download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -</span>

curl -L https:<span class="hljs-comment">//download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers-cri-o.gpg add -</span>

apt update

apt install -qq -y cri-o cri-o-runc cri-tools

systemctl daemon-reload

systemctl enable --now crio

curl -s https:<span class="hljs-comment">//packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -</span>


apt-add-repository <span class="hljs-string">"deb http://apt.kubernetes.io/ kubernetes-xenial main"</span>

apt install -qq -y kubeadm=<span class="hljs-number">1.20</span><span class="hljs-number">.5</span><span class="hljs-number">-00</span> kubelet=<span class="hljs-number">1.20</span><span class="hljs-number">.5</span><span class="hljs-number">-00</span> kubectl=<span class="hljs-number">1.20</span><span class="hljs-number">.5</span><span class="hljs-number">-00</span>

cat &gt;&gt;<span class="hljs-regexp">/etc/m</span>odules-load.d/crio.conf&lt;&lt;EOF
overlay
br_netfilter
EOF

modprobe overlay

modprobe br_netfilter

cat &gt;&gt;<span class="hljs-regexp">/etc/</span>sysctl.d/kubernetes.conf&lt;&lt;EOF
net.bridge.bridge-nf-call-ip6tables = <span class="hljs-number">1</span>
net.bridge.bridge-nf-call-iptables  = <span class="hljs-number">1</span>
net.ipv4.ip_forward                 = <span class="hljs-number">1</span>
EOF

sysctl --system

cat &gt;&gt;<span class="hljs-regexp">/etc/</span>crio/crio.conf.d/<span class="hljs-number">02</span>-cgroup-manager.conf&lt;&lt;EOF
[crio.runtime]
conmon_cgroup = <span class="hljs-string">"pod"</span>
cgroup_manager = <span class="hljs-string">"cgroupfs"</span>
EOF

systemctl daemon-reload

systemctl enable --now crio

systemctl restart crio

sed -i <span class="hljs-string">'/swap/d'</span> /etc/fstab

swapoff -a

systemctl disable --now ufw

kubeadm init --apiserver-advertise-address=<span class="hljs-number">172.16</span><span class="hljs-number">.16</span><span class="hljs-number">.100</span> --pod-network-cidr=<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>/<span class="hljs-number">16</span>

kubectl --kubeconfig=<span class="hljs-regexp">/etc/</span>kubernetes/admin.conf create -f https:<span class="hljs-comment">//docs.projectcalico.org/v3.18/manifests/calico.yaml</span>

kubeadm token create --print-join-command
</code></pre><p>We can use the join command to connect the nodes to the cluster and we're ready with a multi-node cluster of Kubernetes.</p>
<h3 id="heading-heres-an-illustration-of-how-docker-kubernetes-cri-o-containerd-and-runc-work-together">Here's an illustration of how Docker, Kubernetes, CRI-O, containerD and runC work together</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-43.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-container-runtimes">Container Runtimes</h3>
<p>We have seen a lot of details on how containers work, we have defined container runtimes and how we can build our custom container using runC. Now, are there any other tools in hand for us like runC?</p>
<p>Here we will look at landscape of all the container runtimes that are available.</p>
<p>Generally, they fall into two main categories: </p>
<ol>
<li>Open Container Initiative (OCI) runtimes</li>
</ol>
<p>The OCI runtimes are further classified in two broader categories: Native Runtimes and Sandboxed &amp; Virtualized Runtimes</p>
<ol start="2">
<li>Container Runtime Interface (CRI)</li>
</ol>
<p>The CRI consists of containerD and CRI-O.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-47.png" alt="Image" width="600" height="400" loading="lazy">
<em>1. Open Container Initiative (OCI) runtimes</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-48.png" alt="Image" width="600" height="400" loading="lazy">
<em>2. Container Runtime Interface (CRI)</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Here we saw how we can build our custom images and the various tool available at our disposal. It was a long one but I hope you've enjoyed it and have learned something new.</p>
<p>I'm always open to suggestions and discussions on <a target="_blank" href="https://www.linkedin.com/in/gursimarh">LinkedIn</a>. Hit me up with direct messages.</p>
<p>If you've enjoyed my writing and want to keep me motivated, consider leaving starts on <a target="_blank" href="https://github.com/gursimarh">GitHub</a> and endorse me for relevant skills on <a target="_blank" href="https://www.linkedin.com/in/gursimarh">LinkedIn</a>.</p>
<p>Till the next one, stay safe and keep learning.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
