<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged cloud-computing</title>
<link>https://coderlegion.com/tag/cloud-computing</link>
<description>Powered by Question2Answer</description>
<item>
<title>From Big Data to the Cloud, Part 1 — Why One Machine Is Never Enough</title>
<link>https://coderlegion.com/32321/from-big-data-to-the-cloud-part-1-why-one-machine-is-never-enough</link>
<description>&lt;p&gt;&lt;em&gt;A calm, sequential guide for anyone entering the field. The article is divided into smaller chapters to make it easier to understand.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This series grows out of the Cloud Computing labs I teach to fourth-year Computer Science students at the University of Hilla. The labs move quickly, because a lab has ninety minutes. The articles can afford to slow down. Here we take the same path the labs take, but we stop at every step and ask the question a careful student always asks: why this, and not something simpler?&lt;/p&gt;
&lt;p&gt;The path itself is short to state. Data has grown past the point where one machine can store it, process it, or analyse it efficiently. The answer is not a bigger machine but many ordinary machines working together. And the framework that manages those machines is Apache Hadoop. Each of those three sentences hides a chain of reasoning, and the purpose of this part is to lay that chain out link by link — so that by the end, the cluster does not look like a fashionable choice but like the answer the problem forces on us.&lt;/p&gt;
&lt;p&gt;The destination of this series is the cloud. But we will not begin there, because a definition of the cloud means little until you have felt the problem it was built to solve. So the series takes the long road on purpose: first the problem (this part), then the cluster that answered it and the burden that answer carried (Part 2), and only then the cloud — defined in Part 3, and explored service by service in the parts after it.&lt;/p&gt;
&lt;p&gt;We will not touch a configuration file in this part. What we build here is the problem — precisely enough that when Part 2 opens Hadoop up and looks at HDFS, MapReduce, and YARN from the inside, each component reads as the answer to a question we have already asked.&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=14814678934531802993&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;chapter-1-where-all-this-data-comes-from&quot;&gt;Chapter 1: Where All This Data Comes From&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Every Action Leaves a Record&lt;/strong&gt;&lt;br&gt;
Before we define anything, it is worth noticing how ordinary the sources of big data are. Every click, every purchase, every email, every chat message, and every social post creates data. None of these events is large on its own.&lt;/p&gt;
&lt;p&gt;But the sources do not stop at people typing. Sensors and IoT devices report what they measure. Banks record every transaction. Hospitals keep patient records. Streaming services log what their users watch. Each of these produces records continuously, whether or not anything interesting is happening.&lt;/p&gt;
&lt;p&gt;The individual record is small. What makes the situation new is the multiplication: small records, produced by enormous numbers of people and devices, without end. Data now reaches billions of records, and petabytes every day. The important words there are every day. The data does not arrive once. It keeps arriving.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=17695865734488853359&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;chapter-2-what-big-data-actually-means&quot;&gt;Chapter 2: What Big Data Actually Means&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A Definition About Tools, Not Size&lt;/strong&gt;&lt;br&gt;
The most useful definition of big data is not a number. It is this: big data is datasets so large and complex that traditional tools — spreadsheets, a single database server — cannot store, process, or analyse them efficiently.&lt;/p&gt;
&lt;p&gt;It is worth being exact about why the definition is phrased this way. Students often ask how large data must be before it “counts” as big. The definition answers by pointing at the tools rather than at a size: data becomes big at the moment the ordinary tool stops coping with it. Notice also that it names three separate jobs — store, process, analyse — and a tool can fail at any one of them.&lt;/p&gt;
&lt;p&gt;The Goal Is Insight, Not Storage&lt;br&gt;
A second point is easy to miss: the goal is not only storing data. The goal is extracting insights from it — turning a mountain of records into a decision someone can act on.&lt;/p&gt;
&lt;p&gt;The classic example is an online store. It already keeps every purchase as a matter of bookkeeping. The value appears only when it analyses customer habits: what people buy, when, and together with what. With that analysis, the store can make targeted offers and discounts, which increases revenue. The data was there all along; what matters is the ability to read it. Hold onto this, because a system that can store huge data but cannot analyze it has solved only half the problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three Shapes of Data&lt;/strong&gt;&lt;br&gt;
Data does not only come in different sizes. It comes in different shapes, and the shape decides which tools can handle it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Structured data is the familiar case: every row has the same columns. A student table with a name, a department, and an age is structured.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Semi-structured data carries its own labels — tags in XML and HTML, keys in JSON — but does not promise that every record has the same fields. The keys tell you what each value means, yet there is no rigid schema forcing every record into one shape.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unstructured data has no predefined format at all. An email body, a social post, an image, a video: the meaning is in there, but no column tells you where.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15960471738695527241&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;And here is the uncomfortable fact: most of today’s data is unstructured, and that is exactly what traditional databases handle worst. They were built around the first row of that table. The world moved to the third.&lt;/p&gt;
&lt;h3 id=&quot;chapter-3-the-five-v-s&quot;&gt;Chapter 3: The Five V’s&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=10713862101712732463&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Vocabulary for “Why It Is Hard”&lt;/strong&gt;&lt;br&gt;
“Too large and too complex” is a good definition, but it is too blunt to design a system against. We need to name the separate ways data can be difficult, because each one places a different demand on the machine that handles it. The standard vocabulary for this is the five V’s.&lt;/p&gt;
&lt;p&gt;One at a Time&lt;br&gt;
01 — Volume: how much. The huge amount of data, from terabytes to petabytes. Volume is the V that breaks storage first.&lt;/p&gt;
&lt;p&gt;02 — Velocity: how fast. How fast data is created and must be processed — think of stock trading or live streams. The second half of that sentence is the important one: these systems need answers quickly, not just storage quickly. Velocity is the V that breaks time.&lt;/p&gt;
&lt;p&gt;03 — Variety: how many shapes. Many types and formats of data — the structured, semi-structured, and unstructured shapes from Chapter 2, often mixed together. Variety is the V that breaks fixed schemas.&lt;/p&gt;
&lt;p&gt;04 — Veracity: how trustworthy. How accurate and trustworthy the data is. Real data is noisy, messy, and has missing values, so cleaning and checking quality stands between you and a conclusion you can defend.&lt;/p&gt;
&lt;p&gt;05 — Value: what we get out of it. The useful insight we finally get out of the data. This is the V that justifies the other four — the point Chapter 2 already made, now given its own name.&lt;/p&gt;
&lt;p&gt;Notice the split: the first three describe the data itself, while the last two describe whether we can trust it and whether it was worth the effort.&lt;/p&gt;
&lt;p&gt; Chapter 4: Why Traditional Systems Fail&lt;br&gt;
What “Traditional” Means Here&lt;br&gt;
By a traditional system we mean one built for structured data on a single powerful machine. All the data lives on that machine; all the work runs on it. This design is good at what it was built for. The point of this chapter is that big data asks it to do something it was never built for — and it breaks in five places.&lt;/p&gt;
&lt;p&gt;The Five Breaking Points&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It was built for structured data on one machine. Its whole design assumes fixed rows and columns, and one computer doing all the work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It cannot keep up with the volume and speed of modern data. This is Volume and Velocity together: too many bytes, arriving too fast, for one machine to absorb.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It has difficulty handling unstructured data — images, video, text. This is Variety. And since most of today’s data is unstructured, this is not an edge case; it is most of the data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scaling up means buying a bigger, very expensive server — and there is always a limit. When one server is not enough, the traditional move is to scale up: replace it with a bigger one. That works for a while, but each step costs more, and eventually there is no bigger machine to buy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is slow to extract insights from huge datasets. Put the first four together and the last failure follows on its own. This is the failure that matters most, because it is a failure of Value.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Three Challenges, Stated Plainly&lt;br&gt;
All five breaking points reduce to three questions any big data system must answer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Storage — where do we keep data that keeps growing?&lt;/li&gt;
&lt;li&gt;Processing — how do we analyse it fast enough to be useful?&lt;/li&gt;
&lt;li&gt;Scalability — how do we grow (or shrink) resources as data changes?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read the third question twice, because it hides a detail that will matter later in this series. It does not only ask how to grow. It asks how to grow or shrink — how to have exactly as much capacity as the data needs, no more and no less. Keep that small word “shrink” in your pocket; we will come back for it.&lt;/p&gt;
&lt;p&gt;The single powerful machine answers none of them well once the data is big enough. So the question becomes: what architecture answers all three?&lt;/p&gt;
&lt;h3 id=&quot;chapter-5-the-distributed-idea&quot;&gt;Chapter 5: The Distributed Idea&lt;/h3&gt;
&lt;p&gt;Many Ordinary Machines, Working Together&lt;br&gt;
The answer is to stop making one machine bigger. Instead of one big machine (monolithic), we use many ordinary machines working together, called a cluster. Each machine in the cluster is a node. Both the data and the processing are split across the nodes. A cluster can range from a few nodes to thousands — and cheap commodity hardware is enough: normal PCs and servers, not specialised machines.&lt;/p&gt;
&lt;p&gt;This strategy is called scaling out: when you need more capacity, you do not replace the machine — you add more machines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Price of Distribution&lt;/strong&gt;&lt;br&gt;
Scaling out is not free. The moment we spread data across many machines, we inherit three problems the single machine never had:&lt;/p&gt;
&lt;p&gt;Which data lives on which node? With one machine, a file is simply on its disk. With many, something must remember where every piece went.&lt;br&gt;
How do nodes communicate and coordinate? Many machines working on the same job is only useful if the work is divided and the results are brought back together.&lt;br&gt;
What happens when a machine crashes? On one server, a crash is a rare event. In large clusters, failures are normal.&lt;br&gt;
That last point changes how the whole system must be designed. If failure is the normal state of affairs, the system cannot treat it as an emergency. It must expect machines to fail and keep working anyway, without losing data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stated as a General Rule&lt;/strong&gt;&lt;br&gt;
Scaling out trades one hard problem — a machine that cannot grow past its limit — for three new ones: tracking where data lives, coordinating the nodes, and surviving failure. The trade is worth it only if software solves those three problems, so that the people using the cluster do not have to. What the field needed was a framework that solves them once, for everyone.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=16529077324794030625&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;chapter-6-enter-hadoop&quot;&gt;Chapter 6: Enter Hadoop&lt;/h3&gt;
&lt;p&gt;What Hadoop Is&lt;br&gt;
Apache Hadoop is an open-source framework for distributed storage and parallel processing of big data. It runs on clusters of commodity hardware — exactly the cluster Chapter 5 described. It was created around 2005, when the volume of web data, from sites like Facebook and YouTube, exploded. It is free to download from Apache, and commercial distributions also exist, such as Cloudera, Hortonworks, and MapR.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Its Core Components, at a Glance&lt;/strong&gt;&lt;br&gt;
The cleanest way to understand Hadoop’s design is to hold it up against the three challenges from Chapter 4. Each core component answers one of them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=3481848833855820308&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We deliberately stay at this altitude for now. How HDFS splits and tracks blocks, why MapReduce runs the program where the data already is, and how YARN hands out CPU and memory are the subject of Part 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What Hadoop Buys&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scalable — add more nodes as data grows. (Notice: as data grows. The “shrink” half of the Scalability question is still waiting.)&lt;/li&gt;
&lt;li&gt;Fault tolerant — keeps copies of data on different machines, so a hardware failure does not lose data. This is the answer to “what happens when a machine crashes?”&lt;/li&gt;
&lt;li&gt;Cost-effective — uses cheap commodity machines.&lt;/li&gt;
&lt;li&gt;Flexible — handles structured and unstructured data. This is the answer to Variety.&lt;/li&gt;
&lt;li&gt;Parallel — many nodes work at the same time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What Hadoop Costs&lt;/strong&gt;&lt;br&gt;
An honest account includes the other column.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is designed for batch processing, not real time. For real-time work, Apache Spark is better.&lt;/li&gt;
&lt;li&gt;It is complex to configure and maintain — which is exactly what the labs practise.&lt;/li&gt;
&lt;li&gt;Replication uses extra storage space. Keeping copies on different machines is what makes Hadoop fault tolerant, but every copy takes up disk.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Where It Is Used&lt;/strong&gt;&lt;br&gt;
Healthcare: patient records, medical images, early disease prediction.&lt;br&gt;
Banking: fraud detection, transaction analysis.&lt;br&gt;
Social media: sentiment analysis of posts.&lt;br&gt;
E-commerce: recommendations, customer behaviour, inventory management — the online store from Chapter 2, now at full scale.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-comes-in-part-2&quot;&gt;What Comes in Part 2&lt;/h3&gt;
&lt;p&gt;We now have the problem in full, and the shape of the answer. We know why one machine is never enough, why a cluster is the way out, and which new problems the cluster creates. We have met Hadoop’s components by name. What we do not yet have is the inside view.&lt;/p&gt;
&lt;p&gt;Part 2 opens the components one at a time. We follow a 400 MB file as HDFS splits it into 128 MB blocks, and see why, with three copies of each block, that file ends up stored as twelve blocks across the cluster. We meet the NameNode that keeps track of which block is on which machine, and the DataNodes that send it a heartbeat to say “I’m alive” — and we ask what happens when one of them stops. We walk through MapReduce by hand, on a word count and on an average-age example, from Map through Shuffle &amp;amp; Sort to Reduce. And we watch YARN take a submitted job, start an ApplicationMaster for it, and request containers on the nodes that hold the data.&lt;/p&gt;
&lt;p&gt;The single principle running through all of it: Hadoop moves the work to the data, not the data to the work.&lt;/p&gt;
&lt;p&gt;And Part 2 will end where the rest of this series begins. Hadoop solves storage, processing, and growth — but it leaves us holding a cluster: machines to buy, a framework that is complex to configure and maintain, and capacity that can grow but not easily shrink. That remaining burden is exactly what the cloud takes off our hands, and it is where Part 3 picks up the story.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;p&gt;Deshpande, T., Karanth, S., &amp;amp; Turkington, G. Hadoop: Data Processing and Modelling (Learning Path). Packt Publishing.&lt;br&gt;
Oracle. What Is Big Data? &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.oracle.com/big-data/what-is-big-data/&quot;&gt;https://www.oracle.com/big-data/what-is-big-data/&lt;/a&gt;&lt;br&gt;
Big Data — Understanding Hadoop: Architecture, Features, Challenges &amp;amp; Applications. Medium. &lt;a rel=&quot;nofollow&quot; href=&quot;https://medium.com/@rp99452/big-data-understanding-hadoop-architecturefeatures-challenges-applications-c7ab7011e375&quot;&gt;https://medium.com/@rp99452/big-data-understanding-hadoop-architecturefeatures-challenges-applications-c7ab7011e375&lt;/a&gt;&lt;br&gt;
Mehta, C. B. (2022). A Comprehensive Review of Hadoop Ecosystem for Big Data Processing and Analytics. IJNRD, 7(10).&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32321/from-big-data-to-the-cloud-part-1-why-one-machine-is-never-enough</guid>
<pubDate>Sun, 25 Oct 2026 05:46:00 +0000</pubDate>
</item>
<item>
<title>From “Why Is This Pod Pending?” to `HTTP/1.1 200 OK`: My NGINX Gateway Fabric Lab</title>
<link>https://coderlegion.com/31221/from-why-is-this-pod-pending-to-http-1-1-200-ok-my-nginx-gateway-fabric-lab</link>
<description>&lt;blockquote&gt;&lt;p&gt;A beginner-friendly Kubernetes networking story about Gateway API, Services, HTTPRoutes, DNS, a few misleading errors, and the joy of finally seeing a successful response.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;the-mission&quot;&gt;The mission&lt;/h3&gt;
&lt;p&gt;The goal of this exercise was simple to say and slightly less simple to do: deploy &lt;strong&gt;NGINX Gateway Fabric&lt;/strong&gt; in my Kubernetes cluster, create a small NGINX web application, and make the application accessible through a Kubernetes &lt;strong&gt;Gateway&lt;/strong&gt; and &lt;strong&gt;HTTPRoute&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The intended request path was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;My Kali terminal
      |
      | HTTP request to NodePort :30080
      v
NGINX Gateway
      |
      | HTTPRoute matches path /
      v
Kubernetes Service: frontend-svc:80
      |
      v
Pod: frontend-app (NGINX listens on port 80)
      |
      v
HTTP/1.1 200 OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Think of it like sending a parcel. The Gateway is the front desk, the HTTPRoute is the instruction that says where the parcel should go, the Service is the stable address for the destination, and the Pod is the actual person receiving it.&lt;/p&gt;
&lt;p&gt;This post walks through what I did, the problems I hit, and how I worked through them. The useful lesson was not just getting the page to load. It was learning to test one layer at a time instead of randomly changing things until Kubernetes takes pity on me.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-installing-the-gateway-api-building-blocks&quot;&gt;1. Installing the Gateway API building blocks&lt;/h3&gt;
&lt;p&gt;I started in my &lt;code&gt;nginx-gateway-fabric&lt;/code&gt; working directory and applied the standard Gateway API CRDs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -k config/crd/gateway-api/standard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;CRD&lt;/strong&gt; means &lt;em&gt;CustomResourceDefinition&lt;/em&gt;. Kubernetes comes with built-in resources such as Pods, Deployments, and Services. CRDs teach Kubernetes about additional resource types. The Gateway API CRDs add resources such as &lt;code&gt;GatewayClass&lt;/code&gt;, &lt;code&gt;Gateway&lt;/code&gt;, and &lt;code&gt;HTTPRoute&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I then installed the NGINX Gateway Fabric-specific CRDs and the NodePort deployment for version &lt;code&gt;1.6.1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v1.6.1/deploy/crds.yaml

kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v1.6.1/deploy/nodeport/deploy.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The NodePort deployment gave me a way to reach the Gateway using a port on a Kubernetes node. In this lab, HTTP was exposed on port &lt;strong&gt;30080&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;problem-1-kustomize-timed-out-while-fetching-the-crds&quot;&gt;Problem 1: Kustomize timed out while fetching the CRDs&lt;/h4&gt;
&lt;p&gt;My first attempt to fetch the Gateway API CRDs directly from GitHub using &lt;code&gt;kubectl kustomize&lt;/code&gt; failed with a Git fetch timeout. Because the command failed to produce the manifests, the following &lt;code&gt;kubectl apply&lt;/code&gt; command reported that no objects had been passed to it.&lt;/p&gt;
&lt;p&gt;That second message was a consequence of the first failure, not a separate mystery.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I did:&lt;/strong&gt; I worked with the repository locally and applied the Kustomize directory from the checked-out source:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -k config/crd/gateway-api/standard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; When a command downloads configuration and then applies it, check the download/rendering step first. If it produces nothing, &lt;code&gt;kubectl apply&lt;/code&gt; cannot magically apply it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-the-gateway-pod-was-pending&quot;&gt;2. The Gateway Pod was Pending&lt;/h3&gt;
&lt;p&gt;After applying the NGINX Gateway Fabric deployment, I checked the Pod:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get pods -n nginx-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first, it showed &lt;code&gt;Pending&lt;/code&gt;. My first attempt to describe it failed too:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe pod nginx-gateway-55f96886f7-j4kzq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Pod was not found because I had left out its namespace. It lived in &lt;code&gt;nginx-gateway&lt;/code&gt;, not the &lt;code&gt;default&lt;/code&gt; namespace.&lt;/p&gt;
&lt;p&gt;The corrected command was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe pod nginx-gateway-55f96886f7-j4kzq -n nginx-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important event was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;0/2 nodes are available: 2 node(s) had untolerated taint(s).
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;what-does-that-mean-&quot;&gt;What does that mean?&lt;/h4&gt;
&lt;p&gt;A &lt;strong&gt;taint&lt;/strong&gt; is a rule on a Kubernetes node that says, in effect, “Don't schedule Pods here unless they tolerate this condition.” A &lt;strong&gt;toleration&lt;/strong&gt; is a matching permission in a Pod's specification.&lt;/p&gt;
&lt;p&gt;The Gateway Pod was not necessarily broken. Kubernetes was saying it could not find a node where the Pod was allowed to run. I also saw that &lt;code&gt;k8s-worker1&lt;/code&gt; briefly became &lt;code&gt;NotReady&lt;/code&gt; before returning to &lt;code&gt;Ready&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I learned:&lt;/strong&gt; Check the node status and the Pod's scheduling events before changing the deployment. Taints may be protecting the cluster for a reason, so don't remove them blindly just to make a Pod start.&lt;/p&gt;
&lt;p&gt;Useful commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes -o wide
kubectl describe pod nginx-gateway-55f96886f7-j4kzq -n nginx-gateway
kubectl describe node k8s-worker1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eventually, the Gateway Pod was scheduled to &lt;code&gt;k8s-worker1&lt;/code&gt; and progressed toward running.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-creating-the-frontend-application&quot;&gt;3. Creating the frontend application&lt;/h3&gt;
&lt;p&gt;Next, I created a simple NGINX Pod:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl run frontend-app --image=nginx --port=8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One subtle detail caused a later problem: &lt;strong&gt;&lt;code&gt;--port=8080&lt;/code&gt; does not reconfigure NGINX to listen on port 8080.&lt;/strong&gt; It records container-port metadata in the Pod specification. The NGINX image still listens on port &lt;strong&gt;80&lt;/strong&gt; by default.&lt;/p&gt;
&lt;p&gt;I exposed the Pod as a Service:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl expose pod frontend-app \
  --name=frontend-svc \
  --port=80 \
  --target-port=8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;Service&lt;/strong&gt; gives a stable network address to a group of Pods. This is useful because Pods can be replaced, and their IP addresses can change. Clients can keep talking to the Service instead of tracking individual Pod IPs.&lt;/p&gt;
&lt;p&gt;I checked the Service and its endpoints:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe svc frontend-svc -n default
kubectl get endpoints frontend-svc -n default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Initially, the endpoint showed port &lt;code&gt;8080&lt;/code&gt;. That looked consistent with the Service configuration, but it was not consistent with the port NGINX actually used.&lt;/p&gt;
&lt;h4 id=&quot;problem-2-the-service-pointed-to-the-wrong-port&quot;&gt;Problem 2: The Service pointed to the wrong port&lt;/h4&gt;
&lt;p&gt;I tested NGINX from inside its own Pod:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl exec frontend-app -n default -- \
  curl -I --max-time 5 http://127.0.0.1:8080/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It failed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;curl: (7) Failed to connect to 127.0.0.1 port 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of guessing, I tested the default NGINX port:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl exec frontend-app -n default -- \
  curl -I --max-time 5 http://127.0.0.1:80/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;HTTP/1.1 200 OK
Server: nginx/1.31.7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There was the clue. NGINX was alive; I had simply sent it to the wrong port.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; I changed the Service's &lt;code&gt;targetPort&lt;/code&gt; to &lt;code&gt;80&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl patch svc frontend-svc -n default \
  -p '{&quot;spec&quot;:{&quot;ports&quot;:[{&quot;port&quot;:80,&quot;targetPort&quot;:80}]}}'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I checked it again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe svc frontend-svc -n default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The endpoint now pointed to the Pod on port &lt;code&gt;80&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; The Service's &lt;code&gt;port&lt;/code&gt; is the port clients use to reach the Service. The &lt;code&gt;targetPort&lt;/code&gt; is the port on the backend Pod that receives the traffic. Those values can be different, but &lt;code&gt;targetPort&lt;/code&gt; must match the application that is actually listening.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-building-the-httproute&quot;&gt;4. Building the HTTPRoute&lt;/h3&gt;
&lt;p&gt;The next step was to tell the Gateway where to send incoming HTTP requests. I created an &lt;code&gt;HTTPRoute&lt;/code&gt; called &lt;code&gt;frontend-route&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The important parts of the route were:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: frontend-route
  namespace: default
spec:
  parentRefs:
    - name: nginx-gateway
      namespace: nginx-gateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: frontend-svc
          port: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In plain English:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attach this route to the &lt;code&gt;nginx-gateway&lt;/code&gt; Gateway in the &lt;code&gt;nginx-gateway&lt;/code&gt; namespace.&lt;/li&gt;
&lt;li&gt;Match requests whose path starts with &lt;code&gt;/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Forward matching requests to the Service named &lt;code&gt;frontend-svc&lt;/code&gt; on port &lt;code&gt;80&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I checked the result with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe httproute frontend-route -n default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The good news was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Type:    Accepted
Status:  True

Type:    ResolvedRefs
Status:  True
Message: All references are resolved
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These conditions mean the Gateway accepted the route and Kubernetes could resolve its references. They are useful signals, but I still needed to test actual traffic.&lt;/p&gt;
&lt;h4 id=&quot;problem-3-the-httproute-could-not-find-the-backend-service&quot;&gt;Problem 3: The HTTPRoute could not find the backend Service&lt;/h4&gt;
&lt;p&gt;My first route was in the &lt;code&gt;nginx-gateway&lt;/code&gt; namespace and referred to &lt;code&gt;frontend-svc&lt;/code&gt;. Kubernetes returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;BackendNotFound
spec.rules[0].backendRefs[0].name: Not found: &quot;frontend-svc&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had created &lt;code&gt;frontend-svc&lt;/code&gt; in the &lt;code&gt;default&lt;/code&gt; namespace. A Service reference in an HTTPRoute is normally resolved in the route's own namespace. Giving the Service the correct name was not enough; the namespace mattered too.&lt;/p&gt;
&lt;p&gt;I edited the route YAML and placed the working &lt;code&gt;frontend-route&lt;/code&gt; in &lt;code&gt;default&lt;/code&gt;, while keeping its &lt;code&gt;parentRefs&lt;/code&gt; pointing to the Gateway in &lt;code&gt;nginx-gateway&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That fixed the reference. The route then reported both &lt;code&gt;Accepted=True&lt;/code&gt; and &lt;code&gt;ResolvedRefs=True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; In Kubernetes, always check both the resource's &lt;strong&gt;name and namespace&lt;/strong&gt;. Two resources can share a name in different namespaces, and a route can be accepted while still having an unresolved backend reference.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;5-testing-the-service-before-testing-the-gateway&quot;&gt;5. Testing the Service before testing the Gateway&lt;/h3&gt;
&lt;p&gt;Before troubleshooting the Gateway, I tested the Service directly. First, I checked that CoreDNS was running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get pods -n kube-system
kubectl get svc -n kube-system kube-dns
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I created a short-lived diagnostic Pod:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl run dns-test --image=busybox:1.36 \
  --restart=Never --command -- sleep 300

kubectl wait --for=condition=Ready pod/dns-test \
  -n default --timeout=60s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I inspected its DNS settings:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl exec dns-test -- cat /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file showed the cluster DNS Service IP, &lt;code&gt;10.96.0.10&lt;/code&gt;. I then tested DNS resolution:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl exec dns-test -- \
  nslookup kubernetes.default.svc.cluster.local

kubectl exec dns-test -- \
  nslookup frontend-svc.default.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both names resolved. The frontend Service resolved to &lt;code&gt;10.104.158.51&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;problem-4-one-curl-test-could-not-resolve-the-service-name&quot;&gt;Problem 4: One curl test could not resolve the Service name&lt;/h4&gt;
&lt;p&gt;An earlier temporary curl Pod returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;curl: (6) Could not resolve host: frontend-svc.default.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was confusing because the DNS Service and CoreDNS Pods looked healthy.&lt;/p&gt;
&lt;p&gt;Rather than restarting DNS immediately, I used a separate diagnostic Pod to test the basics. Its &lt;code&gt;nslookup&lt;/code&gt; commands successfully resolved both the Kubernetes API Service and &lt;code&gt;frontend-svc&lt;/code&gt;. Then I tested the Service itself:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl exec dns-test -- wget -S -O- \
  http://frontend-svc.default.svc.cluster.local/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returned the default NGINX welcome page and an &lt;code&gt;HTTP/1.1 200 OK&lt;/code&gt; response.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I can conclude:&lt;/strong&gt; DNS resolution and Service connectivity worked from the diagnostic Pod. The earlier curl test failed, but the evidence did not establish its exact cause. The right move was to reproduce the test and inspect the layers separately rather than assume CoreDNS was broken.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;6-the-gateway-was-programmed-but-my-first-request-returned-a-500&quot;&gt;6. The Gateway was programmed, but my first request returned a 500&lt;/h3&gt;
&lt;p&gt;I checked the Gateway and its Service:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get svc -n nginx-gateway
kubectl describe gateway nginx-gateway -n nginx-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Service showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;TYPE       NodePort
PORT(S)    80:30080/TCP,443:30081/TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Gateway status showed &lt;code&gt;Accepted=True&lt;/code&gt; and &lt;code&gt;Programmed=True&lt;/code&gt;. That meant the Gateway configuration had been accepted and programmed, but an end-to-end test was still needed.&lt;/p&gt;
&lt;p&gt;I checked the route in &lt;code&gt;nginx-gateway&lt;/code&gt; and discovered that a &lt;strong&gt;second route with the same name&lt;/strong&gt; existed there. Unlike the working route in &lt;code&gt;default&lt;/code&gt;, this duplicate route still referenced a backend Service that was not in its namespace. Its status included &lt;code&gt;BackendNotFound&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I deleted the broken duplicate route:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl delete httproute frontend-route -n nginx-gateway
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I kept the working route in &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My first request to the NodePort returned &lt;code&gt;500 Internal Server Error&lt;/code&gt;. After removing the broken duplicate route, I tried again. The request succeeded.&lt;/p&gt;
&lt;p&gt;The logs show that the bad duplicate route existed and that the response changed after I removed it. That makes the duplicate route a strong suspect in the earlier failure, although the response alone does not prove it was the only cause.&lt;/p&gt;
&lt;h4 id=&quot;problem-5-two-routes-one-name-different-namespaces&quot;&gt;Problem 5: Two routes, one name, different namespaces&lt;/h4&gt;
&lt;p&gt;Kubernetes permits resources with the same name in different namespaces. That is not automatically an error, but it made this troubleshooting session confusing: one &lt;code&gt;frontend-route&lt;/code&gt; was correctly configured, while the other had an unresolved backend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; When a route behaves unexpectedly, check all routes across namespaces:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get httproute -A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don't check only the namespace where you expect the route to live.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;7-the-final-test-success-through-the-nodeport&quot;&gt;7. The final test: success through the NodePort&lt;/h3&gt;
&lt;p&gt;I checked the node addresses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes -o wide
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The worker node's internal IP was &lt;code&gt;10.0.2.4&lt;/code&gt;. The Gateway's HTTP NodePort was &lt;code&gt;30080&lt;/code&gt;, so I tested:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -i --max-time 10 http://10.0.2.4:30080/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first, I mistakenly typed the placeholder literally:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -i --max-time 10 http://WORKER_IP:30080/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The terminal returned &lt;code&gt;Could not resolve host: WORKER_IP&lt;/code&gt;. The shell did exactly what I asked: it treated &lt;code&gt;WORKER_IP&lt;/code&gt; as a hostname. Placeholders must be replaced with actual values before running a command.&lt;/p&gt;
&lt;p&gt;The final request returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;HTTP/1.1 200 OK
Server: nginx
Content-Length: 896
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, below the headers, the familiar &lt;strong&gt;“Welcome to nginx!”&lt;/strong&gt; HTML page appeared.&lt;/p&gt;
&lt;p&gt;That was the end-to-end confirmation I wanted: a request from my Kali terminal entered through the node's NodePort, reached the NGINX Gateway, matched the HTTPRoute, and was forwarded to the frontend Service and Pod.&lt;/p&gt;
&lt;hr&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31221/from-why-is-this-pod-pending-to-http-1-1-200-ok-my-nginx-gateway-fabric-lab</guid>
<pubDate>Thu, 15 Oct 2026 15:15:48 +0000</pubDate>
</item>
<item>
<title>How a Kubernetes Cluster Works | Control Plane &amp; Worker Nodes</title>
<link>https://coderlegion.com/28959/how-a-kubernetes-cluster-works-control-plane-worker-nodes</link>
<description>&lt;h3 id=&quot;how-does-a-kubernetes-cluster-actually-work-&quot;&gt;How does a Kubernetes cluster actually work?&lt;/h3&gt;
&lt;p&gt;I’ve been learning Kubernetes and realized that it’s easy to memorize terms like &lt;strong&gt;Control Plane, Worker Node, API Server, Scheduler,&lt;/strong&gt; and &lt;strong&gt;kubelet&lt;/strong&gt; without really understanding how they fit together.&lt;/p&gt;
&lt;p&gt;So I put together a video explaining &lt;strong&gt;how a Kubernetes cluster works&lt;/strong&gt;, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Control Plane and Worker Nodes&lt;/li&gt;
&lt;li&gt;API Server&lt;/li&gt;
&lt;li&gt;etcd&lt;/li&gt;
&lt;li&gt;Scheduler&lt;/li&gt;
&lt;li&gt;Controller Manager&lt;/li&gt;
&lt;li&gt;Pods&lt;/li&gt;
&lt;li&gt;kubelet&lt;/li&gt;
&lt;li&gt;Container Runtime&lt;/li&gt;
&lt;li&gt;kube-proxy&lt;/li&gt;
&lt;li&gt;What happens when you run a &lt;code&gt;kubectl&lt;/code&gt; command?&lt;/li&gt;
&lt;li&gt;Different ways to create and operate a Kubernetes cluster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My goal was to understand the &lt;strong&gt;flow&lt;/strong&gt;, not just memorize component definitions.&lt;/p&gt;
&lt;p&gt;🎥 &lt;strong&gt;Watch here:&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=v-Zh2sIPm7s&quot;&gt;How a Kubernetes Cluster Works | Control Plane &amp;amp; Worker Nodes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’d love to hear from other Kubernetes learners like me: &lt;strong&gt;which part of the cluster architecture took you the longest to understand?&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Videos</category>
<guid isPermaLink="true">https://coderlegion.com/28959/how-a-kubernetes-cluster-works-control-plane-worker-nodes</guid>
<pubDate>Tue, 29 Sep 2026 12:00:00 +0000</pubDate>
</item>
<item>
<title>How Kubernetes Works | Kubernetes Explained Simply for Beginners</title>
<link>https://coderlegion.com/27172/how-kubernetes-works-kubernetes-explained-simply-for-beginners</link>
<description>&lt;p&gt;Kubernetes can feel confusing when you first start learning it.&lt;/p&gt;
&lt;p&gt;Pods. Nodes. Services. Deployments. Scaling.&lt;/p&gt;
&lt;p&gt;There are so many new terms that it is easy to focus on memorizing definitions instead of understanding how everything connects.&lt;/p&gt;
&lt;p&gt;I recently created a simple animated explanation of how Kubernetes works, using a small application and a real-world-style scenario to walk through the concepts.&lt;/p&gt;
&lt;p&gt;If you're currently learning Kubernetes, this might help make the pieces click.&lt;/p&gt;
&lt;p&gt;What Kubernetes concept took you the longest to understand?&lt;/p&gt;
&lt;h2 id=&quot;kubernetes-devops-cloudcomputing-k8s-cncf-lfx&quot;&gt;Kubernetes #DevOps #CloudComputing #K8s #CNCF #LFX&lt;/h2&gt;
</description>
<category>Videos</category>
<guid isPermaLink="true">https://coderlegion.com/27172/how-kubernetes-works-kubernetes-explained-simply-for-beginners</guid>
<pubDate>Mon, 14 Sep 2026 14:41:36 +0000</pubDate>
</item>
<item>
<title>From `kubectl` to `jq`: A Beginner's Detective Story Through Kubernetes JSON Paths</title>
<link>https://coderlegion.com/25544/from-kubectl-to-jq-a-beginners-detective-story-through-kubernetes-json-paths</link>
<description>&lt;p&gt; &lt;em&gt;Or: How I Learned to Stop Worrying and Love the Dot-Notation&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-setup-two-nodes-one-mystery&quot;&gt;The Setup: Two Nodes, One Mystery&lt;/h3&gt;
&lt;p&gt;Picture this: you've just spun up a Kubernetes cluster on your laptop. You've got two nodes talking to each other:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NAME          STATUS   ROLES           AGE   VERSION
k8s-worker1   Ready    &amp;lt;none&amp;gt;          9d    v1.36.3
osboxes       Ready    control-plane   9d    v1.36.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything looks calm. But beneath the surface, one node is about to go rogue, and you're about to learn more about JSON paths than you ever thought possible.&lt;/p&gt;
&lt;p&gt;This is the story of how a simple assignment—&lt;strong&gt;&quot;Check the number of schedulable nodes excluding tainted (NoSchedule) and write the number to a file&quot;&lt;/strong&gt;—turned into an epic journey through Kubernetes internals, JSONPath syntax, &lt;code&gt;jq&lt;/code&gt; filters, and the subtle art of handling &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-1-peeking-under-the-hood-with-json&quot;&gt;Chapter 1: Peeking Under the Hood with JSON&lt;/h3&gt;
&lt;p&gt;When you run &lt;code&gt;kubectl get pods&lt;/code&gt;, you get a nice table. But Kubernetes is holding &lt;em&gt;so much more&lt;/em&gt; information than fits in a table. To see everything, you ask for JSON:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get po -o json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What comes back is a massive JSON object with nested objects, arrays, and maps. It's intimidating at first, but think of it like a Russian nesting doll:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;apiVersion&quot;: &quot;v1&quot;,
  &quot;items&quot;: [
    {
      &quot;kind&quot;: &quot;Pod&quot;,
      &quot;metadata&quot;: {
        &quot;name&quot;: &quot;nginx&quot;,
        &quot;labels&quot;: { &quot;run&quot;: &quot;nginx&quot; }
      },
      &quot;spec&quot;: {
        &quot;containers&quot;: [
          {
            &quot;name&quot;: &quot;nginx&quot;,
            &quot;image&quot;: &quot;nginx&quot;
          }
        ]
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; Every Kubernetes object follows this pattern. There's always a top-level structure, and inside &lt;code&gt;.items[]&lt;/code&gt; lives the actual object (Pod, Node, Service, etc.).&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-2-jsonpath-kubernetes-built-in-x-ray-vision&quot;&gt;Chapter 2: JSONPath — Kubernetes' Built-in X-Ray Vision&lt;/h3&gt;
&lt;p&gt;JSONPath is like giving &lt;code&gt;kubectl&lt;/code&gt; a treasure map. Instead of dumping the entire JSON, you say: &lt;em&gt;&quot;Give me exactly this field.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;success-extracting-pod-labels&quot;&gt;Success: Extracting Pod Labels&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -o=jsonpath='{.items[0].metadata.labels}'
# Output: {&quot;run&quot;:&quot;nginx&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Boom! We navigated: &lt;code&gt;.items&lt;/code&gt; → first item &lt;code&gt;[0]&lt;/code&gt; → &lt;code&gt;.metadata&lt;/code&gt; → &lt;code&gt;.labels&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;success-finding-the-container-image&quot;&gt;Success: Finding the Container Image&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -o=jsonpath='{.items[0].spec.containers[0].image}'
# Output: nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how we chain deeper: &lt;code&gt;.spec&lt;/code&gt; → &lt;code&gt;.containers[0]&lt;/code&gt; → &lt;code&gt;.image&lt;/code&gt;. It's like a file path, but for JSON.&lt;/p&gt;
&lt;h4 id=&quot;success-volume-mounts&quot;&gt;Success: Volume Mounts&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -o=jsonpath='{.items[0].spec.containers[0].volumeMounts[0].mountPath}'
# Output: /var/run/secrets/kubernetes.io/serviceaccount
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We're getting good at this! But wait...&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-3-the-node-expedition-where-things-get-interesting&quot;&gt;Chapter 3: The Node Expedition — Where Things Get Interesting&lt;/h3&gt;
&lt;p&gt;Pods were practice. Now let's look at &lt;strong&gt;nodes&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;experiment-1-getting-node-names&quot;&gt;Experiment 1: Getting Node Names&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o=jsonpath='{.items[*].metadata.name}'
# Output: k8s-worker1 osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;[*]&lt;/code&gt; wildcard says: &lt;em&gt;&quot;For every item in the array, give me this field.&quot;&lt;/em&gt; It's the JSONPath way of saying &quot;all of them.&quot;&lt;/p&gt;
&lt;h4 id=&quot;experiment-2-adding-a-newline&quot;&gt;Experiment 2: Adding a Newline&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o=jsonpath='{.items[*].metadata.name}{&quot;\n&quot;}'
# Output: k8s-worker1 osboxes
# (now with a proper newline!)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSONPath can inject literal strings. Handy for formatting.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-4-custom-columns-making-your-own-tables&quot;&gt;Chapter 4: Custom Columns — Making Your Own Tables&lt;/h3&gt;
&lt;p&gt;JSONPath is great for single values. But what if you want a &lt;strong&gt;table&lt;/strong&gt; with only the columns &lt;em&gt;you&lt;/em&gt; care about?&lt;/p&gt;
&lt;p&gt;Enter &lt;code&gt;custom-columns&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;attempt-1-the-syntax-trap&quot;&gt;Attempt 1: The Syntax Trap&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o='custom-columns=Node:{.items[*].metadata.name}'
# Output:
# Node
# &amp;lt;none&amp;gt;
# &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What went wrong?&lt;/strong&gt; With &lt;code&gt;custom-columns&lt;/code&gt;, Kubernetes already iterates over &lt;code&gt;.items&lt;/code&gt; for you. Using &lt;code&gt;{.items[*]...}&lt;/code&gt; is redundant—it expects a path relative to a single item, not the whole list.&lt;/p&gt;
&lt;h4 id=&quot;the-fix-drop-the-items-&quot;&gt;The Fix: Drop the &lt;code&gt;.items[*]&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o='custom-columns=Node:{.metadata.name}'
# Output:
# Node
# k8s-worker1
# osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Aha moment:&lt;/strong&gt; &lt;code&gt;custom-columns&lt;/code&gt; iterates automatically. You write the path as if you're looking at &lt;em&gt;one&lt;/em&gt; node, and Kubernetes repeats it for all nodes.&lt;/p&gt;
&lt;h4 id=&quot;attempt-2-the-unclosed-brace&quot;&gt;Attempt 2: The Unclosed Brace&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o='custom-columns=Node:{.metadata.name},IP:{.status.addresses[*].address'
# error: unexpected path string...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What went wrong?&lt;/strong&gt; Missing closing &lt;code&gt;}&lt;/code&gt; brace. JSONPath expressions in custom-columns must be fully enclosed in &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;the-fix-close-your-braces-&quot;&gt;The Fix: Close Your Braces!&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o='custom-columns=Node:{.metadata.name},IP:{.status.addresses[*].address}'
# Output:
# Node         IP
# k8s-worker1  10.0.2.4,k8s-worker1
# osboxes      10.0.2.15,osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works! But notice the IP column has &lt;em&gt;two&lt;/em&gt; values per node (InternalIP and Hostname). That's because &lt;code&gt;[*]&lt;/code&gt; grabs everything in the array.&lt;/p&gt;
&lt;h4 id=&quot;attempt-3-maps-are-not-arrays&quot;&gt;Attempt 3: Maps Are Not Arrays&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o='custom-columns=Node:{.metadata.name},Capacity:{.status.capacity[*]}'
# error: map[string]interface {} is not array or slice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What went wrong?&lt;/strong&gt; &lt;code&gt;.status.capacity&lt;/code&gt; is a &lt;strong&gt;map&lt;/strong&gt; (key-value pairs: &lt;code&gt;cpu: 2&lt;/code&gt;, &lt;code&gt;memory: 2018648Ki&lt;/code&gt;), not an &lt;strong&gt;array&lt;/strong&gt;. You can't use &lt;code&gt;[*]&lt;/code&gt; on a map.&lt;/p&gt;
&lt;h4 id=&quot;attempt-4-the-map-dump&quot;&gt;Attempt 4: The Map Dump&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o='custom-columns=Node:{.metadata.name},CPUCapacity:{.status.capacity}'
# Output:
# Node         CPUCapacity
# k8s-worker1  map[cpu:2 ephemeral-storage:242470332Ki hugepages-2Mi:0 memory:2018648Ki pods:110]
# osboxes      map[cpu:2 ephemeral-storage:515464096Ki hugepages-2Mi:0 memory:4011360Ki pods:110]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It &lt;em&gt;works&lt;/em&gt;, but it's ugly. We wanted just the CPU number, not the whole map printed as a Go-style &lt;code&gt;map[...]&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;the-fix-drill-into-the-map&quot;&gt;The Fix: Drill Into the Map&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get nodes -o='custom-columns=Node:{.metadata.name},CPUCapacity:{.status.capacity.cpu}'
# Output:
# Node         CPUCapacity
# k8s-worker1  2
# osboxes      2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Aha moment:&lt;/strong&gt; Maps are accessed by key, just like objects. &lt;code&gt;.status.capacity.cpu&lt;/code&gt; says: &lt;em&gt;&quot;Go into capacity, then get the value for key 'cpu'.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-5-the-real-boss-fight-counting-schedulable-nodes&quot;&gt;Chapter 5: The Real Boss Fight — Counting Schedulable Nodes&lt;/h3&gt;
&lt;p&gt;Now for the main event. The assignment sounds simple: &lt;strong&gt;count schedulable nodes, excluding those with a &lt;code&gt;NoSchedule&lt;/code&gt; taint.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But this is where we descend into the underworld.&lt;/p&gt;
&lt;h4 id=&quot;mistake-1-wrong-resource-type&quot;&gt;Mistake 1: Wrong Resource Type&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get pods -o json | jq -r '.items[] | select(.spec.taints[].effect == &quot;NoSchedule&quot;)'
# (empty output)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What went wrong?&lt;/strong&gt; We queried &lt;strong&gt;pods&lt;/strong&gt;. Pods don't have &lt;code&gt;.spec.taints&lt;/code&gt;—&lt;strong&gt;nodes&lt;/strong&gt; do! This is like looking for a car's engine in the trunk.&lt;/p&gt;
&lt;h4 id=&quot;mistake-2-the-null-iteration-bomb&quot;&gt;Mistake 2: The Null Iteration Bomb&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes -o json | jq -r '.items[] | select(.spec.taints[].effect == &quot;NoSchedule&quot;)'
# jq: error: Cannot iterate over null (null)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What went wrong?&lt;/strong&gt; We switched to nodes, but &lt;code&gt;k8s-worker1&lt;/code&gt; has &lt;strong&gt;no taints at all&lt;/strong&gt;. In JSON, a missing field is &lt;code&gt;null&lt;/code&gt;. &lt;code&gt;jq&lt;/code&gt; tried to iterate over &lt;code&gt;null&lt;/code&gt; with &lt;code&gt;[]&lt;/code&gt;, and &lt;code&gt;jq&lt;/code&gt; &lt;em&gt;hates&lt;/em&gt; that.&lt;/p&gt;
&lt;p&gt;Think of it like this: you asked &lt;code&gt;jq&lt;/code&gt; to &quot;open every box in this room,&quot; but one of the boxes doesn't exist. &lt;code&gt;jq&lt;/code&gt; throws its hands up.&lt;/p&gt;
&lt;h4 id=&quot;attempt-3-filtering-for-null-taints&quot;&gt;Attempt 3: Filtering for Null Taints&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes -o json | jq -r '.items[] | select(.spec.taints == null)' &amp;gt; schedulable-nodes.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;em&gt;works&lt;/em&gt; for finding nodes with no taints, but it writes the &lt;strong&gt;entire JSON object&lt;/strong&gt; of &lt;code&gt;k8s-worker1&lt;/code&gt; to the file. The assignment asked for a &lt;strong&gt;number&lt;/strong&gt;, not a novel.&lt;/p&gt;
&lt;p&gt;Also, what if a node &lt;em&gt;has&lt;/em&gt; taints, but none of them are &lt;code&gt;NoSchedule&lt;/code&gt;? This query would miss it.&lt;/p&gt;
&lt;h4 id=&quot;the-working-solution-the-full-jq-pipeline&quot;&gt;The Working Solution: The Full &lt;code&gt;jq&lt;/code&gt; Pipeline&lt;/h4&gt;
&lt;p&gt;After much trial and error, here is the command that actually solves the problem:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes -o json | jq '[.items[] | select(.spec.taints == null or ([.spec.taints[] | select(.effect == &quot;NoSchedule&quot;)] | length == 0))] | length' &amp;gt; schedulable-nodes.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's dissect this beast, piece by piece.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-6-the-jq-command-autopsy&quot;&gt;Chapter 6: The &lt;code&gt;jq&lt;/code&gt; Command Autopsy&lt;/h3&gt;
&lt;h4 id=&quot;stage-1-get-the-data&quot;&gt;Stage 1: Get the Data&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes -o json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Produces the full JSON list of nodes.&lt;/p&gt;
&lt;h4 id=&quot;stage-2-enter-jq&quot;&gt;Stage 2: Enter &lt;code&gt;jq&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;| jq '...'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;jq&lt;/code&gt; is a command-line JSON processor. Think of it as &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; had a baby that only speaks JSON.&lt;/p&gt;
&lt;h4 id=&quot;stage-3-iterate-over-items&quot;&gt;Stage 3: Iterate Over Items&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-jq&quot;&gt;.items[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This says: &lt;em&gt;&quot;Take the &lt;code&gt;items&lt;/code&gt; array and process each element one by one.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;stage-4-the-select-filter&quot;&gt;Stage 4: The &lt;code&gt;select()&lt;/code&gt; Filter&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-jq&quot;&gt;select(.spec.taints == null or (...))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;select()&lt;/code&gt; keeps an item only if the condition is &lt;code&gt;true&lt;/code&gt;. We have two conditions joined by &lt;code&gt;or&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Condition A:&lt;/strong&gt; &lt;code&gt;.spec.taints == null&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does this node have no taints at all?&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;k8s-worker1&lt;/code&gt; (when healthy): &lt;strong&gt;true&lt;/strong&gt; → keep it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Condition B:&lt;/strong&gt; &lt;code&gt;([.spec.taints[] | select(.effect == &quot;NoSchedule&quot;)] | length == 0)&lt;/code&gt;&lt;br&gt;
This is the sophisticated part. Let's break it down:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;.spec.taints[]&lt;/code&gt; — &quot;Go through each taint on this node.&quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;| select(.effect == &quot;NoSchedule&quot;)&lt;/code&gt; — &quot;Keep only the taints whose effect is NoSchedule.&quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[ ... ]&lt;/code&gt; — &quot;Put those matching taints into an array.&quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;| length&lt;/code&gt; — &quot;Count how many items are in that array.&quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;== 0&lt;/code&gt; — &quot;Is that count zero?&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If a node has taints but &lt;em&gt;zero&lt;/em&gt; of them are &lt;code&gt;NoSchedule&lt;/code&gt;, this returns &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why both conditions?&lt;/strong&gt; Because if a node has no taints, &lt;code&gt;.spec.taints&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;, and you can't iterate over &lt;code&gt;null&lt;/code&gt;. Condition A catches the &quot;no taints&quot; case. Condition B catches the &quot;has taints, but none are NoSchedule&quot; case.&lt;/p&gt;
&lt;h4 id=&quot;stage-5-collect-and-count&quot;&gt;Stage 5: Collect and Count&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-jq&quot;&gt;[ ... ] | length
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The outer &lt;code&gt;[ ... ]&lt;/code&gt; gathers all the nodes that survived the filter into a new array. Then &lt;code&gt;| length&lt;/code&gt; counts them.&lt;/p&gt;
&lt;p&gt;In our case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;k8s-worker1&lt;/code&gt; (no NoSchedule taint) → &lt;strong&gt;KEPT&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;osboxes&lt;/code&gt; (has &lt;code&gt;node-role.kubernetes.io/control-plane:NoSchedule&lt;/code&gt;) → &lt;strong&gt;DISCARDED&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Result: &lt;strong&gt;1&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;stage-6-write-to-file&quot;&gt;Stage 6: Write to File&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;gt; schedulable-nodes.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Shell redirection writes the output (just the number &lt;code&gt;1&lt;/code&gt;) to the file.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-7-the-plot-twist-a-node-goes-dark&quot;&gt;Chapter 7: The Plot Twist — A Node Goes Dark&lt;/h3&gt;
&lt;p&gt;Remember when we said &lt;code&gt;k8s-worker1&lt;/code&gt; was healthy? At one point in the session, it wasn't.&lt;/p&gt;
&lt;p&gt;The node JSON revealed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&quot;conditions&quot;: [
  {
    &quot;type&quot;: &quot;Ready&quot;,
    &quot;status&quot;: &quot;Unknown&quot;,
    &quot;reason&quot;: &quot;NodeStatusUnknown&quot;,
    &quot;message&quot;: &quot;Kubelet stopped posting node status.&quot;
  }
],
&quot;spec&quot;: {
  &quot;taints&quot;: [
    {
      &quot;effect&quot;: &quot;NoSchedule&quot;,
      &quot;key&quot;: &quot;node.kubernetes.io/unreachable&quot;
    },
    {
      &quot;effect&quot;: &quot;NoExecute&quot;,
      &quot;key&quot;: &quot;node.kubernetes.io/unreachable&quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The kubelet on &lt;code&gt;k8s-worker1&lt;/code&gt; stopped sending heartbeats. After ~55 minutes of silence, the control plane declared it unreachable and slapped &lt;code&gt;NoSchedule&lt;/code&gt; and &lt;code&gt;NoExecute&lt;/code&gt; taints on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is why JSON exploration matters.&lt;/strong&gt; If you only looked at &lt;code&gt;kubectl get nodes&lt;/code&gt;, you'd see &lt;code&gt;NotReady&lt;/code&gt; or &lt;code&gt;Unknown&lt;/code&gt;. But the JSON tells you &lt;em&gt;why&lt;/em&gt;: the kubelet died. Maybe the VM crashed. Maybe the battery died on the laptop hosting it. The JSON is the detective's notebook.&lt;/p&gt;
&lt;p&gt;Later, the node recovered—its taints disappeared and it started reporting healthy status again. But for a while, the schedulable node count dropped to &lt;strong&gt;zero&lt;/strong&gt; (because both nodes had NoSchedule taints: &lt;code&gt;k8s-worker1&lt;/code&gt; from being unreachable, and &lt;code&gt;osboxes&lt;/code&gt; from being the control plane).&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;chapter-8-key-lessons-the-jsonpath-survival-guide&quot;&gt;Chapter 8: Key Lessons — The JSONPath Survival Guide&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Concept &lt;/th&gt;&lt;th&gt;JSONPath Example &lt;/th&gt;&lt;th&gt;What It Does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Single item &lt;/td&gt;&lt;td&gt;&lt;code&gt;{.items[0].metadata.name}&lt;/code&gt; &lt;/td&gt;&lt;td&gt;First item's name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;All items &lt;/td&gt;&lt;td&gt;&lt;code&gt;{.items[*].metadata.name}&lt;/code&gt; &lt;/td&gt;&lt;td&gt;All names, space-separated&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wildcard in maps &lt;/td&gt;&lt;td&gt;&lt;code&gt;{.status.capacity.cpu}&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Value for key &lt;code&gt;cpu&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Wildcard in arrays &lt;/td&gt;&lt;td&gt;&lt;code&gt;{.spec.containers[*].image}&lt;/code&gt; &lt;/td&gt;&lt;td&gt;All container images&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Literal string &lt;/td&gt;&lt;td&gt;&lt;code&gt;{.metadata.name}{&quot;\n&quot;}&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Add a newline&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Custom columns &lt;/td&gt;&lt;td&gt;&lt;code&gt;-o='custom-columns=NAME:{.metadata.name}'&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Build your own table&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;the-golden-rules&quot;&gt;The Golden Rules&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;custom-columns&lt;/code&gt; iterates for you.&lt;/strong&gt; Don't use &lt;code&gt;.items[*]&lt;/code&gt; inside it. Use &lt;code&gt;.metadata.name&lt;/code&gt;, not &lt;code&gt;.items[*].metadata.name&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maps ≠ Arrays.&lt;/strong&gt; You can't use &lt;code&gt;[*]&lt;/code&gt; on a map like &lt;code&gt;.status.capacity&lt;/code&gt;. Use &lt;code&gt;.status.capacity.cpu&lt;/code&gt; instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;jq&lt;/code&gt; hates null iteration.&lt;/strong&gt; Always guard against &lt;code&gt;null&lt;/code&gt; when using &lt;code&gt;[]&lt;/code&gt;. Use &lt;code&gt;== null&lt;/code&gt; or &lt;code&gt;// []&lt;/code&gt; (default empty array) as safety nets.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Know your resource anatomy.&lt;/strong&gt; Pods have &lt;code&gt;.spec.nodeName&lt;/code&gt; and &lt;code&gt;.spec.tolerations&lt;/code&gt;. Nodes have &lt;code&gt;.spec.taints&lt;/code&gt; and &lt;code&gt;.status.conditions&lt;/code&gt;. Don't mix them up!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Count at the end.&lt;/strong&gt; If the assignment asks for a number, wrap your filter in &lt;code&gt;[ ... ] | length&lt;/code&gt; before writing to the file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-final-file&quot;&gt;The Final File&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat schedulable-nodes.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One file. One number. Hours of learning compressed into a single digit.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;epilogue-why-this-matters&quot;&gt;Epilogue: Why This Matters&lt;/h3&gt;
&lt;p&gt;Kubernetes is an API-driven system. Everything you see in &lt;code&gt;kubectl&lt;/code&gt; is a pretty-printed version of JSON traveling over HTTP. When you learn JSONPath and &lt;code&gt;jq&lt;/code&gt;, you stop being a tourist and start being an explorer. You can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build monitoring scripts that extract exact metrics&lt;/li&gt;
&lt;li&gt;Write admission controllers that inspect object specs&lt;/li&gt;
&lt;li&gt;Debug scheduling failures by reading taints and conditions&lt;/li&gt;
&lt;li&gt;Automate cluster reports without parsing human-readable tables&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25544/from-kubectl-to-jq-a-beginners-detective-story-through-kubernetes-json-paths</guid>
<pubDate>Thu, 27 Aug 2026 11:36:35 +0000</pubDate>
</item>
<item>
<title>Internet-Free Infrastructure: How Two Servers Talk Without Using the Internet</title>
<link>https://coderlegion.com/25364/internet-free-infrastructure-how-two-servers-talk-without-using-the-internet</link>
<description>&lt;p&gt;Imagine you're building a SaaS platform.&lt;/p&gt;
&lt;p&gt;Nothing unusual.&lt;/p&gt;
&lt;p&gt;A web application.&lt;/p&gt;
&lt;p&gt;A PostgreSQL database.&lt;/p&gt;
&lt;p&gt;A Redis cache.&lt;/p&gt;
&lt;p&gt;Everything runs in the cloud.&lt;/p&gt;
&lt;p&gt;The architecture looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Users
  ↓
Application Server
  ↓
PostgreSQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple.&lt;/p&gt;
&lt;p&gt;A user sends a request.&lt;/p&gt;
&lt;p&gt;The application queries the database.&lt;/p&gt;
&lt;p&gt;The database responds.&lt;/p&gt;
&lt;p&gt;The application returns data.&lt;/p&gt;
&lt;p&gt;Feature shipped.&lt;/p&gt;
&lt;p&gt;Customers happy.&lt;/p&gt;
&lt;p&gt;Everyone moves on.&lt;/p&gt;
&lt;p&gt;For a while.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-question-nobody-asks&quot;&gt;The Question Nobody Asks&lt;/h3&gt;
&lt;p&gt;Most engineers focus on:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application Logic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Database Queries
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;API Design
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But infrastructure engineers eventually ask a different question:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;How does the application server actually reach the database server?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not conceptually.&lt;/p&gt;
&lt;p&gt;Literally.&lt;/p&gt;
&lt;p&gt;How does one machine know where another machine is?&lt;/p&gt;
&lt;p&gt;How does a packet travel from one server to another?&lt;/p&gt;
&lt;p&gt;And perhaps the most surprising question:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;If both servers live in the cloud, why doesn't their communication go through the Internet?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-common-misconception&quot;&gt;The Common Misconception&lt;/h3&gt;
&lt;p&gt;Many people imagine cloud infrastructure like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application Server
        ↓
     Internet
        ↓
Database Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It seems reasonable.&lt;/p&gt;
&lt;p&gt;After all, both servers exist somewhere inside AWS, Azure, or Google Cloud.&lt;/p&gt;
&lt;p&gt;Surely the traffic goes through the Internet.&lt;/p&gt;
&lt;p&gt;Right?&lt;/p&gt;
&lt;p&gt;Actually, no.&lt;/p&gt;
&lt;p&gt;In most production systems, internal communication never touches the public Internet.&lt;/p&gt;
&lt;p&gt;Instead, it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application Server
        ↓
 Private Network
        ↓
Database Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No public Internet.&lt;/p&gt;
&lt;p&gt;No ISP.&lt;/p&gt;
&lt;p&gt;No external routers.&lt;/p&gt;
&lt;p&gt;No public IP addresses.&lt;/p&gt;
&lt;p&gt;Just private infrastructure.&lt;/p&gt;
&lt;p&gt;This distinction matters because it changes everything about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;Reliability&lt;/li&gt;
&lt;li&gt;Cost&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To understand why, we need to start with the first building block.&lt;/p&gt;
&lt;p&gt;The VPC.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-cloud-is-a-giant-city&quot;&gt;The Cloud Is A Giant City&lt;/h3&gt;
&lt;p&gt;Imagine AWS as a massive country.&lt;/p&gt;
&lt;p&gt;Inside that country:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Netflix

Airbnb

Stripe

Shopify

Your Startup

Thousands of Others
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of them are running servers.&lt;/p&gt;
&lt;p&gt;All of them are storing data.&lt;/p&gt;
&lt;p&gt;All of them are deploying applications.&lt;/p&gt;
&lt;p&gt;Now imagine there were no boundaries.&lt;/p&gt;
&lt;p&gt;No isolation.&lt;/p&gt;
&lt;p&gt;No separation.&lt;/p&gt;
&lt;p&gt;Every server could see every other server.&lt;/p&gt;
&lt;p&gt;That would be a security nightmare.&lt;/p&gt;
&lt;p&gt;Cloud providers solve this problem using something called a:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Virtual Private Cloud
(VPC)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Think of a VPC as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Your own private city
inside a giant country.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The cloud provider owns the country.&lt;/p&gt;
&lt;p&gt;You own the city.&lt;/p&gt;
&lt;p&gt;Inside that city:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your servers can communicate&lt;/li&gt;
&lt;li&gt;Your databases can communicate&lt;/li&gt;
&lt;li&gt;Your caches can communicate&lt;/li&gt;
&lt;li&gt;Other companies cannot access them&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first thing cloud infrastructure gives you is not a server.&lt;/p&gt;
&lt;p&gt;It's a private network.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-infrastructure-starts-with-a-network&quot;&gt;Why Infrastructure Starts With A Network&lt;/h3&gt;
&lt;p&gt;New engineers often think infrastructure begins here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;EC2 Instance

Virtual Machine

Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It doesn't.&lt;/p&gt;
&lt;p&gt;Infrastructure usually begins here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because servers without networks are useless.&lt;/p&gt;
&lt;p&gt;Imagine buying a house.&lt;/p&gt;
&lt;p&gt;But there are:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;No roads

No addresses

No transportation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The house exists.&lt;/p&gt;
&lt;p&gt;But nobody can reach it.&lt;/p&gt;
&lt;p&gt;Servers have the same problem.&lt;/p&gt;
&lt;p&gt;Before machines can communicate, they need a network.&lt;/p&gt;
&lt;p&gt;The VPC creates that network.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-next-problem&quot;&gt;The Next Problem&lt;/h3&gt;
&lt;p&gt;Suppose your company grows.&lt;/p&gt;
&lt;p&gt;Now you have:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application Servers

Database Servers

Redis

Background Workers

Message Queues

Monitoring Systems

Admin Tools
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything lives inside one VPC.&lt;/p&gt;
&lt;p&gt;At first this sounds convenient.&lt;/p&gt;
&lt;p&gt;Until security enters the conversation.&lt;/p&gt;
&lt;p&gt;Should a database be reachable from everywhere?&lt;/p&gt;
&lt;p&gt;Probably not.&lt;/p&gt;
&lt;p&gt;Should every server have Internet access?&lt;/p&gt;
&lt;p&gt;Probably not.&lt;/p&gt;
&lt;p&gt;Should internal systems be exposed publicly?&lt;/p&gt;
&lt;p&gt;Definitely not.&lt;/p&gt;
&lt;p&gt;This is where subnets appear.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;subnets-are-neighborhoods&quot;&gt;Subnets Are Neighborhoods&lt;/h3&gt;
&lt;p&gt;If a VPC is a city:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;VPC = City
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Subnet = Neighborhood
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A company might create:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;VPC
│
├── Public Subnet
│
├── Application Subnet
│
└── Database Subnet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each subnet serves a purpose.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Public Subnet

Load Balancer
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Private Application Subnet

App Server 1
App Server 2
App Server 3
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Private Database Subnet

PostgreSQL
Redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice something important.&lt;/p&gt;
&lt;p&gt;The database sits deeper inside the infrastructure.&lt;/p&gt;
&lt;p&gt;Further away from the Internet.&lt;/p&gt;
&lt;p&gt;This is intentional.&lt;/p&gt;
&lt;p&gt;Because good infrastructure is built around reducing exposure.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-database-doesn-t-need-the-internet&quot;&gt;The Database Doesn't Need The Internet&lt;/h3&gt;
&lt;p&gt;Many founders are surprised by this.&lt;/p&gt;
&lt;p&gt;A database usually doesn't need users.&lt;/p&gt;
&lt;p&gt;A database needs applications.&lt;/p&gt;
&lt;p&gt;That's a completely different requirement.&lt;/p&gt;
&lt;p&gt;Consider:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Customer
    ↓
Application
    ↓
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The customer never talks directly to PostgreSQL.&lt;/p&gt;
&lt;p&gt;Only the application does.&lt;/p&gt;
&lt;p&gt;So exposing the database publicly creates risk without creating value.&lt;/p&gt;
&lt;p&gt;This is why production databases often live in private subnets.&lt;/p&gt;
&lt;p&gt;The database can still be reached.&lt;/p&gt;
&lt;p&gt;But only by trusted systems.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;every-server-gets-a-private-address&quot;&gt;Every Server Gets A Private Address&lt;/h3&gt;
&lt;p&gt;Now imagine an application server wants to reach PostgreSQL.&lt;/p&gt;
&lt;p&gt;How does it find the database?&lt;/p&gt;
&lt;p&gt;The same way you find a building.&lt;/p&gt;
&lt;p&gt;Addresses.&lt;/p&gt;
&lt;p&gt;Every server receives an IP address.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application

10.0.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Database

10.0.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are private IP addresses.&lt;/p&gt;
&lt;p&gt;Not public ones.&lt;/p&gt;
&lt;p&gt;Nobody on the Internet can reach them.&lt;/p&gt;
&lt;p&gt;But machines inside the VPC can.&lt;/p&gt;
&lt;p&gt;Now the application knows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Database

10.0.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Problem solved?&lt;/p&gt;
&lt;p&gt;Not quite.&lt;/p&gt;
&lt;p&gt;Knowing an address isn't enough.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;knowing-the-address-doesn-t-create-a-path&quot;&gt;Knowing The Address Doesn't Create A Path&lt;/h3&gt;
&lt;p&gt;Imagine someone gives you:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;221B Baker Street
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great.&lt;/p&gt;
&lt;p&gt;You know the destination.&lt;/p&gt;
&lt;p&gt;But how do you get there?&lt;/p&gt;
&lt;p&gt;You need roads.&lt;/p&gt;
&lt;p&gt;Networks have the same problem.&lt;/p&gt;
&lt;p&gt;An IP address tells you:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Where
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;How
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That responsibility belongs to routing.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;routing-is-the-gps-of-the-cloud&quot;&gt;Routing Is The GPS Of The Cloud&lt;/h3&gt;
&lt;p&gt;Every network contains routing rules.&lt;/p&gt;
&lt;p&gt;These rules answer one question:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Where should this packet go next?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A route table might contain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Destination      Target

10.0.0.0/16      Local
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Meaning:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Any traffic
inside this VPC
stays inside this VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now imagine:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application

10.0.1.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;sending a request to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Database

10.0.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The network checks the routing table.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Destination?

10.0.2.20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Inside VPC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Therefore:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Deliver Locally
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The packet never leaves the cloud network.&lt;/p&gt;
&lt;p&gt;The Internet is never involved.&lt;/p&gt;
&lt;p&gt;The communication happens entirely inside private infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-request-s-actual-journey&quot;&gt;The Request's Actual Journey&lt;/h3&gt;
&lt;p&gt;When the application queries PostgreSQL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM users;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What really happens is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application
   ↓
Private IP
   ↓
Route Table
   ↓
Database Subnet
   ↓
Database Server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No Internet.&lt;/p&gt;
&lt;p&gt;No DNS lookup to the public Internet.&lt;/p&gt;
&lt;p&gt;No external networking providers.&lt;/p&gt;
&lt;p&gt;Just internal routing.&lt;/p&gt;
&lt;p&gt;This is why internal communication is usually:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Faster&lt;/li&gt;
&lt;li&gt;More secure&lt;/li&gt;
&lt;li&gt;More predictable&lt;/li&gt;
&lt;li&gt;Less exposed to external failures&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-this-matters-to-founders&quot;&gt;Why This Matters To Founders&lt;/h3&gt;
&lt;p&gt;At first glance this sounds like technical trivia.&lt;/p&gt;
&lt;p&gt;It's not.&lt;/p&gt;
&lt;p&gt;Because infrastructure decisions directly affect business outcomes.&lt;/p&gt;
&lt;p&gt;Imagine two architectures.&lt;/p&gt;
&lt;h4 id=&quot;architecture-a&quot;&gt;Architecture A&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application
     ↓
Internet
     ↓
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;architecture-b&quot;&gt;Architecture B&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Application
     ↓
Private Network
     ↓
Database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second architecture provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better security&lt;/li&gt;
&lt;li&gt;Lower attack surface&lt;/li&gt;
&lt;li&gt;Lower latency&lt;/li&gt;
&lt;li&gt;Fewer compliance concerns&lt;/li&gt;
&lt;li&gt;Better scalability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The customer never notices.&lt;/p&gt;
&lt;p&gt;But the company benefits every day.&lt;/p&gt;
&lt;p&gt;This is one of the reasons mature SaaS platforms invest heavily in infrastructure design.&lt;/p&gt;
&lt;p&gt;Not because customers ask for VPCs.&lt;/p&gt;
&lt;p&gt;Because customers expect reliability.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-most-important-lesson&quot;&gt;The Most Important Lesson&lt;/h3&gt;
&lt;p&gt;When most people think about cloud infrastructure, they think about servers.&lt;/p&gt;
&lt;p&gt;Experienced engineers think about networks.&lt;/p&gt;
&lt;p&gt;Because before applications communicate:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Networks must exist.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before databases respond:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Routes must exist.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before systems scale:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Infrastructure boundaries must exist.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Internet is only one network.&lt;/p&gt;
&lt;p&gt;Most production systems spend far more time communicating inside private networks than across the public Internet.&lt;/p&gt;
&lt;p&gt;And understanding that idea is the first step toward understanding modern cloud infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;frequently-asked-questions&quot;&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;h4 id=&quot;what-is-a-vpc-&quot;&gt;What is a VPC?&lt;/h4&gt;
&lt;p&gt;A Virtual Private Cloud (VPC) is an isolated private network inside a cloud provider where your infrastructure resources can communicate securely.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;what-is-a-subnet-&quot;&gt;What is a subnet?&lt;/h4&gt;
&lt;p&gt;A subnet is a smaller network segment inside a VPC used to organize and isolate infrastructure resources.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;why-do-servers-use-private-ip-addresses-&quot;&gt;Why do servers use private IP addresses?&lt;/h4&gt;
&lt;p&gt;Private IP addresses allow internal communication without exposing systems directly to the public Internet.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;does-traffic-between-servers-always-go-through-the-internet-&quot;&gt;Does traffic between servers always go through the Internet?&lt;/h4&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;p&gt;In most cloud architectures, communication between internal services stays inside the provider's private network.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;what-is-a-route-table-&quot;&gt;What is a route table?&lt;/h4&gt;
&lt;p&gt;A route table contains rules that determine where network traffic should be sent.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;why-are-databases-usually-placed-in-private-subnets-&quot;&gt;Why are databases usually placed in private subnets?&lt;/h4&gt;
&lt;p&gt;Because databases typically only need to communicate with application servers, not with public users.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Most production server-to-server communication never touches the public Internet.&lt;/li&gt;
&lt;li&gt;A VPC creates an isolated private network inside the cloud.&lt;/li&gt;
&lt;li&gt;Subnets divide a network into smaller security and operational boundaries.&lt;/li&gt;
&lt;li&gt;Servers communicate using private IP addresses.&lt;/li&gt;
&lt;li&gt;Route tables determine how packets travel through the network.&lt;/li&gt;
&lt;li&gt;Security starts with network design, not application code.&lt;/li&gt;
&lt;li&gt;Cloud infrastructure is fundamentally a networking problem before it becomes a server problem.&lt;/li&gt;
&lt;li&gt;Understanding VPCs, subnets, private IPs, and routes is the foundation of modern cloud architecture.&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25364/internet-free-infrastructure-how-two-servers-talk-without-using-the-internet</guid>
<pubDate>Tue, 25 Aug 2026 17:21:06 +0000</pubDate>
</item>
<item>
<title>Confidential Computing</title>
<link>https://coderlegion.com/25349/confidential-computing</link>
<description>&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Trusted_system&quot;&gt;Trust systems&lt;/a&gt;&lt;/strong&gt; have long been a contentious topic in cloud computing. Standard cloud models operate on a passive assumption that you trust your cloud provider and you trust the underlying host OS, and more importantly, you trust the hypervisor not to peek at your running data.&lt;/p&gt;
&lt;p&gt;For highly-regulated industries like healthcare, FinTech, and defence contractors, that assumption is ultimately non-compliant. Between nation-state threat models, sophisticated insider risks, and multi-tenant cloud environments, data cannot be left vulnerable while it’s still active. So this is where &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Confidential_computing&quot;&gt;Confidential Computing&lt;/a&gt;&lt;/strong&gt; was created to address that critical trust problem. Unfortunately, while it solves many of these critical privacy problems, it also introduces some operational trade-offs that might still prevent your security teams from adopting it.&lt;/p&gt;
&lt;p&gt;Historically, encryption covered two states: &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.cloudflare.com/learning/security/glossary/data-at-rest/&quot;&gt;Data at-rest&lt;/a&gt;&lt;/strong&gt; (on disk)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.mongodb.com/resources/basics/data-in-transit&quot;&gt;Data in-transit&lt;/a&gt;&lt;/strong&gt; (over the network). &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Confidential Computing completes the trifecta by introducing &lt;strong&gt;Data in-use&lt;/strong&gt; protection. Confidential Computing specifically relies on Trusted Execution Environments (&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Trusted_execution_environment&quot;&gt;TEEs&lt;/a&gt;&lt;/strong&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data at-rest --&amp;gt; Encrypted on disk (&lt;strong&gt;AES-256&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Data in-transit --&amp;gt; Encrypted over network (&lt;strong&gt;TLS&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Data in-use --&amp;gt; Encrypted within memory (&lt;strong&gt;TEEs&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TEEs are &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://vaultody.com/blog/250-hardware-enclaves-the-ultimate-cybersecurity-shield-for-data-protection&quot;&gt;hardware-level enclaves&lt;/a&gt;&lt;/strong&gt; embedded directly into the CPU. Memory pages inside a TEE are cryptographically isolated so that neither other tenants, host operating systems, nor hypervisors can read or manipulate the running code. Through remote attestation, an application can cryptographically prove to a remote verifier that it is running inside a legitimate, uncompromised hardware enclave before any sensitive data is sent.&lt;/p&gt;
&lt;p&gt;For compliance-heavy sectors, Confidential Computing unlocks capabilities that were previously off-limits in shared public clouds. Multiple hospital networks, as an example, could pool proprietary patient data to train large language models or diagnostic algorithms without exposing Protected Health Information (&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Protected_health_information&quot;&gt;PHI data&lt;/a&gt;&lt;/strong&gt;) to each other or the cloud vendor. Likewise, banks can perform real-time cross-institutional fraud detection on combined transaction feeds while strictly maintaining individual consumer privacy. Finally, any and all organisations could choose to simplify compliance under strict regimes like the GDPR or any newly-emerging AI governance frameworks by maintaining mathematical and cryptographic proof of data privacy during computation.&lt;/p&gt;
&lt;p&gt;While TEEs offer powerful hardware guarantees, they are often misunderstood as a complete security cure-all. A clear look at the threat model reveals significant operational boundaries. For example, those hardware TEEs protect the workload from the hypervisor, but they do not protect the hypervisor or any neighbouring workloads from a malicious or compromised application inside the enclave. Similarly, TEEs require specialised hardware instances. These carry encrypted memory limits and in many cases can force organisations into vendor lock-in or complex application refactoring to keep the Trusted Computing Base (&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Trusted_computing_base&quot;&gt;TCB&lt;/a&gt;&lt;/strong&gt;) small. And last but not least, these TEEs unfortunately inevitably contain hardware-level vulnerabilities. Firmware updates and side-channel attacks such as &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2024-56161&quot;&gt;CVE-2024-56161&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://badram.eu/badram.pdf&quot;&gt;BadRAM&lt;/a&gt;&lt;/strong&gt; prove that hardware is not infallible. Patching hardware bugs can mean waiting on microcode updates or replacing silicon entirely.&lt;/p&gt;
&lt;p&gt;For full transparency, I work at a cloud-native security company called Edera looking to solve this issue through a zero-trust lens. Since TEEs focus on protecting against a compromised hypervisor, Edera compliments this by focusing specifically on protecting against a compromised workload. Most modern multi-tenant environments need both. Edera successfully bridges the existing blind spots between hardware-bound TEEs and Kubernetes, ensuring businesses don't simply have to choose between having strict isolation and improved dev agility.&lt;/p&gt;
&lt;p&gt;When paired with physical TEEs, Edera runs within encrypted memory pages. This delivers complete bidirectional security such as data-in-use encryption isolating your app from the cloud provider. Combined with Edera’s hypervisor-level isolation, you can keep your infrastructure safe from untrusted workload code. Unfortunately, it’s worth stating that not every cloud region, edge device, or Kubernetes cluster has access to specialised TEE hardware required for Confidential Computing. For these specific environments, there’s &lt;strong&gt;Edera Confidential Core&lt;/strong&gt;. If you are not familiar with Edera Confidential Core, it’s a feature of Edera’s ultra-slim Xen-based hypervisor architecture that provides hypervisor-enforced memory encryption and &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://spiffe.io/&quot;&gt;SPIFFE&lt;/a&gt;&lt;/strong&gt; identity-driven remote attestation. It isolates the tenant memory on page faults and provides the core benefits that we’ve come to expect from confidential computing such as encryption in memory as well as strict workload boundary protection, without requiring any specialised hardware or forcing disruptive application rewrites.&lt;/p&gt;
&lt;p&gt;Securing data in the cloud shouldn’t be about picking a single security term, instead you should think about how you are going to define your threat model. For example, if your threat model demands protection against a cloud provider or hypervisor peeking at your data, Confidential Computing with TEEs is absolutely &lt;strong&gt;ESSENTIAL&lt;/strong&gt;. If your threat model requires protecting host infrastructure from compromised, user-facing container workloads, hypervisor isolation via &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://edera.dev/use-case/confidential-computing&quot;&gt;Edera&lt;/a&gt;&lt;/strong&gt; becomes the right solution for that specific problem. However, if you need a comprehensive zero-trust isolation without being locked into expensive hardware dependencies, I hope I made the case that Edera Confidential Core is capable of bridging the gap. Cloud security should never be about forcing trade-offs between hardware availability, app performance, and data privacy. By bringing workload isolation into harmony with memory confidentiality, enterprises can run their most sensitive workloads anywhere safely.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25349/confidential-computing</guid>
<pubDate>Tue, 25 Aug 2026 12:39:44 +0000</pubDate>
</item>
<item>
<title>Troubleshooting Kubernetes Application Failures: A Real Debugging Session</title>
<link>https://coderlegion.com/24841/troubleshooting-kubernetes-application-failures-a-real-debugging-session</link>
<description>&lt;p&gt;Here's a scenario every Kubernetes learner eventually runs into: your Pods are all &lt;code&gt;Running&lt;/code&gt;, your Deployments say &lt;code&gt;1/1&lt;/code&gt; or &lt;code&gt;3/3&lt;/code&gt; &lt;code&gt;AVAILABLE&lt;/code&gt;, everything &lt;em&gt;looks&lt;/em&gt; healthy in &lt;code&gt;kubectl get&lt;/code&gt;... and yet when you try to actually hit your app, you get nothing but silence or a flat-out connection refusal.&lt;/p&gt;
&lt;p&gt;That's exactly the situation I found myself in on my two-node cluster (one control-plane node, one worker) while running the classic &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/dockersamples/example-voting-app&quot;&gt;Example Voting App&lt;/a&gt; — &lt;code&gt;vote&lt;/code&gt;, &lt;code&gt;redis&lt;/code&gt;, &lt;code&gt;worker&lt;/code&gt;, &lt;code&gt;db&lt;/code&gt;, and &lt;code&gt;result&lt;/code&gt;. This post walks through the actual debugging session, the dead ends I hit, and the three separate root causes I eventually tracked down. If you're new to Kubernetes networking, this is the kind of thing you'll hit constantly, so it's worth understanding the pattern rather than just memorizing the fix.&lt;/p&gt;
&lt;h3 id=&quot;the-setup&quot;&gt;The Setup&lt;/h3&gt;
&lt;p&gt;A simple 5-component app running across 2 nodes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k get nodes
NAME          STATUS   ROLES           AGE   VERSION
k8s-worker1   Ready    &amp;lt;none&amp;gt;          23h   v1.36.3
osboxes       Ready    control-plane   24h   v1.36.3

$ k get deploy
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
db       1/1     1            1           113m
redis    1/1     1            1           113m
result   1/1     1            1           113m
vote     1/1     1            1           113m
worker   3/3     3            3           113m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything's &lt;code&gt;READY&lt;/code&gt;. Every Pod is &lt;code&gt;Running&lt;/code&gt;. By every surface-level signal, this cluster is healthy. So when &lt;code&gt;curl&lt;/code&gt; to the &lt;code&gt;vote&lt;/code&gt; service just hung and then refused the connection, it was a good reminder that &lt;strong&gt;&quot;Running&quot; only tells you the container started — it says nothing about whether traffic can actually reach it.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-architecture&quot;&gt;The Architecture&lt;/h3&gt;
&lt;p&gt;Before diving into the debugging, it helps to see the full request path this app takes. Five components, two different NodePorts for user-facing traffic, and three internal ClusterIP hops in between:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=11359393275870760347&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The user hits the &lt;strong&gt;&lt;code&gt;vote&lt;/code&gt;&lt;/strong&gt; frontend (Python) from outside the cluster, through a &lt;strong&gt;NodePort&lt;/strong&gt; service on &lt;code&gt;31000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vote&lt;/code&gt; writes each vote into &lt;strong&gt;Redis&lt;/strong&gt;, reached internally via a &lt;strong&gt;ClusterIP&lt;/strong&gt; service — Redis never needs to be exposed outside the cluster.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;worker&lt;/code&gt;&lt;/strong&gt; (.NET) consumes votes off Redis as they come in.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker&lt;/code&gt; writes the processed result into &lt;strong&gt;Postgres&lt;/strong&gt; (the &lt;code&gt;db&lt;/code&gt; component), again over ClusterIP.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;result&lt;/code&gt;&lt;/strong&gt; frontend (Node.js) pulls the current tally from Postgres.&lt;/li&gt;
&lt;li&gt;The user checks the live results through a second &lt;strong&gt;NodePort&lt;/strong&gt;, &lt;code&gt;31001&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a useful diagram to keep next to your terminal while debugging, because it tells you exactly &lt;em&gt;which&lt;/em&gt; Service type to expect at each hop: &lt;code&gt;vote&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt; are the only two components that should ever be reachable via NodePort — everything else (&lt;code&gt;redis&lt;/code&gt;, &lt;code&gt;worker&lt;/code&gt;, &lt;code&gt;db&lt;/code&gt;) should only ever be reachable ClusterIP-to-ClusterIP, inside the cluster. That distinction is what made the three bugs below easy to isolate: I knew from this diagram alone that if &lt;code&gt;vote&lt;/code&gt; (step 1) wasn't reachable, the problem had to be in the &lt;code&gt;vote&lt;/code&gt; Service or Pod itself — and if &lt;code&gt;redis&lt;/code&gt; couldn't be reached by &lt;code&gt;worker&lt;/code&gt; (step 3), the problem had to be either a Service selector or a NetworkPolicy sitting between them.&lt;/p&gt;
&lt;h3 id=&quot;where-to-even-start&quot;&gt;Where To Even Start&lt;/h3&gt;
&lt;p&gt;When an app &quot;isn't working&quot; in Kubernetes, the traffic path you're debugging usually looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client → NodePort/Service → Endpoints → Pod IP:containerPort → Your app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A failure can happen at &lt;em&gt;any&lt;/em&gt; link in that chain, so the debugging flow is basically peeling back one layer at a time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -o wide          # Are the pods actually running, and where?
k get svc                   # Do the services exist, with the right type/ports?
k describe svc &amp;lt;name&amp;gt;       # What's the selector, targetPort, and endpoint?
k get ep                    # Does the service actually have any endpoints?
k get po --show-labels      # Do the pod labels match what the service expects?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That last one ended up being the key to almost everything below. Let's go through what actually broke.&lt;/p&gt;
&lt;h3 id=&quot;issue-1-nodeport-connects-to-nothing&quot;&gt;Issue #1: NodePort Connects... to Nothing&lt;/h3&gt;
&lt;p&gt;First symptom — trying to hit the &lt;code&gt;vote&lt;/code&gt; app from outside the cluster just failed outright:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ curl http://10.0.2.4:31000
curl: (7) Failed to connect to 10.0.2.4:31000 after 4 ms: Could not connect to server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The service existed, and it &lt;em&gt;had&lt;/em&gt; an endpoint, so my first instinct (checking for missing endpoints) was a dead end:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k describe svc vote
Name:                     vote
Selector:                 app=vote
Type:                     NodePort
Port:                     vote-service  5000/TCP
TargetPort:               8080/TCP
NodePort:                 vote-service  31000/TCP
Endpoints:                192.168.194.74:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That all looks fine at a glance — there &lt;em&gt;is&lt;/em&gt; an endpoint. So I went a layer deeper and checked what port the container inside the Pod was actually bound to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get pod vote-6c95bd6c8-hjz4s -o jsonpath='{.spec.containers[*].ports}'
[{&quot;containerPort&quot;:80,&quot;name&quot;:&quot;vote&quot;,&quot;protocol&quot;:&quot;TCP&quot;}]

$ kubectl logs vote-6c95bd6c8-hjz4s
[2026-08-18 12:42:10 +0000] [1] [INFO] Listening at: http://0.0.0.0:80 (1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there's the mismatch: the container was listening on &lt;strong&gt;port 80&lt;/strong&gt;, but the Service's &lt;code&gt;targetPort&lt;/code&gt; was set to &lt;strong&gt;8080&lt;/strong&gt;. The Service was faithfully forwarding traffic to a port nothing was listening on — which from the outside just looks like a dead connection.&lt;/p&gt;
&lt;p&gt;The fix was a one-line edit to the Service spec:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k edit svc vote
# change targetPort from 8080 to 80
service/vote edited
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl describe svc vote
TargetPort:               80/TCP
Endpoints:                192.168.194.74:80

$ curl http://10.0.2.4:31000
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  ...
  &amp;lt;h3&amp;gt;Cats vs Dogs!&amp;lt;/h3&amp;gt;
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; &lt;code&gt;targetPort&lt;/code&gt; on a Service has to match the actual &lt;code&gt;containerPort&lt;/code&gt; your app is listening on inside the Pod — not the port you &lt;em&gt;think&lt;/em&gt; it should be, and not the &lt;code&gt;port&lt;/code&gt; field on the Service itself (those are two different numbers doing two different jobs). Always check &lt;code&gt;kubectl logs&lt;/code&gt; or the container's declared port when a Service &quot;has an endpoint&quot; but still won't respond.&lt;/p&gt;
&lt;h3 id=&quot;issue-2-a-service-with-zero-endpoints-at-all&quot;&gt;Issue #2: A Service With Zero Endpoints At All&lt;/h3&gt;
&lt;p&gt;Next up, the &lt;code&gt;result&lt;/code&gt; service. This one was worse — it didn't even have a broken endpoint, it had &lt;strong&gt;no endpoint whatsoever&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k describe svc result
Name:                     result
Selector:                 app=results
Type:                     NodePort
Port:                     result-service  5001/TCP
TargetPort:               80/TCP
NodePort:                 result-service  31001/TCP
Endpoints:                
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An empty &lt;code&gt;Endpoints:&lt;/code&gt; field is one of the most common Kubernetes networking bugs, and it always means the same thing: &lt;strong&gt;the Service's &lt;code&gt;selector&lt;/code&gt; doesn't match any Pod's labels.&lt;/strong&gt; Kubernetes isn't &quot;broken&quot; here — it's doing exactly what it's told, which is &quot;find me Pods with these exact labels.&quot; If nothing matches, it just quietly gives you nothing.&lt;/p&gt;
&lt;p&gt;So I checked the actual Pod labels:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k get po --show-labels
NAME                     LABELS
result-58c64976b-7qqh4   app=result,pod-template-hash=58c64976b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Found it. The Service selector was looking for &lt;code&gt;app=results&lt;/code&gt; (plural), but the Pod was labeled &lt;code&gt;app=result&lt;/code&gt; (singular). One character, zero traffic. This is an incredibly easy typo to make and an incredibly hard one to &lt;em&gt;see&lt;/em&gt; just by glancing at YAML — &lt;code&gt;describe&lt;/code&gt; output puts it right in front of you.&lt;/p&gt;
&lt;p&gt;Fix: edit the Service selector to match the Pod's real label.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k edit svc result
service/result edited

$ k get ep
NAME     ENDPOINTS
result   192.168.194.83:80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Endpoint populated immediately — no Pod restart needed, since the Service just watches for matching labels live.&lt;/p&gt;
&lt;h3 id=&quot;issue-3-networkpolicies-fail-silently-too&quot;&gt;Issue #3: NetworkPolicies Fail Silently Too&lt;/h3&gt;
&lt;p&gt;At this point &lt;code&gt;vote&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt; were both reachable, but &lt;code&gt;vote&lt;/code&gt; still couldn't talk to &lt;code&gt;redis&lt;/code&gt; internally — a &lt;code&gt;NetworkPolicy&lt;/code&gt; was involved:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k describe netpol access-redis
Name:         access-redis
Spec:
  PodSelector:     app=redis
  Allowing ingress traffic:
    From:
      PodSelector: app=frontend
  Policy Types: Ingress
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This policy says: &lt;em&gt;&quot;Only allow ingress to &lt;code&gt;redis&lt;/code&gt; Pods from Pods labeled &lt;code&gt;app=frontend&lt;/code&gt;.&quot;&lt;/em&gt; Sounds reasonable — except nothing in this cluster was labeled &lt;code&gt;app=frontend&lt;/code&gt;. The actual frontend-facing app was labeled &lt;code&gt;app=vote&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k get po --show-labels | grep vote
vote-6c95bd6c8-hjz4s   app=vote,pod-template-hash=6c95bd6c8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same root cause as Issue #2 — a selector referencing a label that doesn't exist anywhere in the cluster — just applied to a &lt;code&gt;NetworkPolicy&lt;/code&gt; instead of a &lt;code&gt;Service&lt;/code&gt;. That's worth internalizing: &lt;strong&gt;NetworkPolicies are also just label selectors under the hood&lt;/strong&gt;, and they fail the exact same silent way. There's no error, no event, no warning. Traffic is simply dropped, and unless you specifically go look at &lt;code&gt;k get netpol&lt;/code&gt; you might never think to check it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ k edit netpol access-redis
# change podSelector under &quot;From&quot; to app=vote
networkpolicy.networking.k8s.io/access-redis edited
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-quick-debugging-checklist&quot;&gt;A Quick Debugging Checklist&lt;/h3&gt;
&lt;p&gt;If your app is deployed, Pods are &lt;code&gt;Running&lt;/code&gt;, but traffic isn't flowing, walk this list roughly top to bottom:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -o wide                              # Pods running? Which node/IP?
k get svc                                        # Service exists, right type/ports?
k describe svc &amp;lt;svc-name&amp;gt;                        # selector, targetPort, endpoints
k get ep                                         # any endpoints at all?
k get po --show-labels                           # do labels actually match the selector?
kubectl logs &amp;lt;pod&amp;gt;                               # is the app listening where you expect?
kubectl get pod &amp;lt;pod&amp;gt; -o jsonpath='{.spec.containers[*].ports}'  # real containerPort
k get netpol                                     # any policies restricting traffic?
k describe netpol &amp;lt;name&amp;gt;                         # does its selector match real Pods?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A couple of things I ran into along the way that are worth a quick mention: some minimal app images don't ship with &lt;code&gt;ss&lt;/code&gt;, &lt;code&gt;netstat&lt;/code&gt;, or even much of a shell (&lt;code&gt;exec: &quot;ss&quot;: executable file not found in $PATH&lt;/code&gt; was a fun one), so don't assume you can always debug &lt;em&gt;from inside&lt;/em&gt; the container — sometimes &lt;code&gt;kubectl logs&lt;/code&gt; and the Pod's declared ports are more reliable than trying to exec in. Also, &lt;code&gt;kubectl get endpoints&lt;/code&gt; is deprecated in favor of &lt;code&gt;discovery.k8s.io/v1 EndpointSlice&lt;/code&gt; from v1.33 onward, so &lt;code&gt;kubectl get endpointslice -l kubernetes.io/service-name=&amp;lt;svc&amp;gt;&lt;/code&gt; is the more future-proof command going forward.&lt;/p&gt;
&lt;p&gt;None of these were exotic bugs — a wrong port number, a pluralized label, and a stale selector in a policy. But that's honestly the nature of most Kubernetes networking issues: small, easy-to-miss mismatches between YAML files that Kubernetes will never flag as an &quot;error,&quot; because as far as the control plane is concerned, you asked for exactly what you got. Learning to methodically walk the Service → Endpoints → Pod chain is what turns &quot;my app doesn't work and I have no idea why&quot; into a two-minute fix.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24841/troubleshooting-kubernetes-application-failures-a-real-debugging-session</guid>
<pubDate>Tue, 18 Aug 2026 16:09:53 +0000</pubDate>
</item>
<item>
<title>Kubernetes ETCD Backup And Restore — Part 2: Restoring etcd and Recovering the Cluster</title>
<link>https://coderlegion.com/24753/kubernetes-etcd-backup-and-restore-part-2-restoring-etcd-and-recovering-the-cluster</link>
<description>&lt;p&gt; In Part 1, we created and validated an etcd snapshot while an &lt;code&gt;nginx&lt;/code&gt; Deployment existed. Now we deliberately remove that workload, restore the snapshot, reconfigure the static etcd Pod, troubleshoot the problems that appear, and bring etcd back to a healthy state.&lt;/p&gt;
&lt;p&gt;This is &lt;strong&gt;Part 2&lt;/strong&gt; of a two-part series.&lt;/p&gt;
&lt;p&gt;The restore workflow covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;deleting the test &lt;code&gt;nginx&lt;/code&gt; Deployment;&lt;/li&gt;
&lt;li&gt;making and diagnosing an incorrect restore command;&lt;/li&gt;
&lt;li&gt;restoring the snapshot into a separate data directory;&lt;/li&gt;
&lt;li&gt;understanding why the restored data should initially be kept separate;&lt;/li&gt;
&lt;li&gt;handling filesystem and &lt;code&gt;sudo&lt;/code&gt; mistakes;&lt;/li&gt;
&lt;li&gt;changing the static etcd manifest;&lt;/li&gt;
&lt;li&gt;understanding the impact of the static Pod manifest directory;&lt;/li&gt;
&lt;li&gt;troubleshooting namespace and RBAC errors;&lt;/li&gt;
&lt;li&gt;investigating an etcd Pod stuck in &lt;code&gt;Pending&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;checking kubelet;&lt;/li&gt;
&lt;li&gt;restarting kubelet to reconcile the static Pod;&lt;/li&gt;
&lt;li&gt;confirming that etcd returned to &lt;code&gt;1/1 Running&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;documenting the final recovery workflow and lessons learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important distinction is that the terminal evidence explicitly confirms successful snapshot restoration and recovery of the etcd Pod. It does &lt;strong&gt;not&lt;/strong&gt; include a final &lt;code&gt;k get all&lt;/code&gt; proving that the &lt;code&gt;nginx&lt;/code&gt; Deployment reappeared after recovery, so this article does not claim that as independently verified.&lt;/p&gt;
&lt;h2 id=&quot;17-delete-nginx&quot;&gt;17. Delete nginx&lt;/h2&gt;
&lt;p&gt;I deleted the Deployment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k delete deploy nginx
deployment.apps &quot;nginx&quot; deleted from default namespace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    &amp;lt;none&amp;gt;        443/TCP   76m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The nginx Deployment was gone.&lt;/p&gt;
&lt;p&gt;This gave us the desired recovery scenario:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;BEFORE BACKUP
    |
    +-- nginx Deployment exists
    |
    v
TAKE ETCD SNAPSHOT
    |
    v
DELETE nginx
    |
    v
nginx no longer exists
    |
    v
RESTORE SNAPSHOT
    |
    v
expect previous cluster state
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;18-first-restore-mistake-wrong-snapshot-filename&quot;&gt;18. First restore mistake: wrong snapshot filename&lt;/h2&gt;
&lt;p&gt;I attempted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdutl --data-dir /opt/etcd/backup snapshot restore snapshot.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The restore process immediately told me:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error: open snapshot.db: no such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the filename was wrong.&lt;/p&gt;
&lt;p&gt;The actual snapshot was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a very common command-line mistake: creating a file with one name and later trying to restore a similarly named file.&lt;/p&gt;
&lt;p&gt;The first restore attempt was therefore not an etcd failure. It was simply a path/filename error.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;19-restore-the-snapshot-into-a-separate-data-directory&quot;&gt;19. Restore the snapshot into a separate data directory&lt;/h2&gt;
&lt;p&gt;Instead of overwriting the active etcd data directory immediately, I restored the snapshot into a separate directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command used was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot restore /opt/etcd-backup.db \
--data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output included:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Deprecated: Use `etcdutl snapshot restore` instead.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;restoring snapshot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;followed by:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Trimming membership information from the backend...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;added member
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;restored snapshot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was the actual successful restore of the snapshot into the new data directory.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;20-why-use-a-separate-restore-directory-&quot;&gt;20. Why use a separate restore directory?&lt;/h2&gt;
&lt;p&gt;The original etcd data directory was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The restored copy was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This distinction is important.&lt;/p&gt;
&lt;p&gt;It allows the restored data to be prepared without immediately destroying the existing data directory.&lt;/p&gt;
&lt;p&gt;For a beginner, think of it like restoring a database backup into a new folder first:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Original:
    /var/lib/etcd

Restored:
    /var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only after the restored data exists do we configure etcd to use it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;21-more-path-mistakes-while-inspecting-the-restored-data&quot;&gt;21. More path mistakes while inspecting the restored data&lt;/h2&gt;
&lt;p&gt;I attempted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ cd /var/lib/data
bash: cd: /var/lib/data: No such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the directory did not exist.&lt;/p&gt;
&lt;p&gt;The restore directory was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sudo cd /var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and got:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sudo: cd: command not found
sudo: &quot;cd&quot; is a shell built-in command, it cannot be run directly.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This error is worth understanding.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; is a shell built-in command. &lt;code&gt;sudo&lt;/code&gt; normally executes an external command, so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo cd ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;does not work.&lt;/p&gt;
&lt;p&gt;Instead, because the directory required elevated permissions, I used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sudo ls /var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;member
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That confirmed that the restore had created the expected etcd member directory structure.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;22-editing-the-static-etcd-manifest&quot;&gt;22. Editing the static etcd manifest&lt;/h2&gt;
&lt;p&gt;The next step was to configure the static etcd pod to use the restored data directory.&lt;/p&gt;
&lt;p&gt;The original manifest used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--data-dir=/var/lib/etcd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The modified configuration used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The corresponding hostPath was also changed to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting Pod description later confirmed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Path: /var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is how the restored database was connected to the etcd process.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;23-why-moving-the-manifest-files-caused-disruption&quot;&gt;23. Why moving the manifest files caused disruption&lt;/h2&gt;
&lt;p&gt;During the troubleshooting process, I temporarily moved the static pod manifests out of the manifest directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo mv * /tmp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ ls -lrt
total 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The directory was empty.&lt;/p&gt;
&lt;p&gt;I then restored the manifests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo mv /tmp/*.yaml .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and confirmed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ ls -lrt
total 16
-rw------- 1 root root 3939 Aug 13 11:07 kube-apiserver.yaml
-rw------- 1 root root 3230 Aug 13 11:07 kube-controller-manager.yaml
-rw------- 1 root root 1726 Aug 13 11:07 kube-scheduler.yaml
-rw------- 1 root root 2596 Aug 13 12:37 etcd.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This demonstrates how sensitive the static pod manifest directory is.&lt;/p&gt;
&lt;p&gt;When the kubelet stops seeing a static pod manifest, the corresponding static pod can disappear.&lt;/p&gt;
&lt;p&gt;For this reason, moving files in &lt;code&gt;/etc/kubernetes/manifests&lt;/code&gt; should be done carefully.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;24-another-small-typo&quot;&gt;24. Another small typo&lt;/h2&gt;
&lt;p&gt;I accidentally ran:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get oi
error: the server doesn't have a resource type &quot;oi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The intended command was clearly not &lt;code&gt;oi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The correct command for Pods was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get po
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a harmless error, but it illustrates another important habit:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;When &lt;code&gt;kubectl&lt;/code&gt; reports that a resource type does not exist, first check the command spelling before assuming the Kubernetes API is broken.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;25-the-rbac-error-after-the-manifest-changes&quot;&gt;25. The RBAC error after the manifest changes&lt;/h2&gt;
&lt;p&gt;After the static pod manipulation, this happened:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get po
Error from server (Forbidden): pods is forbidden: User &quot;kubernetes-admin&quot; cannot list resource &quot;pods&quot; in API group &quot;&quot; in the namespace &quot;default&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was different from the earlier errors.&lt;/p&gt;
&lt;p&gt;This time, the Kubernetes API server was responding, but the authenticated user was being denied access.&lt;/p&gt;
&lt;p&gt;The command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo k get po
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;was also not a solution:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sudo: k: command not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reason is that &lt;code&gt;k&lt;/code&gt; was a shell alias, and aliases normally are not available to &lt;code&gt;sudo&lt;/code&gt; in that way.&lt;/p&gt;
&lt;p&gt;More importantly, &lt;code&gt;sudo&lt;/code&gt; does not automatically solve Kubernetes RBAC problems.&lt;/p&gt;
&lt;p&gt;I then checked the system namespace explicitly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get po -n=kube-system
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returned the control-plane Pods.&lt;/p&gt;
&lt;p&gt;That helped separate the problem from the actual etcd state.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;26-etcd-was-now-pending&quot;&gt;26. etcd was now Pending&lt;/h2&gt;
&lt;p&gt;The output showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcd-osboxes   0/1   Pending
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I first tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k describe po etcd-osboxes
Error from server (NotFound): pods &quot;etcd-osboxes&quot; not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the namespace mattered.&lt;/p&gt;
&lt;p&gt;The correct command was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k describe po -n=kube-system etcd-osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The description showed the important configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Status: Pending
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but also:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Image: registry.k8s.io/etcd:3.6.8-0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Pod also showed the restored directory mounted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup from etcd-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Path: /var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The kubelet events showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Normal  Pulled   ...
Normal  Created  ...
Normal  Started  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the container had actually been created and started even though the Kubernetes status remained &lt;code&gt;Pending&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is an important troubleshooting clue:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Do not rely on one status field alone. Read the full Pod description and events.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;27-trying-to-read-etcd-logs&quot;&gt;27. Trying to read etcd logs&lt;/h2&gt;
&lt;p&gt;I tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k logs etcd-osboxes -n kube-system
Error from server (BadRequest): container &quot;etcd&quot; in pod &quot;etcd-osboxes&quot; is not available
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also accidentally ran:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;error: expected 'logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]'.
POD or TYPE/NAME is a required argument for the logs command
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second error was simply because &lt;code&gt;kubectl logs&lt;/code&gt; requires a Pod or workload name.&lt;/p&gt;
&lt;p&gt;The first error was more interesting: Kubernetes did not consider the container available for normal log retrieval.&lt;/p&gt;
&lt;p&gt;I then checked the Pod in wide format:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get pod etcd-osboxes -n kube-system -o wide
NAME           READY   STATUS    RESTARTS   AGE     IP       NODE      NOMINATED NODE   READINESS GATES
etcd-osboxes   0/1     Pending   0          4m58s   &amp;lt;none&amp;gt;   osboxes   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lack of a Pod IP was another indication that the Pod was not fully ready.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;28-inspecting-kubelet&quot;&gt;28. Inspecting kubelet&lt;/h2&gt;
&lt;p&gt;Since etcd was a static Pod, the kubelet was a key component to inspect.&lt;/p&gt;
&lt;p&gt;I ran:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo systemctl status kubelet --no-pager
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;● kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/usr/lib/systemd/system/kubelet.service; disabled; preset: disabled)
     Active: active (running)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The kubelet was running.&lt;/p&gt;
&lt;p&gt;The logs also showed repeated activity around the time of the problem.&lt;/p&gt;
&lt;p&gt;At this point, rather than making more changes to the etcd manifest, I restarted kubelet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo systemctl restart kubelet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;29-the-recovery&quot;&gt;29. The recovery&lt;/h2&gt;
&lt;p&gt;After restarting kubelet, I checked the system namespace again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get po -n=kube-system
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-74c68c8864-fjtnv   1/1     Running   5 (7m47s ago)   95m
calico-node-dzlcp                          1/1     Running   0               95m
coredns-589f44dc88-l522w                   1/1     Running   0               101m
coredns-589f44dc88-nzsh9                   1/1     Running   0               101m
etcd-osboxes                               1/1     Running   0               6m51s
kube-apiserver-osboxes                     1/1     Running   0               101m
kube-controller-manager-osboxes            1/1     Running   1 (7m32s ago)   101m
kube-proxy-d8krd                           1/1     Running   0               101m
kube-scheduler-osboxes                     1/1     Running   1               101m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was the desired state.&lt;/p&gt;
&lt;p&gt;Most importantly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcd-osboxes   1/1   Running
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;30-confirming-the-restored-etcd-configuration&quot;&gt;30. Confirming the restored etcd configuration&lt;/h2&gt;
&lt;p&gt;I then described the etcd Pod again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k describe po -n=kube-system etcd-osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important portion was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Status: Running
IP: 10.0.2.15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The etcd container was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;State: Running
Ready: True
Restart Count: 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the command still showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The mounted volume was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup from etcd-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with the host path:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirmed that etcd was now running using the restored data directory.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;31-what-happened-to-the-nginx-deployment-&quot;&gt;31. What happened to the nginx Deployment?&lt;/h2&gt;
&lt;p&gt;The exercise was designed around the snapshot that was taken while nginx existed.&lt;/p&gt;
&lt;p&gt;The important sequence was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1. Create nginx Deployment
2. Wait for nginx to become Running
3. Take etcd snapshot
4. Delete nginx
5. Restore the snapshot
6. Point etcd at restored data
7. Restart kubelet
8. Confirm etcd is Running
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The backup validation showed a snapshot revision of:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;6934
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;918 total keys
3.9 MB total size
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The restore operation successfully rebuilt an etcd data directory.&lt;/p&gt;
&lt;p&gt;The final terminal state confirmed that etcd was successfully running from:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The terminal session provided here does &lt;strong&gt;not&lt;/strong&gt; contain a final &lt;code&gt;k get all&lt;/code&gt; after the successful etcd recovery showing nginx reappearing, so I would not claim that nginx restoration was independently verified from the terminal evidence.&lt;/p&gt;
&lt;p&gt;That distinction matters.&lt;/p&gt;
&lt;p&gt;The exercise successfully demonstrated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;snapshot creation;&lt;/li&gt;
&lt;li&gt;snapshot validation;&lt;/li&gt;
&lt;li&gt;snapshot restoration;&lt;/li&gt;
&lt;li&gt;switching the static etcd Pod to restored data;&lt;/li&gt;
&lt;li&gt;recovery of the etcd Pod.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The source terminal output does not provide a final explicit post-recovery &lt;code&gt;k get all&lt;/code&gt; proving that the nginx Deployment was recreated from the restored snapshot.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;reference-validate-the-backup-before-restoring&quot;&gt;Reference: Validate the Backup Before Restoring&lt;/h2&gt;
&lt;p&gt;The session showed that &lt;code&gt;etcdctl snapshot status&lt;/code&gt; is deprecated and recommended &lt;code&gt;etcdutl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The working validation command was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdutl --write-out=table snapshot status /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example output from the session:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──────────┬──────────┬────────────┬────────────┐
│   HASH   │ REVISION │ TOTAL KEYS │ TOTAL SIZE │
├──────────┼──────────┼────────────┼────────────┤
│ eb688bf4 │     6934 │        918 │     3.9 MB │
└──────────┴──────────┴────────────┴────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is useful because a backup file existing on disk does not, by itself, prove that it is a valid etcd snapshot.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;reference-the-restore-command&quot;&gt;Reference: The Restore Command&lt;/h2&gt;
&lt;p&gt;The restore performed successfully with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot restore /opt/etcd-backup.db \
  --data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The terminal explicitly reported:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Deprecated: Use `etcdutl snapshot restore` instead.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So for a newer workflow, prefer the modern &lt;code&gt;etcdutl snapshot restore&lt;/code&gt; command rather than copying the deprecated command blindly.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;troubleshooting-lessons-from-the-lab&quot;&gt;Troubleshooting Lessons From the Lab&lt;/h2&gt;
&lt;h3 id=&quot;error-1-wrong-directory&quot;&gt;Error 1: Wrong directory&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;cd /etc/kkubenetes/manifests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;cd /etc/kubenetes/manifests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;failed because of spelling mistakes.&lt;/p&gt;
&lt;h4 id=&quot;fix&quot;&gt;Fix&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /etc/kubernetes/manifests
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-2-docker-container-not-found&quot;&gt;Error 2: Docker container not found&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;docker exec -it osboxes bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;No such container: osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;lesson&quot;&gt;Lesson&lt;/h4&gt;
&lt;p&gt;A Kubernetes node name is not automatically a Docker container name.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-3-permission-denied-reading-etcd-files&quot;&gt;Error 3: Permission denied reading etcd files&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;cat etcd.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;fix-1&quot;&gt;Fix&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo cat etcd.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same principle applied to the protected etcd private key.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-4-invalid-etcdctl-flag&quot;&gt;Error 4: Invalid etcdctl flag&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;---endpoint=...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error: bad flag syntax
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;fix-2&quot;&gt;Fix&lt;/h4&gt;
&lt;p&gt;Use the correctly spelled flag:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;--endpoints=...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-5-private-key-permission-denied&quot;&gt;Error 5: Private key permission denied&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error: open /etc/kubernetes/pki/etcd/server.key: permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;fix-3&quot;&gt;Fix&lt;/h4&gt;
&lt;p&gt;Run the etcd client command with sufficient privileges:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdctl ...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-6-wrong-snapshot-filename&quot;&gt;Error 6: Wrong snapshot filename&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;snapshot.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;did not exist.&lt;/p&gt;
&lt;p&gt;The actual file was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;lesson-1&quot;&gt;Lesson&lt;/h4&gt;
&lt;p&gt;Always verify the exact backup path before restoring.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-7-etcdctl-snapshot-status-deprecated&quot;&gt;Error 7: &lt;code&gt;etcdctl snapshot status&lt;/code&gt; deprecated&lt;/h3&gt;
&lt;p&gt;The client reported:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Deprecated: Use `etcdutl snapshot status` instead.
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;fix-4&quot;&gt;Fix&lt;/h4&gt;
&lt;p&gt;Install/use &lt;code&gt;etcdutl&lt;/code&gt; and run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdutl --write-out=table snapshot status /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-8-etcdutl-not-installed&quot;&gt;Error 8: &lt;code&gt;etcdutl&lt;/code&gt; not installed&lt;/h3&gt;
&lt;p&gt;The command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcdutl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;was initially unavailable.&lt;/p&gt;
&lt;h4 id=&quot;fix-5&quot;&gt;Fix&lt;/h4&gt;
&lt;p&gt;The system suggested installing &lt;code&gt;etcd-server&lt;/code&gt;, which provided the utility in this environment.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-9-sudo-cd&quot;&gt;Error 9: &lt;code&gt;sudo cd&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This failed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sudo cd /var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sudo: cd: command not found
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;lesson-2&quot;&gt;Lesson&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; is a shell built-in.&lt;/p&gt;
&lt;p&gt;Use commands such as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo ls /var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or start a privileged shell if you genuinely need one.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-10-pod-name-not-found&quot;&gt;Error 10: Pod name not found&lt;/h3&gt;
&lt;p&gt;This:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k describe po etcd-osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;pods &quot;etcd-osboxes&quot; not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;because the command defaulted to the &lt;code&gt;default&lt;/code&gt; namespace.&lt;/p&gt;
&lt;h4 id=&quot;fix-6&quot;&gt;Fix&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k describe po -n=kube-system etcd-osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-11-kubectl-logs-without-a-pod&quot;&gt;Error 11: &lt;code&gt;kubectl logs&lt;/code&gt; without a Pod&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k logs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;POD or TYPE/NAME is a required argument for the logs command
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;fix-7&quot;&gt;Fix&lt;/h4&gt;
&lt;p&gt;Provide the resource:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k logs &amp;lt;pod-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and specify the namespace when needed.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-12-kubectl-forbidden&quot;&gt;Error 12: &lt;code&gt;kubectl&lt;/code&gt; Forbidden&lt;/h3&gt;
&lt;p&gt;After the control-plane changes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error from server (Forbidden): pods is forbidden:
User &quot;kubernetes-admin&quot; cannot list resource &quot;pods&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was an authorization/RBAC problem rather than a shell permission problem.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; did not solve it because Kubernetes authorization is separate from Linux &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;error-13-etcd-remained-pending&quot;&gt;Error 13: etcd remained Pending&lt;/h3&gt;
&lt;p&gt;The etcd Pod stayed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;0/1 Pending
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;even though the container had been created and started according to the events.&lt;/p&gt;
&lt;p&gt;The investigation included:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k describe po -n=kube-system etcd-osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo systemctl status kubelet --no-pager
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The practical recovery step that resolved the state in this lab was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo systemctl restart kubelet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcd-osboxes   1/1   Running
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-static-pods-matter-in-this-exercise&quot;&gt;Why Static Pods Matter in This Exercise&lt;/h2&gt;
&lt;p&gt;The etcd Pod was not created with a normal Deployment such as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;kind: Deployment
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, it was defined by:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/etc/kubernetes/manifests/etcd.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That makes it a static Pod.&lt;/p&gt;
&lt;p&gt;The kubelet watches the manifest directory and manages the Pod locally.&lt;/p&gt;
&lt;p&gt;This explains several things that happened during the exercise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;changing &lt;code&gt;etcd.yaml&lt;/code&gt; affected etcd;&lt;/li&gt;
&lt;li&gt;temporarily moving manifests out of the directory affected the control plane;&lt;/li&gt;
&lt;li&gt;restarting kubelet caused it to re-read and reconcile the manifests;&lt;/li&gt;
&lt;li&gt;etcd could be controlled without creating a normal Kubernetes Deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For kubeadm clusters, understanding static Pods is essential when troubleshooting the control plane.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;a-safer-mental-model-for-etcd-restore&quot;&gt;A Safer Mental Model for etcd Restore&lt;/h2&gt;
&lt;p&gt;Do not think of restore as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;copy backup file over etcd&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A better mental model is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;ETCD SNAPSHOT
     |
     v
restore snapshot
     |
     v
new etcd data directory
     |
     v
configure etcd to use restored directory
     |
     v
kubelet recreates/restarts static etcd Pod
     |
     v
etcd becomes healthy
     |
     v
Kubernetes API becomes available against restored state
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is why the exercise used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;instead of immediately destroying:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-i-would-do-differently-next-time&quot;&gt;What I Would Do Differently Next Time&lt;/h2&gt;
&lt;p&gt;The lab worked, but it also exposed several areas where the workflow could be cleaner.&lt;/p&gt;
&lt;h3 id=&quot;1-check-the-exact-paths-first&quot;&gt;1. Check the exact paths first&lt;/h3&gt;
&lt;p&gt;Before typing a long command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ls -l /etc/kubernetes/pki/etcd/
ls -l /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This avoids guessing filenames and permissions.&lt;/p&gt;
&lt;h3 id=&quot;2-inspect-the-manifest-before-changing-it&quot;&gt;2. Inspect the manifest before changing it&lt;/h3&gt;
&lt;p&gt;First:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo cp /etc/kubernetes/manifests/etcd.yaml /root/etcd.yaml.backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then edit the manifest.&lt;/p&gt;
&lt;p&gt;That gives you a known-good copy if something goes wrong.&lt;/p&gt;
&lt;h3 id=&quot;3-prefer-the-current-etcd-utilities&quot;&gt;3. Prefer the current etcd utilities&lt;/h3&gt;
&lt;p&gt;The terminal explicitly showed that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcdctl snapshot status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;is deprecated and recommended:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcdutl snapshot status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Likewise, the restore output recommended:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcdutl snapshot restore
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-avoid-unnecessary-movement-of-all-manifests&quot;&gt;4. Avoid unnecessary movement of all manifests&lt;/h3&gt;
&lt;p&gt;This command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo mv * /tmp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;is powerful and potentially disruptive.&lt;/p&gt;
&lt;p&gt;Moving all control-plane manifests affects more than etcd.&lt;/p&gt;
&lt;p&gt;A safer approach is to modify only the required manifest and keep backups of the original.&lt;/p&gt;
&lt;h3 id=&quot;5-verify-each-stage&quot;&gt;5. Verify each stage&lt;/h3&gt;
&lt;p&gt;After every major step:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -n kube-system
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and inspect:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k describe pod &amp;lt;pod&amp;gt; -n kube-system
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if anything looks abnormal.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;compact-recovery-checklist&quot;&gt;Compact Recovery Checklist&lt;/h2&gt;
&lt;p&gt;For a kubeadm single-control-plane lab similar to this one:&lt;/p&gt;
&lt;h4 id=&quot;identify-etcd&quot;&gt;Identify etcd&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -n kube-system | grep etcd
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;inspect-the-manifest&quot;&gt;Inspect the manifest&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /etc/kubernetes/manifests
sudo cat etcd.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;identify-&quot;&gt;Identify:&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--data-dir
--listen-client-urls
--cert-file
--key-file
--trusted-ca-file
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;create-snapshot&quot;&gt;Create snapshot&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;validate-snapshot&quot;&gt;Validate snapshot&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdutl --write-out=table snapshot status /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;restore-to-a-separate-directory&quot;&gt;Restore to a separate directory&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdutl snapshot restore /opt/etcd-backup.db \
  --data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;configure-etcd-to-use-the-restored-directory&quot;&gt;Configure etcd to use the restored directory&lt;/h4&gt;
&lt;p&gt;Update:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the corresponding hostPath.&lt;/p&gt;
&lt;h4 id=&quot;restart-reconcile-kubelet-if-required&quot;&gt;Restart/reconcile kubelet if required&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo systemctl restart kubelet
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;verify&quot;&gt;Verify&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -n kube-system
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcd-osboxes   1/1   Running
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-this-lab-actually-taught-me&quot;&gt;What This Lab Actually Taught Me&lt;/h2&gt;
&lt;p&gt;The most valuable part of this exercise was not memorizing one command.&lt;/p&gt;
&lt;p&gt;It was learning how the pieces connect:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Kubernetes
    |
    +-- kube-apiserver
    |
    +-- kube-controller-manager
    |
    +-- kube-scheduler
    |
    +-- kubelet
            |
            +-- static Pod manifests
                    |
                    +-- etcd
                            |
                            +-- /var/lib/etcd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The backup process interacted directly with etcd:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcd
  |
  +-- TLS certificates
  |
  +-- etcdctl
  |
  +-- snapshot
  |
  +-- /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The restore process then created:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the static Pod was changed to consume that restored data.&lt;/p&gt;
&lt;p&gt;Finally, kubelet reconciled the static Pod and etcd returned to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1/1 Running
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;final-takeaway&quot;&gt;Final Takeaway&lt;/h2&gt;
&lt;p&gt;An etcd backup is not just another Kubernetes YAML export.&lt;/p&gt;
&lt;p&gt;The core workflow is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1. Verify etcd is healthy.
2. Find the etcd endpoint and TLS certificates.
3. Take an etcd snapshot.
4. Validate the snapshot.
5. Restore the snapshot into a separate data directory.
6. Configure the etcd static Pod to use the restored data.
7. Let kubelet reconcile the static Pod.
8. Verify etcd and the Kubernetes control plane.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The terminal session also demonstrated something that documentation often hides: &lt;strong&gt;the commands do not always work on the first attempt.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;spelling mistakes;&lt;/li&gt;
&lt;li&gt;incorrect flags;&lt;/li&gt;
&lt;li&gt;permission problems;&lt;/li&gt;
&lt;li&gt;wrong filenames;&lt;/li&gt;
&lt;li&gt;deprecated commands;&lt;/li&gt;
&lt;li&gt;missing utilities;&lt;/li&gt;
&lt;li&gt;namespace mistakes;&lt;/li&gt;
&lt;li&gt;RBAC errors;&lt;/li&gt;
&lt;li&gt;attempts to use &lt;code&gt;sudo&lt;/code&gt; where it did not apply;&lt;/li&gt;
&lt;li&gt;a static etcd Pod that remained &lt;code&gt;Pending&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;and finally a kubelet restart that brought etcd back to &lt;code&gt;Running&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those failures were not separate from the learning experience. They were the learning experience.&lt;/p&gt;
&lt;p&gt;The most useful troubleshooting habit from this lab is simple:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;When Kubernetes gives you an error, do not immediately change random things. Read the error, identify which layer produced it, inspect the relevant component, make the smallest reasonable correction, and verify the result.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is the difference between memorizing Kubernetes commands and actually learning how the control plane works.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;terminal-command-reference-from-the-lab&quot;&gt;Terminal command reference from the lab&lt;/h3&gt;
&lt;h4 id=&quot;cluster-health&quot;&gt;Cluster health&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get pods -A
k get pods -A -w
k get nodes
k get all
k get all -A
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;static-pod-manifests&quot;&gt;Static Pod manifests&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /etc/kubernetes/manifests
ls
sudo cat etcd.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;install-tooling&quot;&gt;Install tooling&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install etcd-client
sudo apt install etcd-server
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;configure-etcdctl&quot;&gt;Configure etcdctl&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;export ETCDCTL_API=3
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;backup&quot;&gt;Backup&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;validate&quot;&gt;Validate&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdutl --write-out=table snapshot status /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;test-workload&quot;&gt;Test workload&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k create deploy nginx --image=nginx
k get po
k get po -w
k describe po nginx-7f8fbb96d-9f7wm
k get all
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;delete-workload&quot;&gt;Delete workload&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k delete deploy nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;restore&quot;&gt;Restore&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot restore /opt/etcd-backup.db \
  --data-dir=/var/lib/etcd-restore-from-backup
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;troubleshoot-etcd&quot;&gt;Troubleshoot etcd&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get po -n=kube-system
k describe po -n=kube-system etcd-osboxes
k get pod etcd-osboxes -n kube-system -o wide
k logs etcd-osboxes -n kube-system
sudo systemctl status kubelet --no-pager
sudo systemctl restart kubelet
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;final-verification&quot;&gt;Final verification&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get po -n=kube-system
k describe po -n=kube-system etcd-osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;closing-note&quot;&gt;Closing note&lt;/h3&gt;
&lt;p&gt;This was a lab on a single-node kubeadm cluster. In a production environment, etcd backup and restore requires much stricter operational controls, including secure off-host backup storage, tested restore procedures, careful handling of TLS credentials, cluster topology awareness, and a clearly defined disaster-recovery procedure.&lt;/p&gt;
&lt;p&gt;A backup is only useful if you can successfully restore it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take the backup. Validate it. Practice the restore.&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24753/kubernetes-etcd-backup-and-restore-part-2-restoring-etcd-and-recovering-the-cluster</guid>
<pubDate>Mon, 17 Aug 2026 10:56:09 +0000</pubDate>
</item>
<item>
<title>Kubernetes ETCD Backup And Restore — Part 1: Creating and Validating the Backup</title>
<link>https://coderlegion.com/24752/kubernetes-etcd-backup-and-restore-part-1-creating-and-validating-the-backup</link>
<description>&lt;p&gt;This is &lt;strong&gt;Part 1&lt;/strong&gt; of a two-part series.&lt;/p&gt;
&lt;p&gt;In this part, the focus is entirely on the &lt;strong&gt;backup side&lt;/strong&gt; of the disaster-recovery exercise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;understanding what etcd does;&lt;/li&gt;
&lt;li&gt;verifying the Kubernetes control plane;&lt;/li&gt;
&lt;li&gt;locating the static etcd manifest;&lt;/li&gt;
&lt;li&gt;understanding the etcd endpoint and TLS certificates;&lt;/li&gt;
&lt;li&gt;installing &lt;code&gt;etcdctl&lt;/code&gt; and &lt;code&gt;etcdutl&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;dealing with command-line mistakes and permission errors;&lt;/li&gt;
&lt;li&gt;creating a valid etcd snapshot;&lt;/li&gt;
&lt;li&gt;validating the snapshot;&lt;/li&gt;
&lt;li&gt;creating an &lt;code&gt;nginx&lt;/code&gt; Deployment;&lt;/li&gt;
&lt;li&gt;taking a second snapshot containing that workload;&lt;/li&gt;
&lt;li&gt;preparing the cluster for the restore exercise in Part 2.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The actual restoration, static Pod reconfiguration, kubelet troubleshooting, and recovery are covered in &lt;strong&gt;Part 2&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A beginner-friendly, hands-on walkthrough of backing up and restoring etcd in a kubeadm-based Kubernetes cluster — including the mistakes, errors, debugging steps, and the terminal commands that actually happened during the lab.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;If you are learning Kubernetes, you will eventually hear a simple but important statement:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;etcd is the database of a Kubernetes cluster.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That description is short, but it has a major consequence: if the etcd data is lost or corrupted, the Kubernetes control plane can lose the information it needs to know what exists in the cluster.&lt;/p&gt;
&lt;p&gt;In this lab, I practiced an end-to-end etcd backup and restore workflow on a single-node kubeadm cluster running on a machine named &lt;code&gt;osboxes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The exercise covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;identifying the etcd pod and confirming that the control plane was healthy;&lt;/li&gt;
&lt;li&gt;locating the static etcd manifest;&lt;/li&gt;
&lt;li&gt;inspecting the etcd configuration;&lt;/li&gt;
&lt;li&gt;installing &lt;code&gt;etcdctl&lt;/code&gt; and &lt;code&gt;etcdutl&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;creating an etcd snapshot;&lt;/li&gt;
&lt;li&gt;validating the snapshot;&lt;/li&gt;
&lt;li&gt;deliberately creating an &lt;code&gt;nginx&lt;/code&gt; Deployment so there was something meaningful to restore;&lt;/li&gt;
&lt;li&gt;deleting the Deployment;&lt;/li&gt;
&lt;li&gt;restoring the etcd snapshot into a separate data directory;&lt;/li&gt;
&lt;li&gt;changing the static etcd manifest to use the restored data;&lt;/li&gt;
&lt;li&gt;troubleshooting an etcd pod that remained &lt;code&gt;Pending&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;restarting kubelet;&lt;/li&gt;
&lt;li&gt;confirming that etcd eventually returned to &lt;code&gt;Running&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The important part of this exercise was not simply getting a successful backup command. It was understanding what each error meant and how to reason from the evidence in the terminal.&lt;/p&gt;
&lt;p&gt;The terminal session showed the etcd pod running before the backup, with the control plane components also healthy. Later, after changing the etcd static pod configuration, etcd became &lt;code&gt;Pending&lt;/code&gt;; the investigation eventually led to restarting kubelet, after which etcd became &lt;code&gt;1/1 Running&lt;/code&gt;. The original terminal output is the source for the commands and results reproduced throughout this article.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-first-what-is-etcd-&quot;&gt;1. First: What is etcd?&lt;/h3&gt;
&lt;p&gt;Before touching commands, it helps to understand what we are backing up.&lt;/p&gt;
&lt;p&gt;Kubernetes has many components, but the important relationship for this exercise is roughly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;kubectl
   |
   v
kube-apiserver
   |
   v
  etcd
   |
   +---- Kubernetes cluster state
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The API server is the main interface through which Kubernetes clients interact with the cluster. etcd is the persistent key-value store used by Kubernetes to store cluster state.&lt;/p&gt;
&lt;p&gt;That state includes information such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kubernetes objects;&lt;/li&gt;
&lt;li&gt;Deployments;&lt;/li&gt;
&lt;li&gt;Pods and their specifications;&lt;/li&gt;
&lt;li&gt;Services;&lt;/li&gt;
&lt;li&gt;ConfigMaps;&lt;/li&gt;
&lt;li&gt;Secrets;&lt;/li&gt;
&lt;li&gt;cluster configuration and metadata.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A useful mental model for a beginner is:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;The Kubernetes API is how you ask Kubernetes about the cluster; etcd is where much of that cluster state is persisted.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is why backing up etcd is fundamentally different from simply exporting Kubernetes YAML.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-verify-that-the-cluster-is-healthy-first&quot;&gt;2. Verify that the cluster is healthy first&lt;/h2&gt;
&lt;p&gt;Before taking a backup, I first checked the cluster.&lt;/p&gt;
&lt;h3 id=&quot;terminal&quot;&gt;Terminal&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ k get pods -A
NAMESPACE     NAME                                       READY   STATUS              RESTARTS   AGE
kube-system   calico-kube-controllers-74c68c8864-fjtnv   0/1     ContainerCreating   0          3m10s
kube-system   calico-node-dzlcp                          0/1     Init:2/3             0          3m10s
kube-system   coredns-589f44dc88-l522w                   0/1     ContainerCreating   0          8m56s
kube-system   coredns-589f44dc88-nzsh9                   0/1     ContainerCreating   0          8m56s
kube-system   etcd-osboxes                               1/1     Running             0          9m6s
kube-system   kube-apiserver-osboxes                     1/1     Running             0          9m9s
kube-system   kube-controller-manager-osboxes            1/1     Running             0          9m5s
kube-system   kube-proxy-d8krd                           1/1     Running             0          8m56s
kube-system   kube-scheduler-osboxes                     1/1     Running             0          9m8s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The most important observation here is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcd-osboxes  1/1  Running
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The API server, controller manager, scheduler and kube-proxy were also running.&lt;/p&gt;
&lt;p&gt;Some networking components were still starting, so I watched the pods:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ k get pods -A -w
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eventually CoreDNS and Calico became ready.&lt;/p&gt;
&lt;p&gt;I then checked the node:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ k get nodes
NAME      STATUS   ROLES           AGE   VERSION
osboxes   Ready    control-plane   10m   v1.36.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point the single control-plane node was &lt;code&gt;Ready&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The initial cluster state is important because a backup should be taken from a functioning etcd instance rather than blindly assuming that etcd is healthy.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-an-important-distinction-kubernetes-yaml-backup-vs-etcd-backup&quot;&gt;3. An important distinction: Kubernetes YAML backup vs etcd backup&lt;/h2&gt;
&lt;p&gt;Before working directly with etcd, I also ran:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ k get all -A -o yaml &amp;gt; backup.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produced:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ ls
backup.yaml  Documents  kubectl  Pictures  Public  Videos
Desktop      Downloads  Music    Projects  Templates  VM-Share
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is useful, but it is &lt;strong&gt;not the same thing as an etcd snapshot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;k get all -A -o yaml &amp;gt; backup.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;exports Kubernetes resources returned by &lt;code&gt;kubectl get all&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An etcd snapshot, on the other hand, is a snapshot of the etcd backend itself.&lt;/p&gt;
&lt;p&gt;For an etcd disaster-recovery exercise, the etcd snapshot is the important artifact.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-finding-the-etcd-static-pod&quot;&gt;4. Finding the etcd static pod&lt;/h2&gt;
&lt;p&gt;This cluster was created with kubeadm, so etcd was running as a static pod.&lt;/p&gt;
&lt;p&gt;I initially made a typo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ cd /etc/kkubenetes/manifests
bash: cd: /etc/kkubenetes/manifests: No such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem was simply the spelling:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;kkubenetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;instead of:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;kubernetes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I then made another typo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ cd /etc/kubenetes/manifests
bash: cd: /etc/kubenetes/manifests: No such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the correct directory is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/etc/kubernetes/manifests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eventually:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ cd /etc/kubernetes/manifests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ ls
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This directory is extremely important on a kubeadm control-plane node.&lt;/p&gt;
&lt;p&gt;The files in &lt;code&gt;/etc/kubernetes/manifests&lt;/code&gt; are static pod manifests. The kubelet watches this directory and makes sure the described control-plane containers are running.&lt;/p&gt;
&lt;p&gt;That means editing &lt;code&gt;etcd.yaml&lt;/code&gt; is effectively changing how the control-plane etcd process is launched.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-another-wrong-assumption-trying-to-use-docker&quot;&gt;5. Another wrong assumption: trying to use Docker&lt;/h2&gt;
&lt;p&gt;I also tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[~]
└─$ docker exec -it osboxes bash
Error response from daemon: No such container: osboxes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This failed because the Kubernetes node name &lt;code&gt;osboxes&lt;/code&gt; is not necessarily a Docker container name.&lt;/p&gt;
&lt;p&gt;In this setup, the node was running Kubernetes with containerd, and the etcd pod later showed a container ID beginning with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;containerd://
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the important lesson is:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Do not assume that a Kubernetes node or Pod name is a Docker container name.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you need to inspect a Kubernetes container, first determine which container runtime the node is using.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-inspecting-the-etcd-manifest&quot;&gt;6. Inspecting the etcd manifest&lt;/h2&gt;
&lt;p&gt;The first attempt to read the manifest without elevated privileges also failed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ cat etcd.yaml
cat: etcd.yaml: Permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The solution was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo cat etcd.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The manifest revealed several important values.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- --advertise-client-urls=https://10.0.2.15:2379
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --listen-client-urls=https://127.0.0.1:2379,https://10.0.2.15:2379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also showed that the etcd data directory was originally:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/var/lib/etcd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the TLS certificates were under:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/etc/kubernetes/pki/etcd/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This information is essential because &lt;code&gt;etcdctl&lt;/code&gt; needs to connect to the correct endpoint and authenticate with the appropriate certificates.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;7-install-etcdctl&quot;&gt;7. Install etcdctl&lt;/h2&gt;
&lt;p&gt;The machine did not initially have the etcd client installed, so I installed it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo apt install etcd-client
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The package installed successfully:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Installing:
  etcd-client

Summary:
  Upgrading: 0, Installing: 1, Removing: 0, Not Upgrading: 205
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I then checked the snapshot command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ ETCDCTL_API=3 etcdctl snapshot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;COMMANDS:
    restore  Restores an etcd member snapshot to an etcd directory
    save     Stores an etcd node backend snapshot to a given file
    status   [deprecated] Gets backend snapshot status of a given file
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key command for the backup is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;etcdctl snapshot save
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;8-etcdctl-api-3&quot;&gt;8. ETCDCTL_API=3&lt;/h2&gt;
&lt;p&gt;I also explicitly exported:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ export ETCDCTL_API=3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the lab, this made it explicit that &lt;code&gt;etcdctl&lt;/code&gt; should use the v3 API.&lt;/p&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdctl snapshot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;again showed the snapshot subcommands.&lt;/p&gt;
&lt;p&gt;For a beginner, the important idea is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;ETCDCTL_API=3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;selects the etcd API version used by the client.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;9-creating-the-first-etcd-snapshot-and-making-a-typo&quot;&gt;9. Creating the first etcd snapshot — and making a typo&lt;/h2&gt;
&lt;p&gt;I attempted the backup with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdctl ---endpoint=https://127.0.0.1:2379,https://10.0.2.15:2379 \
&amp;gt; --cacert=/etc/kubernetes/pki/etcd/ca.crt \
&amp;gt; --cert=/etc/kubernetes/pki/etcd/server.crt \
&amp;gt; --key=/etc/kubernetes/pki/etcd/server.key \
&amp;gt; snapshot save /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error: bad flag syntax: ---endpoint=https://127.0.0.1:2379,https://10.0.2.15:2379
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The mistake was the number of hyphens.&lt;/p&gt;
&lt;p&gt;I typed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;---endpoint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;instead of:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;--endpoints
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There were actually two problems worth noticing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There were three hyphens.&lt;/li&gt;
&lt;li&gt;The correct flag is &lt;code&gt;--endpoints&lt;/code&gt;, plural.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a classic CLI problem: the command can look almost correct to a human while being completely invalid to the parser.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;10-the-next-error-permission-denied&quot;&gt;10. The next error: permission denied&lt;/h2&gt;
&lt;p&gt;I corrected the flag and tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command reached the certificate files but failed with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error: open /etc/kubernetes/pki/etcd/server.key: permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This made sense.&lt;/p&gt;
&lt;p&gt;The etcd private key is protected, and the regular user did not have permission to read it.&lt;/p&gt;
&lt;p&gt;The solution was to run the command with &lt;code&gt;sudo&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time the backup succeeded.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;11-the-successful-etcd-backup&quot;&gt;11. The successful etcd backup&lt;/h2&gt;
&lt;p&gt;The successful command produced:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:&quot;2026-08-13T12:11:59.649233-0400&quot;,&quot;caller&quot;:&quot;snapshot/v3_snapshot.go:65&quot;,&quot;msg&quot;:&quot;created temporary db file&quot;,&quot;path&quot;:&quot;/opt/etcd-backup.db.part&quot;}
{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:&quot;2026-08-13T12:11:59.660384-0400&quot;,&quot;logger&quot;:&quot;client&quot;,&quot;caller&quot;:&quot;v3/maintenance.go:212&quot;,&quot;msg&quot;:&quot;opened snapshot stream; downloading&quot;}
{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:&quot;2026-08-13T12:11:59.660467-0400&quot;,&quot;caller&quot;:&quot;snapshot/v3_snapshot.go:73&quot;,&quot;msg&quot;:&quot;fetching snapshot&quot;,&quot;endpoint&quot;:&quot;https://127.0.0.1:2379&quot;}
{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:&quot;2026-08-13T12:11:59.831074-0400&quot;,&quot;logger&quot;:&quot;client&quot;,&quot;caller&quot;:&quot;v3/maintenance.go:220&quot;,&quot;msg&quot;:&quot;completed snapshot read; closing&quot;}
{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:&quot;2026-08-13T12:11:59.894020-0400&quot;,&quot;caller&quot;:&quot;snapshot/v3_snapshot.go:88&quot;,&quot;msg&quot;:&quot;fetched snapshot&quot;,&quot;endpoint&quot;:&quot;https://127.0.0.1:2379&quot;,&quot;size&quot;:&quot;3.9 MB&quot;,&quot;took&quot;:&quot;now&quot;}
{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:&quot;2026-08-13T12:11:59.894158-0400&quot;,&quot;caller&quot;:&quot;snapshot/v3_snapshot.go:97&quot;,&quot;msg&quot;:&quot;saved&quot;,&quot;path&quot;:&quot;/opt/etcd-backup.db&quot;}
Snapshot saved at /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting backup file was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The snapshot was approximately:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;3.9 MB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was the first major milestone.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;12-validating-the-snapshot&quot;&gt;12. Validating the snapshot&lt;/h2&gt;
&lt;p&gt;I initially tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdctl --write-out=table snapshot status snapshot.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The client responded:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Deprecated: Use `etcdutl snapshot status` instead.

Error: stat snapshot.db: no such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There were two lessons here.&lt;/p&gt;
&lt;h4 id=&quot;lesson-1-the-filename-was-wrong&quot;&gt;Lesson 1: The filename was wrong&lt;/h4&gt;
&lt;p&gt;The backup was saved as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;snapshot.db
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;lesson-2-the-command-was-deprecated&quot;&gt;Lesson 2: The command was deprecated&lt;/h4&gt;
&lt;p&gt;The output explicitly recommended:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;etcdutl snapshot status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I attempted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdutl --write-out=table snapshot status snapshot.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but &lt;code&gt;etcdutl&lt;/code&gt; was not installed.&lt;/p&gt;
&lt;p&gt;The system suggested:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sudo apt install etcd-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I installed the package.&lt;/p&gt;
&lt;p&gt;After installation, I still used the wrong filename once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdutl --write-out=table snapshot status snapshot.db
Error: stat snapshot.db: no such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I used the correct path:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ etcdutl --write-out=table snapshot status /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produced:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error: open /opt/etcd-backup.db: permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the issue was file permissions.&lt;/p&gt;
&lt;p&gt;So I used &lt;code&gt;sudo&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo etcdutl --write-out=table snapshot status /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──────────┬──────────┬────────────┬────────────┐
│   HASH   │ REVISION │ TOTAL KEYS │ TOTAL SIZE │
├──────────┼──────────┼────────────┼────────────┤
│ a633855e │     5973 │       1298 │     3.9 MB │
└──────────┴──────────┴────────────┴────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirmed that the snapshot was readable and contained etcd data.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;13-why-create-an-nginx-deployment-&quot;&gt;13. Why create an nginx Deployment?&lt;/h2&gt;
&lt;p&gt;A backup is much more meaningful if we have something we can verify after restoring it.&lt;/p&gt;
&lt;p&gt;At this point, I created an &lt;code&gt;nginx&lt;/code&gt; Deployment.&lt;/p&gt;
&lt;p&gt;My first attempt was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k create deploy nginx
error: required flag(s) &quot;image&quot; not set
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command was missing the container image.&lt;/p&gt;
&lt;p&gt;I then tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k create deploy --image=nginx
error: exactly one NAME is required, got 0
See 'kubectl create deployment -h' for help and examples
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the image was present, but the Deployment name was missing.&lt;/p&gt;
&lt;p&gt;The correct command was:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k create deploy nginx --image=nginx
deployment.apps/nginx created
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a good beginner lesson:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create deployment &amp;lt;NAME&amp;gt; --image=&amp;lt;IMAGE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create deployment nginx --image=nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create a Deployment;&lt;/li&gt;
&lt;li&gt;call it &lt;code&gt;nginx&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;use the &lt;code&gt;nginx&lt;/code&gt; container image.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;14-waiting-for-the-nginx-pod&quot;&gt;14. Waiting for the nginx Pod&lt;/h2&gt;
&lt;p&gt;Immediately after creation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get all
NAME                        READY   STATUS              RESTARTS   AGE
pod/nginx-7f8fbb96d-9f7wm   0/1     ContainerCreating   0          4s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Pod remained in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;ContainerCreating
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I watched it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get po -w
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After waiting, I checked again.&lt;/p&gt;
&lt;p&gt;The Pod eventually became:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;nginx-7f8fbb96d-9f7wm   1/1   Running   0   3m16s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;describe&lt;/code&gt; output explained why it initially took time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Events:
  Type    Reason     Age   From               Message
  ----    ------     ---   ----               -------
  Normal  Scheduled  83s   default-scheduler  Successfully assigned default/nginx-7f8fbb96d-9f7wm to osboxes
  Normal  Pulling    82s   kubelet            spec.containers{nginx}: Pulling image &quot;nginx&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Pod had been scheduled successfully. The kubelet was simply pulling the image.&lt;/p&gt;
&lt;p&gt;This is an important troubleshooting principle:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;ContainerCreating&lt;/code&gt; does not automatically mean something is broken. Check the Pod events before changing anything.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Eventually:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;k get po
NAME                    READY   STATUS    RESTARTS   AGE
nginx-7f8fbb96d-9f7wm   1/1     Running   0          3m16s
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;15-take-another-backup-after-the-nginx-deployment-exists&quot;&gt;15. Take another backup after the nginx Deployment exists&lt;/h2&gt;
&lt;p&gt;This step is important because the first snapshot was taken before the nginx Deployment was created.&lt;/p&gt;
&lt;p&gt;After nginx was running, I created another snapshot:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The snapshot was again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;3.9 MB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the command ended with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Snapshot saved at /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I validated it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ sudo etcdutl --write-out=table snapshot status /opt/etcd-backup.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──────────┬──────────┬────────────┬────────────┐
│   HASH   │ REVISION │ TOTAL KEYS │ TOTAL SIZE │
├──────────┼──────────┼────────────┼────────────┤
│ eb688bf4 │     6934 │        918 │     3.9 MB │
└──────────┴──────────┴────────────┴────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the revision changed.&lt;/p&gt;
&lt;p&gt;The backup now represented a later state of the cluster.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;16-verify-the-state-we-want-to-recover&quot;&gt;16. Verify the state we want to recover&lt;/h2&gt;
&lt;p&gt;At this point:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;┌──(osboxes㉿osboxes)-[/etc/kubernetes/manifests]
└─$ k get all
NAME                        READY   STATUS    RESTARTS   AGE
pod/nginx-7f8fbb96d-9f7wm   1/1     Running   0          4m1s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    &amp;lt;none&amp;gt;        443/TCP   76m

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1            4m2s

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-7f8fbb96d   1         1         1       4m2s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important object is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;deployment.apps/nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was healthy.&lt;/p&gt;
&lt;p&gt;Now the test was simple:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If I delete nginx, can I use the etcd snapshot to recover the cluster state that existed when the snapshot was taken?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24752/kubernetes-etcd-backup-and-restore-part-1-creating-and-validating-the-backup</guid>
<pubDate>Mon, 17 Aug 2026 10:54:12 +0000</pubDate>
</item>
<item>
<title>Debugging a Broken Ingress Setup: A Step-by-Step Walkthrough</title>
<link>https://coderlegion.com/23396/debugging-a-broken-ingress-setup-a-step-by-step-walkthrough</link>
<description>&lt;p&gt;This post documents a real debugging session that started with a simple symptom — &lt;code&gt;example.com&lt;/code&gt; wouldn't load — and ended up uncovering several separate, unrelated problems layered on top of each other. It's written to walk through the actual diagnostic process, not just the final fix, since the process is usually the more useful part to learn from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Starting point:&lt;/strong&gt; an Ingress setup (from a previous post) was working, then stopped working after some changes were made mid-session, including installing a different CNI (Calico) on top of the cluster's existing one. This is the story of tracking that down.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-symptom&quot;&gt;The Symptom&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ curl example.com
curl: (7) Failed to connect to example.com port 80 after 21007 ms: Could not connect to server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A connection timeout like this can mean a lot of different things: DNS pointing to the wrong place, a firewall silently dropping packets, a service that's down, or a machine that simply can't reach the target network at all. The rest of this post is the process of ruling each of those out, one at a time.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-1-confirm-what-the-hostname-actually-resolves-to&quot;&gt;Step 1: Confirm What the Hostname Actually Resolves To&lt;/h3&gt;
&lt;p&gt;Before assuming anything about networking, the first thing to check is whether &lt;code&gt;example.com&lt;/code&gt; is even resolving to the IP it's supposed to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ getent hosts example.com
10.96.101.127   example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirmed the local &lt;code&gt;/etc/hosts&lt;/code&gt; entry was working correctly — &lt;code&gt;example.com&lt;/code&gt; resolved to &lt;code&gt;10.96.101.127&lt;/code&gt;, matching the Ingress controller's IP from earlier setup. So the problem wasn't DNS/hosts resolution. The IP itself was the next thing to check.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-test-the-ip-directly-bypassing-the-hostname&quot;&gt;Step 2: Test the IP Directly, Bypassing the Hostname&lt;/h3&gt;
&lt;p&gt;If the hostname resolves correctly but the connection still fails, the next step is to test the raw IP directly — this removes DNS/hosts from the equation entirely and asks: &quot;is this address reachable at all?&quot;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ curl -v http://10.96.101.127
*   Trying 10.96.101.127:80...
* connect to 10.96.101.127 port 80 from 10.0.2.15 port 57576 failed: Connection refused
* Failed to connect to 10.96.101.127 port 80 after 21003 ms: Could not connect to server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two useful details came out of this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Connection refused&lt;/code&gt;, not a timeout.&lt;/strong&gt; This is a meaningful difference. A timeout usually means packets are going out and nothing is answering. &quot;Refused&quot; happens quickly and means something &lt;em&gt;did&lt;/em&gt; respond — but actively said &quot;no.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The source IP was &lt;code&gt;10.0.2.15&lt;/code&gt;.&lt;/strong&gt; This is VirtualBox's default address for a guest machine in NAT networking mode, which confirmed this was being tested from inside a VM.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The actual explanation:&lt;/strong&gt; &lt;code&gt;10.96.101.127&lt;/code&gt; is a Kubernetes &lt;strong&gt;ClusterIP&lt;/strong&gt;. A ClusterIP isn't a real address that exists anywhere on the network — it's a virtual IP that only works because of routing rules (&lt;code&gt;iptables&lt;/code&gt;/IPVS) that Kubernetes' &lt;code&gt;kube-proxy&lt;/code&gt; installs inside the specific machine running the cluster. No other machine — not a VM, not a laptop on the same network — can ever reach a ClusterIP directly, because that address doesn't exist anywhere outside that one machine's own routing table.&lt;/p&gt;
&lt;p&gt;This meant the original approach (pointing &lt;code&gt;/etc/hosts&lt;/code&gt; at the ClusterIP) was never going to work from a separate machine, regardless of any other fix.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-find-a-real-reachable-address-instead&quot;&gt;Step 3: Find a Real, Reachable Address Instead&lt;/h3&gt;
&lt;p&gt;Since ClusterIPs don't work across machines, the next step was finding an address that &lt;em&gt;does&lt;/em&gt; — specifically, the IP of one of the actual Docker containers backing the &lt;code&gt;kind&lt;/code&gt; cluster's nodes, combined with the Ingress controller's &lt;strong&gt;NodePort&lt;/strong&gt; (a real port opened on the node itself, unlike a ClusterIP).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED      STATUS          PORTS                       NAMES
691fe58f2715   kindest/node:v1.35.0   &quot;/usr/local/bin/entr…&quot;   2 days ago   Up 18 minutes   127.0.0.1:38079-&amp;gt;6443/tcp   cka-new-control-plane
aae68ca53b7b   kindest/node:v1.35.0   &quot;/usr/local/bin/entr…&quot;   2 days ago   Up 18 minutes                               cka-new-worker2
b51bce23b84f   kindest/node:v1.35.0   &quot;/usr/local/bin/entr…&quot;   2 days ago   Up 18 minutes                               cka-new-worker
75634b82514e   kindest/node:v1.35.0   &quot;/usr/local/bin/entr…&quot;   2 days ago   Up 18 minutes                               cka-new-worker3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;None of the worker nodes had any ports published to the host — only the control-plane's Kubernetes API port was mapped. So the node's actual IP address on Docker's internal network was needed instead:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ docker inspect cka-new-worker | grep -A 15 '&quot;kind&quot;'
...
&quot;IPAddress&quot;: &quot;172.18.0.5&quot;,
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A discrepancy showed up here worth noting:&lt;/strong&gt; this IP (&lt;code&gt;172.18.0.5&lt;/code&gt;) didn't match what &lt;code&gt;kubectl get nodes -o wide&lt;/code&gt; had shown earlier in the session for this same node (&lt;code&gt;172.18.0.3&lt;/code&gt;). Docker assigns container IPs dynamically, and since these containers showed &lt;code&gt;Up 18 minutes&lt;/code&gt; (meaning they had recently restarted), the IP had simply changed. This is a good general reminder that hardcoding container IPs is fragile — they aren't guaranteed to stay the same across restarts.&lt;/p&gt;
&lt;p&gt;Testing the NodePort against this IP, however, still failed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ curl -v http://172.18.0.5:31003 -H &quot;Host: example.com&quot;
*   Trying 172.18.0.5:31003...
* connect to 172.18.0.5 port 31003 from 172.18.0.1 port 53748 failed: Connection timed out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So even with a real, reachable-in-theory IP and the correct port, nothing answered. This meant the problem was something deeper than just &quot;wrong IP&quot; — worth investigating the cluster's internal health next.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-ruling-out-the-obvious-culprits&quot;&gt;Step 4: Ruling Out the Obvious Culprits&lt;/h3&gt;
&lt;p&gt;At this point, several standard checks were run to narrow down where the actual fault was.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was the Ingress controller pod even healthy?&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get pods -n ingress-nginx -o wide
NAME                                        READY   STATUS    RESTARTS      AGE   IP           NODE
ingress-nginx-controller-7d65c586d6-kvn9s   1/1     Running   3 (20m ago)   16h   10.244.1.2   cka-new-worker2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was &lt;code&gt;Running&lt;/code&gt;, but had restarted 3 times recently — worth remembering, but not conclusive on its own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was &lt;code&gt;kube-proxy&lt;/code&gt; (the component responsible for NodePort/ClusterIP routing) healthy on every node?&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get pods -n kube-system -l k8s-app=kube-proxy -o wide
NAME               READY   STATUS    RESTARTS      AGE     NODE
kube-proxy-2mlbd   1/1     Running   4 (25m ago)   2d18h   cka-new-worker
kube-proxy-jb2rt   1/1     Running   4             2d18h   cka-new-worker2
kube-proxy-m2vq9   1/1     Running   4             2d18h   cka-new-control-plane
kube-proxy-rnlwc   1/1     Running   4             2d18h   cka-new-worker3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All &lt;code&gt;Running&lt;/code&gt;, though &lt;code&gt;cka-new-worker&lt;/code&gt; had also restarted recently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was there a conflict between two CNI plugins&lt;/strong&gt; (since Calico had been installed on top of the cluster's default &lt;code&gt;kindnet&lt;/code&gt; networking earlier)?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ docker exec cka-new-worker2 ls /etc/cni/net.d/
10-kindnet.conflist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only one CNI config was present — no conflict there, at least on this node.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Did basic pod-to-pod networking inside the cluster even work at all?&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl run curl --rm -it --image=curlimages/curl -- curl http://hello-world
curl: (6) Could not resolve host: hello-world
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was the first real breakthrough. This same command had worked earlier in the setup process — now it couldn't even resolve the Service's name. This shifted the investigation toward DNS specifically.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-5-investigating-the-dns-failure&quot;&gt;Step 5: Investigating the DNS Failure&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;First, check whether restarting &lt;code&gt;kube-proxy&lt;/code&gt; (to clear out any stale routing rules) fixes it:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl delete pods -n kube-system -l k8s-app=kube-proxy
pod &quot;kube-proxy-2mlbd&quot; deleted from kube-system namespace
pod &quot;kube-proxy-jb2rt&quot; deleted from kube-system namespace
pod &quot;kube-proxy-m2vq9&quot; deleted from kube-system namespace
pod &quot;kube-proxy-rnlwc&quot; deleted from kube-system namespace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After waiting for the new pods to come back &lt;code&gt;Running&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl run curl --rm -it --image=curlimages/curl -- curl http://hello-world
curl: (6) Could not resolve host: hello-world
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No change. This ruled out stale &lt;code&gt;kube-proxy&lt;/code&gt; rules as the cause.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Check whether the cluster's internal DNS service (CoreDNS) has healthy endpoints behind it:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get endpoints -n kube-system kube-dns
NAME       ENDPOINTS                                                   AGE
kube-dns   10.244.0.2:9153,10.244.0.3:9153,10.244.0.2:53 + 3 more...   2d18h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looked healthy — CoreDNS pods were properly registered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Check whether a real pod is even configured to use the right DNS server:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl exec -it hello-world-c8b6f8dbd-9t9n6 -- sh
# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was also correct — &lt;code&gt;10.96.0.10&lt;/code&gt; is the standard internal DNS Service IP.&lt;/p&gt;
&lt;p&gt;So far: correct DNS configuration, healthy-looking CoreDNS, no stale &lt;code&gt;kube-proxy&lt;/code&gt; rules — yet DNS lookups still failed. The next step was testing whether this was actually a DNS-specific issue, or something more fundamental with networking between nodes.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-6-isolating-dns-vs-general-networking&quot;&gt;Step 6: Isolating DNS vs. General Networking&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Test a plain HTTP connection to a Service, bypassing DNS entirely (using the raw ClusterIP):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# python3 -c &quot;import urllib.request; print(urllib.request.urlopen('http://10.96.74.127').read())&quot;
b'Hello, World!'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This worked. So general Service routing (HTTP, TCP) was fine — the problem was specific to DNS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test raw connectivity to the DNS port itself (port 53), both against the Service IP and a CoreDNS pod's IP directly:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# python3 -c &quot;
import socket
try:
    s = socket.create_connection(('10.96.0.10', 53), timeout=3)
    print('connected')
    s.close()
except Exception as e:
    print('failed:', e)
&quot;
failed: timed out
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# python3 -c &quot;
import socket
try:
    s = socket.create_connection(('10.244.0.2', 53), timeout=3)
    print('connected')
    s.close()
except Exception as e:
    print('failed:', e)
&quot;
failed: timed out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both failed — even a direct connection attempt to a CoreDNS pod's own IP, with no DNS resolution or Service routing involved at all, still timed out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The key detail that explained this:&lt;/strong&gt; checking which node each pod involved was running on showed that the working test (&lt;code&gt;10.96.74.127&lt;/code&gt;, resolving to the &lt;code&gt;hello-world&lt;/code&gt; pod) happened to be a pod on the &lt;em&gt;same node&lt;/em&gt; the test was run from. The failing tests (both CoreDNS IPs) were both on the &lt;em&gt;control-plane&lt;/em&gt; node — a different node entirely. This pointed toward a &lt;strong&gt;cross-node networking problem&lt;/strong&gt;, not a DNS-specific one.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-7-confirming-cross-node-networking-was-broken&quot;&gt;Step 7: Confirming Cross-Node Networking Was Broken&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Checked whether the Ingress controller's NodePort Service had a networking policy that might explain uneven behavior across nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get svc -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.externalTrafficPolicy}'
Local
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This turned out to be a real, separate finding: &lt;code&gt;externalTrafficPolicy: Local&lt;/code&gt; means kube-proxy will only forward NodePort traffic on a node if that node happens to be running a copy of the target pod locally — every other node will actively drop the traffic rather than forward it elsewhere. This fully explained the earlier NodePort timeout, since the Ingress controller pod only ran on &lt;code&gt;cka-new-worker2&lt;/code&gt;, and the test had hit a different node.&lt;/p&gt;
&lt;p&gt;Confirmed by checking &lt;code&gt;iptables&lt;/code&gt; on the failing node:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ docker exec cka-new-worker3 iptables-save | grep -i &quot;53\|drop&quot; | head -30
-A KUBE-EXTERNAL-SERVICES -p tcp -m comment --comment &quot;ingress-nginx/ingress-nginx-controller:http has no local endpoints&quot; -m addrtype --dst-type LOCAL -m tcp --dport 31003 -j DROP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line confirms it directly: any NodePort traffic to port &lt;code&gt;31003&lt;/code&gt; on this node is explicitly dropped, because this node has no local copy of the Ingress controller pod.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fixing the NodePort routing issue was straightforward&lt;/strong&gt; — hit the correct node directly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ curl -v http://172.18.0.4:31003 -H &quot;Host: example.com&quot;
* Connected to 172.18.0.4 (172.18.0.4) port 31003
&amp;lt; HTTP/1.1 504 Gateway Time-out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The connection succeeded this time — but nginx itself returned a &lt;code&gt;504 Gateway Time-out&lt;/code&gt;. This meant the request reached the Ingress controller fine, but the Ingress controller couldn't reach its own backend (the &lt;code&gt;hello-world&lt;/code&gt; Service). And, notably, the Ingress controller pod and the &lt;code&gt;hello-world&lt;/code&gt; pod were running on two &lt;em&gt;different&lt;/em&gt; nodes — another cross-node hop, timing out in exactly the same pattern as the DNS failures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This was the real conclusion:&lt;/strong&gt; same-node pod-to-pod traffic worked consistently throughout this session. Cross-node pod-to-pod traffic (DNS lookups to CoreDNS, and now the Ingress controller reaching its backend) consistently failed. Along the way, other explanations were ruled out — no competing CNI configs, no blocking NetworkPolicy, correctly configured DNS, correct iptables NAT rules, and Calico's own control-plane pods weren't even running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get pods -n calico-system -o wide
No resources found in calico-system namespace.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The most likely explanation: installing Calico mid-way through the cluster's life (on top of the existing &lt;code&gt;kindnet&lt;/code&gt; CNI, without removing it) had left the routes between nodes in a broken, inconsistent state — even after Calico itself was no longer running. Untangling that kind of mixed-CNI networking state by hand is generally not worth the time; the standard, reliable fix is to rebuild the cluster from scratch.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-8-rebuilding-the-cluster&quot;&gt;Step 8: Rebuilding the Cluster&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ kind delete cluster --name cka-new
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make future testing easier, a &lt;code&gt;kind&lt;/code&gt; config file was created to forward the Ingress controller's expected ports straight from the container to &lt;code&gt;localhost&lt;/code&gt; on the host machine — removing the need to look up container IPs at all going forward:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: cka-new
nodes:
  - role: control-plane
    extraPortMappings:
      - containerPort: 31003
        hostPort: 31003
        protocol: TCP
      - containerPort: 30437
        hostPort: 30437
        protocol: TCP
  - role: worker
  - role: worker
  - role: worker
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;❯ kind create cluster --name cka-new --config kind-config.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, Calico was intentionally left out — the default &lt;code&gt;kindnet&lt;/code&gt; CNI had been working fine before Calico was introduced mid-session, and nothing about the setup actually required Calico's features.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reapplying the application and Ingress manifests:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl apply -f deployment.yaml -f service.yaml -f ingress.yaml
❯ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.15.1/deploy/static/provider/aws/deploy.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-9-a-slow-pod-isn-t-always-a-stuck-pod&quot;&gt;Step 9: A Slow Pod Isn't Always a Stuck Pod&lt;/h3&gt;
&lt;p&gt;While waiting for the Ingress controller to come up, it sat in &lt;code&gt;ContainerCreating&lt;/code&gt; for several minutes, which raised the question of whether something was actually wrong:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get pods -n ingress-nginx -w
ingress-nginx-controller-7d65c586d6-fz54r   0/1   ContainerCreating   0   2m59s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Checking the pod's events showed the actual cause:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl describe pod -n ingress-nginx ingress-nginx-controller-7d65c586d6-fz54r
...
Events:
  Warning  FailedMount  4m41s (x8 over 5m45s)  kubelet  MountVolume.SetUp failed for volume &quot;webhook-cert&quot; : secret &quot;ingress-nginx-admission&quot; not found
  Normal   Pulling      3m30s                  kubelet  Pulling image &quot;registry.k8s.io/ingress-nginx/controller:v1.15.1@sha256:...&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looked alarming at first, but both issues were self-resolving, expected steps of the install process rather than actual problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;FailedMount&lt;/code&gt; warnings happened because two setup Jobs (&lt;code&gt;ingress-nginx-admission-create&lt;/code&gt; and &lt;code&gt;ingress-nginx-admission-patch&lt;/code&gt;) needed to finish first — they're responsible for generating the certificate secret the controller pod was waiting to mount. Until those Jobs completed, that secret simply didn't exist yet.&lt;/li&gt;
&lt;li&gt;The image pull itself was just slow — checking &lt;code&gt;kubectl get events&lt;/code&gt; showed the two setup Jobs' images had each taken over a minute to pull, which suggested a slow registry pull rather than anything broken locally.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Waiting it out confirmed this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get pods -n ingress-nginx
ingress-nginx-controller-7d65c586d6-fz54r   1/1   Running   0   7m34s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lesson here:&lt;/strong&gt; not every &lt;code&gt;ContainerCreating&lt;/code&gt; or warning event means something is broken — checking the actual &lt;code&gt;Events&lt;/code&gt; section (via &lt;code&gt;kubectl describe pod&lt;/code&gt;) before assuming failure saves a lot of unnecessary troubleshooting.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-10-fixing-the-service-configuration-correctly&quot;&gt;Step 10: Fixing the Service Configuration Correctly&lt;/h3&gt;
&lt;p&gt;With the controller running, the &lt;code&gt;externalTrafficPolicy&lt;/code&gt; and Service type still needed to be set correctly, to avoid re-hitting the earlier &lt;code&gt;Local&lt;/code&gt;-policy and &lt;code&gt;LoadBalancer&lt;/code&gt;-pending issues.&lt;/p&gt;
&lt;p&gt;The first attempt patched only &lt;code&gt;externalTrafficPolicy&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{&quot;spec&quot;:{&quot;externalTrafficPolicy&quot;:&quot;Cluster&quot;}}'
❯ kubectl get svc -n ingress-nginx ingress-nginx-controller
NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)
ingress-nginx-controller   LoadBalancer   10.96.61.252   &amp;lt;pending&amp;gt;     80:32087/TCP,443:32290/TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This revealed two remaining issues: the Service was still &lt;code&gt;type: LoadBalancer&lt;/code&gt; (stuck &lt;code&gt;&amp;lt;pending&amp;gt;&lt;/code&gt;, same problem as before), and the NodePorts had landed on different numbers (&lt;code&gt;32087&lt;/code&gt;/&lt;code&gt;32290&lt;/code&gt;) than what &lt;code&gt;kind-config.yaml&lt;/code&gt; was forwarding (&lt;code&gt;31003&lt;/code&gt;/&lt;code&gt;30437&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fixing both at once&lt;/strong&gt;, by explicitly setting the type to &lt;code&gt;NodePort&lt;/code&gt; and pinning the exact port numbers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{&quot;spec&quot;:{&quot;type&quot;:&quot;NodePort&quot;,&quot;ports&quot;:[{&quot;name&quot;:&quot;http&quot;,&quot;port&quot;:80,&quot;targetPort&quot;:&quot;http&quot;,&quot;protocol&quot;:&quot;TCP&quot;,&quot;nodePort&quot;:31003},{&quot;name&quot;:&quot;https&quot;,&quot;port&quot;:443,&quot;targetPort&quot;:&quot;https&quot;,&quot;protocol&quot;:&quot;TCP&quot;,&quot;nodePort&quot;:30437}]}}'
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get svc -n ingress-nginx ingress-nginx-controller
NAME                       TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)
ingress-nginx-controller   NodePort   10.96.61.252   &amp;lt;none&amp;gt;        80:31003/TCP,443:30437/TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This matched the port forwarding configured in &lt;code&gt;kind-config.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-11-confirming-everything-works&quot;&gt;Step 11: Confirming Everything Works&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ curl -v http://localhost:31003 -H &quot;Host: example.com&quot;
*   Trying [::1]:31003...
* connect to ::1 port 31003 from ::1 port 49216 failed: Connection refused
*   Trying 127.0.0.1:31003...
* Connected to localhost (127.0.0.1) port 31003
&amp;lt; HTTP/1.1 200 OK
Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirmed everything was working correctly: the port forwarding in &lt;code&gt;kind-config.yaml&lt;/code&gt;, the &lt;code&gt;Cluster&lt;/code&gt; traffic policy correctly routing regardless of which node the request landed on, and the Ingress controller successfully reaching the &lt;code&gt;hello-world&lt;/code&gt; backend (no more &lt;code&gt;504 Gateway Time-out&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;::1&lt;/code&gt; (IPv6) connection attempt failing before falling back to IPv4 is expected — &lt;code&gt;kind-config.yaml&lt;/code&gt; only forwards the port over IPv4, so curl's dual-stack attempt simply skips it and retries over IPv4 instead. Not an error to fix.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Final step — update &lt;code&gt;/etc/hosts&lt;/code&gt;, this time pointing at &lt;code&gt;127.0.0.1&lt;/code&gt; instead of any container IP&lt;/strong&gt;, since port forwarding now handles the routing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;127.0.0.1   example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;❯ curl http://example.com:31003
Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-the-port-still-has-to-be-specified&quot;&gt;Why the Port Still Has to Be Specified&lt;/h3&gt;
&lt;p&gt;Running &lt;code&gt;curl http://example.com&lt;/code&gt; without a port defaults to port 80 — but nothing is mapped to host port 80 in this setup, only &lt;code&gt;31003&lt;/code&gt; and &lt;code&gt;30437&lt;/code&gt;. Without a port, the connection fails immediately:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl: (7) Failed to connect to example.com port 80 after ...: Connection refused
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is expected: the Ingress controller is exposed via a &lt;code&gt;NodePort&lt;/code&gt; Service, and NodePorts are, by design, high-numbered ports (typically in the 30000–32767 range) — they were never going to answer on plain port 80 without an explicit mapping.&lt;/p&gt;
&lt;p&gt;To make &lt;code&gt;curl http://example.com&lt;/code&gt; work without a port number, &lt;code&gt;kind-config.yaml&lt;/code&gt; could instead map host port 80 directly to the NodePort:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;extraPortMappings:
  - containerPort: 31003
    hostPort: 80
    protocol: TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This requires a cluster rebuild to take effect, and on Linux, binding to port 80 may require elevated (&lt;code&gt;sudo&lt;/code&gt;) privileges since ports below 1024 are privileged. For local testing and practice environments, simply including the NodePort in the URL is generally the more common and simpler approach — production clusters solve the &quot;no port number&quot; problem differently anyway, using a real external load balancer or a bare-metal solution like MetalLB in front of the cluster.&lt;/p&gt;
&lt;hr&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23396/debugging-a-broken-ingress-setup-a-step-by-step-walkthrough</guid>
<pubDate>Fri, 24 Jul 2026 10:05:45 +0000</pubDate>
</item>
<item>
<title>Setting Up Ingress for a Flask App</title>
<link>https://coderlegion.com/23390/setting-up-ingress-for-a-flask-app</link>
<description>&lt;p&gt;Today's goal: take a simple Flask app running in Kubernetes and expose it to the outside world using &lt;strong&gt;Ingress&lt;/strong&gt;, instead of relying on &lt;code&gt;NodePort&lt;/code&gt; or &lt;code&gt;LoadBalancer&lt;/code&gt; services. This post walks through the setup, the errors I hit along the way, and how each one was resolved.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-use-ingress-instead-of-nodeport-or-loadbalancer-&quot;&gt;Why Use Ingress Instead of NodePort or LoadBalancer?&lt;/h3&gt;
&lt;p&gt;Kubernetes gives you a few ways to expose a Service outside the cluster:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NodePort&lt;/strong&gt; — opens a fixed port (usually in the 30000–32767 range) on every node. Works, but the port numbers are ugly and it doesn't scale well for multiple applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LoadBalancer&lt;/strong&gt; — provisions a cloud load balancer per Service. This has real drawbacks:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cost&lt;/strong&gt; — each &lt;code&gt;LoadBalancer&lt;/code&gt; Service typically means a new cloud load balancer, billed separately.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud lock-in&lt;/strong&gt; — it depends on your cloud provider's integration (AWS, GCP, Azure, etc.).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No advanced routing&lt;/strong&gt; — no path-based or host-based routing, and no built-in SSL termination.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ingress&lt;/strong&gt; solves this with two separate pieces:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Ingress Resource&lt;/strong&gt; — a YAML manifest where you declare routing rules (e.g., &quot;requests for &lt;code&gt;example.com/&lt;/code&gt; should go to the &lt;code&gt;hello-world&lt;/code&gt; Service&quot;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress Controller&lt;/strong&gt; — the component that actually watches the API server for Ingress Resources and configures a real proxy (in this case, NGINX) to implement those rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You write the rules; the controller enforces them. Without a running Ingress Controller, an Ingress Resource does nothing on its own.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-0-building-and-pushing-the-docker-image&quot;&gt;Step 0: Building and Pushing the Docker Image&lt;/h3&gt;
&lt;p&gt;Before any of the Kubernetes manifests would work, the Flask app first had to be containerized and pushed to a registry, Kubernetes only pulls and runs images, not raw source code. This step happens before everything else, even though it isn't captured in the terminal history below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.py&lt;/code&gt;&lt;/strong&gt; — a minimal Flask app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;# Use the official image as a parent image
FROM python:3.7-slim

# Set the working directory in the container
WORKDIR /app

# Copy the dependencies file to the working directory
COPY requirements.txt .

# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt

# Copy the content of the local src directory to the working directory
COPY . .

# Run app.py when the container launches
CMD [&quot;python&quot;, &quot;app.py&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Flask==2.2.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This image is built and pushed to Docker Hub as &lt;code&gt;oyebobs/ingress-demo:v1&lt;/code&gt; — the same tag referenced in &lt;code&gt;deployment.yaml&lt;/code&gt; below. If this step is skipped, &lt;code&gt;kubectl&lt;/code&gt; will still accept the Deployment manifest, but the Pod will get stuck in &lt;code&gt;ImagePullBackOff&lt;/code&gt; because there's nothing to pull.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-1-the-kubernetes-manifests&quot;&gt;Step 1: The Kubernetes Manifests&lt;/h3&gt;
&lt;p&gt;Three manifests, each with a distinct job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;deployment.yaml&lt;/code&gt;&lt;/strong&gt; — defines the Pod and keeps it running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
  labels:
    app: hello-world
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
      - name: hello-world
        image: oyebobs/ingress-demo:v1
        ports:
        - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;service.yaml&lt;/code&gt;&lt;/strong&gt; — gives the Pod(s) a stable internal address:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: Service
metadata:
  name: hello-world
spec:
  selector:
    app: hello-world
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ingress.yaml&lt;/code&gt;&lt;/strong&gt; — defines the routing rule for external traffic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: &quot;example.com&quot;
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-world
            port:
              number: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ingressClassName: nginx&lt;/code&gt; field matters: in a cluster with more than one Ingress Controller installed, this tells Kubernetes which controller should handle this particular Ingress Resource.&lt;/p&gt;
&lt;p&gt;After applying the Deployment and Service, both looked healthy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k get po
NAME                          READY   STATUS    RESTARTS      AGE
curl-test                     1/1     Running   1 (44s ago)   3m43s
hello-world-c8b6f8dbd-9t9n6   1/1     Running   1             33m

❯ k get svc
NAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
hello-world   ClusterIP   10.96.74.127   &amp;lt;none&amp;gt;        80/TCP    26m
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-debugging-internal-connectivity&quot;&gt;Step 2: Debugging Internal Connectivity&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;curl-test&lt;/code&gt; Pod was already running to test connectivity to the &lt;code&gt;hello-world&lt;/code&gt; Service. The first attempt failed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k exec -it curl-test -- curl 10.96.74.127
command terminated with exit code 137
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Exit code 137 means the container was OOM-killed&lt;/strong&gt; (killed for exceeding its memory limit) — this is not a networking error. Running &lt;code&gt;kubectl describe pod curl-test&lt;/code&gt; confirmed repeated restarts with &lt;code&gt;Last State: Terminated&lt;/code&gt;, &lt;code&gt;Reason: Error&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To check whether the app itself was actually working, I shelled directly into the &lt;code&gt;hello-world&lt;/code&gt; Pod:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl exec -it hello-world-c8b6f8dbd-9t9n6 -- curl localhost:80
error: ... exec: &quot;curl&quot;: executable file not found in $PATH
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;python:3.7-slim&lt;/code&gt; base image doesn't include &lt;code&gt;curl&lt;/code&gt; — &quot;slim&quot; images intentionally leave out extras like this. As a workaround, I used Python's built-in &lt;code&gt;urllib&lt;/code&gt; module instead:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# python3 -c &quot;import urllib.request; print(urllib.request.urlopen('http://localhost:80').read())&quot;
b'Hello, World!'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirmed the app itself was working correctly inside its own Pod. The issue was isolated to the &lt;code&gt;curl-test&lt;/code&gt; Pod repeatedly getting OOM-killed, not the app or the network.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; rather than continuing to debug a resource-constrained, long-running Pod, I switched to a disposable Pod using &lt;code&gt;kubectl run --rm -it&lt;/code&gt;, which creates a temporary Pod, opens a shell, and deletes the Pod automatically on exit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl run curl-test --image=curlimages/curl -it --rm -- curl -v 10.244.3.2:80
...
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Server: Werkzeug/2.2.3 Python/3.7.17
...
Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same worked against the Service's ClusterIP directly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl run curl-test --image=curlimages/curl -it --rm -- curl -v 10.96.74.127:80
&amp;lt; HTTP/1.1 200 OK
Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; internal networking and the app were fine the entire time. The failures were caused by one Pod being killed for memory usage, not by a cluster-wide issue. When only one Pod misbehaves and everything else works, the Pod itself is usually the place to look first.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-applying-the-ingress-address-stays-empty&quot;&gt;Step 3: Applying the Ingress — Address Stays Empty&lt;/h3&gt;
&lt;p&gt;With internal connectivity confirmed, I applied the Ingress resource:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k apply -f ingress.yaml
ingress.networking.k8s.io/hello-world created

❯ k get ingress
NAME          CLASS   HOSTS         ADDRESS   PORTS   AGE
hello-world   nginx   example.com             80      8s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ADDRESS&lt;/code&gt; column stayed empty. This is expected at this stage: the Ingress &lt;em&gt;Resource&lt;/em&gt; exists, but no Ingress &lt;em&gt;Controller&lt;/em&gt; is running yet to act on it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-installing-the-nginx-ingress-controller&quot;&gt;Step 4: Installing the NGINX Ingress Controller&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.15.1/deploy/static/provider/aws/deploy.yaml
namespace/ingress-nginx created
...
deployment.apps/ingress-nginx-controller created
...
ingressclass.networking.k8s.io/nginx created
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This manifest creates a dedicated namespace, RBAC rules, the controller Deployment, and admission webhooks. The controller Pod came up successfully:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k get po -A | grep nginx
ingress-nginx   ingress-nginx-controller-7d65c586d6-kvn9s   1/1   Running   0   7m24s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Its logs confirmed it detected the Ingress resource and reloaded its configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;I0723 16:19:18.803001 ... &quot;Found valid IngressClass&quot; ingress=&quot;default/hello-world&quot; ingressclass=&quot;nginx&quot;
I0723 16:19:19.839235 ... &quot;Backend successfully reloaded&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The controller was running and had picked up the routing rule. The next question was why the Ingress still had no address.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-5-loadbalancer-stuck-on-lt-pending-gt-&quot;&gt;Step 5: LoadBalancer Stuck on &lt;code&gt;&amp;lt;pending&amp;gt;&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k get svc -n ingress-nginx
NAME                        TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)
ingress-nginx-controller    LoadBalancer   10.96.101.127   &amp;lt;pending&amp;gt;     80:31003/TCP,443:30437/TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;EXTERNAL-IP&lt;/code&gt; stayed on &lt;code&gt;&amp;lt;pending&amp;gt;&lt;/code&gt; indefinitely. This happens because a &lt;code&gt;type: LoadBalancer&lt;/code&gt; Service depends on a &lt;strong&gt;Cloud Controller Manager&lt;/strong&gt; to provision an actual external load balancer and assign it an IP. On a self-managed &lt;code&gt;kind&lt;/code&gt;/kubeadm cluster with no cloud provider integration, there's nothing available to fulfill that request, so it never resolves.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; change the Service type to &lt;code&gt;NodePort&lt;/code&gt;, which doesn't require any cloud integration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k edit svc ingress-nginx-controller -n ingress-nginx
service/ingress-nginx-controller edited

❯ k get svc -n ingress-nginx
NAME                        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)
ingress-nginx-controller    NodePort   10.96.101.127   &amp;lt;none&amp;gt;        80:31003/TCP,443:30437/TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After deleting and re-applying &lt;code&gt;ingress.yaml&lt;/code&gt;, the &lt;code&gt;ADDRESS&lt;/code&gt; field populated:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k get ing -w
NAME          CLASS   HOSTS         ADDRESS         PORTS   AGE
hello-world   nginx   example.com   10.96.101.127   80      44s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Testing directly from the local machine, however, still failed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ curl 10.96.101.127
curl: (7) Failed to connect to 10.96.101.127 port 80 after 21024 ms: Could not connect to server
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-6-investigating-the-cni-calico-installation-&quot;&gt;Step 6: Investigating the CNI (Calico Installation)&lt;/h3&gt;
&lt;p&gt;While troubleshooting the connection timeout, I also installed &lt;strong&gt;Calico&lt;/strong&gt; as the cluster's CNI (Container Network Interface) plugin, replacing the default &lt;code&gt;kindnet&lt;/code&gt; networking that &lt;code&gt;kind&lt;/code&gt; clusters ship with. Calico is a common choice in real-world clusters because of its more detailed network policy support and easier debugging tools.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/tigera-operator.yaml
namespace/tigera-operator created
...
deployment.apps/tigera-operator created

❯ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/custom-resources.yaml
resource mapping not found for name: &quot;default&quot; ... no matches for kind &quot;Installation&quot; in version &quot;operator.tigera.io/v1&quot;
ensure CRDs are installed first
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This error occurs when the Calico custom resources are applied before the &lt;code&gt;tigera-operator&lt;/code&gt; has finished installing its Custom Resource Definitions (CRDs) — the CRDs need to exist before Kubernetes can accept objects of that kind. &lt;strong&gt;Fix:&lt;/strong&gt; wait for the operator Pod to reach &lt;code&gt;Running&lt;/code&gt;, then re-apply:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl get pods -n tigera-operator -w
tigera-operator-75c7c596d9-tsmbz   1/1   Running   0   2m4s

❯ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/custom-resources.yaml
installation.operator.tigera.io/default created
apiserver.operator.tigera.io/default created
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calico's components came up correctly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k get po -A -n calico-system | grep calico
calico-apiserver   calico-apiserver-64cf87458d-qrwnb   1/1   Running   0   3m58s
calico-apiserver   calico-apiserver-64cf87458d-tqw44   1/1   Running   0   3m58s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even with Calico running, curling the Ingress IP from the local machine still timed out:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ curl 10.96.101.127
curl: (7) Failed to connect to 10.96.101.127 port 80 after 21007 ms: Could not connect to server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Important clarification:&lt;/strong&gt; &lt;code&gt;10.96.101.127&lt;/code&gt; is a &lt;strong&gt;ClusterIP&lt;/strong&gt;, which is only routable &lt;em&gt;inside&lt;/em&gt; the cluster's network — it is not reachable from an external machine like a laptop, regardless of which CNI is installed. Swapping the CNI plugin did not (and could not) resolve this particular timeout, since the address itself is not meant to be reachable externally. The correct way to test was to send traffic from inside the cluster, or through the exposed NodePort.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-7-testing-from-inside-the-cluster&quot;&gt;Step 7: Testing From Inside the Cluster&lt;/h3&gt;
&lt;p&gt;To test correctly, I ran a temporary Pod inside the cluster and issued requests from there, which reflects how real traffic would actually reach the Service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ kubectl run curl --rm -it --image=curlimages/curl -- sh
~ $ curl http://hello-world
Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirmed internal DNS-based service discovery was working. Next, hitting the Ingress Service's ClusterIP directly by IP, without specifying a hostname:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~ $ curl http://10.96.101.127
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;404 Not Found&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;&amp;lt;center&amp;gt;&amp;lt;h1&amp;gt;404 Not Found&amp;lt;/h1&amp;gt;&amp;lt;/center&amp;gt;
&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt;nginx&amp;lt;/center&amp;gt;&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This 404 is expected behavior, not an error. The Ingress rule only matches requests where the &lt;code&gt;Host&lt;/code&gt; header is &lt;code&gt;example.com&lt;/code&gt;. Curling the raw IP sends no &lt;code&gt;Host&lt;/code&gt; header, so NGINX has no matching rule and returns a 404.&lt;/p&gt;
&lt;p&gt;To simulate a request with the correct hostname, I used curl's &lt;code&gt;--resolve&lt;/code&gt; flag to manually map &lt;code&gt;example.com&lt;/code&gt; to the Ingress IP. The first attempt used the wrong syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~ $ curl example.com --resolve example.com:80 http://10.96.101.127
curl: (49) Could not parse CURLOPT_RESOLVE entry 'example.com:80'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--resolve&lt;/code&gt; expects the format &lt;code&gt;host:port:ip&lt;/code&gt;, not a separate URL. Corrected:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~ $ curl example.com --resolve example.com:80:10.96.101.127
Hello, World!

~ $ curl http://example.com
Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confirmed host-based routing was working as configured: the same Ingress IP serves different responses depending on the requested hostname — the core capability that distinguishes Ingress from a plain NodePort or LoadBalancer setup.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-8-mapping-example-com-in-etc-hosts&quot;&gt;Step 8: Mapping example.com in /etc/hosts&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;--resolve&lt;/code&gt; is convenient for one-off curl requests, but it only applies to that single command — it doesn't help if you want to open &lt;code&gt;http://example.com&lt;/code&gt; in a browser or run multiple tools against the same hostname. For that, the standard approach is to edit &lt;code&gt;/etc/hosts&lt;/code&gt; directly, which tells the local machine to resolve &lt;code&gt;example.com&lt;/code&gt; to the Ingress IP for every request, not just one curl call.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ sudo nano /etc/hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the file, a line was added mapping the hostname &lt;code&gt;example.com&lt;/code&gt; to the Ingress controller's IP address:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10.96.101.127   example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After saving the file, any tool on the machine — curl, a browser, etc. — resolves &lt;code&gt;example.com&lt;/code&gt; to that IP without needing &lt;code&gt;--resolve&lt;/code&gt; or any other flag:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ curl http://example.com
Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simulates what a real DNS record would do in production: pointing a domain name at the Ingress controller's IP. In production, you'd create an actual DNS &lt;code&gt;A&lt;/code&gt; record for &lt;code&gt;example.com&lt;/code&gt; pointing at the Ingress controller's external IP; &lt;code&gt;/etc/hosts&lt;/code&gt; is the local-machine equivalent for testing without needing a real, registered domain.&lt;/p&gt;
&lt;p&gt;One thing worth noting: this entry only affects DNS resolution on the local machine — it doesn't change how anyone else resolves the domain. It's also worth removing once testing is done, so it doesn't cause confusion later if the Ingress IP changes.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23390/setting-up-ingress-for-a-flask-app</guid>
<pubDate>Fri, 24 Jul 2026 08:53:23 +0000</pubDate>
</item>
<item>
<title>How a Football Match Helped Me Understand Kubernetes: Desired State vs Actual State</title>
<link>https://coderlegion.com/22896/how-a-football-match-helped-me-understand-kubernetes-desired-state-vs-actual-state</link>
<description>&lt;p&gt;Have you ever wondered what Desired State and Actual State mean in Kubernetes?&lt;/p&gt;
&lt;p&gt;I used to hear those terms all the time, but they didn't truly make sense until I watched a football match.&lt;/p&gt;
&lt;p&gt;In this &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=X7LAFxM1Yt4&quot;&gt;video&lt;/a&gt;, Ada explains one of Kubernetes' most important concepts using a simple football analogy. Instead of complicated diagrams and technical jargon, you'll see how a football coach, substitutions, and an unexpected injury perfectly explain how Kubernetes constantly works to keep your applications running.&lt;/p&gt;
&lt;p&gt;Whether you're preparing for the KCNA, CKA, or CKAD, learning Kubernetes for DevOps, or just getting started with cloud-native technologies, this real-world story will help you understand one of Kubernetes' core ideas.&lt;/p&gt;
&lt;h4 id=&quot;what-you-ll-learn&quot;&gt;What you'll learn&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;What Desired State means in Kubernetes&lt;/li&gt;
&lt;li&gt;What Actual State means&lt;/li&gt;
&lt;li&gt;How Kubernetes compares both states&lt;/li&gt;
&lt;li&gt;What reconciliation is&lt;/li&gt;
&lt;li&gt;Why Kubernetes automatically creates new Pods&lt;/li&gt;
&lt;li&gt;Why this makes Kubernetes reliable&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;-watch-next&quot;&gt;🎯 Watch next&lt;/h4&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://youtu.be/21v-aDkHNOI&quot;&gt;What a Busy Restaurant Can Teach You About Kubernetes Services&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;-want-to-practice-kubernetes-yourself-&quot;&gt;🚀 Want to practice Kubernetes yourself?&lt;/h4&gt;
&lt;p&gt;Spin up a managed Kubernetes cluster on &lt;a rel=&quot;nofollow&quot; href=&quot;http://%20https://www.awin1.com/cread.php?awinmid=123996&amp;amp;awinaffid=2852319&amp;amp;clickref=kubernetes&amp;amp;ued=https%3A%2F%2Fwww.digitalocean.com%2Fproducts%2Fkubernetes&quot;&gt;DigitalOcean&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can follow my work and projects on &lt;a rel=&quot;nofollow&quot; href=&quot;https://x.com/ijaydimples&quot;&gt;Twitter&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/ijeoma-igboagu/&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/ijayhub&quot;&gt;GitHub&lt;/a&gt;, and &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/@cloudinreallife&quot;&gt;YouTube&lt;/a&gt;, where I share what I am building and learning along the way.&lt;/p&gt;
&lt;p&gt;If this video helped you understand Kubernetes better, consider subscribing for more &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/@cloudinreallife&quot;&gt;real-life cloud and DevOps stories.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for reading.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22896/how-a-football-match-helped-me-understand-kubernetes-desired-state-vs-actual-state</guid>
<pubDate>Sat, 18 Jul 2026 10:00:00 +0000</pubDate>
</item>
<item>
<title>Understanding PersistentVolumes (PV) and PersistentVolumeClaims (PVC)</title>
<link>https://coderlegion.com/22836/understanding-persistentvolumes-pv-and-persistentvolumeclaims-pvc</link>
<description>&lt;p&gt;Today I learned one of the most confusing Kubernetes concepts for beginners: &lt;strong&gt;PersistentVolumes (PV)&lt;/strong&gt; and &lt;strong&gt;PersistentVolumeClaims (PVC)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At first, my PVC refused to bind and stayed in the &lt;code&gt;Pending&lt;/code&gt; state. After some troubleshooting, I finally got everything working. And honestly? Breaking it first helped me understand it much better.&lt;/p&gt;
&lt;h3 id=&quot;why-do-we-even-need-pvs-&quot;&gt;Why do we even need PVs?&lt;/h3&gt;
&lt;p&gt;Imagine you're living in a rented apartment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pod&lt;/strong&gt; = You.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Container filesystem&lt;/strong&gt; = Your temporary room.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PersistentVolume (PV)&lt;/strong&gt; = A storage unit that exists independently of you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PersistentVolumeClaim (PVC)&lt;/strong&gt; = The rental agreement saying, &quot;I'd like to use a storage unit.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your Pod dies, everything inside the container normally disappears.&lt;/p&gt;
&lt;p&gt;A PV lets your data survive even when the Pod is deleted.&lt;/p&gt;
&lt;h3 id=&quot;the-relationship&quot;&gt;The Relationship&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Pod
 │
 ▼
PersistentVolumeClaim (PVC)
 │
 ▼
PersistentVolume (PV)
 │
 ▼
Actual storage (hostPath, NFS, cloud disk, etc.)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Pod never talks directly to the PV.&lt;/p&gt;
&lt;p&gt;Instead it says:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Hey PVC, can I borrow some storage?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The PVC then finds a suitable PV.&lt;/p&gt;
&lt;h3 id=&quot;step-1-create-a-persistentvolume&quot;&gt;Step 1 — Create a PersistentVolume&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-demo
  labels:
    type: local
spec:
  storageClassName: &quot;&quot;
  capacity:
    storage: 512Mi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: &quot;/data/config&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates &lt;strong&gt;512Mi&lt;/strong&gt; of storage backed by a directory on the node.&lt;/p&gt;
&lt;h3 id=&quot;step-2-create-a-persistentvolumeclaim&quot;&gt;Step 2 — Create a PersistentVolumeClaim&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo
spec:
  storageClassName: &quot;&quot;
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 256Mi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the claim only requests &lt;strong&gt;256Mi&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Kubernetes looks for a PV that satisfies the request and binds them together.&lt;/p&gt;
&lt;h3 id=&quot;my-first-roadblock&quot;&gt;My First Roadblock&lt;/h3&gt;
&lt;p&gt;After creating the PVC:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f pvc.yaml
kubectl get pvc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I saw:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;STATUS
Pending
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;why-was-my-pvc-stuck-in-pending-&quot;&gt;Why Was My PVC Stuck in &lt;code&gt;Pending&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;This was the part that confused me the most.&lt;/p&gt;
&lt;p&gt;I had already created my PersistentVolume (PV), so I expected my PersistentVolumeClaim (PVC) to bind to it immediately. Instead, every time I checked, the PVC was still in the &lt;code&gt;Pending&lt;/code&gt; state.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get pvc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;NAME       STATUS
pvc-demo   Pending
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To investigate, I ran:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe pvc pvc-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Events section showed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;FailedBinding
no persistent volumes available for this claim and no storage class is set
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first, I thought Kubernetes couldn't see my PersistentVolume at all. That wasn't actually the problem.&lt;/p&gt;
&lt;p&gt;The issue was that my PVC and PV didn't agree on the access mode.&lt;/p&gt;
&lt;p&gt;My PVC requested:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;accessModes:
  - ReadWriteOnce
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;while my PV was configured with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;accessModes:
  - ReadWriteMany
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because of this difference, Kubernetes couldn't match the claim to the volume, so the PVC stayed in the &lt;code&gt;Pending&lt;/code&gt; state.&lt;/p&gt;
&lt;p&gt;After deleting the old resources, correcting the configuration, and recreating both the PV and PVC, Kubernetes successfully matched them and their status changed to &lt;strong&gt;Bound&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The biggest lesson I learned is that whenever a PVC is stuck in &lt;code&gt;Pending&lt;/code&gt;, the first command to run should be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe pvc pvc-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;strong&gt;Events&lt;/strong&gt; section usually contains the clue you need to figure out why the claim couldn't be bound.&lt;/p&gt;
&lt;h3 id=&quot;step-3-mount-the-pvc-inside-a-pod&quot;&gt;Step 3 — Mount the PVC inside a Pod&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: pv-container
      image: nginx:latest
      volumeMounts:
        - name: pv-storage
          mountPath: /var/app/config
      ports:
        - containerPort: 80
          name: http-server
  volumes:
    - name: pv-storage
      persistentVolumeClaim:
        claimName: pvc-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Think of this as plugging an external hard drive into your laptop.&lt;/p&gt;
&lt;p&gt;The Pod can now read and write files through the PVC.&lt;/p&gt;
&lt;h3 id=&quot;step-4-test-it&quot;&gt;Step 4 — Test It&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl exec -it app -- bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the container:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /var/app/config

echo &quot;This is a test&quot; &amp;gt; test.html

cat test.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;This is a test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Success! &lt;/p&gt;
&lt;p&gt;I accidentally tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl test.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which failed because &lt;code&gt;curl&lt;/code&gt; fetches URLs, not local files.&lt;/p&gt;
&lt;p&gt;Lesson learned. &lt;/p&gt;
&lt;h3 id=&quot;the-big-idea&quot;&gt;The Big Idea&lt;/h3&gt;
&lt;p&gt;Many beginners confuse PVs and PVCs.&lt;/p&gt;
&lt;p&gt;Remember this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PersistentVolume (PV)&lt;/strong&gt; = The actual storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PersistentVolumeClaim (PVC)&lt;/strong&gt; = The request for storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pod&lt;/strong&gt; = The application that uses the claim.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A simple analogy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🍕 PV = The pizza.&lt;/li&gt;
&lt;li&gt;🧾 PVC = The order receipt.&lt;/li&gt;
&lt;li&gt;😋 Pod = The hungry person.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You don't grab the pizza straight from the oven—you present your receipt first!&lt;/p&gt;
&lt;h3 id=&quot;commands-i-used&quot;&gt;Commands I Used&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f pv.yaml
kubectl get pv

kubectl apply -f pvc.yaml
kubectl get pvc
kubectl describe pvc pvc-demo

kubectl apply -f pod.yaml
kubectl get pods

kubectl exec -it app -- bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-i-learned&quot;&gt;What I Learned&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Persistent storage survives Pod restarts.&lt;/li&gt;
&lt;li&gt;Pods use PVCs, not PVs, directly.&lt;/li&gt;
&lt;li&gt;A PVC must successfully bind before a Pod can use it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl describe&lt;/code&gt; is one of the best debugging tools when something is stuck.&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22836/understanding-persistentvolumes-pv-and-persistentvolumeclaims-pvc</guid>
<pubDate>Thu, 16 Jul 2026 16:23:41 +0000</pubDate>
</item>
<item>
<title>If you're just getting started, think of AWS, GCP, and Azure as cloud platforms</title>
<link>https://coderlegion.com/22293/if-youre-just-getting-started-think-of-aws-gcp-and-azure-as-cloud-platforms</link>
<description>&lt;p&gt;&lt;strong&gt;What is Cloud Computing?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Traditionally, if you wanted to run an application, you had to buy:&lt;/p&gt;
&lt;p&gt;Physical servers&lt;br&gt;
Storage devices&lt;br&gt;
Networking equipment&lt;br&gt;
Cooling systems&lt;br&gt;
Backup power&lt;br&gt;
Security infrastructure&lt;/p&gt;
&lt;p&gt;Cloud providers own this infrastructure and let you use it on demand.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Three &lt;/strong&gt;Major Cloud Providers&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    **1. Amazon Web Services (AWS)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Released: 2006&lt;/p&gt;
&lt;p&gt;Company: Amazon Web Services&lt;/p&gt;
&lt;p&gt;AWS is the world's largest cloud platform.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   ****Common Services
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;EC2 (Virtual Servers)&lt;/li&gt;
&lt;li&gt;S3 (Object Storage)&lt;/li&gt;
&lt;li&gt;RDS (Managed Databases)&lt;/li&gt;
&lt;li&gt;Lambda (Serverless Functions)&lt;/li&gt;
&lt;li&gt;IAM (Identity &amp;amp; Access Management)&lt;/li&gt;
&lt;li&gt;CloudWatch (Monitoring)&lt;/li&gt;
&lt;li&gt;SageMaker (Machine Learning)&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bedrock (Generative AI)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                   **Used by
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Netflix&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Airbnb&lt;/li&gt;
&lt;li&gt;NASA&lt;/li&gt;
&lt;li&gt;Samsung&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BMW&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                 **Strengths
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Largest service ecosystem&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Very mature platform&lt;/li&gt;
&lt;li&gt;Excellent scalability&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strong AI and ML offerings&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;         **2. Google Cloud Platform (GCP)**
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Released: 2008&lt;br&gt;
Company: Google Cloud&lt;br&gt;
Google Cloud is known for AI, machine learning, big data, and Kubernetes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                 **Common Services
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Compute Engine&lt;/li&gt;
&lt;li&gt;Cloud Storage&lt;/li&gt;
&lt;li&gt;Cloud SQL&lt;/li&gt;
&lt;li&gt;BigQuery&lt;/li&gt;
&lt;li&gt;Cloud Run&lt;/li&gt;
&lt;li&gt;Vertex AI&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kubernetes Engine (GKE)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                **Used by
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Spotify&lt;/li&gt;
&lt;li&gt;PayPal&lt;/li&gt;
&lt;li&gt;Snapchat&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Twitter/X&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;              **Strengths
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Excellent AI ecosystem&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Big data analytics&lt;/li&gt;
&lt;li&gt;&lt;p&gt;High-performance networking&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        **3. Microsoft Azure
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Released: 2010&lt;br&gt;
Company: Microsoft Azure&lt;br&gt;
Azure is widely adopted by enterprises and organizations already using Microsoft technologies.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             **Common Services
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Virtual Machines&lt;/li&gt;
&lt;li&gt;Blob Storage&lt;/li&gt;
&lt;li&gt;Azure SQL Database&lt;/li&gt;
&lt;li&gt;Azure Kubernetes Service (AKS)&lt;/li&gt;
&lt;li&gt;Azure OpenAI Service&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Azure AI Search&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             **Used by
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Walmart&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Adobe&lt;/li&gt;
&lt;li&gt;LinkedIn&lt;/li&gt;
&lt;li&gt;Many government organizations&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Large enterprise businesses&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;            **Strengths
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enterprise integration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Strong business adoption&lt;/li&gt;
&lt;/ol&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22293/if-youre-just-getting-started-think-of-aws-gcp-and-azure-as-cloud-platforms</guid>
<pubDate>Sat, 11 Jul 2026 11:52:48 +0000</pubDate>
</item>
<item>
<title>Optimizing CPU Bounds: Maximizing Python Throughput in 2026</title>
<link>https://coderlegion.com/22228/optimizing-cpu-bounds-maximizing-python-throughput-in-2026</link>
<description>&lt;p&gt;When application scalability depends entirely on processing efficiency, software teams must look beyond standard code structures. We analyze how modern Python minimizes time-to-market and processing latency under intensive production workloads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The High-Throughput Implementation Plan:&lt;/strong&gt;&lt;br&gt;
The blueprint relies on keeping infrastructure slim while taking total advantage of modern multi-core processors.&lt;/p&gt;
&lt;p&gt;Configure container instances with free-threaded execution modules to unlock absolute physical CPU capabilities.&lt;br&gt;
Integrate lightning-fast system package managers to reduce continuous deployment image build times significantly.&lt;br&gt;
Structure background workers to leverage shared memory pools to entirely prevent cross-process messaging overhead.&lt;/p&gt;
&lt;p&gt;The Failure Points of Scale:&lt;br&gt;
Without careful optimization, intense thread utilization and data volumes can degrade platform stability.&lt;br&gt;
Race conditions multiply across unshielded variables when utilizing true multi-threaded thread parallelism.&lt;br&gt;
Heavy initial compilation times degrade user experience if code paths aren't warmed up effectively before launch. Stale information structures plague execution pipelines if caching layers lack automated invalidation flags.  &lt;/p&gt;
&lt;p&gt;The Architectural Remedies We guarantee stability by decoupling operational paths and establishing clear performance guardrails. &lt;br&gt;
Inject atomic variable locks around critical memory vectors to ensure complete safety across concurrent threads.Utilize adaptive specialized bytecode compilation to optimize active paths dynamically based on data types.&lt;br&gt;
Offload heavy mathematical workloads to specialized underlying arrays written in highly optimized native languages. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visit our official site: www.nextbigcreative.com&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22228/optimizing-cpu-bounds-maximizing-python-throughput-in-2026</guid>
<pubDate>Fri, 10 Jul 2026 15:37:48 +0000</pubDate>
</item>
<item>
<title>Kubernetes Network Policies Explained (and How I Actually Made Them Work)</title>
<link>https://coderlegion.com/22177/kubernetes-network-policies-explained-and-how-i-actually-made-them-work</link>
<description>&lt;p&gt;If you've ever wondered, &quot;How do I stop my pods from randomly talking to everything in my cluster?&quot; – this is the post for you.&lt;/p&gt;
&lt;p&gt;Today, I dove into &lt;strong&gt;Kubernetes Network Policies&lt;/strong&gt; – the way you control who can talk to whom inside your cluster. I started with &lt;code&gt;weavenet&lt;/code&gt;, then switched to &lt;strong&gt;Calico&lt;/strong&gt;, and I'm excited to walk you through how it all came together.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-even-is-a-network-policy-&quot;&gt;What Even Is a Network Policy?&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;NetworkPolicy&lt;/strong&gt; in Kubernetes is like a firewall rule for your pods. It lets you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Control &lt;strong&gt;inbound traffic&lt;/strong&gt; (who can talk to a pod)&lt;/li&gt;
&lt;li&gt;Control &lt;strong&gt;outbound traffic&lt;/strong&gt; (where a pod can talk to)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can create a &lt;strong&gt;deny-all&lt;/strong&gt; policy that blocks all incoming traffic to a pod.&lt;/li&gt;
&lt;li&gt;Or an &lt;strong&gt;allow-only&lt;/strong&gt; policy that says: &quot;Only the &lt;code&gt;backend&lt;/code&gt; pods can talk to the &lt;code&gt;mysql&lt;/code&gt; pod on port 3306.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without network policies, by default, &lt;strong&gt;everything can talk to everything&lt;/strong&gt; in your cluster. That's fine for demos, terrible for real security.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-i-needed-a-different-cni&quot;&gt;Why I Needed a Different CNI&lt;/h3&gt;
&lt;p&gt;Kubernetes itself doesn't implement network policies. It just defines them. The actual work is done by your &lt;strong&gt;CNI plugin&lt;/strong&gt; (Container Network Interface).&lt;/p&gt;
&lt;p&gt;I started with &lt;strong&gt;weavenet&lt;/strong&gt;, which supports basic network policies. But as I dug deeper, I realized I wanted something more powerful and production-friendly. That's when I switched to &lt;strong&gt;Calico&lt;/strong&gt;, which is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;li&gt;Scalable&lt;/li&gt;
&lt;li&gt;Great for complex network policies&lt;/li&gt;
&lt;li&gt;Works well with &lt;code&gt;kind&lt;/code&gt; clusters (as long as you configure it correctly)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're just experimenting, weavenet is fine. If you want to level up your cluster networking, Calico is a great next step.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;my-test-cluster-a-kind-setup-with-calico&quot;&gt;My Test Cluster: A Kind Setup with Calico&lt;/h3&gt;
&lt;p&gt;To test network policies, I created a simple &lt;code&gt;kind&lt;/code&gt; cluster with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 control-plane node&lt;/li&gt;
&lt;li&gt;2 worker nodes&lt;/li&gt;
&lt;li&gt;Disabled default CNI (&lt;code&gt;disableDefaultCNI: true&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Custom pod subnet: &lt;code&gt;192.168.0.0/16&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;kind-cluster-yaml&quot;&gt;kind Cluster YAML&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    extraPortMappings:
      - containerPort: 30001
        hostPort: 30001
  - role: worker
  - role: worker
networking:
  disableDefaultCNI: true
  podSubnet: &quot;192.168.0.0/16&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;creating-the-cluster&quot;&gt;Creating the Cluster&lt;/h4&gt;
&lt;p&gt;With the YAML saved as &lt;code&gt;kind-config.yaml&lt;/code&gt;, I created the cluster like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kind create cluster --name day26 --config kind-config.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I checked the nodes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's the part that was a bit confusing at first:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Until I installed a CNI (like Calico), the worker nodes stayed in a &lt;code&gt;NotReady&lt;/code&gt; state.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's because Kubernetes needs a CNI to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assign IPs to pods&lt;/li&gt;
&lt;li&gt;Set up networking between nodes&lt;/li&gt;
&lt;li&gt;Enable traffic to flow across the cluster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without a CNI, the control-plane node can be &lt;code&gt;Ready&lt;/code&gt;, but the worker nodes will remain &lt;code&gt;NotReady&lt;/code&gt; until networking is configured.&lt;/p&gt;
&lt;p&gt;Only after installing Calico did all nodes show as &lt;code&gt;Ready&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get nodes
# NAME           STATUS   ROLES           AGE   VERSION
# day26-control-plane   Ready    control-plane   ...
# day26-worker          Ready    worker          ...
# day26-worker2         Ready    worker          ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once Calico was running, my cluster was ready for real network policy experiments.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-app-i-built-frontend-backend-mysql&quot;&gt;The App I Built: Frontend → Backend → MySQL&lt;/h3&gt;
&lt;p&gt;To make network policies meaningful, I created a tiny 3-tier app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;frontend&lt;/code&gt; pod + service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backend&lt;/code&gt; pod + service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysql&lt;/code&gt; pod + service (&lt;code&gt;db&lt;/code&gt; service)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;pods-amp-services&quot;&gt;Pods &amp;amp; Services&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  name: frontend
  labels:
    role: frontend
spec:
  containers:
    - name: nginx
      image: nginx
      ports:
        - name: http
          containerPort: 80
          protocol: TCP
***
apiVersion: v1
kind: Service
metadata:
  name: frontend
  labels:
    role: frontend
spec:
  selector:
    role: frontend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
***
apiVersion: v1
kind: Pod
metadata:
  name: backend
  labels:
    role: backend
spec:
  containers:
    - name: nginx
      image: nginx
      ports:
        - name: http
          containerPort: 80
          protocol: TCP
***
apiVersion: v1
kind: Service
metadata:
  name: backend
  labels:
    role: backend
spec:
  selector:
    role: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
***
apiVersion: v1
kind: Service
metadata:
  name: db
  labels:
    name: mysql
spec:
  selector:
    name: mysql
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
***
apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    name: mysql
spec:
  containers:
    - name: mysql
      image: mysql:latest
      env:
        - name: &quot;MYSQL_USER&quot;
          value: &quot;mysql&quot;
        - name: &quot;MYSQL_PASSWORD&quot;
          value: &quot;mysql&quot;
        - name: &quot;MYSQL_DATABASE&quot;
          value: &quot;testdb&quot;
        - name: &quot;MYSQL_ROOT_PASSWORD&quot;
          value: &quot;verysecure&quot;
      ports:
        - name: http
          containerPort: 3306
          protocol: TCP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, &lt;strong&gt;everything could talk to everything&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;frontend&lt;/code&gt; could reach &lt;code&gt;backend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backend&lt;/code&gt; could reach &lt;code&gt;mysql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;frontend&lt;/code&gt; could also reach &lt;code&gt;mysql&lt;/code&gt; directly (which we probably don't want)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now it was time to lock it down.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;my-first-real-network-policy-only-backend-mysql&quot;&gt;My First Real Network Policy: Only Backend → MySQL&lt;/h3&gt;
&lt;p&gt;The goal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mysql&lt;/code&gt; should &lt;strong&gt;only&lt;/strong&gt; accept traffic from pods with label &lt;code&gt;role: backend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On port &lt;strong&gt;3306&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;No one else (including &lt;code&gt;frontend&lt;/code&gt;) should touch the database&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;networkpolicy-manifest&quot;&gt;NetworkPolicy Manifest&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-test
spec:
  podSelector:
    matchLabels:
      name: mysql
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: backend
      ports:
        - port: 3306
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Key parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;podSelector&lt;/code&gt;: targets the &lt;code&gt;mysql&lt;/code&gt; pod (&lt;code&gt;name: mysql&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;policyTypes: [Ingress]&lt;/code&gt;: we're controlling inbound traffic&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ingress.from.podSelector&lt;/code&gt;: only pods with &lt;code&gt;role: backend&lt;/code&gt; are allowed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ports&lt;/code&gt;: only port 3306&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After applying this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;backend&lt;/code&gt; → &lt;code&gt;mysql&lt;/code&gt;  works&lt;/li&gt;
&lt;li&gt;&lt;code&gt;frontend&lt;/code&gt; → &lt;code&gt;mysql&lt;/code&gt;  blocked&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysql&lt;/code&gt; → anywhere (outbound) still allowed (we didn't restrict Egress)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;how-i-tested-it&quot;&gt;How I Tested It&lt;/h3&gt;
&lt;p&gt;I used a simple approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run a temporary pod with &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;mysql&lt;/code&gt; client.&lt;/li&gt;
&lt;li&gt;Try to reach services from different pods.&lt;/li&gt;
&lt;li&gt;Observe which connections succeed or fail.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# From frontend pod – should fail
kubectl exec -it frontend -- curl -s http://db:3306

# From backend pod – should succeed
kubectl exec -it backend -- curl -s http://db:3306
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Seeing the first one fail and the second one succeed was the &quot;aha!&quot; moment: &lt;strong&gt;the policy is actually working&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;Network Policies are one of those things that feel abstract until you actually apply them and see connections blocked in real time. Once that happens, you suddenly understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why security matters&lt;/li&gt;
&lt;li&gt;Why &quot;everything can talk to everything&quot; is not a strategy&lt;/li&gt;
&lt;li&gt;How Kubernetes gives you granular control over your cluster's traffic&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22177/kubernetes-network-policies-explained-and-how-i-actually-made-them-work</guid>
<pubDate>Thu, 09 Jul 2026 16:50:22 +0000</pubDate>
</item>
<item>
<title>Learning Cloud My Own Way</title>
<link>https://coderlegion.com/21914/learning-cloud-my-own-way</link>
<description>&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; Some of the links in this article are affiliate links. This means I may earn a small commission if you click on them. I only recommend tools that I have used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Learning cloud and DevOps takes patience, discipline, and consistency. There are days when everything clicks, and there are days when nothing seems to make sense. That is completely normal.&lt;/p&gt;
&lt;p&gt;One thing I have discovered is that everyone learns differently.&lt;/p&gt;
&lt;p&gt;Some people love following a detailed roadmap from beginning to end. Others prefer structured courses with a fixed schedule. For me, learning is more spontaneous. I follow my curiosity. When I find a topic interesting, I dive deep into it. No amount of advice or motivation can make me learn something if I genuinely have no interest in it.&lt;/p&gt;
&lt;p&gt;Recently, I have been learning Kubernetes, and it has been one of the most interesting technologies I have studied so far. Instead of only reading documentation or watching tutorials, I decided to explain what I was learning by creating videos.&lt;/p&gt;
&lt;h4 id=&quot;here-are-two-videos-i-created-while-learning-kubernetes-&quot;&gt;Here are two videos I created while learning Kubernetes:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=NCcXfrbzKz0&quot;&gt;Kubernetes Component Explained Simply&lt;/a&gt;: &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://youtu.be/21v-aDkHNOI&quot;&gt;What a Busy Restaurant Can Teach You About Kubernetes Services&lt;/a&gt;: &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;tools-that-have-helped-me-learn&quot;&gt;Tools That Have Helped Me Learn&lt;/h4&gt;
&lt;p&gt;Along the way, I have used a few tools that have made learning easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DigitalOcean&lt;/strong&gt; has been a great platform for experimenting with cloud services. If you are a startup or someone learning cloud on a budget, it is worth checking out because getting basic services running is straightforward.&lt;/p&gt;
&lt;p&gt;I have also used &lt;strong&gt;Gamma&lt;/strong&gt; to create presentations and portfolio content, and &lt;strong&gt;Lovable&lt;/strong&gt; to build portfolio projects more quickly.&lt;/p&gt;
&lt;p&gt;If you would like to explore these tools, here are the links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.awin1.com/cread.php?awinmid=123996&amp;amp;awinaffid=2852319&quot;&gt;DigitalOcean&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://ishosting.com/affiliate/NzY3NCM2&quot;&gt;IS*Hosting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://truehost.com.ng/cloud/aff.php?aff=3509&quot;&gt;Truehost (Domains)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;do-you-really-need-aws-to-learn-cloud-&quot;&gt;Do You Really Need AWS to Learn Cloud?&lt;/h4&gt;
&lt;p&gt;One question I see often is whether you need AWS before you can start learning cloud.&lt;/p&gt;
&lt;p&gt;My answer might surprise you.&lt;/p&gt;
&lt;p&gt;Other cloud providers are friendly and can help you build practical skills before moving into AWS, like DigitalOcean.&lt;/p&gt;
&lt;p&gt;There is no single right way to learn cloud computing.&lt;/p&gt;
&lt;p&gt;Find a learning style that works for you.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/rmemlmtrd2h8qf5wmk8q.png&quot; alt=&quot;cloud learning&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you enjoy reflections like this, you can subscribe to the &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7336744982432600064&quot;&gt;newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can follow my work and projects on &lt;a rel=&quot;nofollow&quot; href=&quot;https://x.com/ijaydimples&quot;&gt;Twitter&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/ijeoma-igboagu/&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/ijayhub&quot;&gt;GitHub&lt;/a&gt;, and &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/@cloudinreallife&quot;&gt;YouTube&lt;/a&gt;, where I share what I am building and learning along the way.&lt;/p&gt;
&lt;p&gt;Thank you for reading.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21914/learning-cloud-my-own-way</guid>
<pubDate>Wed, 08 Jul 2026 10:00:00 +0000</pubDate>
</item>
<item>
<title>Understanding Kubernetes Service Accounts (The Identity Every Pod Uses)</title>
<link>https://coderlegion.com/22055/understanding-kubernetes-service-accounts-the-identity-every-pod-uses</link>
<description>&lt;p&gt;Most of us learn about Kubernetes users before we learn about Service Accounts. That's actually where the confusion starts Service Accounts end up looking like &quot;just another kind of user,&quot; and you file them away without really getting what makes them different.&lt;/p&gt;
&lt;p&gt;They're not just another user. They solve a completely different problem.&lt;/p&gt;
&lt;p&gt;Today I learned that human users authenticate &lt;em&gt;from outside&lt;/em&gt; the cluster — you, sitting at your laptop, running &lt;code&gt;kubectl&lt;/code&gt; with your certificate or your login. But Pods run &lt;em&gt;inside&lt;/em&gt; the cluster, and they often need to talk to the Kubernetes API too — to list other pods, read a ConfigMap, watch for changes, whatever. A Pod can't exactly type in a username and password. It needs its own identity.&lt;/p&gt;
&lt;p&gt;That identity is called a &lt;strong&gt;Service Account&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;user-vs-service-account&quot;&gt;User vs. Service Account&lt;/h3&gt;
&lt;p&gt;Before touching a single command, it's worth seeing the two side by side:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;User &lt;/th&gt;&lt;th&gt;Service Account&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Used by humans &lt;/td&gt;&lt;td&gt;Used by Pods&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;External to Kubernetes &lt;/td&gt;&lt;td&gt;Managed by Kubernetes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Usually authenticated using certificates &lt;/td&gt;&lt;td&gt;Authenticated using tokens&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;You create it outside the cluster &lt;/td&gt;&lt;td&gt;Kubernetes creates and manages it&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Keep that table in your head — everything below is really just this table playing out in the terminal.&lt;/p&gt;
&lt;h3 id=&quot;step-1-checking-existing-service-accounts&quot;&gt;Step 1 — Checking Existing Service Accounts&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k get sa
NAME      AGE
default   38d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice I didn't create this. It was already there, 38 days old — as old as the namespace itself.&lt;/p&gt;
&lt;p&gt;That's the first thing to internalize: &lt;strong&gt;every namespace automatically gets a Service Account called &lt;code&gt;default&lt;/code&gt;.&lt;/strong&gt; You don't ask for it. If you create a Pod and never say which Service Account it should use, Kubernetes quietly attaches this one for you. Keep that in mind — it comes back to bite (in a good way) later in this post.&lt;/p&gt;
&lt;h3 id=&quot;step-2-creating-my-own-service-account&quot;&gt;Step 2 — Creating My Own Service Account&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k create sa build-sa
serviceaccount/build-sa created

❯ k describe sa build-sa
Name:                build-sa
Namespace:           default
Labels:              &amp;lt;none&amp;gt;
Annotations:         &amp;lt;none&amp;gt;
Image pull secrets:  &amp;lt;none&amp;gt;
Events:              &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple enough — I now have a second identity, &lt;code&gt;build-sa&lt;/code&gt;, sitting in the &lt;code&gt;default&lt;/code&gt; namespace, ready to be attached to Pods later.&lt;/p&gt;
&lt;p&gt;But here's the question that trips a lot of beginners up: &lt;strong&gt;why doesn't it have a token?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you learned Kubernetes a few years ago, or you're reading an older tutorial, you'll expect &lt;code&gt;describe sa&lt;/code&gt; to show a &lt;code&gt;Tokens:&lt;/code&gt; field pointing at an auto-generated Secret. Not anymore. Newer versions of Kubernetes stopped automatically minting long-lived Secret-based tokens for every Service Account, mainly for security reasons — a token that never expires and just sits around as a Secret is a standing risk if it leaks. Instead, Kubernetes now prefers short-lived, automatically-rotated tokens issued on demand.&lt;/p&gt;
&lt;p&gt;Since I specifically wanted a durable token I could inspect and use for &lt;code&gt;--as&lt;/code&gt; testing, I had to create it myself.&lt;/p&gt;
&lt;h3 id=&quot;step-3-creating-a-serviceaccount-token-secret&quot;&gt;Step 3 — Creating a ServiceAccount Token Secret&lt;/h3&gt;
&lt;p&gt;I wrote a &lt;code&gt;secret.yaml&lt;/code&gt; that, at minimum, needs this annotation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;metadata:
  annotations:
    kubernetes.io/service-account.name: build-sa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This one line is doing all the work. It tells the Kubernetes controller: &lt;em&gt;&quot;This Secret isn't just a random Opaque blob — it's a token for the &lt;code&gt;build-sa&lt;/code&gt; Service Account.&quot;&lt;/em&gt; Because of that annotation, a built-in controller notices the Secret, generates a signed token for &lt;code&gt;build-sa&lt;/code&gt;, and populates the Secret with it automatically.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k apply -f secret.yaml
secret/build-robot-secret created

❯ k get secret
NAME                 TYPE                                  DATA   AGE
backend-user         Opaque                                1      5d3h
build-robot-secret   kubernetes.io/service-account-token   3      14s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the &lt;code&gt;TYPE&lt;/code&gt; column — &lt;code&gt;kubernetes.io/service-account-token&lt;/code&gt;, not &lt;code&gt;Opaque&lt;/code&gt;. That type is exactly what tells Kubernetes &quot;treat this Secret specially and fill it with SA credentials.&quot;&lt;/p&gt;
&lt;h4 id=&quot;inspecting-the-secret&quot;&gt;Inspecting the Secret&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;❯ k describe secret build-robot-secret
Name:         build-robot-secret
Namespace:    default
Labels:       &amp;lt;none&amp;gt;
Annotations:  kubernetes.io/service-account.name: build-sa
              kubernetes.io/service-account.uid: d065d358-58fa-44a6-9656-8263e0fa05eb

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1107 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIs... (truncated)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three fields, each with a job:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ca.crt&lt;/code&gt;&lt;/strong&gt; — the cluster's certificate authority. Whoever holds this Secret can verify they're really talking to the real API server, not an impersonator.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;namespace&lt;/code&gt;&lt;/strong&gt; — just the namespace this identity belongs to (&lt;code&gt;default&lt;/code&gt;), so any client using this Secret knows where it &quot;lives.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;token&lt;/code&gt;&lt;/strong&gt; — the important one. This is a &lt;strong&gt;JWT (JSON Web Token)&lt;/strong&gt;, signed by the cluster. This is what a Pod, script, or client hands to the API server to say &quot;I am &lt;code&gt;build-sa&lt;/code&gt;, and here's proof.&quot; I've truncated the token above — treat these things like passwords, not like log output, even in a lab cluster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you decode a Service Account JWT (there's nothing secret about the &lt;em&gt;structure&lt;/em&gt;, just don't paste your actual token online), you'll find claims like the issuer, the namespace, and a &lt;code&gt;sub&lt;/code&gt; field that looks like &lt;code&gt;system:serviceaccount:default:build-sa&lt;/code&gt;. That string is the Service Account's real, canonical identity inside Kubernetes — remember it, it matters in a minute.&lt;/p&gt;
&lt;h3 id=&quot;testing-permissions&quot;&gt;Testing Permissions&lt;/h3&gt;
&lt;p&gt;Now the interesting part. I wanted to see what &lt;code&gt;build-sa&lt;/code&gt; could actually do, without creating a Pod yet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k get pods --as build-sa
Error from server (Forbidden): pods is forbidden: User &quot;build-sa&quot; cannot list resource &quot;pods&quot; in API group &quot;&quot; in the namespace &quot;default&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things to unpack here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First — what does &lt;code&gt;--as&lt;/code&gt; actually do?&lt;/strong&gt; It's easy to assume you're &quot;logging in&quot; as &lt;code&gt;build-sa&lt;/code&gt;. You're not. &lt;code&gt;--as&lt;/code&gt; is &lt;strong&gt;impersonation&lt;/strong&gt;. You're still using &lt;em&gt;your own&lt;/em&gt; admin credentials to talk to the API server, but you're telling it: &quot;Evaluate this request as if it came from &lt;code&gt;build-sa&lt;/code&gt; instead of me.&quot; The API server checks whether &lt;em&gt;your&lt;/em&gt; account is allowed to impersonate &lt;code&gt;build-sa&lt;/code&gt; (admin usually is), and if so, it re-runs the authorization check as that identity. It's a testing and debugging superpower — you get to try on someone else's permissions without actually needing their credentials.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second — why Forbidden?&lt;/strong&gt; This is the single most important lesson in this whole exercise: &lt;strong&gt;the Service Account existed. The token existed. Authentication succeeded. Authorization failed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Those are two separate gates in Kubernetes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt; — &quot;Who are you?&quot; &lt;code&gt;build-sa&lt;/code&gt; proved this fine, via impersonation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorization&lt;/strong&gt; — &quot;What are you allowed to do?&quot; Nothing had granted &lt;code&gt;build-sa&lt;/code&gt; any permissions at all, so RBAC said no.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A lot of beginners collapse these into one concept. They're not the same thing, and separating them in your head will save you hours of confused debugging later.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-role&quot;&gt;Creating the Role&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k create role build-role \
--verb=list,get,watch \
--resource=pod
role.rbac.authorization.k8s.io/build-role created
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Breaking down the flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;role build-role&lt;/code&gt; — I'm creating a &lt;strong&gt;Role&lt;/strong&gt;, which is a namespaced set of permissions (as opposed to a &lt;strong&gt;ClusterRole&lt;/strong&gt;, which applies cluster-wide).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--verb=list,get,watch&lt;/code&gt; — the specific actions this Role allows. Not &lt;code&gt;create&lt;/code&gt;, not &lt;code&gt;delete&lt;/code&gt; — just read-style operations.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--resource=pod&lt;/code&gt; — the Kubernetes resource type these verbs apply to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On its own, a Role does nothing. It's a permission &lt;em&gt;template&lt;/em&gt; sitting unused until something binds an identity to it.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-rolebinding&quot;&gt;Creating the RoleBinding&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k create rolebinding rb \
--role=build-role \
--user=build-sa
rolebinding.rbac.authorization.k8s.io/rb created
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the glue: it binds the &lt;code&gt;build-role&lt;/code&gt; permissions to the identity &lt;code&gt;build-sa&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One honest caveat worth flagging, since I want this post to be technically accurate and not just &quot;it worked so it's fine&quot;: I used &lt;code&gt;--user=build-sa&lt;/code&gt; here, and it worked in this exercise because I was testing purely through impersonation with &lt;code&gt;--as build-sa&lt;/code&gt;, and &lt;code&gt;--as&lt;/code&gt; treats whatever string you give it as a plain username.&lt;/p&gt;
&lt;p&gt;But that's not actually how a real Service Account identifies itself to the cluster. Its canonical identity is &lt;code&gt;system:serviceaccount:&amp;lt;namespace&amp;gt;:&amp;lt;name&amp;gt;&lt;/code&gt; — in my case, &lt;code&gt;system:serviceaccount:default:build-sa&lt;/code&gt;. In production, the standard, correct way to bind a RoleBinding to a Service Account is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--serviceaccount=default:build-sa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I'd actually mounted this token inside a real client and tried to use it (rather than testing through admin impersonation), a binding made with &lt;code&gt;--user=build-sa&lt;/code&gt; would &lt;strong&gt;not&lt;/strong&gt; match that Service Account's real identity, and the request would still be Forbidden. So: my command worked for this specific impersonation test, but if you're setting this up for a real workload, use &lt;code&gt;--serviceaccount=&amp;lt;namespace&amp;gt;:&amp;lt;name&amp;gt;&lt;/code&gt; instead. Good to know the difference exists before it costs you a debugging session.&lt;/p&gt;
&lt;h3 id=&quot;testing-again&quot;&gt;Testing Again&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k get pods --as build-sa
No resources found in default namespace.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No error this time — just an empty result, because there genuinely were no pods yet. Authentication &lt;em&gt;and&lt;/em&gt; authorization both passed. That's the fix landing.&lt;/p&gt;
&lt;h3 id=&quot;creating-a-deployment&quot;&gt;Creating a Deployment&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k create deploy test --image=nginx
deployment.apps/test created
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Worth pointing out deliberately: I created this Deployment as &lt;em&gt;myself&lt;/em&gt; (admin), not as &lt;code&gt;build-sa&lt;/code&gt;. &lt;code&gt;build-sa&lt;/code&gt; only has &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, and &lt;code&gt;watch&lt;/code&gt; on pods — nowhere near enough permission to create a Deployment. If I'd tried &lt;code&gt;k create deploy test --image=nginx --as build-sa&lt;/code&gt;, it would have been Forbidden too.&lt;/p&gt;
&lt;h3 id=&quot;watching-the-pod&quot;&gt;Watching the Pod&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;❯ k get po -w --as build-sa
NAME                    READY   STATUS    RESTARTS   AGE
test-56848fd9dc-fhdjv   1/1     Running   0          89s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-w&lt;/code&gt; flag means &lt;strong&gt;watch&lt;/strong&gt; — instead of printing the pod state once and exiting, &lt;code&gt;kubectl&lt;/code&gt; keeps the connection open and streams updates as the pod's status changes. Combined with &lt;code&gt;--as build-sa&lt;/code&gt;, this also confirms &lt;code&gt;build-sa&lt;/code&gt;'s &lt;code&gt;watch&lt;/code&gt; verb from the Role is working, not just &lt;code&gt;list&lt;/code&gt; and &lt;code&gt;get&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;going-inside-the-pod&quot;&gt;Going Inside the Pod&lt;/h3&gt;
&lt;p&gt;This is where it got genuinely interesting.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k exec -it test-56848fd9dc-fhdjv bash
error: exec [POD] [COMMAND] is not supported anymore. Use exec [POD] -- [COMMAND] instead
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hit this error a few times before it clicked. Older &lt;code&gt;kubectl&lt;/code&gt; versions let you run &lt;code&gt;kubectl exec pod bash&lt;/code&gt; and it would figure out where your flags ended and the container's command began. Modern &lt;code&gt;kubectl&lt;/code&gt; refuses to guess — it wants an explicit &lt;code&gt;--&lt;/code&gt; to separate &quot;arguments meant for kubectl&quot; from &quot;the command to run inside the container.&quot; So:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ k exec -it test-56848fd9dc-fhdjv -- bash
root@test-56848fd9dc-fhdjv:/#
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That extra &lt;code&gt;--&lt;/code&gt; is the whole fix. Everything after it belongs to the container, not to &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-most-interesting-discovery&quot;&gt;The Most Interesting Discovery&lt;/h3&gt;
&lt;p&gt;Once inside, I went looking for exactly the kind of thing this Pod would need to talk to the API server — and there it was:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@test-56848fd9dc-fhdjv:/var/run/secrets/kubernetes.io/serviceaccount# ls -lrt
total 0
lrwxrwxrwx 1 root root 12 Jul  7 14:38 token -&amp;gt; ..data/token
lrwxrwxrwx 1 root root 16 Jul  7 14:38 namespace -&amp;gt; ..data/namespace
lrwxrwxrwx 1 root root 13 Jul  7 14:38 ca.crt -&amp;gt; ..data/ca.crt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same three files as the Secret I inspected earlier — &lt;code&gt;token&lt;/code&gt;, &lt;code&gt;namespace&lt;/code&gt;, &lt;code&gt;ca.crt&lt;/code&gt; — automatically mounted at &lt;code&gt;/var/run/secrets/kubernetes.io/serviceaccount&lt;/code&gt;, with &lt;strong&gt;no configuration from me at all.&lt;/strong&gt; Kubernetes does this for every Pod by default, via a projected volume, so that any process running inside the container can immediately authenticate to the API server if it needs to (this is how things like controllers and operators, running as Pods themselves, talk back to Kubernetes).&lt;/p&gt;
&lt;p&gt;Now the obvious beginner question, and the one I asked myself immediately: &lt;strong&gt;&quot;Wait — I created &lt;code&gt;build-sa&lt;/code&gt;. Why does the token in here say &lt;code&gt;default&lt;/code&gt;?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure enough, decoding what's inside shows a &lt;code&gt;sub&lt;/code&gt; claim of &lt;code&gt;system:serviceaccount:default:default&lt;/code&gt; — the &lt;code&gt;default&lt;/code&gt; Service Account, not &lt;code&gt;build-sa&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The answer is almost anticlimactic once you see it: my Deployment spec never included &lt;code&gt;serviceAccountName: build-sa&lt;/code&gt;. I never told Kubernetes which Service Account this Pod should use — so it fell back to the one thing every namespace already has, the one from Step 1. &lt;strong&gt;The &lt;code&gt;default&lt;/code&gt; Service Account.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is, genuinely, the most valuable lesson from the whole exercise: creating a Service Account doesn't automatically attach it to anything. You have to explicitly wire it into a Pod (or Deployment, or Job, etc.) with &lt;code&gt;serviceAccountName&lt;/code&gt; — or Kubernetes will silently keep using &lt;code&gt;default&lt;/code&gt; on your behalf, and you won't get an error telling you. You'll just quietly have the wrong permissions, or, worse in production, the &lt;em&gt;default&lt;/em&gt; Service Account might have more access than you meant to grant that workload.&lt;/p&gt;
&lt;h3 id=&quot;key-takeaways-1&quot;&gt;Key Takeaways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Service Accounts are identities for Pods — not humans.&lt;/li&gt;
&lt;li&gt;Every namespace automatically gets a &lt;code&gt;default&lt;/code&gt; Service Account.&lt;/li&gt;
&lt;li&gt;Service Accounts authenticate using tokens (JWTs), not certificates.&lt;/li&gt;
&lt;li&gt;Newer Kubernetes versions don't auto-create long-lived token Secrets anymore — you create them explicitly when you need one.&lt;/li&gt;
&lt;li&gt;RBAC still governs what a Service Account is allowed to do, exactly like it does for users.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--as&lt;/code&gt; impersonates another identity for testing — it doesn't log you in as them.&lt;/li&gt;
&lt;li&gt;Authentication and authorization are two separate checks: proving who you are is not the same as being allowed to do something.&lt;/li&gt;
&lt;li&gt;Bind RoleBindings to Service Accounts with &lt;code&gt;--serviceaccount=&amp;lt;namespace&amp;gt;:&amp;lt;name&amp;gt;&lt;/code&gt; in real setups, not &lt;code&gt;--user=&amp;lt;name&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pods automatically get their Service Account's credentials mounted at &lt;code&gt;/var/run/secrets/kubernetes.io/serviceaccount&lt;/code&gt; — no extra config needed.&lt;/li&gt;
&lt;li&gt;If you don't set &lt;code&gt;serviceAccountName&lt;/code&gt; on a Pod, Kubernetes silently uses &lt;code&gt;default&lt;/code&gt;. Always check.&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22055/understanding-kubernetes-service-accounts-the-identity-every-pod-uses</guid>
<pubDate>Tue, 07 Jul 2026 15:58:52 +0000</pubDate>
</item>
<item>
<title>Understanding Kubernetes ClusterRoles and ClusterRoleBindings</title>
<link>https://coderlegion.com/22053/understanding-kubernetes-clusterroles-and-clusterrolebindings</link>
<description>&lt;p&gt;Yesterday I learned about Roles and RoleBindings. Today I explored ClusterRoles and ClusterRoleBindings for cluster-scoped resources like Nodes.&lt;/p&gt;
&lt;h3 id=&quot;why-a-role-wasn-t-enough&quot;&gt;Why a Role Wasn't Enough&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl auth can-i get nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Warning: resource 'nodes' is not namespace scoped
no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nodes are cluster-scoped resources, so a namespace Role cannot grant access.&lt;/p&gt;
&lt;h3 id=&quot;creating-a-clusterrole&quot;&gt;Creating a ClusterRole&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create clusterrole node-reader --verb=get,list,watch --resource=nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get clusterrole | grep node-reader
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;creating-a-clusterrolebinding&quot;&gt;Creating a ClusterRoleBinding&lt;/h3&gt;
&lt;p&gt;I first made a mistake:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create clusterrolebinding reader-binding --clusterrole=cluster-reader --user=adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Checking permissions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl auth can-i get nodes --as adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;no - RBAC: clusterrole.rbac.authorization.k8s.io &quot;cluster-reader&quot; not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The binding referenced a ClusterRole that didn't exist.&lt;/p&gt;
&lt;p&gt;I fixed it by deleting and recreating the binding:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl delete clusterrolebinding reader-binding
kubectl create clusterrolebinding reader-binding --clusterrole=node-reader --user=adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl auth can-i get nodes --as adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;yes
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;testing-as-adeoye&quot;&gt;Testing as adeoye&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl config use-context adeoye
kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Listing nodes worked.&lt;/p&gt;
&lt;p&gt;Describing a node:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl describe node cka-cluster3-worker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;showed most information, but RBAC blocked access to &lt;strong&gt;leases&lt;/strong&gt; and &lt;strong&gt;pods&lt;/strong&gt; because the ClusterRole only granted access to &lt;strong&gt;nodes&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Trying to delete a node:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl delete node cka-cluster3-worker
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returned &lt;strong&gt;Forbidden&lt;/strong&gt; because the ClusterRole only included &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, and &lt;code&gt;watch&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;key-takeaways-2&quot;&gt;Key Takeaways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Roles are namespace-scoped.&lt;/li&gt;
&lt;li&gt;ClusterRoles are cluster-scoped.&lt;/li&gt;
&lt;li&gt;ClusterRoleBindings grant cluster-wide permissions.&lt;/li&gt;
&lt;li&gt;RBAC permissions are resource-specific.&lt;/li&gt;
&lt;li&gt;Kubernetes follows the principle of least privilege.&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22053/understanding-kubernetes-clusterroles-and-clusterrolebindings</guid>
<pubDate>Tue, 07 Jul 2026 15:03:06 +0000</pubDate>
</item>
<item>
<title>Understanding Kubernetes RBAC: Roles, RoleBindings, and and Client Certificates</title>
<link>https://coderlegion.com/22007/understanding-kubernetes-rbac-roles-rolebindings-and-and-client-certificates</link>
<description>&lt;p&gt;One thing I discovered today is that before Kubernetes can decide &lt;strong&gt;what you're allowed to do&lt;/strong&gt;, it first needs to know &lt;strong&gt;who you are&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That means there are two separate steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt; – Proving your identity using a client certificate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorization&lt;/strong&gt; – Deciding what you're allowed to do using RBAC.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this lab, I created my own Kubernetes user named &lt;strong&gt;adeoye&lt;/strong&gt;, authenticated the user with a certificate, and then used RBAC to control what that user could access.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-1-generate-a-private-key&quot;&gt;Step 1 – Generate a Private Key&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openssl genrsa -out adeoye.key 2048
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This generates a 2048-bit RSA private key.&lt;/p&gt;
&lt;p&gt;Think of this as your digital identity. It should never be shared.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-generate-a-certificate-signing-request-csr-&quot;&gt;Step 2 – Generate a Certificate Signing Request (CSR)&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;openssl req -new -key adeoye.key -out adeoye.csr -subj &quot;/CN=adeoye&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A Certificate Signing Request asks Kubernetes to issue a client certificate.&lt;/p&gt;
&lt;p&gt;The important part is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;/CN=adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Common Name (CN) becomes the Kubernetes username.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-base64-encode-the-csr&quot;&gt;Step 3 – Base64 Encode the CSR&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat adeoye.csr | base64 | tr -d '\n'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kubernetes expects the CSR to be embedded inside a YAML manifest as Base64-encoded text. The &lt;code&gt;tr -d '\n'&lt;/code&gt; removes line breaks so it becomes a single continuous string.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-submit-the-csr&quot;&gt;Step 4 – Submit the CSR&lt;/h3&gt;
&lt;p&gt;After inserting the encoded CSR into &lt;code&gt;csr.yaml&lt;/code&gt;, I submitted it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f csr.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Initially, the request was in the &lt;strong&gt;Pending&lt;/strong&gt; state so I had to approve the request.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-5-approve-the-certificate&quot;&gt;Step 5 – Approve the Certificate&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl certificate approve adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Approving the request tells Kubernetes to trust the user and issue a signed client certificate.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-6-extract-the-signed-certificate&quot;&gt;Step 6 – Extract the Signed Certificate&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get csr adeoye -o jsonpath='{.status.certificate}' | base64 -d &amp;gt; adeoye.crt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;adeoye.key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;adeoye.crt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key proves my identity, while the certificate proves Kubernetes trusts that identity.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-7-configure-kubectl&quot;&gt;Step 7 – Configure kubectl&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl config set-credentials adeoye \
--client-key=adeoye.key \
--client-certificate=adeoye.crt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I created a context.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl config set-context adeoye \
--cluster=kind-cka-cluster3 \
--user=adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;A mistake I made:&lt;/strong&gt; I initially typed &lt;code&gt;lind-cka-cluster3&lt;/code&gt; instead of &lt;code&gt;kind-cka-cluster3&lt;/code&gt;, which caused API errors until I corrected the cluster name.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, I switched to my new user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl config use-context adeoye
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point I was authenticated, but I still didn't have permissions to perform actions.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;rbac-time-&quot;&gt;RBAC Time!&lt;/h3&gt;
&lt;p&gt;Authentication tells Kubernetes &lt;strong&gt;who I am&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;RBAC tells Kubernetes &lt;strong&gt;what I'm allowed to do&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;creating-the-role-1&quot;&gt;Creating the Role&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;role.yaml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader

rules:
- apiGroups: [&quot;&quot;]
  resources: [&quot;pods&quot;]
  verbs:
    - get
    - watch
    - list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This Role only allows reading Pods.&lt;/p&gt;
&lt;p&gt;Apply it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f role.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;creating-the-rolebinding-1&quot;&gt;Creating the RoleBinding&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;binding.yaml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default

subjects:
- kind: User
  name: adeoye
  apiGroup: rbac.authorization.k8s.io

roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This binds the &lt;strong&gt;adeoye&lt;/strong&gt; user to the &lt;strong&gt;pod-reader&lt;/strong&gt; Role.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f binding.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;testing-the-permissions&quot;&gt;Testing the Permissions&lt;/h4&gt;
&lt;p&gt;Verify permission:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl auth can-i get pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;List Pods:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;No resources found in default namespace.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That means the command succeeded, but there were simply no Pods.&lt;/p&gt;
&lt;p&gt;Next, I tried listing Deployments.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error from server (Forbidden): deployments.apps is forbidden
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-could-i-read-pods-but-not-deployments-&quot;&gt;Why Could I Read Pods but Not Deployments?&lt;/h3&gt;
&lt;p&gt;The answer is in the Role.&lt;/p&gt;
&lt;p&gt;It only grants access to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;resources:
- pods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; include Deployments.&lt;/p&gt;
&lt;p&gt;Deployments belong to the &lt;strong&gt;apps&lt;/strong&gt; API group, while Pods belong to the core API group.&lt;/p&gt;
&lt;p&gt;Since my RoleBinding connects &lt;strong&gt;adeoye&lt;/strong&gt; to the &lt;strong&gt;pod-reader&lt;/strong&gt; Role, Kubernetes only allows the permissions defined there.&lt;/p&gt;
&lt;p&gt;No Deployment permissions were granted, so Kubernetes correctly denied access.&lt;/p&gt;
&lt;p&gt;This is the Principle of Least Privilege in action.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-i-learned-1&quot;&gt;What I Learned&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Kubernetes first authenticates users using client certificates.&lt;/li&gt;
&lt;li&gt;The certificate's Common Name becomes the Kubernetes username.&lt;/li&gt;
&lt;li&gt;A Role defines permissions.&lt;/li&gt;
&lt;li&gt;A RoleBinding assigns those permissions to users.&lt;/li&gt;
&lt;li&gt;Authentication and authorization are separate processes.&lt;/li&gt;
&lt;li&gt;RBAC only grants explicitly defined permissions.&lt;/li&gt;
&lt;li&gt;Pods and Deployments are different resources, so access to one doesn't imply access to the other.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h4&gt;
&lt;p&gt;Today's lab tied together authentication and authorization. Creating my own client certificate, configuring a new kubectl context, and then restricting that user with RBAC made the concepts much easier to understand.&lt;/p&gt;
&lt;p&gt;Security in Kubernetes isn't about giving users full access,but about giving them exactly the permissions they need, nothing more.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22007/understanding-kubernetes-rbac-roles-rolebindings-and-and-client-certificates</guid>
<pubDate>Mon, 06 Jul 2026 14:15:05 +0000</pubDate>
</item>
<item>
<title>Have you ever left a tech meetup feeling like everyone else understood the conversation except you?</title>
<link>https://coderlegion.com/21723/have-you-ever-left-tech-meetup-feeling-like-everyone-else-understood-conversation-except</link>
<description>&lt;p&gt;Have you ever left a tech meetup feeling like everyone else understood the conversation except you?&lt;/p&gt;
&lt;p&gt;I've been there.&lt;/p&gt;
&lt;p&gt;I enjoyed the networking, met some amazing people, and even looked forward to the food. But there were times I got home wondering if I'd actually learned anything or just spent my time, energy, and money.&lt;/p&gt;
&lt;p&gt;That experience reminded me how overwhelming Kubernetes can feel when it's explained with too much technical jargon.&lt;/p&gt;
&lt;p&gt;So I created a short video where Ada explains Kubernetes to Tunde during a walk to the bus stop. The goal was simple: make Kubernetes easier to understand without assuming any prior knowledge.&lt;/p&gt;
&lt;p&gt;If you're learning Kubernetes or know someone who's just getting started, I'd love to hear your thoughts.&lt;/p&gt;
&lt;p&gt;🎥 &lt;a rel=&quot;nofollow&quot; href=&quot;https://youtu.be/NCcXfrbzKz0&quot;&gt;https://youtu.be/NCcXfrbzKz0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What's one tech topic you wish had been explained more simply when you were starting out?&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21723/have-you-ever-left-tech-meetup-feeling-like-everyone-else-understood-conversation-except</guid>
<pubDate>Thu, 02 Jul 2026 10:00:00 +0000</pubDate>
</item>
<item>
<title>Kubernetes Autoscaling: HPA vs VPA Explained With Hands-On Practice</title>
<link>https://coderlegion.com/21685/kubernetes-autoscaling-hpa-vs-vpa-explained-with-hands-on-practice</link>
<description>&lt;p&gt;If you've ever wondered how Kubernetes knows when to spin up more pods or give a pod more memory, that's autoscaling — and it's one of those concepts that sounds intimidating until you actually do it yourself. Day 17 of the &lt;strong&gt;#40DaysOfKubernetes&lt;/strong&gt; challenge is where it clicked for me.&lt;/p&gt;
&lt;h3 id=&quot;what-is-autoscaling-in-kubernetes-&quot;&gt;What is Autoscaling in Kubernetes?&lt;/h3&gt;
&lt;p&gt;At its core, autoscaling means Kubernetes adjusts resources automatically based on demand. You don't manually intervene every time traffic spikes. There are two main types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HPA (Horizontal Pod Autoscaler)&lt;/strong&gt; — adds or removes &lt;em&gt;pods&lt;/em&gt; based on CPU/memory usage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPA (Vertical Pod Autoscaler)&lt;/strong&gt; — adjusts the &lt;em&gt;resources&lt;/em&gt; (CPU/memory) of existing pods&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of HPA as hiring more staff when the shop gets busy. VPA is more like giving one staff member more tools to handle the workload alone.&lt;/p&gt;
&lt;h3 id=&quot;what-i-did-setting-up-hpa&quot;&gt;What I Did — Setting Up HPA&lt;/h3&gt;
&lt;p&gt;First I deployed the sample &lt;code&gt;php-apache&lt;/code&gt; app with defined CPU requests and limits:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m

apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/6lq2po2w7eyqa0rbnudv.png&quot; alt=&quot;Applying the yaml file&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/3c2jkflui4osryhdzexl.png&quot; alt=&quot;The pod is up and running&quot;&gt;&lt;/p&gt;
&lt;p&gt;The key part is setting &lt;code&gt;resources.requests.cpu&lt;/code&gt; — HPA needs this to calculate utilization. Without it, the autoscaler has nothing to measure against.&lt;/p&gt;
&lt;p&gt;Then I created the HPA object targeting &lt;strong&gt;50% average CPU utilization&lt;/strong&gt;, with a minimum of 1 pod and maximum of 10. This is the declarative method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this is the imperative method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/ssc3zqmdmziq9do8m8e6.png&quot; alt=&quot;autoscale applied&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/yvs8u3wxankaprcqgdtr.png&quot; alt=&quot;Autoscale complete&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;generating-load-to-watch-it-scale&quot;&gt;Generating Load to Watch It Scale&lt;/h3&gt;
&lt;p&gt;This is the fun part. I ran a load generator in a separate pod — basically a loop hammering the apache service with requests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- \
  /bin/sh -c &quot;while sleep 0.01; do wget -q -O- http://php-apache; done&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then watched the HPA respond in real time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl get hpa php-apache --watch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/k8v89l3t8fryl174now5.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;Watching the replica count climb from 1 to several pods as CPU utilization crossed 50% made the whole concept land in a way that reading documentation never does.&lt;/p&gt;
&lt;h3 id=&quot;hpa-vs-vpa-when-do-you-use-which-&quot;&gt;HPA vs VPA — When Do You Use Which?&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;HPA &lt;/th&gt;&lt;th&gt;VPA&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Scales&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Number of pods &lt;/td&gt;&lt;td&gt;Pod resource limits&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Stateless apps with variable traffic &lt;/td&gt;&lt;td&gt;Apps where sizing is hard to predict upfront&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Works with&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;CPU, memory, custom metrics &lt;/td&gt;&lt;td&gt;CPU and memory&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In practice, most production workloads use HPA. VPA is useful during early deployment when you're still figuring out the right resource requests for an app.&lt;/p&gt;
&lt;h3 id=&quot;key-takeaway&quot;&gt;Key Takeaway&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;Don't skip setting &lt;code&gt;resources.requests&lt;/code&gt; in your deployment spec. HPA is blind without it. That one line is what connects your workload to the autoscaler.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21685/kubernetes-autoscaling-hpa-vs-vpa-explained-with-hands-on-practice</guid>
<pubDate>Wed, 01 Jul 2026 12:25:29 +0000</pubDate>
</item>
<item>
<title>The more I learn about AWS, the more I respect fundamentals.</title>
<link>https://coderlegion.com/19232/the-more-i-learn-about-aws-the-more-i-respect-fundamentals</link>
<description>&lt;p&gt;One thing I have noticed lately while learning cloud is how easy it is to feel behind, especially online.&lt;/p&gt;
&lt;p&gt;You open LinkedIn or YouTube and see people talking about Kubernetes, advanced architectures, multi-cloud setups, and dozens of AWS services, as if everybody already understands everything.&lt;/p&gt;
&lt;p&gt;Meanwhile, some people are still trying to fully understand what a VPC even does.&lt;/p&gt;
&lt;p&gt;Many people quietly feel pressured to skip fundamentals because everyone else seems “ahead.” &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/raac8spsctzhq7ed2jqx.gif&quot; alt=&quot;thinking other are ahead&quot;&gt;&lt;/p&gt;
&lt;p&gt;I used to feel that way too.&lt;/p&gt;
&lt;p&gt;At first, I thought learning AWS was mostly about memorising services and launching servers.&lt;/p&gt;
&lt;p&gt;But once I started learning AWS more deeply, I realized the cloud is much bigger than that.&lt;/p&gt;
&lt;p&gt;Things like VPCs, subnets, routing tables, NAT gateways, and security groups felt overwhelming at first.&lt;br&gt;
Not because they were impossible to learn, but because many explanations made them sound overly technical.&lt;/p&gt;
&lt;p&gt;At some point, I decided to create a video explaining VPCs to myself using a &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/shorts/bT97-fRCFMM&quot;&gt;simple neighborhood analogy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And that changed a lot for me.&lt;/p&gt;
&lt;p&gt;For the first time, things genuinely started making sense.&lt;/p&gt;
&lt;p&gt;The VPC became the neighborhood itself.&lt;/p&gt;
&lt;p&gt;Public subnets felt like major roads anyone could access publicly.&lt;/p&gt;
&lt;p&gt;Private subnets became quieter streets where sensitive resources like databases stay protected.&lt;/p&gt;
&lt;p&gt;Even security groups stopped feeling like random rules and started making sense as gates controlling who can enter specific buildings.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iy5touokyajzugib9bjk.png&quot; alt=&quot;A simple analogy of VPC&quot;&gt;&lt;/p&gt;
&lt;p&gt;That small shift changed the way I understood networking. I stopped trying to memorize definitions and started understanding why companies structure cloud environments the way they do.&lt;/p&gt;
&lt;p&gt;That is the difference between passive learning and real understanding.&lt;/p&gt;
&lt;p&gt;Watching tutorials feels productive, but troubleshooting teaches deeper lessons. I even wrote about that in my &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/pulse/everyone-understands-tutorial-hell-ijeoma-igboagu-sg98c&quot;&gt;previous newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, I understood security groups much better after accidentally blocking traffic to my EC2 instance and trying to figure out why my application suddenly stopped responding.&lt;/p&gt;
&lt;p&gt;That frustration taught me more than multiple videos combined.&lt;/p&gt;
&lt;p&gt;Many people underestimate how normal confusion is in cloud computing.&lt;/p&gt;
&lt;p&gt;Some concepts take time. Sometimes you revisit the same topic three or four times before it finally clicks.&lt;/p&gt;
&lt;p&gt;Even experienced engineers still go back to fundamentals once in a while.&lt;/p&gt;
&lt;p&gt;You do not need to understand everything immediately.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The internet sometimes makes tech careers look very linear.&lt;br&gt;
Study. Get certified. Get hired.&lt;br&gt;
But real learning usually looks messier than that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are moments of confusion. There are things you break accidentally. And there are concepts that make no sense today but suddenly click weeks later.&lt;/p&gt;
&lt;p&gt;And that is probably how it is supposed to be.&lt;/p&gt;
&lt;p&gt;So these days, I am trying to focus less on looking impressive online and more on actually understanding what I am learning or building.&lt;/p&gt;
&lt;p&gt;The deeper I go into AWS, the more I realize strong fundamentals make advanced concepts less intimidating.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you enjoy reflections like this, you can subscribe to the &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7336744982432600064&quot;&gt;newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;You can follow my work and projects on &lt;a rel=&quot;nofollow&quot; href=&quot;https://x.com/ijaydimples&quot;&gt;Twitter&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/ijeoma-igboagu/&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/ijayhub&quot;&gt;GitHub&lt;/a&gt;, and &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/@cloudinreallife&quot;&gt;YouTube&lt;/a&gt;, where I share what I am building and learning along the way.&lt;/p&gt;
&lt;p&gt;Thank you for reading.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/19232/the-more-i-learn-about-aws-the-more-i-respect-fundamentals</guid>
<pubDate>Wed, 10 Jun 2026 09:00:00 +0000</pubDate>
</item>
<item>
<title>Developer Journar Day5:  How to Launch and Configure an Amazon EC2 Instance (From Scratch)</title>
<link>https://coderlegion.com/19274/developer-journar-day5-how-to-launch-and-configure-an-amazon-ec2-instance-from-scratch</link>
<description>&lt;p&gt;When you start working with cloud computing on AWS, one of the first major milestones is understanding how EC2 instances work. In simple terms, it’s like spinning up your own server on the internet in just a few minutes.&lt;/p&gt;
&lt;p&gt;In this article, I’ll walk you through how to create and launch an EC2 instance that works as a basic web server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; What is an EC2 instance?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An instance in Amazon Web Services, specifically within the Amazon EC2 service, is a virtual machine that you can configure based on your needs: CPU, memory, storage, and operating system.&lt;/p&gt;
&lt;p&gt;Think of it as renting a computer in the cloud that you can start, stop, and customize anytime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;⚙️ Step 1: Create the instance&lt;/strong&gt;&lt;br&gt;
The first step is to go to the EC2 dashboard and click “Launch Instance.”&lt;/p&gt;
&lt;p&gt;Here you define some key settings:&lt;/p&gt;
&lt;p&gt;️ Instance name&lt;/p&gt;
&lt;p&gt;You can assign a descriptive name such as:&lt;/p&gt;
&lt;p&gt;“My Web Server”&lt;/p&gt;
&lt;p&gt;This helps you easily identify it later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 2: Choose the AMI&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An Amazon Machine Image is basically the base image used to create your server.&lt;/p&gt;
&lt;p&gt;In this case, we use Amazon Linux, a lightweight and optimized OS for cloud environments.&lt;br&gt;
&lt;strong&gt;&lt;br&gt;
️ Step 3: Instance type&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This defines the computing power of your virtual machine.&lt;br&gt;
For this example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;t3.micro&lt;/li&gt;
&lt;li&gt;1 vCPU&lt;/li&gt;
&lt;li&gt;1 GB RAM&lt;br&gt;
Free Tier eligible This is perfect for learning and small projects.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt; Step 4: Key pair (SSH access)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To securely connect to your instance, you need a key pair:&lt;/p&gt;
&lt;p&gt; Public key: stored in the instance&lt;br&gt;
 Private key: kept on your machine&lt;br&gt;
This enables secure SSH access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 5: Network settings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here you control how your instance is accessed.&lt;/p&gt;
&lt;p&gt;In this setup:&lt;/p&gt;
&lt;p&gt;HTTPS traffic is allowed from the internet&lt;br&gt;
A Security Group is used to manage inbound rules&lt;/p&gt;
&lt;p&gt;This is what makes your server accessible from a browser.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 6: Storage configuration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You assign virtual disk storage (EBS):&lt;/p&gt;
&lt;p&gt;8 GB&lt;br&gt;
gp3 volume type Enough for a basic web server setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 7: User Data script (bootstrapping the server)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The base AMI only includes the operating system, so no web server is installed by default.&lt;/p&gt;
&lt;p&gt;To fix this, we use User Data, which allows us to run a script at launch time that:&lt;/p&gt;
&lt;p&gt;Installs a web server (like Apache or Nginx)&lt;br&gt;
Starts and enables the service automatically&lt;br&gt;
Prepares the instance to serve web content&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 8: Launch the instance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once everything is configured:&lt;br&gt;
 Click “Launch Instance”&lt;/p&gt;
&lt;p&gt;AWS handles the rest: provisioning, setup, and booting your virtual machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 9: Access your server&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After a couple of minutes, the instance will be in a running state.&lt;/p&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;p&gt;Copy the public IP address&lt;br&gt;
Open a browser&lt;br&gt;
Paste the IP&lt;/p&gt;
&lt;p&gt;And you’ll see your web server running &lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Conclusion&lt;/strong&gt;&lt;br&gt;
Launching an EC2 instance is one of the first essential steps in understanding cloud computing on AWS.&lt;/p&gt;
&lt;p&gt;With just a few clicks, you can deploy a fully functional virtual server ready to host applications, APIs, or websites.&lt;/p&gt;
&lt;p&gt;If you want, I can also help you next with:&lt;/p&gt;
&lt;p&gt;adding AWS architecture diagrams&lt;br&gt;
explaining VPC, subnets, and security groups visually&lt;br&gt;
or turning this into a “Cloud Engineer roadmap series” post&lt;/p&gt;
&lt;p&gt;Just tell me &lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/19274/developer-journar-day5-how-to-launch-and-configure-an-amazon-ec2-instance-from-scratch</guid>
<pubDate>Sat, 30 May 2026 07:38:57 +0000</pubDate>
</item>
<item>
<title>10 Tools Every Gen Z Developer Should Know About (2026 Edition)</title>
<link>https://coderlegion.com/12861/10-tools-every-gen-z-developer-should-know-about-2026-edition</link>
<description>&lt;h2 id=&quot;10-tools-every-gen-z-developer-should-know-about-2026-edition-&quot;&gt;&lt;strong&gt;10 Tools Every Gen Z Developer Should Know About (2026 Edition)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;If you’re a Gen Z developer trying to survive the chaotic tech world, knowing the right tools isn’t optional — it’s your superpower. The right tools can save hours of work, make your projects look professional, and even help you land your dream job.&lt;/p&gt;
&lt;p&gt;Here are &lt;strong&gt;10 tools that will level up your coding, design, and productivity game — fast.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-ai-coding-assistants-chatgpt-amp-github-copilot&quot;&gt;&lt;strong&gt;1. AI Coding Assistants – ChatGPT &amp;amp; GitHub Copilot&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AI is no longer sci-fi. These assistants can write code snippets, debug, and even explain complex algorithms in plain English.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Speeds up coding and learning simultaneously.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Ask ChatGPT to explain your own code — it’s like having a tutor 24/7.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-modern-ides-amp-editors-vs-code-amp-jetbrains-fleet&quot;&gt;&lt;strong&gt;2. Modern IDEs &amp;amp; Editors – VS Code &amp;amp; JetBrains Fleet&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Your development environment can make or break your workflow.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Extensions and smart suggestions turn small projects into pro-level apps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Use VS Code extensions like Live Share to collaborate in real-time.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-cloud-development-platforms-replit-amp-codesandbox&quot;&gt;&lt;strong&gt;3. Cloud Development Platforms – Replit &amp;amp; CodeSandbox&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Set up a dev environment in seconds, no heavy installations needed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Instantly share your projects with anyone online.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Experiment with new frameworks without messing up your local machine.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-version-control-tools-github-amp-gitlab&quot;&gt;&lt;strong&gt;4. Version Control Tools – GitHub &amp;amp; GitLab&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Version control isn’t just for pros — it’s how developers keep their work organized.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Collaboration, portfolio building, and job-ready skills.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Use GitHub Copilot integration to save time on pull requests and commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;5-design-amp-prototyping-tools-figma-canva-amp-midjourney&quot;&gt;&lt;strong&gt;5. Design &amp;amp; Prototyping Tools – Figma, Canva, &amp;amp; MidJourney&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Modern developers aren’t just coders — design matters.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Build prototypes, mockups, or AI-generated graphics for your projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Use Figma community templates to speed up your UI design process.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;6-api-amp-backend-tools-postman-supabase-amp-firebase&quot;&gt;&lt;strong&gt;6. API &amp;amp; Backend Tools – Postman, Supabase &amp;amp; Firebase&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;You don’t need to be a backend wizard anymore.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Build full-stack apps quickly with minimal server setup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Connect Firebase authentication and database in under 30 minutes.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;7-dev-automation-productivity-tools-notion-obsidian-amp-linear&quot;&gt;&lt;strong&gt;7. Dev Automation / Productivity Tools – Notion, Obsidian &amp;amp; Linear&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Managing projects can be messy. These tools make it clean and automated.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Organize your projects, track progress, and automate repetitive tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Use Notion templates to manage your coding projects like a startup.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;8-learning-amp-experimentation-platforms-leetcode-kaggle-amp-hackerrank&quot;&gt;&lt;strong&gt;8. Learning &amp;amp; Experimentation Platforms – LeetCode, Kaggle &amp;amp; HackerRank&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Practice makes perfect. These platforms turn learning into a challenge.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Sharpen skills, prepare for interviews, or compete globally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Kaggle competitions are perfect for building a real portfolio.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;9-ai-powered-design-amp-writing-tools-chatgpt-runway-copymatic&quot;&gt;&lt;strong&gt;9. AI-Powered Design &amp;amp; Writing Tools – ChatGPT, Runway, Copymatic&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Content, docs, and even marketing materials can be handled with AI.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Helps solo developers focus on coding while AI handles the rest.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Generate README files or documentation instantly — makes your project look pro.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;10-emerging-tech-tools-web3-dev-langchain-amp-quantum-sdks&quot;&gt;&lt;strong&gt;10. Emerging Tech Tools – Web3 Dev, LangChain &amp;amp; Quantum SDKs&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Stay ahead of the curve. The future belongs to developers who innovate.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Skills in emerging tech give you an edge in the next 5–10 years.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Experiment with LangChain for AI-powered apps — it’s the next big trend.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;closing-thoughts&quot;&gt;&lt;strong&gt;Closing Thoughts&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;These 10 tools won’t just make you a better developer — they’ll make you &lt;strong&gt;unstoppable&lt;/strong&gt;. The trick is to &lt;strong&gt;pick a few, master them, and build projects that showcase your skills&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Which of these tools have you tried? And which one are you starting with today? Drop a comment and share this with your coding squad!&lt;/p&gt;
&lt;hr&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/12861/10-tools-every-gen-z-developer-should-know-about-2026-edition</guid>
<pubDate>Sat, 14 Mar 2026 12:32:58 +0000</pubDate>
</item>
<item>
<title>Docker key terms simplified</title>
<link>https://coderlegion.com/12450/docker-key-terms-simplified</link>
<description>&lt;p&gt;Containerization is a must-have skill for DevOps engineers and software developers alike. It is essential for creating robust, deployable applications. In this article, I will explain the Docker concepts every developer needs to know and provide a hands-on example.&lt;/p&gt;
&lt;h3 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#what-is-docker&quot;&gt;What is Docker?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#why-is-docker-important&quot;&gt;Why is Docker Important&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#idea-of-how-docker-works&quot;&gt;Idea of How Docker Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#what-is-a-docker-image&quot;&gt;What is a Docker Image?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#docker-file-commands-explanation&quot;&gt;Dockerfile Commands Explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#running-the-image&quot;&gt;Running the Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#what-is-docker-container&quot;&gt;What is a Docker Container?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#how-to-run-a-docker-container&quot;&gt;How to Run a Docker Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#docker-volumes&quot;&gt;Docker Volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;prerequisites-&quot;&gt;Prerequisites:&lt;/h3&gt;
&lt;p&gt;to follow along this article be sure to &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Download and install Docker Desktop.&lt;/li&gt;
&lt;li&gt;Ensure Docker is running (especially on macOS or Windows) while practicing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-is-docker-&quot;&gt;What is docker:&lt;/h3&gt;
&lt;p&gt;Docker is a software platform that helps package and run applications on any machine with the exact environment you have configured.&lt;/p&gt;
&lt;p&gt;Teams often face the &quot;it works on my machine&quot; issue, where an application runs locally but crashes when a teammate tries to run it. This happens due to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mismatched environment or library versions.&lt;/li&gt;
&lt;li&gt;Differences in Operating Systems (OS) that don't support specific features.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Configuring every environment to match can be time-consuming and slows down development. Docker solves this by &quot;containerizing&quot; the environment.&lt;/p&gt;
&lt;h4 id=&quot;why-is-docker-important-&quot;&gt;Why is docker important:&lt;/h4&gt;
&lt;p&gt;As a developer, you shouldn't waste time troubleshooting environment setups. Docker allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure the environment once and reuse it throughout the development process.&lt;/li&gt;
&lt;li&gt;Run multiple copies of the same application with different environments without conflicts.&lt;/li&gt;
&lt;li&gt;Eliminate library version mismatches.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;idea-of-how-docker-works-&quot;&gt;Idea of how docker works:&lt;/h5&gt;
&lt;p&gt;Imagine you have a minivan that you use as a home, a business venture, and transport all at once. You can drive anywhere, and everything you need is already inside. You don't need to find a new bed or kitchen every time you move; it's all in the van.&lt;/p&gt;
&lt;p&gt;That is the idea of Docker. It contains all the essentials needed to run an application in a single container. This container can be used by anyone, anywhere, without further configuration.&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-docker-image-&quot;&gt;What is a docker image:&lt;/h3&gt;
&lt;p&gt;Docker image is a blueprint that describes how our application environment will look like and how it will be built from the ground up and after it is created it cannot be modified.&lt;/p&gt;
&lt;p&gt;with docker image we describe how docker should allocate and arrange our application environment this process happens in a file called &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Dockerfile&lt;/code&gt; defines the layers (stages) required to run the container, starting from the OS up to your codebase.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-docker&quot;&gt;#this creates a node runtime of version 18 and OS of alpine
From node:18-alpine
 
#this specifies the path where docker will store you application codes this could be any name of path you want
WORKDIR /app 

#copies the package file to docker files directory so that when npm can have packages to install
COPY package.json 

#this will run and install all the packages you are using in your package file
RUN npm run install 

#copies all the codebase in your directory to the docker files
COPY . . 

#define the port that will be used when testing the application

EXPOSE 3000

# if you are using nodemon you write a command to start your application like this
CMD [&quot;npm&quot;, &quot;ru&quot;, &quot;dev&quot;]

# if you are using node to execute the code you use
CMD [&quot;node&quot;, &quot;name of the file.js&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;docker-file-commands-explanation&quot;&gt;Docker file commands Explanation&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;From&lt;/code&gt;  specifies which kind of runtime you are using in my case I am using JavaScript, but you can use whatever based on your project setup and the colon helps in specifying the version and the hyphen to specify the OS system the system will be built on top of. &lt;/p&gt;
&lt;p&gt;&lt;code&gt;WORKDIR&lt;/code&gt;  this command specifies the directory in which docker will store your application codes generally you can specify any path you want but &lt;code&gt;/app&lt;/code&gt;  is the convenient one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;COPY&lt;/code&gt;  this command copies a specific file from your project files to docker&lt;/p&gt;
&lt;p&gt;&lt;code&gt;EXPOSE&lt;/code&gt;  this command specifies the port in which you are application is running on and also helps to define a port your application will run on when starting a container&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CMD&lt;/code&gt;  this command is the one that runs you application after it have been initialized.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; for window users and macOS when running your application using &lt;code&gt;nodemon&lt;/code&gt;  package inside your run script file in &lt;code&gt;package.json&lt;/code&gt;  file place &lt;code&gt;-L&lt;/code&gt;  flag before your file for it to run, without it your application won’t get started unless you are a Linux user&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87bdvc2sw2arj1uokhkv.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;running-the-image&quot;&gt;Running the image&lt;/h4&gt;
&lt;p&gt;After setting your docker file you can create an image by running the &lt;code&gt;build&lt;/code&gt;  command in your terminal using the &lt;code&gt;docker&lt;/code&gt;  command&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker build -t my-first-docker-image:version-one .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;build&lt;/code&gt;  command is the one used to build the image for your docker, and the &lt;code&gt;-t&lt;/code&gt; flag us used to specify the tag of the image.&lt;/p&gt;
&lt;p&gt;Image tag helps to differentiate images with the same name, docker image cannot be modified after they are built to edit it you would need to create a new image, but you may want to keep the same image but change its versions so you can track your changes and version over time and to do that the &lt;code&gt;-t&lt;/code&gt;  flag helps create a tag that you can refer as a version of the image, to specify the tag or version of your image you use double colon(&lt;code&gt;:&lt;/code&gt; )&lt;/p&gt;
&lt;p&gt;e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker build -t my-first-docker-image:version-two .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you didn’t define the tag name by default docker will assign it the &lt;code&gt;latest&lt;/code&gt;  as the default tag name&lt;/p&gt;
&lt;p&gt;e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker build -t my-first-docker-image .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;without &lt;code&gt;-t&lt;/code&gt;  flag it would hard to track down the changes of the image when we are constantly making changes and rebuilding the image&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.&lt;/code&gt;  tells docker where to look for files to copy&lt;/p&gt;
&lt;h3 id=&quot;what-is-docker-container-&quot;&gt;What is docker container:&lt;/h3&gt;
&lt;p&gt;Docker container is the implementation of a plan created in docker image, now all of the specifications you’ve specified inside your &lt;code&gt;Dockerfile&lt;/code&gt; will be executed one by one and create a container of your application codes and also create the underlying OS which is &lt;code&gt;alpine&lt;/code&gt;  and a runtime environment of &lt;code&gt;node.js&lt;/code&gt;  below is the command to run and create a container.&lt;/p&gt;
&lt;h4 id=&quot;how-to-run-a-docker-container&quot;&gt;How to run a docker container&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run --name container_name -p  image-name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Let’s start with knowing each command step by step&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;run&lt;/code&gt;  command is used to start a new container.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--name&lt;/code&gt; flag specifies the name for your container, the name you would like your container to have&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-p&lt;/code&gt;  flag is referred as port mapping this should be used if you have specified &lt;code&gt;EXPOSE&lt;/code&gt;  command in your &lt;code&gt;Dockerfile&lt;/code&gt;  it helps map any port you specify to the exposed port in docker file you put you preferred port on the left and the exposed port on the right and separate them using a colon.&lt;/p&gt;
&lt;p&gt;e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;-p prefferedPort:exposedPort
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;image-name&lt;/code&gt;  and then you have to specify the name of image in which you want to create a container from.&lt;/p&gt;
&lt;p&gt;running a container from the image we’ve created above we can something like this&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run --name container_one -p 3000:3000 my-first-docker-image:version-one
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;docker-volumes&quot;&gt;Docker Volumes&lt;/h3&gt;
&lt;p&gt;Docker images are &quot;read-only.&quot; If you change your code on your computer, the running container won't see those changes unless you rebuild the image. Docker Volumes solve this.&lt;/p&gt;
&lt;p&gt;Volumes act as a bridge between your local development environment and the running container.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run --name container_one -p 3000:3000 -v /our apps location:./our docker specified path
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the command is the one we’ve been using to create a container before but The -v flag binds your local folder to the folder inside the container (e.g., /app). Now, any changes you make in your code editor will instantly reflect inside the running container!&lt;/p&gt;
&lt;p&gt;So, the real command can look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run --name container_one -p 3000:3000 -v /C:\Users\arnol\OneDrive\Documentos\newContent\client:./app
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;final-thoughts-1&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Docker makes development faster and smoother. Whether you are aiming to be a DevOps engineer or a Full-stack developer, understanding these basics is essential for modern software engineering.&lt;/p&gt;
&lt;p&gt;Thank you for reading! If you learned something new or have suggestions, please let me know in the comments below.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/12450/docker-key-terms-simplified</guid>
<pubDate>Sat, 07 Mar 2026 10:28:38 +0000</pubDate>
</item>
<item>
<title>OCI Generative AI Security: Dedicated GPUs, RDMA Networks, and Enterprise-Grade Data Protection</title>
<link>https://coderlegion.com/9917/oci-generative-security-dedicated-gpus-rdma-networks-enterprise-grade-data-protection</link>
<description>&lt;p&gt;Security and privacy of customer workloads is an essential design tenet for Oracle Cloud Infrastructure (OCI) Generative AI. In an era where data breaches and AI security vulnerabilities dominate headlines, OCI has architected a comprehensive security framework that ensures enterprise-grade protection for AI workloads. This deep dive explores the multi-layered security approach that makes OCI Generative AI one of the most secure platforms for enterprise AI deployments.&lt;/p&gt;
&lt;h3 id=&quot;the-foundation-gpu-isolation-and-dedicated-infrastructure&quot;&gt;The Foundation: GPU Isolation and Dedicated Infrastructure&lt;/h3&gt;
&lt;h4 id=&quot;dedicated-gpu-allocation&quot;&gt;Dedicated GPU Allocation&lt;/h4&gt;
&lt;p&gt;GPUs allocated for a customer's generative AI tasks are pooled within a dedicated RDMA network, ensuring they are exclusively allocated to a single customer and not shared with others. This fundamental isolation guarantees that customer data remains secure and inaccessible to unauthorized parties.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Isolation Characteristics:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Physical Separation:&lt;/strong&gt; Each customer's GPU cluster operates on dedicated hardware, preventing any cross-contamination or data leakage between tenants.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Network Isolation:&lt;/strong&gt; RDMA cluster networks with less than 10 microsecond latency provide ultra-high-bandwidth connections (1.6 TB/sec internode bandwidth) while maintaining complete isolation from other customers' workloads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compute Isolation:&lt;/strong&gt; OCI Supercluster can deploy up to 32,768 GPUs per cluster, all dedicated to a single customer with no sharing of computational resources.&lt;/p&gt;
&lt;h4 id=&quot;rdma-network-architecture&quot;&gt;RDMA Network Architecture&lt;/h4&gt;
&lt;p&gt;Remote Direct Memory Access (RDMA) is a critical component of OCI's AI infrastructure, providing both performance and security benefits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RDMA Technology Overview:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RDMA allows for low-latency connections between nodes and access to GPU memory without involving the CPU. This technology enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ultra-Low Latency:&lt;/strong&gt; Less than 10 microseconds between nodes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High Bandwidth:&lt;/strong&gt; 1.6 TB/sec internode bandwidth for massive data transfers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU Offload:&lt;/strong&gt; Direct memory-to-memory transfers without CPU intervention&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security:&lt;/strong&gt; Dedicated network fabric preventing cross-tenant access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Network Types:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OCI's cluster network uses RDMA over Converged Ethernet Version 2 (RoCE v2) on top of NVIDIA ConnectX-7 network interface cards (NICs) to support high-throughput and latency-sensitive workloads.&lt;/p&gt;
&lt;p&gt;For advanced deployments, OCI utilizes NVIDIA Quantum InfiniBand or NVIDIA Spectrum-X Ethernet with RDMA over Converged Ethernet (RoCE) configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scale and Performance:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OCI enables customers to cluster up to 4,096 bare metal nodes, each with 8 GPUs, totaling up to 32,768 GPUs. The latest infrastructure scales even further—zettascale OCI Supercluster scales up to 131,072 GPUs, making it the largest hyperscale AI supercomputer in the cloud.&lt;/p&gt;
&lt;h4 id=&quot;hardware-security-modules-hsm-&quot;&gt;Hardware Security Modules (HSM)&lt;/h4&gt;
&lt;p&gt;Keys are stored on Hardware Security Modules (HSMs) that meet Federal Information Processing Standards (FIPS) 140-2 Security Level 3 security certification.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HSM Protection Modes:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Software Protection:&lt;/strong&gt; Keys stored and processed on servers, recommended for most use cases with strong encryption.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HSM Protection:&lt;/strong&gt; Keys stored on HSMs meeting FIPS 140-2 Security Level 3 certification, recommended for stringent compliance requirements like financial services and healthcare.&lt;/p&gt;
&lt;h3 id=&quot;model-endpoint-security&quot;&gt;Model Endpoint Security&lt;/h3&gt;
&lt;h4 id=&quot;single-customer-model-endpoints&quot;&gt;Single-Customer Model Endpoints&lt;/h4&gt;
&lt;p&gt;For strong data privacy and security, a dedicated GPU cluster only handles fine-tuned models for a single customer. This architectural decision ensures:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data Isolation:&lt;/strong&gt; No model from one customer processes data from another customer&lt;br&gt;
&lt;strong&gt;Performance Isolation:&lt;/strong&gt; Resources allocated exclusively for your workloads&lt;br&gt;
&lt;strong&gt;Compliance:&lt;/strong&gt; Easier to meet regulatory requirements with clear tenant boundaries&lt;br&gt;
&lt;strong&gt;Security Boundaries:&lt;/strong&gt; Physical and logical separation of processing environments&lt;/p&gt;
&lt;h4 id=&quot;endpoint-access-control&quot;&gt;Endpoint Access Control&lt;/h4&gt;
&lt;p&gt;Model endpoints implement multiple layers of access control:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Authentication:&lt;/strong&gt; API keys, OAuth tokens, or IAM credentials required for all requests&lt;br&gt;
&lt;strong&gt;Authorization:&lt;/strong&gt; Role-Based Access Control (RBAC) determines what actions authenticated users can perform&lt;br&gt;
&lt;strong&gt;Network Security:&lt;/strong&gt; Private endpoints within Virtual Cloud Networks (VCNs), with optional public access through controlled ingress&lt;br&gt;
&lt;strong&gt;Rate Limiting:&lt;/strong&gt; Configurable throttling to prevent abuse and ensure fair resource allocation&lt;/p&gt;
&lt;h3 id=&quot;customer-data-and-model-isolation&quot;&gt;Customer Data and Model Isolation&lt;/h3&gt;
&lt;h4 id=&quot;tenancy-level-isolation&quot;&gt;Tenancy-Level Isolation&lt;/h4&gt;
&lt;p&gt;Customer data access is restricted within a customer's tenancy so that one customer's data cannot be seen by another customer. This fundamental principle manifests across multiple dimensions:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compartment Isolation:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OCI uses compartments to organize and isolate resources. The architecture implements compartmentalization and private subnets to isolate different operational environments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Best Practice:&lt;/strong&gt; Create separate compartments for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Development environments&lt;/li&gt;
&lt;li&gt;Staging/testing&lt;/li&gt;
&lt;li&gt;Production workloads&lt;/li&gt;
&lt;li&gt;Different business units or projects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Data Separation:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Training data, fine-tuned model weights, embeddings, and inference logs are all stored within customer-controlled storage with strict access controls preventing cross-tenant access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Workload Isolation:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A single NVIDIA GB200 NVL72 rack can be configured to launch multiple NVLink groupings for smaller workloads and provide strong isolation for efficient workload distribution.&lt;/p&gt;
&lt;h4 id=&quot;network-level-isolation&quot;&gt;Network-Level Isolation&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Private Subnets:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Resources deployed in private subnets within VCNs, preventing direct internet access unless explicitly configured.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security Lists and Network Security Groups (NSGs):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Stateful firewalls controlling inbound and outbound traffic at the subnet and network interface level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service Gateway and NAT Gateway:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Controlled access to Oracle services and internet resources without exposing instances to inbound internet traffic.&lt;/p&gt;
&lt;h3 id=&quot;integrated-oci-security-services&quot;&gt;Integrated OCI Security Services&lt;/h3&gt;
&lt;p&gt;OCI Generative AI leverages Oracle's comprehensive security ecosystem to provide defense-in-depth.&lt;/p&gt;
&lt;h4 id=&quot;oci-identity-and-access-management-iam-&quot;&gt;OCI Identity and Access Management (IAM)&lt;/h4&gt;
&lt;p&gt;IAM provides the foundation for authentication and authorization across all OCI services.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key IAM Capabilities:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;User and Group Management:&lt;/strong&gt; Create users, organize them into groups, and assign permissions based on job functions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Policies:&lt;/strong&gt; Stringent access controls using OCI IAM policies enforce least-privilege access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example IAM Policy for Generative AI:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Allow group GenAI-Engineers to manage generative-ai-family in compartment GenAI-Prod
Allow group GenAI-Engineers to use virtual-network-family in compartment GenAI-Networking
Allow group Data-Scientists to read generative-ai-endpoints in compartment GenAI-Prod
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Identity Providers:&lt;/strong&gt; Integration with corporate identity systems (SAML, SCIM) for single sign-on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-Factor Authentication (MFA):&lt;/strong&gt; Additional security layer requiring multiple forms of verification.&lt;/p&gt;
&lt;h4 id=&quot;oci-key-management-service-vault-&quot;&gt;OCI Key Management Service (Vault)&lt;/h4&gt;
&lt;p&gt;The Key Management Service is critical for protecting data at rest and managing encryption keys.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vault Architecture:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Oracle Vault is a logical grouping of keys. There are two types of vaults: Private and Virtual, which have different levels of isolation, pricing, and computing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Centralized Key Management:&lt;/strong&gt; OCI Key Management provides centralized management of the encryption of your data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customer-Managed Keys (CMK):&lt;/strong&gt; Customers create and control their own encryption keys, maintaining full ownership.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Oracle-Managed Keys:&lt;/strong&gt; Default encryption with Oracle-managed keys that are automatically rotated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Rotation:&lt;/strong&gt; Each master encryption key (MEK) is automatically assigned a key version. When you rotate a key, the Vault service generates a new key version.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integration with Generative AI:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OCI Generative AI uses Key Management Service to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Store Base Model Keys Securely:&lt;/strong&gt; Encryption keys for foundational models are managed through Vault&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encrypt Fine-Tuned Models:&lt;/strong&gt; Custom model weights encrypted with customer-controlled keys&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protect Training Data:&lt;/strong&gt; Datasets used for fine-tuning encrypted before storage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secure Inference Data:&lt;/strong&gt; Input and output data encrypted in transit and at rest&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;oci-object-storage-security&quot;&gt;OCI Object Storage Security&lt;/h4&gt;
&lt;p&gt;Object Storage buckets store critical AI assets including training data, model weights, and embeddings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Default Encryption:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OCI encrypts all objects by default with Oracle-managed keys, which are periodically rotated. This ensures data is protected even if customers don't explicitly configure encryption.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customer-Managed Encryption:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OCI provides options for customers to use their own keys for more security. Using IAM policies that authenticate users performing tasks, a best practice is creating and periodically rotating encryption keys in the Vault service to protect resources in Object Storage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Encryption at Multiple Layers:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object-Level Encryption:&lt;/strong&gt; Each object encrypted with a unique Data Encryption Key (DEK)&lt;br&gt;
&lt;strong&gt;Bucket-Level Encryption:&lt;/strong&gt; Entire buckets can be encrypted with a specific Master Encryption Key (MEK)&lt;br&gt;
&lt;strong&gt;Client-Side Encryption:&lt;/strong&gt; Customers can encrypt data before sending it to Oracle Object Storage for additional control&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Required IAM Policies:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To use customer-managed keys with Object Storage, create a policy like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;allow service objectstorage-&amp;lt;region_name&amp;gt; to use keys in compartment &amp;lt;compartment_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Access Control:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pre-Authenticated Requests (PARs):&lt;/strong&gt; Time-bound access to objects without requiring IAM credentials&lt;br&gt;
&lt;strong&gt;Bucket Visibility:&lt;/strong&gt; Private by default, with explicit configuration required for public access&lt;br&gt;
&lt;strong&gt;Versioning:&lt;/strong&gt; Track and restore previous versions of objects&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security Best Practices:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Restrict BUCKET_UPDATE permission to a minimal set of IAM groups to minimize the possibility of existing buckets being made public inadvertently or maliciously.&lt;/p&gt;
&lt;h4 id=&quot;cloud-guard-active-threat-detection&quot;&gt;Cloud Guard: Active Threat Detection&lt;/h4&gt;
&lt;p&gt;Comprehensive logging and audit trails maintained for all significant operations.&lt;/p&gt;
&lt;p&gt;Cloud Guard continuously monitors your OCI environment for security weaknesses and threats.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Detector Rules for Object Storage:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cloud Guard includes detector rules for Object Storage to identify public buckets, unencrypted data, and other security issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Capabilities:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automated Detection:&lt;/strong&gt; Identifies misconfigurations and security threats in real-time&lt;br&gt;
&lt;strong&gt;Responder Actions:&lt;/strong&gt; Automatically remediate issues or notify administrators&lt;br&gt;
&lt;strong&gt;Problem Dashboard:&lt;/strong&gt; Centralized view of all detected security problems&lt;br&gt;
&lt;strong&gt;Integration:&lt;/strong&gt; Works across all OCI services including Generative AI resources&lt;/p&gt;
&lt;h3 id=&quot;data-protection-throughout-the-ai-lifecycle&quot;&gt;Data Protection Throughout the AI Lifecycle&lt;/h3&gt;
&lt;h4 id=&quot;training-data-security&quot;&gt;Training Data Security&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Ingestion:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data uploaded to Object Storage with automatic encryption&lt;/li&gt;
&lt;li&gt;Customer-managed keys available for additional control&lt;/li&gt;
&lt;li&gt;Access restricted via IAM policies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Processing:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Training occurs on dedicated GPUs isolated within customer's RDMA network&lt;/li&gt;
&lt;li&gt;No data sharing between customers&lt;/li&gt;
&lt;li&gt;Temporary data purged after training completion&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Storage:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fine-tuned model weights stored in Object Storage buckets&lt;/li&gt;
&lt;li&gt;Encrypted by default and managed by Key Management Service&lt;/li&gt;
&lt;li&gt;Version control for model iterations&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;inference-data-security&quot;&gt;Inference Data Security&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Input Processing:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requests authenticated via IAM or API keys&lt;/li&gt;
&lt;li&gt;Data encrypted in transit using TLS 1.2+&lt;/li&gt;
&lt;li&gt;Processed on dedicated endpoints with no cross-tenant access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Output Generation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Responses encrypted in transit&lt;/li&gt;
&lt;li&gt;Optional logging with encryption at rest&lt;/li&gt;
&lt;li&gt;Retention policies configurable per use case&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Continuous monitoring of resource usage to proactively mitigate contention&lt;/li&gt;
&lt;li&gt;Audit logs for all API calls&lt;/li&gt;
&lt;li&gt;Integration with OCI Logging Analytics&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;advanced-security-features&quot;&gt;Advanced Security Features&lt;/h3&gt;
&lt;h4 id=&quot;security-zones&quot;&gt;Security Zones&lt;/h4&gt;
&lt;p&gt;Security Zones provide compartment-associated Oracle-defined recipes of security policies based on best practices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enforced Policies:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No Public Access:&lt;/strong&gt; Resources cannot be accessible from public internet&lt;br&gt;
&lt;strong&gt;Customer-Managed Keys:&lt;/strong&gt; Data encryption enforced using Customer-Managed Keys for block volumes, boot volumes, and Object Storage buckets&lt;br&gt;
&lt;strong&gt;Deny Public Buckets:&lt;/strong&gt; Public access to Object Storage buckets is denied to prevent accidental exposure&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use Case:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Deploy Generative AI workloads in Security Zones to automatically enforce security best practices and maintain compliance.&lt;/p&gt;
&lt;h4 id=&quot;compliance-and-certifications&quot;&gt;Compliance and Certifications&lt;/h4&gt;
&lt;p&gt;OCI maintains extensive compliance certifications relevant to AI workloads:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Regional Compliance:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GDPR:&lt;/strong&gt; European data protection requirements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HIPAA:&lt;/strong&gt; Healthcare data in the United States&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FedRAMP:&lt;/strong&gt; U.S. government cloud security&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISO 27001/27017/27018:&lt;/strong&gt; International security standards&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Industry-Specific:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PCI DSS:&lt;/strong&gt; Payment card industry&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SOC 1/2/3:&lt;/strong&gt; Service organization controls&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FIPS 140-2 Level 3:&lt;/strong&gt; Cryptographic module security&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;sovereign-cloud-options&quot;&gt;Sovereign Cloud Options&lt;/h4&gt;
&lt;p&gt;Oracle's distributed cloud, AI infrastructure, and generative AI services enable governments and enterprises to deploy AI factories that run cloud services locally and within a country's secure premises with operational controls supporting sovereign goals.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Available Options:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OCI Dedicated Region:&lt;/strong&gt; Entire cloud region operated exclusively for a single customer&lt;br&gt;
&lt;strong&gt;Oracle Alloy:&lt;/strong&gt; Cloud platform for partners to deliver sovereign cloud&lt;br&gt;
&lt;strong&gt;Oracle EU Sovereign Cloud:&lt;/strong&gt; European data residency and operational sovereignty&lt;br&gt;
&lt;strong&gt;Oracle Government Cloud:&lt;/strong&gt; FedRAMP-authorized regions for U.S. government&lt;/p&gt;
&lt;h3 id=&quot;best-practices-for-secure-generative-ai-deployments&quot;&gt;Best Practices for Secure Generative AI Deployments&lt;/h3&gt;
&lt;h4 id=&quot;1-implement-least-privilege-access&quot;&gt;1. Implement Least-Privilege Access&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Principle:&lt;/strong&gt; Grant only the minimum permissions necessary for each role.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Implementation:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Development team - read-only on production
Allow group GenAI-Developers to read generative-ai-family in compartment GenAI-Prod

# Production team - full management
Allow group GenAI-Production to manage generative-ai-family in compartment GenAI-Prod
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;2-use-customer-managed-keys&quot;&gt;2. Use Customer-Managed Keys&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Full control over encryption key lifecycle and usage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create Vault in Key Management Service&lt;/li&gt;
&lt;li&gt;Generate or import master encryption key&lt;/li&gt;
&lt;li&gt;Create IAM policy allowing services to use key&lt;/li&gt;
&lt;li&gt;Configure buckets and resources to use customer key&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;3-enable-comprehensive-logging&quot;&gt;3. Enable Comprehensive Logging&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Audit Logs:&lt;/strong&gt; Enable audit logging for all API calls to Generative AI services&lt;br&gt;
&lt;strong&gt;Flow Logs:&lt;/strong&gt; Monitor network traffic to/from GPU clusters&lt;br&gt;
&lt;strong&gt;Application Logs:&lt;/strong&gt; Capture inference requests and responses for analysis&lt;/p&gt;
&lt;h4 id=&quot;4-leverage-network-isolation&quot;&gt;4. Leverage Network Isolation&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Private Endpoints:&lt;/strong&gt; Deploy model endpoints in private subnets&lt;br&gt;
&lt;strong&gt;Service Gateway:&lt;/strong&gt; Access Oracle services without internet exposure&lt;br&gt;
&lt;strong&gt;Bastion Hosts:&lt;/strong&gt; Secure administrative access to resources&lt;/p&gt;
&lt;h4 id=&quot;5-implement-defense-in-depth&quot;&gt;5. Implement Defense-in-Depth&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Multiple Layers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Network security (NSGs, Security Lists)&lt;/li&gt;
&lt;li&gt;Identity security (IAM, MFA)&lt;/li&gt;
&lt;li&gt;Data security (encryption at rest and in transit)&lt;/li&gt;
&lt;li&gt;Application security (input validation, rate limiting)&lt;/li&gt;
&lt;li&gt;Monitoring security (Cloud Guard, Logging Analytics)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;6-regular-security-reviews&quot;&gt;6. Regular Security Reviews&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Periodic Assessments:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review IAM policies quarterly&lt;/li&gt;
&lt;li&gt;Rotate encryption keys according to policy&lt;/li&gt;
&lt;li&gt;Audit user access and remove unused accounts&lt;/li&gt;
&lt;li&gt;Update network security rules based on traffic patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;7-secure-development-practices&quot;&gt;7. Secure Development Practices&lt;/h4&gt;
&lt;p&gt;The architecture includes a CI/CD pipeline for promoting models from the playground environment to production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Separation of Environments:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Development: Unrestricted experimentation with synthetic data&lt;/li&gt;
&lt;li&gt;Staging: Production-like with access controls&lt;/li&gt;
&lt;li&gt;Production: Maximum security with customer data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;monitoring-and-incident-response&quot;&gt;Monitoring and Incident Response&lt;/h3&gt;
&lt;h4 id=&quot;real-time-monitoring&quot;&gt;Real-Time Monitoring&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Metrics to Track:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API request rates and latency&lt;/li&gt;
&lt;li&gt;Authentication failures&lt;/li&gt;
&lt;li&gt;Unusual access patterns&lt;/li&gt;
&lt;li&gt;Resource utilization anomalies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Alerting:&lt;/strong&gt;&lt;br&gt;
Configure Cloud Events to trigger notifications for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IAM policy changes&lt;/li&gt;
&lt;li&gt;Network security group modifications&lt;/li&gt;
&lt;li&gt;Encryption key access&lt;/li&gt;
&lt;li&gt;Dedicated cluster scaling events&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;incident-response&quot;&gt;Incident Response&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Preparation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Define incident response procedures&lt;/li&gt;
&lt;li&gt;Establish communication channels&lt;/li&gt;
&lt;li&gt;Designate response team members&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Detection:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloud Guard active monitoring&lt;/li&gt;
&lt;li&gt;Log analysis for anomalies&lt;/li&gt;
&lt;li&gt;User-reported issues&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Containment:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Isolate affected resources&lt;/li&gt;
&lt;li&gt;Revoke compromised credentials&lt;/li&gt;
&lt;li&gt;Block suspicious network traffic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Recovery:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restore from backups if necessary&lt;/li&gt;
&lt;li&gt;Rotate encryption keys&lt;/li&gt;
&lt;li&gt;Update security configurations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lessons Learned:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Document incident timeline&lt;/li&gt;
&lt;li&gt;Identify root causes&lt;/li&gt;
&lt;li&gt;Update procedures and controls&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;future-security-enhancements&quot;&gt;Future Security Enhancements&lt;/h3&gt;
&lt;p&gt;Oracle continues investing in security capabilities:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI-Powered Security:&lt;/strong&gt;&lt;br&gt;
Machine learning models detecting anomalous behavior in API usage patterns and access patterns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Zero Trust Architecture:&lt;/strong&gt;&lt;br&gt;
Moving toward continuous verification of all access requests regardless of source.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Confidential Computing:&lt;/strong&gt;&lt;br&gt;
NVIDIA BlueField-3 DPUs accelerate networking, storage, and security workloads, enabling hardware-based isolation for sensitive computations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enhanced Compliance:&lt;/strong&gt;&lt;br&gt;
Expanding certifications and attestations for emerging regulatory requirements.&lt;/p&gt;
&lt;p&gt;OCI Generative AI security is built on a comprehensive, multi-layered approach that addresses the unique challenges of enterprise AI deployments:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Infrastructure Security:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dedicated GPUs pooled within RDMA networks exclusively for single customers&lt;/li&gt;
&lt;li&gt;Dedicated GPU clusters handling only customer's base and fine-tuned models&lt;/li&gt;
&lt;li&gt;Ultra-low latency RDMA networking with complete tenant isolation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Data Security:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customer data access restricted within tenancy&lt;/li&gt;
&lt;li&gt;Object Storage encrypted by default with periodic key rotation&lt;/li&gt;
&lt;li&gt;Customer-managed keys for maximum control&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Identity and Access:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comprehensive IAM with fine-grained policies&lt;/li&gt;
&lt;li&gt;Integration with enterprise identity providers&lt;/li&gt;
&lt;li&gt;Multi-factor authentication support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Compliance:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FIPS 140-2 Level 3 certified HSMs&lt;/li&gt;
&lt;li&gt;Sovereign cloud options for data residency&lt;/li&gt;
&lt;li&gt;Extensive regulatory certifications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Security and privacy of customer workloads is truly an essential design tenet at OCI. By combining dedicated infrastructure, comprehensive encryption, identity controls, and continuous monitoring, OCI Generative AI provides enterprise-grade security that enables organizations to confidently deploy AI at scale.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How does your organization approach AI security? What security features are most critical for your use cases? Share your experiences in the comments&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/9917/oci-generative-security-dedicated-gpus-rdma-networks-enterprise-grade-data-protection</guid>
<pubDate>Sat, 17 Jan 2026 18:12:41 +0000</pubDate>
</item>
<item>
<title>OCI Generative AI Service: Enterprise-Grade LLMs on Oracle Cloud</title>
<link>https://coderlegion.com/8424/oci-generative-ai-service-enterprise-grade-llms-on-oracle-cloud</link>
<description>&lt;p&gt;Oracle Cloud Infrastructure (OCI) Generative AI is a fully managed service providing enterprises with access to state-of-the-art, customizable large language models through a comprehensive API. OCI positions itself as a neutral, enterprise-focused platform offering unprecedented choice and flexibility in the generative AI space.&lt;/p&gt;
&lt;h3 id=&quot;what-is-oci-generative-ai-&quot;&gt;What is OCI Generative AI?&lt;/h3&gt;
&lt;p&gt;OCI Generative AI helps enterprises seamlessly integrate advanced language comprehension capabilities into applications, providing a complete end-to-end platform for building, customizing, and deploying LLM-powered applications at scale.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Capabilities:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access to pretrained foundational models from multiple leading AI providers&lt;/li&gt;
&lt;li&gt;Flexible fine-tuning with custom datasets on dedicated infrastructure&lt;/li&gt;
&lt;li&gt;Enterprise-grade security, compliance, and data sovereignty&lt;/li&gt;
&lt;li&gt;Integration with Oracle's broader AI ecosystem&lt;/li&gt;
&lt;li&gt;Support for both on-demand usage and dedicated hosting&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;available-models-2025-&quot;&gt;Available Models (2025)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Cohere Models:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Command A (03-2025)&lt;/strong&gt;: 256K token context, excels at tool use, agents, RAG, and multilingual tasks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command R/R+&lt;/strong&gt;: 128K context for RAG and enterprise use cases&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embed models&lt;/strong&gt;: English v3.0, Multilingual v3.0, Embed 4&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Meta Llama Models:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Llama 4 Maverick&lt;/strong&gt;: 17B active from ~400B total (mixture-of-experts)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Llama 4 Scout&lt;/strong&gt;: 17B active from ~109B total&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Llama 3.3 (70B)&lt;/strong&gt;, &lt;strong&gt;Llama 3.2 Vision&lt;/strong&gt; (90B, 11B), &lt;strong&gt;Llama 3.1&lt;/strong&gt; (405B, 70B)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Google Gemini Models (Coming Soon):&lt;/strong&gt;&lt;br&gt;
Oracle will be the only hyperscaler aside from Google Cloud to offer Gemini as a managed service.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gemini 2.5 Pro/Flash/Flash-Lite&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;xAI Grok Models:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Grok 4/Grok 4 Fast&lt;/strong&gt;, &lt;strong&gt;Grok 3 series&lt;/strong&gt;, &lt;strong&gt;Grok Code Fast 1&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;OpenAI Models:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;gpt-oss-120b&lt;/strong&gt; and &lt;strong&gt;gpt-oss-20b&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;core-features&quot;&gt;Core Features&lt;/h3&gt;
&lt;h4 id=&quot;1-pretrained-models&quot;&gt;1. Pretrained Models&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chat Models&lt;/strong&gt;: Multi-turn conversational AI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text Generation&lt;/strong&gt;: Content creation, code generation, documentation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embedding Models&lt;/strong&gt;: Vector representations for semantic search (384-1024 dimensions)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rerank Models&lt;/strong&gt;: Relevance scoring for search results&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;2-fine-tuning&quot;&gt;2. Fine-Tuning&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Strategies:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;T-Few &amp;amp; Vanilla&lt;/strong&gt; for Cohere models (with layer-specific optimization)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LoRA&lt;/strong&gt; for Llama 3 models (efficient parameter adaptation)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Customization:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Training epochs, learning rate, batch size&lt;/li&gt;
&lt;li&gt;Early stopping controls&lt;/li&gt;
&lt;li&gt;JSONL format with prompt/completion pairs&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-dedicated-ai-clusters&quot;&gt;3. Dedicated AI Clusters&lt;/h4&gt;
&lt;p&gt;GPU-based compute resources exclusive to your tenancy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Isolated infrastructure for fine-tuning&lt;/li&gt;
&lt;li&gt;Private GPUs for hosting with zero-downtime scaling&lt;/li&gt;
&lt;li&gt;Multiple cluster sizes (Small/Large/Large Generic 2/4 for 405B models)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;4-deployment-options&quot;&gt;4. Deployment Options&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;On-Demand&lt;/strong&gt;: Pay-per-character, ideal for experimentation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dedicated Clusters&lt;/strong&gt;: Predictable costs for production workloads&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;5-oci-generative-ai-agents-2024-2025-&quot;&gt;5. OCI Generative AI Agents (2024-2025)&lt;/h4&gt;
&lt;p&gt;Fully managed RAG service combining LLMs with enterprise search.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent Hub Features (March 2025):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQL Tool&lt;/strong&gt;: Self-correction, multi-dialect support (Oracle SQL, SQLite)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced RAG Tool&lt;/strong&gt;: Hybrid search, multi-modal parsing, multi-lingual support (7+ languages)&lt;/li&gt;
&lt;li&gt;Integration with OCI Object Storage, OpenSearch, Oracle Database 23ai&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;use-cases&quot;&gt;Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Text Generation&lt;/strong&gt;: Blog posts, marketing copy, documentation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic Search&lt;/strong&gt;: Intent-based search, recommendations, document retrieval&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document Summarization&lt;/strong&gt;: Executive summaries, support tickets, research papers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Classification&lt;/strong&gt;: Support ticket routing, sentiment analysis, intent detection&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Question Answering&lt;/strong&gt;: Intelligent responses from documents and knowledge bases&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise Knowledge Management&lt;/strong&gt;: RAG-powered customer support&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;developer-experience&quot;&gt;Developer Experience&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Access Methods:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OCI Console Playground&lt;/li&gt;
&lt;li&gt;REST API&lt;/li&gt;
&lt;li&gt;OCI CLI&lt;/li&gt;
&lt;li&gt;SDKs (Python, Java, TypeScript, Node.js)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Framework Integration:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LangChain&lt;/strong&gt;: Prompt templating, memory, chain-of-thought&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LlamaIndex&lt;/strong&gt;: Context-augmented applications, RAG solutions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tool Use&lt;/strong&gt;: Chat models can integrate with external tools and APIs for complex queries requiring external data.&lt;/p&gt;
&lt;h3 id=&quot;security-amp-compliance&quot;&gt;Security &amp;amp; Compliance&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data isolation within your tenancy&lt;/li&gt;
&lt;li&gt;Encryption at rest and in transit&lt;/li&gt;
&lt;li&gt;Fine-grained IAM policies and RBAC&lt;/li&gt;
&lt;li&gt;Comprehensive audit trails&lt;/li&gt;
&lt;li&gt;Private endpoints and VPN connectivity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Regional Availability:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;US (Chicago, Phoenix, Ashburn)&lt;/li&gt;
&lt;li&gt;Europe (Frankfurt, London, Amsterdam)&lt;/li&gt;
&lt;li&gt;Asia Pacific (Tokyo, Mumbai, Seoul)&lt;/li&gt;
&lt;li&gt;Middle East (Dubai, Jeddah)&lt;/li&gt;
&lt;li&gt;Latin America (São Paulo)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sovereign Cloud&lt;/strong&gt;: Oracle EU Sovereign Cloud for data residency&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;advanced-features&quot;&gt;Advanced Features&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Configurable Parameters:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Temperature (0.0-1.0)&lt;/li&gt;
&lt;li&gt;Top-k and top-p sampling&lt;/li&gt;
&lt;li&gt;Frequency/presence penalties&lt;/li&gt;
&lt;li&gt;Seed parameter for reproducibility&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Performance Benchmarks:&lt;/strong&gt;&lt;br&gt;
RAG scenarios with 2,000-token prompts and 200-token responses benchmarked across cluster types.&lt;/p&gt;
&lt;h3 id=&quot;pricing&quot;&gt;Pricing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free Tier&lt;/strong&gt;: $300 credits for trial&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On-Demand&lt;/strong&gt;: Pay-per-character (input/output)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dedicated Clusters&lt;/strong&gt;: Predictable monthly costs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;oracle-s-ai-ecosystem&quot;&gt;Oracle's AI Ecosystem&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Oracle Database 23ai:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native AI Vector Search&lt;/li&gt;
&lt;li&gt;In-database LLM integration&lt;/li&gt;
&lt;li&gt;Support for RAG workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;MySQL HeatWave:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In-database LLMs (HeatWave GenAI)&lt;/li&gt;
&lt;li&gt;Automated vector store&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Oracle Fusion Applications:&lt;/strong&gt;&lt;br&gt;
Generative AI embedded across ERP, HCM, SCM, and CX applications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OCI Data Science:&lt;/strong&gt;&lt;br&gt;
No-code access to open-source LLMs (Meta, Mistral AI) with Hugging Face Transformers and PyTorch.&lt;/p&gt;
&lt;h3 id=&quot;certification&quot;&gt;Certification&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;OCI 2025 Generative AI Professional Certification&lt;/strong&gt; covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLM Fundamentals &amp;amp; Transformer Architecture&lt;/li&gt;
&lt;li&gt;Prompt Engineering&lt;/li&gt;
&lt;li&gt;Fine-Tuning Techniques&lt;/li&gt;
&lt;li&gt;RAG Workflows &amp;amp; Vector Databases&lt;/li&gt;
&lt;li&gt;Agent Development&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt; Free tutorials, Coursera courses, Oracle MyLearn platform&lt;/p&gt;
&lt;h3 id=&quot;competitive-advantages&quot;&gt;Competitive Advantages&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Model Choice&lt;/strong&gt;: Access to Cohere, Meta, Google, xAI, OpenAI through unified platform&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise-First&lt;/strong&gt;: Security, compliance, data sovereignty&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost-Effective&lt;/strong&gt;: Better price-performance with transparent pricing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database Integration&lt;/strong&gt;: Unique integration with Oracle Database 23ai and MySQL HeatWave&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sovereign Cloud&lt;/strong&gt;: Data residency guarantees&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create OCI account (free tier available)&lt;/li&gt;
&lt;li&gt;Navigate to Analytics &amp;amp; AI → Generative AI&lt;/li&gt;
&lt;li&gt;Choose approach: Playground, API/SDK, or Fine-tuning&lt;/li&gt;
&lt;li&gt;Select model and configure parameters&lt;/li&gt;
&lt;li&gt;Start building&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Example: Building a Support Chatbot&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ingest documentation into Oracle Database 23ai vector store&lt;/li&gt;
&lt;li&gt;Create embeddings using Cohere Embed models&lt;/li&gt;
&lt;li&gt;Deploy RAG Agent&lt;/li&gt;
&lt;li&gt;Implement chat interface with LangChain&lt;/li&gt;
&lt;li&gt;Enable multi-turn conversations with tool calling&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;OCI Generative AI offers comprehensive, enterprise-focused LLM capabilities addressing real-world needs: security, sovereignty, choice, and integration. Whether building chatbots, implementing semantic search, or developing multi-agent systems, OCI provides the foundation for enterprise-grade AI applications.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Are you using OCI Generative AI? Share your experiences below&lt;/em&gt;&lt;/p&gt;
</description>
<category>Machine Learning</category>
<guid isPermaLink="true">https://coderlegion.com/8424/oci-generative-ai-service-enterprise-grade-llms-on-oracle-cloud</guid>
<pubDate>Fri, 12 Dec 2025 09:55:53 +0000</pubDate>
</item>
<item>
<title>Overcoming Key Challenges to Machine Learning Adoption</title>
<link>https://coderlegion.com/6438/overcoming-key-challenges-to-machine-learning-adoption</link>
<description>&lt;p&gt;Introduction&lt;br&gt;
Machine Learning (ML) promises transformative insights and automation, but adopting it at scale is far from simple. Organizations often underestimate the complexity of operationalizing ML models. This article explores the four major challenges to ML adoption—and how to address them effectively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Data Preparation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;High-quality data is the foundation of any ML initiative. &lt;/p&gt;
&lt;p&gt;Yet, most projects stall here because:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Access Issues:&lt;/strong&gt; Data silos and compliance restrictions make it hard to gather complete datasets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pipeline Management:&lt;/strong&gt; Cleaning, labeling, and maintaining data pipelines over time is resource-intensive.&lt;/p&gt;
&lt;p&gt;✅ Actionable Solutions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Centralize Data Access:&lt;/strong&gt; Implement a data lake or warehouse with role-based access controls.&lt;br&gt;
&lt;strong&gt;Automate Data Quality Checks&lt;/strong&gt;: Use tools like Great Expectations or Deequ for continuous validation.&lt;br&gt;
&lt;strong&gt;Version Control for Data:&lt;/strong&gt; Adopt DVC (Data Version Control) to track changes and maintain reproducibility.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Invest in automated data validation tools and establish clear data governance policies early.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Model Development&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Building accurate and interpretable models is harder than it looks:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Model Selection &amp;amp; Training:&lt;/strong&gt; Choosing the right algorithm and tuning hyperparameters requires expertise. Selecting the &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deployment at Scale:&lt;/strong&gt; Rolling out multiple models across environments introduces complexity.&lt;/p&gt;
&lt;p&gt;✅ Actionable Solutions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Leverage AutoML:&lt;/strong&gt; Tools like H2O.ai or Google AutoML can accelerate model selection and tuning.&lt;br&gt;
&lt;strong&gt;Adopt MLOps Frameworks:&lt;/strong&gt; Use Kubeflow or MLflow for streamlined training, deployment, and monitoring.&lt;br&gt;
&lt;strong&gt;Containerize Models:&lt;/strong&gt; Package models in Docker containers for portability and scalability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Use MLOps frameworks like Kubeflow or MLflow to streamline training and deployment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Model Governance &amp;amp; Security&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once deployed, models need continuous oversight:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bias &amp;amp; Drift Monitoring:&lt;/strong&gt; Models degrade over time as data changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adversarial Attacks:&lt;/strong&gt; ML systems can be manipulated if not properly secured.&lt;/p&gt;
&lt;p&gt;✅ Actionable Solutions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bias Audits:&lt;/strong&gt; Integrate fairness metrics using libraries like AIF360 or Fairlearn.&lt;br&gt;
&lt;strong&gt;Drift Detection:&lt;/strong&gt; Automate drift alerts with Evidently AI or WhyLabs.&lt;br&gt;
&lt;strong&gt;Security Hardening:&lt;/strong&gt; Apply adversarial testing and encrypt model endpoints using TLS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Implement automated drift detection and adversarial testing as part of your CI/CD pipeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Access to Compute Resources&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Training ML models demands significant compute power:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GPU Availability:&lt;/strong&gt; Limited GPU resources can bottleneck training.&lt;br&gt;
&lt;strong&gt;Workload Scheduling:&lt;/strong&gt; Efficient orchestration is essential for cost control.&lt;/p&gt;
&lt;p&gt;✅ Actionable Solutions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud GPU Clusters:&lt;/strong&gt;  Use AWS EC2 GPU instances or Azure Machine Learning Compute for elasticity.&lt;br&gt;
&lt;strong&gt;Autoscaling:&lt;/strong&gt;  Implement Kubernetes autoscaling for dynamic resource allocation.&lt;br&gt;
&lt;strong&gt;Spot Instances:&lt;/strong&gt;  Reduce costs by leveraging spot pricing for non-critical workloads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt;  Explore cloud-based GPU clusters and autoscaling strategies to optimize resource usage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Talent: The Hidden Barrier&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Scarcity of specialized talent remains one of the biggest hurdles. Upskilling your team and leveraging community resources can bridge this gap.&lt;/p&gt;
&lt;p&gt;✅ Actionable Solutions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Internal Bootcamps:&lt;/strong&gt; Organize ML enablement sessions for engineers and analysts.&lt;br&gt;
&lt;strong&gt;Mentorship Programs:&lt;/strong&gt; Pair junior staff with experienced ML practitioners.&lt;br&gt;
&lt;strong&gt;Community Engagement:&lt;/strong&gt; Encourage participation in open-source projects and forums.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ML adoption isn’t just about algorithms—it’s about data readiness, governance, infrastructure, and talent. By addressing these challenges proactively, organizations can unlock the full potential of machine learning.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/6438/overcoming-key-challenges-to-machine-learning-adoption</guid>
<pubDate>Tue, 14 Oct 2025 21:01:11 +0000</pubDate>
</item>
<item>
<title>What is Edge Computing, and Why Should Developers Care?</title>
<link>https://coderlegion.com/5550/what-is-edge-computing-and-why-should-developers-care</link>
<description>&lt;h2 id=&quot;what-is-edge-computing-and-why-should-developers-care-&quot;&gt;What is Edge Computing, and Why Should Developers Care?&lt;/h2&gt;
&lt;hr&gt;
&lt;h4 id=&quot;introduction-1&quot;&gt;Introduction&lt;/h4&gt;
&lt;p&gt;You’ve probably noticed it before: even cloud apps running on top-tier internet sometimes lag. Now imagine that lag happening in a self-driving car that needs to make a decision in milliseconds—or in a medical device monitoring live patient data. That “half‑a‑second delay” suddenly feels like forever.  &lt;/p&gt;
&lt;p&gt;And that’s exactly why edge computing exists. Instead of sending all your data on a round trip to the cloud and back, edge computing shifts the processing power closer to where the data is born—your phone, your IoT device, or even the microcontroller inside a factory sensor.  &lt;/p&gt;
&lt;p&gt;For us developers, this isn’t just another infrastructure buzzword. Edge computing flips the playbook, giving us new ways to build apps that are insanely fast, smarter, and more resilient. Let’s unpack what it is—and why you should definitely have it on your radar.  &lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;understanding-edge-computing&quot;&gt;Understanding Edge Computing&lt;/h3&gt;
&lt;h4 id=&quot;what-actually-is-edge-computing-&quot;&gt;What Actually Is Edge Computing?&lt;/h4&gt;
&lt;p&gt;At its simplest, edge computing means &lt;strong&gt;pushing computation closer to the data source.&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The old cloud model (traditional):&lt;/strong&gt;&lt;br&gt;
Data → sent to a centralized cloud → processed → response sent back to the device.  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The edge model (new):&lt;/strong&gt;&lt;br&gt;
Data → processed locally at the “edge” → only essential info goes to the cloud.  &lt;/p&gt;
&lt;p&gt;Think of it as turning “dumb” endpoints into smart, decision‑making nodes. No more waiting around for a cloud server thousands of miles away.  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real‑world use cases include:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AR/VR apps that need frame‑perfect, real‑time performance.  &lt;/li&gt;
&lt;li&gt;Smart cameras that can detect faces or threats on‑device.  &lt;/li&gt;
&lt;li&gt;Autonomous vehicles reacting in milliseconds without asking permission from the cloud.  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;why-edge-computing-rocks-benefits-that-matter-&quot;&gt;Why Edge Computing Rocks (Benefits That Matter)&lt;/h4&gt;
&lt;p&gt;Here’s why this isn’t hype:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⚡ &lt;strong&gt;Low latency:&lt;/strong&gt; Real‑time feels &lt;em&gt;truly&lt;/em&gt; real‑time.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bandwidth savings:&lt;/strong&gt; You’re not shooting terabytes of raw data to the cloud.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Higher reliability:&lt;/strong&gt; Systems keep working even if connectivity drops.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better security:&lt;/strong&gt; Sensitive data can stay local instead of traveling across networks.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For apps, this translates directly into a smoother, stronger user experience—and for devs, that’s a competitive edge.  &lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-developers-should-care&quot;&gt;Why Developers Should Care&lt;/h3&gt;
&lt;h4 id=&quot;new-playground-new-problems-to-solve&quot;&gt;New Playground, New Problems to Solve&lt;/h4&gt;
&lt;p&gt;Edge isn’t just an infra tweak—it’s opening &lt;strong&gt;entirely new categories of software.&lt;/strong&gt; Right now, people are already building:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IoT ecosystems for smart cars, homes, and wearables.  &lt;/li&gt;
&lt;li&gt;Drones and robots that drive themselves.  &lt;/li&gt;
&lt;li&gt;Immersive AR/VR apps that break the latency barrier.  &lt;/li&gt;
&lt;li&gt;Fintech and healthcare solutions where milliseconds literally matter.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Guess what? Every single one of those needs developers who &lt;strong&gt;understand edge.&lt;/strong&gt;  &lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;skills-worth-leveling-up&quot;&gt;Skills Worth Leveling Up&lt;/h4&gt;
&lt;p&gt;If you want to future‑proof your skill set, here’s where to start hacking:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Distributed systems thinking:&lt;/strong&gt; Split workloads between cloud and edge.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimization for resource‑constrained devices:&lt;/strong&gt; Write lightweight, efficient code that still packs a punch.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hands‑on with frameworks:&lt;/strong&gt; AWS IoT Greengrass, Azure IoT Edge, Google Distributed Cloud Edge, etc.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design for hybrid:&lt;/strong&gt; Decide what &lt;em&gt;must&lt;/em&gt; run locally and what makes sense in the cloud.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This isn’t just “learn another cloud service.” It’s about rethinking where your app’s &lt;strong&gt;intelligence actually lives.&lt;/strong&gt;  &lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;watch-out-for-these-challenges&quot;&gt;Watch Out for These Challenges&lt;/h4&gt;
&lt;p&gt;Not everything is shiny—there are some headaches you’ll run into:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Device chaos:&lt;/strong&gt; Every device is different. → &lt;em&gt;Fix:&lt;/em&gt; Use containers and lightweight Kubernetes (K3s) to standardize deployments.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mass deployment hell:&lt;/strong&gt; Updating thousands of devices isn’t fun. → &lt;em&gt;Fix:&lt;/em&gt; Leverage DevOps pipelines and orchestration tooling.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost vs. performance juggling:&lt;/strong&gt; Some tasks are better in the cloud; some must stay at the edge. → &lt;em&gt;Fix:&lt;/em&gt; Design hybrid strategies from day one.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As with any paradigm shift, knowing the pitfalls upfront helps you build smarter.  &lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Let’s be real: edge computing isn’t just hype—it’s happening. By crunching data closer to where it originates, it brings blazing speed, improved reliability, and opens the door to the kind of apps we’ve only daydreamed about.  &lt;/p&gt;
&lt;p&gt;For developers, this means opportunities everywhere: from IoT gadgets to autonomous vehicles to smart city systems. But it also means you’ll need to adapt—sharpen your distributed systems mindset, get comfortable with hybrid architectures, and start experimenting with edge frameworks.  &lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Next step?&lt;/strong&gt; Don’t just read about it. Spin up a Raspberry Pi, push some logic to the edge, deploy a tiny ML model, or mess around with an IoT sensor. The future of computing is already here—waiting at the edge.  &lt;/p&gt;
</description>
<category>Edge Computing</category>
<guid isPermaLink="true">https://coderlegion.com/5550/what-is-edge-computing-and-why-should-developers-care</guid>
<pubDate>Thu, 25 Sep 2025 08:40:26 +0000</pubDate>
</item>
<item>
<title>Understanding OCI Infrastructure: Regions, Availability Domains, and Fault Domains</title>
<link>https://coderlegion.com/4915/understanding-oci-infrastructure-regions-availability-domains-and-fault-domains</link>
<description>&lt;h2 id=&quot;oracle-cloud-infrastructure-oci-physical-architecture-a-complete-guide&quot;&gt;Oracle Cloud Infrastructure (OCI) Physical Architecture: A Complete Guide&lt;/h2&gt;
&lt;p&gt;Oracle Cloud Infrastructure (OCI) is built on a robust physical architecture designed to deliver high availability, fault tolerance, and optimal performance. Understanding this architecture is crucial for designing resilient cloud solutions. Let's dive into the key components that make up OCI's infrastructure.&lt;/p&gt;
&lt;h3 id=&quot;core-infrastructure-components&quot;&gt;Core Infrastructure Components&lt;/h3&gt;
&lt;p&gt;OCI's physical architecture is organized into three main levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Regions&lt;/strong&gt; - Geographic locations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Availability Domains (ADs)&lt;/strong&gt; - Data centers within regions  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault Domains (FDs)&lt;/strong&gt; - Hardware groupings within availability domains&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;regions-your-geographic-foundation&quot;&gt;Regions: Your Geographic Foundation&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;region&lt;/strong&gt; is a localized geographical area where Oracle has deployed OCI infrastructure. Think of regions as Oracle's data center hubs strategically placed around the world. For example, Phoenix serves as a major region on the US West Coast.&lt;/p&gt;
&lt;p&gt;As of August 2024, Oracle Cloud Infrastructure (OCI) boasts more than 45 active regions and over 100 Availability Domains globally, making it comparable to major cloud providers like AWS and Microsoft Azure.&lt;/p&gt;
&lt;h4 id=&quot;choosing-the-right-region&quot;&gt;Choosing the Right Region&lt;/h4&gt;
&lt;p&gt;The golden rule for region selection is simple: &lt;strong&gt;choose the region closest to your users&lt;/strong&gt;. This ensures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lowest network latency&lt;/li&gt;
&lt;li&gt;Best application performance&lt;/li&gt;
&lt;li&gt;Optimal user experience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Data sovereignty and compliance requirements may also influence your region choice, especially for regulated industries.&lt;/p&gt;
&lt;h3 id=&quot;availability-domains-isolated-data-centers&quot;&gt;Availability Domains: Isolated Data Centers&lt;/h3&gt;
&lt;p&gt;An &lt;strong&gt;Availability Domain (AD)&lt;/strong&gt; consists of one or more fault-tolerant data centers located within a single OCI region. Here's what makes them special:&lt;/p&gt;
&lt;h4 id=&quot;key-characteristics&quot;&gt;Key Characteristics&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Availability domains are isolated from each other, fault tolerant, and very unlikely to fail simultaneously&lt;/li&gt;
&lt;li&gt;Connected by low-latency, high-bandwidth networks&lt;/li&gt;
&lt;li&gt;No shared physical infrastructure (power, cooling, or internal networks)&lt;/li&gt;
&lt;li&gt;Traffic between availability domains and between regions is encrypted&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;availability-domain-distribution&quot;&gt;Availability Domain Distribution&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Every Region can have up to 3 Availability Domains&lt;/li&gt;
&lt;li&gt;Some regions may have fewer ADs depending on their size and scope&lt;/li&gt;
&lt;li&gt;Each AD operates independently to prevent cascading failures&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;fault-domains-hardware-level-resilience&quot;&gt;Fault Domains: Hardware-Level Resilience&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Fault Domains (FDs)&lt;/strong&gt; represent the finest level of isolation in OCI's architecture. They're groupings of hardware and infrastructure within an availability domain.&lt;/p&gt;
&lt;h4 id=&quot;fault-domain-structure&quot;&gt;Fault Domain Structure&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Each region has at least three fault domains&lt;/li&gt;
&lt;li&gt;Every availability domain contains exactly &lt;strong&gt;3 fault domains&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Software deployments across multiple fault domains are staggered&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;protection-benefits&quot;&gt;Protection Benefits&lt;/h4&gt;
&lt;p&gt;Fault domains provide &lt;strong&gt;anti-affinity&lt;/strong&gt; protection against:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unexpected hardware failures&lt;/strong&gt; - Server crashes, network issues, storage problems&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Planned maintenance&lt;/strong&gt; - Scheduled updates and infrastructure work&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Power and cooling issues&lt;/strong&gt; - Localized infrastructure problems&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;oracle-maximum-availability-architecture-maa-&quot;&gt;Oracle Maximum Availability Architecture (MAA)&lt;/h3&gt;
&lt;p&gt;Oracle Maximum Availability Architecture (MAA) is a set of best practices developed by Oracle engineers over many years for the integrated use of Oracle High Availability, data protection, and disaster recovery technologies.&lt;/p&gt;
&lt;h4 id=&quot;maa-components&quot;&gt;MAA Components&lt;/h4&gt;
&lt;p&gt;The MAA blueprint includes these critical technologies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Oracle Flashback&lt;/strong&gt; - optimizes logical failure repair&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backup and Recovery&lt;/strong&gt; - Comprehensive data protection strategies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multitenancy&lt;/strong&gt; - Efficient resource sharing and isolation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Guard&lt;/strong&gt; - Database disaster recovery and high availability&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real Application Clusters (RAC)&lt;/strong&gt; - allow customers to run a single Oracle Database across multiple servers to maximize availability and enable horizontal scalability&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application Continuity&lt;/strong&gt; - Seamless failover for database connections&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;integrated-security&quot;&gt;Integrated Security&lt;/h4&gt;
&lt;p&gt;MAA implements a &lt;strong&gt;defense-in-depth&lt;/strong&gt; security approach covering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data encryption and protection&lt;/li&gt;
&lt;li&gt;Identity and access management&lt;/li&gt;
&lt;li&gt;Network security controls&lt;/li&gt;
&lt;li&gt;Compute infrastructure security&lt;/li&gt;
&lt;li&gt;OCI tenancy-level protections&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;organizational-structure-tenancy-and-compartments&quot;&gt;Organizational Structure: Tenancy and Compartments&lt;/h3&gt;
&lt;h4 id=&quot;tenancy-your-oci-account&quot;&gt;Tenancy: Your OCI Account&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Each OCI account receives &lt;strong&gt;one tenancy&lt;/strong&gt; (root compartment)&lt;/li&gt;
&lt;li&gt;Think of tenancy as your organization's master container&lt;/li&gt;
&lt;li&gt;Provides the highest level of resource organization&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;compartments-logical-organization&quot;&gt;Compartments: Logical Organization&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Compartments&lt;/strong&gt; are logical containers that help you organize and isolate cloud resources:&lt;/p&gt;
&lt;h5 id=&quot;key-features&quot;&gt;Key Features&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Can be nested &lt;strong&gt;up to 6 levels deep&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inherit policies&lt;/strong&gt; from parent compartments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tenancy-wide availability&lt;/strong&gt; - accessible across all subscribed regions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource mobility&lt;/strong&gt; - most resources can be moved between compartments&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;best-practices&quot;&gt;Best Practices&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Use compartments to separate environments (dev, test, prod)&lt;/li&gt;
&lt;li&gt;Align compartments with your organizational structure&lt;/li&gt;
&lt;li&gt;Implement least-privilege access through compartment-based policies&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;virtual-cloud-network-vcn-your-software-defined-network&quot;&gt;Virtual Cloud Network (VCN): Your Software-Defined Network&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;Virtual Cloud Network (VCN)&lt;/strong&gt; is your private software-defined network in OCI, functioning like a traditional physical network but with cloud flexibility.&lt;/p&gt;
&lt;h4 id=&quot;vcn-characteristics&quot;&gt;VCN Characteristics&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Regional scope&lt;/strong&gt; - Each VCN exists within a single OCI region&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CIDR support&lt;/strong&gt; - Supports both IPv4 and IPv6 addressing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complete networking stack&lt;/strong&gt; - Includes subnets, route tables, and security lists&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;subnet-types&quot;&gt;Subnet Types&lt;/h4&gt;
&lt;h5 id=&quot;public-subnets-internet-gateway-&quot;&gt;Public Subnets (Internet Gateway)&lt;/h5&gt;
&lt;p&gt;Public subnets enable direct internet connectivity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Allow ingress traffic&lt;/strong&gt; from the internet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allow egress traffic&lt;/strong&gt; to the internet  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support public IP addresses&lt;/strong&gt; for resources&lt;/li&gt;
&lt;li&gt;Ideal for web servers, load balancers, and public-facing services&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;private-subnets-nat-gateway-&quot;&gt;Private Subnets (NAT Gateway)&lt;/h5&gt;
&lt;p&gt;Private subnets provide secure, isolated environments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No direct ingress&lt;/strong&gt; from the internet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controlled egress&lt;/strong&gt; through NAT Gateway&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No public IP addresses&lt;/strong&gt; assigned&lt;/li&gt;
&lt;li&gt;Perfect for databases, application servers, and sensitive workloads&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;networking-components&quot;&gt;Networking Components&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Route Tables&lt;/strong&gt; - Define traffic routing rules&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Lists&lt;/strong&gt; - Act as subnet-level firewalls&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gateways&lt;/strong&gt; - Provide connectivity options (Internet, NAT, Service)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;identity-and-access-management-iam-policies&quot;&gt;Identity and Access Management (IAM) Policies&lt;/h3&gt;
&lt;p&gt;IAM policies form the backbone of OCI security, controlling who can access what resources and when.&lt;/p&gt;
&lt;h4 id=&quot;policy-hierarchy&quot;&gt;Policy Hierarchy&lt;/h4&gt;
&lt;p&gt;Fleet administrators can set IAM policies at multiple levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tenancy level&lt;/strong&gt; - Organization-wide policies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compartment level&lt;/strong&gt; - Environment or project-specific access&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User level&lt;/strong&gt; - Individual user permissions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group level&lt;/strong&gt; - Role-based access control&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;policy-capabilities&quot;&gt;Policy Capabilities&lt;/h4&gt;
&lt;p&gt;IAM policies enable you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create, manage, and delete&lt;/strong&gt; cloud resources&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control access&lt;/strong&gt; to specific services and features&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement compliance&lt;/strong&gt; requirements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit and monitor&lt;/strong&gt; resource usage&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;best-practices-1&quot;&gt;Best Practices&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Follow the &lt;strong&gt;principle of least privilege&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;groups&lt;/strong&gt; instead of individual user assignments&lt;/li&gt;
&lt;li&gt;Regularly &lt;strong&gt;review and audit&lt;/strong&gt; policy assignments&lt;/li&gt;
&lt;li&gt;Implement &lt;strong&gt;separation of duties&lt;/strong&gt; for critical operations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;conclusion-1&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Oracle Cloud Infrastructure's physical architecture provides a solid foundation for building highly available, scalable, and secure cloud applications. By understanding regions, availability domains, and fault domains, you can design resilient architectures that withstand various failure scenarios.&lt;/p&gt;
&lt;p&gt;The combination of MAA best practices, flexible compartment organization, robust VCN networking, and comprehensive IAM policies gives you the tools needed to build enterprise-grade cloud solutions.&lt;/p&gt;
&lt;p&gt;Whether you're migrating existing workloads or building new cloud-native applications, OCI's architecture provides the reliability and performance your business demands.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ready to start your OCI journey? Consider your region selection carefully, plan your compartment strategy, and always design for high availability across multiple fault domains.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Cloud Computing</category>
<guid isPermaLink="true">https://coderlegion.com/4915/understanding-oci-infrastructure-regions-availability-domains-and-fault-domains</guid>
<pubDate>Fri, 22 Aug 2025 20:29:15 +0000</pubDate>
</item>
<item>
<title>Kubernetes Predictions Were Wrong</title>
<link>https://coderlegion.com/3825/kubernetes-predictions-were-wrong</link>
<description>&lt;p&gt;&lt;strong&gt;Why has the solution to the Kubernetes complexity problem proven so elusive?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In 2020, people were predicting that Kubernetes would disappear within a year. They believed someone would create a service that would reduce the adjacent choices and make Kubernetes the easy default. Everyone would use Kubernetes, but few people would work at the nuts-and-bolts level.&lt;/p&gt;
&lt;p&gt;I checked this morning, and it’s still here — and so are the nuts and bolts. So, why has the solution to the Kubernetes complexity problem proven so elusive?&lt;/p&gt;
&lt;h3 id=&quot;an-ecosystem-of-choices&quot;&gt;An Ecosystem of Choices&lt;/h3&gt;
&lt;p&gt;In isolation, Kubernetes isn’t particularly complicated, but a broad ecosystem of tools, options and decisions surrounds it. You can run Kubernetes anywhere, from a local machine to the cloud. You can run on a single low-powered machine or thousands of hyperscale nodes. You can use it to run one monolith or thousands of microservices.&lt;/p&gt;
&lt;p&gt;There isn’t one opinionated way to use Kubernetes. It’s designed to be highly flexible. That means you get to make all the decisions. You choose exactly how to &lt;a rel=&quot;nofollow&quot; href=&quot;https://roadmap.sh/kubernetes&quot;&gt;configure Kubernetes&lt;/a&gt; and which tools to use alongside it.&lt;/p&gt;
&lt;p&gt;It’s the sheer volume of decisions you have to make to get started that people are talking about when they say things are hard, not the complexity of Kubernetes itself.&lt;/p&gt;
&lt;p&gt;And this is before you consider the software itself. If you’ve just written a microservice in Go that runs in a container, it’s pretty easy to run it in Kubernetes. If you have a heritage monolith written under the assumption it would run on a virtual machine, there’s a great deal of work to bend it to work in a container.&lt;/p&gt;
&lt;p&gt;It’s no wonder a developer responsible for delivering software that solves business problems reaches overload when faced with so many options along the way, especially when seen in aggregate across the different choices to be made for containers, infrastructure automation and container registries, with the various file formats and conventions used.&lt;/p&gt;
&lt;p&gt;If you want to cycle to work, selecting a bicycle is a research-heavy task, so imagine buying a frame, wheels, handlebars, brakes and gearing separately. Some riders will want this level of control, but it’s overwhelming when your job is just getting to a destination.&lt;/p&gt;
&lt;h3 id=&quot;-cognitive-overload-and-platform-teams&quot;&gt; Cognitive Overload and Platform Teams&lt;/h3&gt;
&lt;p&gt;The view that Kubernetes would settle into quiet utility and effectively disappear while also running all our workloads failed to materialize. Nobody managed to create a single opinionated path for Kubernetes that would take care of all these choices.&lt;/p&gt;
&lt;p&gt;The simple reason for this is that the mythical one true way wouldn’t work for most applications and services. It’s impossible to create a single simple path without acknowledging the context of the application and organization.&lt;/p&gt;
&lt;p&gt;This is why platform engineering has gained traction. While there’s little chance of creating an industrywide path of simplified choices, creating one within an organization is perfectly feasible.&lt;/p&gt;
&lt;p&gt;A minimal viable platform could be a wiki page listing pre-baked decisions and providing a standard example for each configuration file. This might evolve into a facade that allows developers to specify what they need along a simple dimension, such as “size,” with the platform taking care of the details behind the flag.&lt;/p&gt;
&lt;p&gt;Platforms should provide simplified ways to do the right thing while letting expert developers peel back the layers when the standard approach isn’t suitable.&lt;/p&gt;
&lt;h3 id=&quot;fewer-options-without-limiting-teams&quot;&gt;Fewer Options Without Limiting Teams&lt;/h3&gt;
&lt;p&gt;The lack of a single opinionated path for Kubernetes underscores the importance of contextual factors for the application and organization. While creating a universal, simplified approach is impractical, platform engineering is one way to reduce the many decisions that need to be made along the way, especially when such decisions aren’t crucial.&lt;/p&gt;
&lt;p&gt;Despite the perceived complexity issues, Kubernetes has done nothing but grow. Clearly, the benefits outweigh the adoption pain. So, imagine what would happen if Kubernetes and the associated moving parts were easier to adopt?&lt;/p&gt;
&lt;p&gt;Platform teams could be the crucial factor in creating an opinionated Kubernetes setup that still respects the local context. Perhaps the predictions aren’t wrong, just delayed.&lt;/p&gt;
</description>
<category>Containerization</category>
<guid isPermaLink="true">https://coderlegion.com/3825/kubernetes-predictions-were-wrong</guid>
<pubDate>Tue, 08 Jul 2025 08:56:45 +0000</pubDate>
</item>
<item>
<title>Power Up Your App with Server-Sent Push Notifications</title>
<link>https://coderlegion.com/3274/power-up-your-app-with-server-sent-push-notifications</link>
<description>&lt;p&gt;You will need a server-side implementation to send push notifications. Here’s an example using Node.js with the &lt;code&gt;web-push&lt;/code&gt; library.&lt;/p&gt;
&lt;h5 id=&quot;install-web-push&quot;&gt;Install &lt;code&gt;web-push&lt;/code&gt;&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;npm install web-push
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;server-code-example&quot;&gt;Server Code  Example&lt;/h5&gt;
&lt;p&gt; server.js&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const webPush = require('web-push');

// Replace with your own VAPID keys
const vapidKeys = webPush.generateVAPIDKeys();

webPush.setVapidDetails(
  'mailto:*Emails are not allowed*',
  vapidKeys.publicKey,
  vapidKeys.privateKey
);

// Example subscription object (should be obtained from the client)
const subscription = {
  endpoint: 'USER_SUBSCRIPTION_ENDPOINT',
  keys: {
    auth: 'USER_AUTH_KEY',
    p256dh: 'USER_P256DH_KEY',
  },
};

// Send a push notification
const payload = JSON.stringify({
  title: 'Hello!',
  body: 'This is a push notification from Angular!',
});

webPush.sendNotification(subscription, payload)
  .then(response =&amp;gt; console.log('Notification sent successfully:', response))
  .catch(error =&amp;gt; console.error('Error sending notification:', error));
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;running-the-application&quot;&gt;Running the Application&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Serve your Angular application:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   ng serve --prod
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open your browser and navigate to your application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accept the notification permissions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trigger a push notification from your server.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;summary&quot;&gt;Summary&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Setting up Angular service workers for push notifications.&lt;/li&gt;
&lt;li&gt;Requesting notification permissions in the Angular app.&lt;/li&gt;
&lt;li&gt;Sending push notifications from a Node.js server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make sure to replace &lt;code&gt;YOUR_PUBLIC_VAPID_KEY&lt;/code&gt; with your actual VAPID key from your server-side implementation.&lt;/p&gt;
&lt;p&gt;To see the frontend implementation, check out this post.&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/3273/leveraging-service-workers-to-enhance-web-app-performance-and-reliability&quot;&gt;https://coderlegion.com/3273/leveraging-service-workers-to-enhance-web-app-performance-and-reliability&lt;/a&gt;&lt;/p&gt;
</description>
<category>Backend Dev</category>
<guid isPermaLink="true">https://coderlegion.com/3274/power-up-your-app-with-server-sent-push-notifications</guid>
<pubDate>Sun, 08 Jun 2025 05:36:54 +0000</pubDate>
</item>
<item>
<title>How to login to your remote server like Digital Ocean using SSH key on window</title>
<link>https://coderlegion.com/3127/how-to-login-to-your-remote-server-like-digital-ocean-using-ssh-key-on-window</link>
<description>&lt;p&gt;SSH stands for Secure Shell. it is a cryptographic network protocol used to securely assess and manage remote computers over the internet. &lt;br&gt;
There are several use cases of SSH, which include:&lt;br&gt;
a.Secure data transfer&lt;br&gt;
b.Passwordless login&lt;br&gt;
c.Secure file transfer&lt;br&gt;
d.Remote login&lt;br&gt;
e.Port forwarding&lt;br&gt;
This article is focused on how to login to your remote server using ssh key on windows, so e will not be talking about the other use case of ssh.&lt;br&gt;
To log in to your remote server using Windows, you need to be sure your Windows has openSSH installed. To confirm this,&lt;br&gt;
•Go to the window search bar and type “PowerShell”, this will bring it out, click it to open the PowerShell&lt;br&gt;
•In the PowerShell, type ‘ssh’ and click the Enter key on your keyboard&lt;br&gt;
You are expected to see the usage instructions like this&lt;/p&gt;
&lt;p&gt;`PS C:\Users\USER&amp;gt; ssh&lt;br&gt;
usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address]&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;       [-c cipher_spec] [-D [bind_address:]port] [-E log_file]
       [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file]
       [-J destination] [-L address] [-l login_name] [-m mac_spec]
       [-O ctl_cmd] [-o option] [-P tag] [-p port] [-Q query_option]
       [-R address] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]
       destination [command [argument ...]]`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you did not see this, then you will have to install OpenSSH, which can be found in the settings of your Windows OS.&lt;br&gt;
•The next step is to create the SSH key on the PowerShell by typing the command ‘ssh-keygen’&lt;br&gt;
This will prompt you to input the file name you want to save the key into; if you do not input this, it will save the key into a default file name.&lt;br&gt;
You will also be prompted to type in a password twice, which will act as the passphrase for the key&lt;br&gt;
After this, you will see a message like this:&lt;/p&gt;
&lt;p&gt; &lt;code&gt;Your identification has been saved in ozoSSh
Your public key has been saved in ozoSSh.pub
The key fingerprint is:
SHA256:SRxDqca9xn0U64HewqfjHcuKJSw0llIhVDPIa0oj+ms user@DESKTOP-EB25MV0
The key's randomart image is:
+--[ED25519 256]--+
|   ooo=.+.       |
|    o. =.o  .    |
|     o.oo  . o   |
|. o o.+o... +    |
|.o +..=.S= + .   |
|. .  + o+ = =    |
| .    ..o .=.    |
|  E    . +oo o   |
| ...    ..oo+    |
+----[SHA256]-----+&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This signifies that the keys have been created.&lt;br&gt;
•Type the ‘ls’ command to display the files in that directory. Search for the file you saved the key in, you will see two files with the same file name, just that one of them has ‘.pub’ attached to it as a suffix&lt;br&gt;
•Type “cat   root@”&lt;br&gt;
This will prompt you to type in your passphrase used to set up the SSH key before you are logged in.&lt;br&gt;
The logic here is that as the SSH key pair is created, the public key is saved in your remote server; you need the corresponding private key, which the server will compare with that of the public key in order to grant you access to the remote server. If, for any reason, the private key does not match the public key, you will be denied access to the server.&lt;/p&gt;
</description>
<category>Cloud Computing</category>
<guid isPermaLink="true">https://coderlegion.com/3127/how-to-login-to-your-remote-server-like-digital-ocean-using-ssh-key-on-window</guid>
<pubDate>Thu, 22 May 2025 12:25:58 +0000</pubDate>
</item>
<item>
<title>How Kubernetes Simplifies Cloud Application Deployment, Scaling, and Management</title>
<link>https://coderlegion.com/1460/how-kubernetes-simplifies-cloud-application-deployment-scaling-and-management</link>
<description>&lt;p&gt;As cloud-native applications continue to gain momentum, the need for efficient, scalable, and automated management of containers becomes more essential. &lt;strong&gt;Kubernetes&lt;/strong&gt; has emerged as the industry-standard platform for automating the deployment, scaling, and management of containerized applications across various cloud environments. This article dives deep into how Kubernetes transforms the way organizations handle their cloud application lifecycle, providing advanced features such as auto-scaling, self-healing, and high availability.&lt;/p&gt;
&lt;h3 id=&quot;what-is-kubernetes-&quot;&gt;What is Kubernetes?&lt;/h3&gt;
&lt;p&gt;Kubernetes, often abbreviated as K8s, is an open-source container orchestration platform designed to automate the deployment, scaling, and management of containerized applications. Originally developed by Google, Kubernetes has become the go-to solution for organizations looking to streamline their cloud infrastructure management. By abstracting away the complexity of infrastructure management, Kubernetes allows developers to focus on application code while leaving operational concerns to the platform.&lt;/p&gt;
&lt;p&gt;In a modern cloud environment, Kubernetes enables seamless container management across on-premises data centers, public clouds, and hybrid environments. This abstraction makes it possible to run applications in a consistent manner, regardless of the underlying hardware or cloud provider.&lt;/p&gt;
&lt;h3 id=&quot;automating-application-deployment-with-kubernetes&quot;&gt;Automating Application Deployment with Kubernetes&lt;/h3&gt;
&lt;p&gt;One of the most powerful features of Kubernetes is its ability to automate the deployment of applications. Traditionally, deploying an application to a cloud environment involves manually provisioning servers, configuring networking, and installing dependencies. Kubernetes eliminates much of this manual effort by using containers as the foundation for deploying applications. Containers encapsulate an application and its dependencies, ensuring that the application runs consistently across various environments, from local development to production in the cloud.&lt;/p&gt;
&lt;p&gt;In Kubernetes, deployments are defined using declarative configuration files, typically written in YAML or JSON. These configuration files describe the desired state of the application, including the number of replicas, storage requirements, and networking policies. Kubernetes then works to ensure that the application is deployed according to the defined specifications, automatically handling the provisioning of resources and setting up the necessary services to make the application accessible to users.&lt;/p&gt;
&lt;p&gt;The declarative nature of Kubernetes means that developers can version control their application’s infrastructure. If an update is made to the configuration, Kubernetes automatically adjusts the system to match the desired state, whether that’s adding more replicas or rolling back to a previous version. This results in faster, more reliable deployments.&lt;/p&gt;
&lt;h3 id=&quot;scaling-applications-automatically-with-kubernetes&quot;&gt;Scaling Applications Automatically with Kubernetes&lt;/h3&gt;
&lt;p&gt;Scaling is one of the key challenges faced when managing cloud applications, especially as the number of users fluctuates. Kubernetes excels in automatic scaling, providing both horizontal and vertical scaling mechanisms for applications. Horizontal scaling is the process of increasing or decreasing the number of application instances (pods) to match the demand. Kubernetes can scale your application based on a variety of metrics, such as CPU usage, memory usage, or custom metrics that you define.&lt;/p&gt;
&lt;p&gt;The Kubernetes Horizontal Pod Autoscaler (HPA) is a built-in feature that automatically adjusts the number of pods running in a deployment based on real-time metrics. For example, if the CPU usage of a pod exceeds a threshold, the HPA can spin up additional replicas to distribute the load. Conversely, when demand decreases, Kubernetes will scale down the number of replicas to save resources. This elasticity ensures that resources are used efficiently, while maintaining optimal performance under varying traffic loads.&lt;/p&gt;
&lt;p&gt;In addition to HPA, Kubernetes also supports **Cluster Autoscaling**. This feature allows Kubernetes to automatically scale the underlying infrastructure by adding or removing nodes (virtual machines) in response to resource demands. This is particularly useful when running workloads in a cloud environment, where infrastructure scaling can be automated based on predefined policies. Kubernetes can add more nodes when there are too many pending pods or remove nodes when there is excess capacity.&lt;/p&gt;
&lt;h3 id=&quot;self-healing-and-fault-tolerance-in-kubernetes&quot;&gt;Self-Healing and Fault Tolerance in Kubernetes&lt;/h3&gt;
&lt;p&gt;Cloud applications need to be highly available and resilient to failures. Kubernetes helps ensure that applications are self-healing and fault-tolerant by continuously monitoring the health of deployed services. When an application or service experiences an issue, Kubernetes automatically takes corrective action to restore the desired state.&lt;/p&gt;
&lt;p&gt;For example, if a pod crashes due to an error or becomes unresponsive, Kubernetes will automatically restart it or replace it with a new pod. This process is transparent to users, who experience minimal disruptions. Additionally, Kubernetes supports the concept of “replicas” where multiple instances of an application are run simultaneously across different nodes, ensuring that the application remains available even if one of the instances fails.&lt;/p&gt;
&lt;p&gt;Kubernetes also performs regular health checks using readiness and liveness probes. A readiness probe checks if a container is ready to accept traffic, while a liveness probe checks if the container is still running. If a liveness probe fails, Kubernetes will automatically restart the container, ensuring that unhealthy services are quickly replaced with healthy ones.&lt;/p&gt;
&lt;h3 id=&quot;service-discovery-and-load-balancing-in-kubernetes&quot;&gt;Service Discovery and Load Balancing in Kubernetes&lt;/h3&gt;
&lt;p&gt;In modern cloud applications, services often need to communicate with one another. Kubernetes simplifies service discovery by providing an internal DNS-based service discovery system. Every service within a Kubernetes cluster is automatically assigned a DNS name, allowing other services to connect to it by using its service name, rather than hardcoding IP addresses. This dynamic service discovery makes it easy to update or replace services without disrupting the entire application.&lt;/p&gt;
&lt;p&gt;Kubernetes also provides built-in load balancing. When users or other services send traffic to an application, Kubernetes automatically distributes that traffic across all the healthy instances (pods) of the service, ensuring that no single instance is overloaded. This load balancing mechanism helps achieve high availability and ensures that resources are used effectively, providing a smooth user experience even under heavy traffic conditions.&lt;/p&gt;
&lt;h3 id=&quot;configuring-and-managing-cloud-environments-with-kubernetes&quot;&gt;Configuring and Managing Cloud Environments with Kubernetes&lt;/h3&gt;
&lt;p&gt;Managing different environments in the cloud can be a complex task, especially as the number of services and applications grows. Kubernetes simplifies this by using namespaces, which allow you to isolate resources within a cluster. This makes it easy to manage multiple environments, such as development, staging, and production, all within a single cluster. Each environment can have its own set of resources, configurations, and access controls, while still sharing the underlying infrastructure.&lt;/p&gt;
&lt;p&gt;Additionally, Kubernetes provides the ability to manage configuration data and sensitive information using ConfigMaps and Secrets. ConfigMaps store non-sensitive configuration data, such as environment variables or configuration files, while Secrets store sensitive data, such as passwords or API keys. These resources can be injected into applications at runtime, making it easier to manage environment-specific configurations without having to modify application code.&lt;/p&gt;
&lt;h3 id=&quot;integrating-kubernetes-with-ci-cd-pipelines&quot;&gt;Integrating Kubernetes with CI/CD Pipelines&lt;/h3&gt;
&lt;p&gt;Continuous integration and continuous deployment (CI/CD) practices are critical for modern software development. Kubernetes integrates seamlessly with CI/CD pipelines, enabling automated deployment of containerized applications as new code is pushed to version control systems.&lt;/p&gt;
&lt;p&gt;By integrating Kubernetes with CI/CD tools like Jenkins, GitLab CI, or CircleCI, developers can create automated workflows that deploy new versions of an application to the Kubernetes cluster whenever new changes are made. This enables faster feedback loops, improved code quality, and more frequent releases. Kubernetes helps automate the entire process, from building containers to deploying them to production, ensuring consistency and reliability in application delivery.&lt;/p&gt;
&lt;h3 id=&quot;conclusion-2&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Kubernetes is a powerful tool for automating the deployment, scaling, and management of containerized applications in the cloud. By leveraging its robust features, such as self-healing, auto-scaling, service discovery, and CI/CD integration, organizations can achieve greater efficiency, reliability, and flexibility in their cloud environments. Kubernetes empowers developers to focus on building applications while leaving the complexities of infrastructure management to the platform.&lt;/p&gt;
&lt;p&gt;Whether you're deploying simple microservices or large-scale cloud applications, Kubernetes helps ensure that your applications are always available, scalable, and resilient, providing a smooth and reliable experience for both developers and users alike.&lt;/p&gt;
</description>
<category>Cloud Computing</category>
<guid isPermaLink="true">https://coderlegion.com/1460/how-kubernetes-simplifies-cloud-application-deployment-scaling-and-management</guid>
<pubDate>Fri, 14 Mar 2025 04:29:22 +0000</pubDate>
</item>
<item>
<title>Important Concept In Cloud Computing.</title>
<link>https://coderlegion.com/1436/important-concept-in-cloud-computing</link>
<description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Important Concept In Cloud Computing&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is Cloud Computing&lt;/strong&gt;&lt;br&gt;
Cloud computing is providing computing services which include servers, storage, software, networking over the internet to provide faster innovation and flexible resources.&lt;br&gt;
Instead of storing files on a storage device or hard drive, a user can save them on the cloud making it possible to access the files from anywhere as long as there is access to the internet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Models of Cloud Computing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Public cloud&lt;/strong&gt;: this cloud computing is open to the general public and is owned by a third party provider.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Private cloud&lt;/strong&gt;: this cloud computing is provisioned and managed within an organizations premises.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hybrid cloud&lt;/strong&gt;: this cloud computing combines public and private cloud services which allows data and application to be shared between them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is virtualization&lt;/strong&gt;&lt;br&gt;
Virtualization in cloud computing is a technology that allows multiple virtual machines (VMs) to run on a single physical machine or host by simulating hardware components like processors, memory and storage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Types of Virtualization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Server Virtualization&lt;/strong&gt;: this is also known as hardware virtualization and is most common type of virtualization in cloud computing. It can also partition physical server into multiple virtual machines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Desktop virtualization&lt;/strong&gt;: it allows users simulate a workstaion load to access a desktop from a connected device.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Network virtualization&lt;/strong&gt;: can be assigned to a specific device or server and can also combine network resources into separate channels.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is scalability&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Scalability in cloud computing is the ability of a cloud system to increase or decrease its resources and capacity to match changing business needs. Cloud scalability can either be flexible (it allows users to quickly add or remove resources as needed, providing adaptability to fluctuating workloads) or cost efficiency (it help optimize costs by only paying for the resource actually used).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is Agility&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Agility in cloud computing is the ability of an organization to quickly respond to changing business needs, opportunities by rapidly deploying, scaling and managing cloud based resources and applications. It also means being able to respond fast to new challenges through the use of cloud technology.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Services that Enables Agility&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Infrastructure as a service(IaaS) provides scalable infrastructure resources such as servers, storage, and networking.&lt;/p&gt;
&lt;p&gt;Platform as a Service(PaaS) offers scalable platform for developing, running and managing applications.&lt;/p&gt;
&lt;p&gt;Software as a Service(SaaS) provides scalable software applications with automatic updates and maintenance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is High Availability&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;High availability in cloud computing refers to the ability of a cloud system to ensure that applications, services and data are accessible and usable at all times with minimal downtime or disruption. It aims to maintain a high level of uptime by distributing resources across multiple locations and automatically switching to backups in case of failures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Benefits of High Availability in Cloud Computing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Improves user experience: users can access applications and services at all times with minimal disruption.&lt;/p&gt;
&lt;p&gt;Increase productivity: businesses and companies can maintain operations and productivity even in the event of hardware or software failures.&lt;/p&gt;
&lt;p&gt;Enhanced reputation: high availability demonstrates a commitment to reliability and customer satisfaction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is Fault Tolerant&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Fault tolerance in cloud computing is the ability of a cloud system to detect, recover from and continue operating despite hardware or software failures or disruption. Essentially the system can withstand failures and keep running smoothly.&lt;br&gt;
High availability, reduce downtime, improve reliability and increase customer satisfaction are all benefits of fault tolerance in cloud computing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is Global Reach&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Global reach in cloud computing refers to the ability of a cloud provider to deliver cloud services and applications to users anywhere in the world regardless of geographical location. Essentially, it means a cloud service can be accessed from anywhere with an internet connection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Characteristics of Global Reach in Cloud Computing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worldwide availability&lt;/strong&gt;: cloud service are available to users in multiple regions and countries.&lt;br&gt;
High availability: cloud services are designed to be always on with minimal downtime or disruption.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: cloud services can scale to meet the needs of a global user base.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low latency&lt;/strong&gt;: cloud services are delivered with minimal delay ensuring fast and responsive performance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the Difference Between Elasticity and Scalability&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In cloud computing, elasticity means the ability of a cloud system to automatically adjust its resources to match changing workload demands without manual intervention while scalability means the capacity to increase or decrease resources (e. g, computer power, storage or networking) to match changing workload demands.&lt;/p&gt;
</description>
<category>Java</category>
<guid isPermaLink="true">https://coderlegion.com/1436/important-concept-in-cloud-computing</guid>
<pubDate>Wed, 12 Mar 2025 09:06:32 +0000</pubDate>
</item>
<item>
<title>Securing ASGI Server with AWS Cognito</title>
<link>https://coderlegion.com/1187/securing-asgi-server-with-aws-cognito</link>
<description>&lt;h2 id=&quot;introduction-2&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I published an article on hash node a couple weeks ago titled: [Deploying Complete Serverless API with any containerised Python ASGI Framework on AWS Lambda, API][1] &lt;/p&gt;
&lt;p&gt;I figured I needed to add a logical next step to securing the api. I was also partly inspired by the course by Steven Marek towards AWS Solutions Architect Certification, which I'm studying.&lt;/p&gt;
&lt;h3 id=&quot;-src-code&quot;&gt;/src_code&lt;/h3&gt;
&lt;p&gt;The GitHub code repo for this project is here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/652-Animashaun/blog-serverless.git&quot;&gt;https://github.com/652-Animashaun/blog-serverless.git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Its written in Python - FastAPI, deployed to AWS Lambda, then put an API Gateway in front to route client requests to appropriate endpoints. That's it you're all caught up. &lt;/p&gt;
&lt;p&gt;While code example used here is Fast API framework, I implore you the implementation discussed is python framework agnostic. Come on I'll show you.&lt;/p&gt;
&lt;h2 id=&quot;what-is-aws-cognito-&quot;&gt;What is AWS Cognito?&lt;/h2&gt;
&lt;p&gt;I must admit the AWS Cognito documentation gave me the run around. I spent way more time than I thought I should implementing this mechanism. I'm not all that new to JWT authentication. I've implemented mechanisms using the OAuth before. &lt;br&gt;
Anyways I’ve done the work, gone through the belly of the beast that is the AWS documentation, so that you won’t have to. I’ll try to cut out the fluff.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Amazon Cognito is an identity platform for web and mobile apps. It’s a&lt;br&gt;
user directory, an authentication server, and an authorization service&lt;br&gt;
for OAuth 2.0 access tokens and AWS credentials. With Amazon Cognito,&lt;br&gt;
you can authenticate and authorize users from the built-in user&lt;br&gt;
directory, from your enterprise directory, and from consumer identity&lt;br&gt;
providers like Google and Facebook.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So off the bat, we can already see several use cases for the AWS Cognito service. For now we want a simple authentication process, i.e user is served a login page to enter credentials, redirected to homepage on successful login, or presented a register page to create an account get OTP via provided email to verify ID. They get a token (JWT) which is presented to the server’s gate keeper for some resource access, in this case an API endpoint.&lt;br&gt;
What is happening under the hood is simple enough too. Well relatively, if you compare to implementing the mechanism from scratch.&lt;/p&gt;
&lt;h2 id=&quot;user-authentication-with-cognito-user-pools&quot;&gt;User authentication with Cognito user pools&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Login &amp;amp; Register Pages - Cognito&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While you can build and customise to your liking, but AWS Cognito comes with a ready-to-use login and register pages where you can just redirect users to, you’ll also provide a redirect url where the returned token can be processed to authorize user.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sending &amp;amp; Verifying OTP - Cognito&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Usually one would be inclined to use a service like SES or SNS on AWS or Twilio, but you’ll have to manually call or implement the mechanism from the server side. AWS cognito takes care of this out of the box.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Encoding &amp;amp; Signing Tokens - Cognito&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cognito also takes care of encoding tokens. RS256 or HS256 base64encoding, also add features like expiry, a refresh token if you want. A Json Web Token  contains 3 parts header, payload and a signature. Payload is where the user identity like email, username are returned. Cognito returns 3 tokens, the access_token, id_token and a refresh_token, more about that later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Decoding and Granting Access - Server&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When a token is returned to the server, the receiver of the JWT verifies the signature using the secret key or the public key. And maybe go a step further and include it in request header so that subsequent requests can bear the authorisation token.&lt;/p&gt;
&lt;p&gt;Look, point is Cognito takes a lot of manual implementation out of the developers hand. I’m sold!.&lt;/p&gt;
&lt;p&gt;Let's dive right into the AWS Cognito dashboard create a user pool in 3 steps.&lt;/p&gt;
&lt;h3 id=&quot;creating-and-configuring-a-user-pool&quot;&gt;Creating and configuring a user pool&lt;/h3&gt;
&lt;p&gt;Select Create user pool from the User pools menu, or select Get started for free in less than five minutes.&lt;/p&gt;
&lt;p&gt;Under Define your application, I’m choosing “traditional web application” you can choose the Application type that best fits the application scenario that you want to create authentication and authorization services for.&lt;/p&gt;
&lt;p&gt;In Name your application, enter a descriptive name or proceed with the default name.&lt;/p&gt;
&lt;p&gt;You must make some basic choices under Configure options that support settings that you can't change after you create your user pool. For this use case I’m selecting username, email and full name.&lt;/p&gt;
&lt;p&gt;Add a return url on the server that handles payload receipts and process the payload. in this case mine is &lt;a rel=&quot;nofollow&quot; href=&quot;http://localhost:8000/api/v1/users/token&quot;&gt;http://localhost:8000/api/v1/users/token&lt;/a&gt; for development and testing purposes. You can add more redirect url options. Once you're ready to update lambda function with local changes, we'll be sure to add another return url , this time with the API Gateway stage endpoint. Else we get some funny error &lt;code&gt;client_id redirect_uri mismatch&lt;/code&gt;. Hit create.&lt;/p&gt;
&lt;h2 id=&quot;web-app-server&quot;&gt;Web App Server&lt;/h2&gt;
&lt;p&gt;Lets take a look in the user pool thats just been created:&lt;/p&gt;
&lt;p&gt;Under recommendations you should go ahead and click “setup your web app”.&lt;/p&gt;
&lt;p&gt;AWS was kind enough to show some code examples for different languages.&lt;/p&gt;
&lt;p&gt;Selecting python will give you a quick preview how things would look like:&lt;/p&gt;
&lt;p&gt;As shown, the framework in Cognitgo example is Flask, but it doesnt matter, that about how we’ll be implementing ours. I can already see that to start with I’ll need a /login endpoints and an /authorize endpoints at a minimum.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/app.api.enpoints.users.py&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import jwt
from pprint import pprint
from fastapi import APIRouter, HTTPException, status, Depends
from starlette.requests import Request
from app.utils.auth import oauth, verify_token
from starlette.responses import RedirectResponse

router = APIRouter()

@router.get(&quot;/login&quot;)
async def login(request: Request):
    return await oauth.oidc.authorize_redirect(request, &quot;http://localhost:8000/api/v1/users/token&quot;)

@router.get(&quot;/token&quot;)
async def authorize(request: Request):
    payload = await oauth.oidc.authorize_access_token(request)
    token = payload[&quot;id_token&quot;]
    res = await verify_token(token)
    user = payload[&quot;userinfo&quot;]
    return token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These endpoints aren’t doing much heavy lifting. &lt;code&gt;/login&lt;/code&gt; simply calls on &lt;code&gt;oidc.authorize_redirect()&lt;/code&gt; provided by the oauth import from utils where OAuth was instanced and passed to oauth, more on that subsequently. It takes a request and a redirect url to process response.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;async def authorize(request)&lt;/code&gt; will receive a get request on signing completion on cognito, with a json payload that looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ &quot;id_token&quot;: &quot;eyJraWQiOiJ3ekxUT1lrNVR....&quot;, &quot;access_token&quot;: &quot;eyJraWQiOiI3b0pqeFhY...&quot;, &quot;refresh_token&quot;: &quot;eyJjdHkiOiJKV1QiLC....&quot;, &quot;expires_in&quot;: 3600, &quot;token_type&quot;: &quot;Bearer&quot;, &quot;expires_at&quot;: 1738976151, &quot;userinfo&quot;: { &quot;at_hash&quot;: &quot;aYWSJq...&quot;, &quot;sub&quot;: &quot;b4d8e428-f091-7040-80a5-f2&quot;, &quot;email_verified&quot;: true, &quot;iss&quot;: &quot;https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ftTN1aEr4&quot;, &quot;cognito:username&quot;: &quot;shaun&quot;, &quot;nonce&quot;: &quot;SYqZdIip5wBjjI10983&quot;, &quot;origin_jti&quot;: &quot;edc6ytb3c-4870-4979-8672-7d9a261ff471&quot;, &quot;aud&quot;: &quot;47re0a7e8l43ok719rtqcqnjih&quot;, &quot;token_use&quot;: &quot;id&quot;, &quot;auth_time&quot;: 1738972551, &quot;exp&quot;: 1738976151, &quot;iat&quot;: 1738972551, &quot;jti&quot;: &quot;f20cf2a4-5c3f-44f9-8d0b-919816d41f38&quot;, &quot;email&quot;: &quot;*Emails are not allowed*&quot; } }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As seen above we can already grab userinfo and quickly see the user ID. But theoretically some skilled man in the middle can provide their own ID, I dont know how it's done, the main thing is it is possible. And I like to preempt that, I want to do a quick verify.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import jwt
from jwt import PyJWKClient
from authlib.integrations.starlette_client import OAuth
from fastapi import APIRouter, HTTPException, status, Depends, Security, HTTPException
from datetime import date, datetime, time, timedelta, timezone
from typing import Annotated
from app.models.users import User
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials, OAuth2PasswordBearer
from starlette.responses import RedirectResponse
from starlette.requests import Request


signin_url = 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ftTN1aEr4/.well-known/jwks.json'
security = HTTPBearer(auto_error=False)

CLIENT_SECRET = os.environ[&quot;CLIENT_SECRET&quot;]
CLIENT_ID = os.environ[&quot;CLIENT_ID&quot;]
ISSUER = &quot;https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ftTN1aEr4&quot;


oauth = OAuth()
oauth.register(
  name='oidc',
  authority=ISSUER,
  client_id=CLIENT_ID,
  client_secret=CLIENT_SECRET,
  server_metadata_url='https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ftTN1aEr4/.well-known/openid-configuration',
  client_kwargs={'scope': 'email openid phone'}
)

async def verify_token(token:str)-&amp;gt; User:
jwks_client = PyJWKClient(signin_url)

try:
signing_key = jwks_client.get_signing_key_from_jwt(token)
payload = jwt.decode(
token,
signing_key,
audience=CLIENT_ID,
options={&quot;verify_exp&quot;: True},
algorithms=[&quot;RS256&quot;],
)
user = User(username=payload[&quot;cognito:username&quot;], email=payload[&quot;email&quot;], access_token=token)
return User
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail=&quot;Token has expired&quot;)
except jwt.InvalidTokenError as e:
raise HTTPException(status_code=403, detail=&quot;Invalid token&quot;)

async def get_current_user(credentials: Annotated[HTTPAuthorizationCredentials, Security(security)]):
if not credentials:
return False
try:
return await verify_token(credentials.credentials)
except HTTPException:
return False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lets do a quick run through the code:&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;singing_url&lt;/code&gt; is provided by congnito in the userpool dashboard, this an endpoint provided by Cognito. At the back of it is a json_body of keys used to sign the token. More on that subsequently.&lt;/p&gt;
&lt;p&gt;In FastApi using Oauth2 as dependency is through the &lt;code&gt;Security()&lt;/code&gt; class provided. You can read more about the stuff here. TLDR &lt;code&gt;fastapi.security.HTTPBearer&lt;/code&gt; is one of the tools provided to use called as a dependable during visit of protect endpoints. It’s use case is for bearer token authentication. &lt;code&gt;auto_error=False&lt;/code&gt; because as per docs, by default, if the HTTP Bearer token is not provided (in an Authorization header), it'll automatically cancel the request and send the client an error. I don’t want that, I want to catch that and redirect to login so user can try challenge again.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HTTPBearer&lt;/code&gt; returns an object &lt;code&gt;HTTPAuthorizationCredentials&lt;/code&gt; which I believe is received via the request header and provides it to the application.&lt;/p&gt;
&lt;p&gt;Then we just shamelessly copied the boiler plate code on cognito recommendation page to instantiate &lt;code&gt;Oauth.register()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;async def verify_token()&lt;/code&gt; will take in a token, first it want’s to retrieve signing keys from the signing_url using the python module PyJWKClient class provided by JWT module. Next it calls jwt.decode(), takes the token, signing_key and a couple other keyword arguments. The decoded payload contains a dictionary with several user identifying information, but it’ll go ahead, returning username and email.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;async def get_current_user()&lt;/code&gt; where the first injection takes place. I’ve provided the &lt;code&gt;HTTPAuthorizationCredentials&lt;/code&gt; as HTTPBearer security which would try to retrieve the automaticall from the incoming request header the Bearer Authorization this is where the token is expected to be for an authenticated request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/app.api.endpoints.posts.py&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To show the authentication mechanism actually works we have to create an endpoint that is protected:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from fastapi import APIRouter, Depends, HTTPException, status
from typing_extensions import Annotated
from app.utils.auth import oauth, verify_token, get_current_user
from app.models.users import User
from starlette.requests import Request
from starlette.responses import RedirectResponse

router = APIRouter()

@router.get(&quot;/&quot;)
async def all_posts(current_user: Annotated[User, Depends(get_current_user)]):
    if not current_user:
        return RedirectResponse(url=&quot;/api/v1/users/login&quot;)
    print(&quot;current_user&quot;, current_user)
    return {&quot;Welcome&quot;: &quot;Shaun's Blog&quot;, &quot;user&quot;: current_user}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty straightforward right? &lt;code&gt;async def all_posts&lt;/code&gt; depends on &lt;code&gt;get_current_user&lt;/code&gt; which in turns returns a user object  or None, in which case user will be redirected to /login.&lt;/p&gt;
&lt;p&gt;Oh did I mention and AWS Cognito is free for 10K monthly active users. Check it out:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Amazon Cognito Essentials and Lite have a free tier. The free tier&lt;br&gt;
does not automatically expire at the end of your 12-month AWS Free&lt;br&gt;
Tier term, and it is available to both existing and new AWS customers&lt;br&gt;
indefinitely. Please note - the free tier pricing isn’t available in&lt;br&gt;
the AWS GovCloud (US-West) region.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For users who sign in directly via Amazon Cognito or through a social identity provider, Amazon Cognito user pools has a free tier of&lt;br&gt;
10,000 monthly active user (MAU) per month per account or per AWS&lt;br&gt;
organization. This free tier is applicable for customers that&lt;br&gt;
configure their user pools to either the Lite or Essentials tier.&lt;br&gt;
There is no free tier for the Plus tier.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Stick around next one up is integrating social ID providers like google social media accounts. Would be fun.&lt;/p&gt;
&lt;p&gt;One more thing, remember when you push changes to lambda, add the api gateway endpoint version of your /token (authorise) to the list of return urls in the Cognito UserPool dashboard. This might be the cause of client_id redirect_uri mismatch error, watch out.&lt;/p&gt;
&lt;h3 id=&quot;references-&quot;&gt;References:&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-user-pools-application.html&quot;&gt;https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-user-pools-application.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://pyjwt.readthedocs.io/en/stable/installation.html&quot;&gt;https://pyjwt.readthedocs.io/en/stable/installation.html&lt;/a&gt;&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/1187/securing-asgi-server-with-aws-cognito</guid>
<pubDate>Thu, 20 Feb 2025 19:02:49 +0000</pubDate>
</item>
<item>
<title>Cloud Fundamentals</title>
<link>https://coderlegion.com/1104/cloud-fundamentals</link>
<description>&lt;h2 id=&quot;what-is-cloud-computing&quot;&gt;What is Cloud Computing&lt;/h2&gt;
&lt;p&gt;Cloud computing is a method of delivering computing services over the Internet. This enables faster computing, flexible resources, and easy scaling.&lt;/p&gt;
&lt;h2 id=&quot;cloud-models&quot;&gt;Cloud Models&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Public Cloud&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Private Cloud&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hybrid Cloud&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;1-public-cloud&quot;&gt;1. Public Cloud&lt;/h2&gt;
&lt;p&gt;The public cloud is owned by cloud service providers. This cloud service provider provides resources and services to multiple users and organizations. These users or organizations access the network over the internet.&lt;/p&gt;
&lt;p&gt;There are no deep technical skills required to operate the public cloud. As this is a public cloud there services are available to everyone(public).&lt;/p&gt;
&lt;p&gt;No capital expenditure is required to scale up the resources when required.&lt;/p&gt;
&lt;p&gt;Applications can be quickly provisioned and de-provisioned.&lt;/p&gt;
&lt;p&gt;Users or Organizations pay only for what they use.&lt;/p&gt;
&lt;h2 id=&quot;2-private-cloud&quot;&gt;2. Private Cloud&lt;/h2&gt;
&lt;p&gt;The private cloud is owned by an organization. Organizations create a cloud environment in their datacenter.&lt;/p&gt;
&lt;p&gt;The organization is responsible for everything from purchasing the hardware to the updates to networking and security. The users outside of the organization cannot access the data or services of the private cloud.&lt;/p&gt;
&lt;p&gt;Hardware must be purchased for start-up and maintenance.&lt;/p&gt;
&lt;p&gt;Organizations have complete control over resources and security.&lt;/p&gt;
&lt;p&gt;Organizations are responsible for hardware maintenance and updates.&lt;/p&gt;
&lt;h2 id=&quot;3-hybrid-cloud&quot;&gt;3. Hybrid Cloud&lt;/h2&gt;
&lt;p&gt;As you might guess, a Hybrid cloud is the combination of public and private cloud to allow applications to run in the most appropriate location.&lt;/p&gt;
&lt;p&gt;The organization decides what resources to put in the public cloud and what resources to put in the private cloud.&lt;/p&gt;
&lt;p&gt;Deep technical skills are required to maintain a private cloud and also ensure both clouds can operate together efficiently.&lt;/p&gt;
&lt;p&gt;There is flexibility about what to be in public and what to be in a private cloud.&lt;/p&gt;
&lt;p&gt;Provides the most flexibility to the organization.&lt;/p&gt;
&lt;p&gt;Organizations determine where to run their applications.&lt;/p&gt;
&lt;p&gt;Organizations control security, compliance, or legal requirements.&lt;/p&gt;
&lt;h2 id=&quot;benefits-of-cloud&quot;&gt;Benefits of Cloud&lt;/h2&gt;
&lt;p&gt;The following are the biggest reasons &quot;Why customers are moving to the cloud?&quot;&lt;/p&gt;
&lt;p&gt;High availability&lt;/p&gt;
&lt;p&gt;Fault tolerance&lt;/p&gt;
&lt;p&gt;Scalability&lt;/p&gt;
&lt;p&gt;Elasticity&lt;/p&gt;
&lt;p&gt;Global reach&lt;/p&gt;
&lt;p&gt;Customer latency capabilities&lt;/p&gt;
&lt;p&gt;Agility&lt;/p&gt;
&lt;p&gt;Predictive cost considerations&lt;/p&gt;
&lt;h3 id=&quot;1-high-availability&quot;&gt;1. High availability&lt;/h3&gt;
&lt;p&gt;It is the availability to keep the resources up and running for long periods of time with very little downtime (negligible).&lt;/p&gt;
&lt;h3 id=&quot;2-fault-tolerance&quot;&gt;2. Fault tolerance&lt;/h3&gt;
&lt;p&gt;The ability to remain up and running, if a component or service has a failure and is no longer working. For example, some hardware failure in the machine.&lt;/p&gt;
&lt;h3 id=&quot;3-scalability&quot;&gt;3. Scalability&lt;/h3&gt;
&lt;p&gt;There are two types of scaling. They are: Horizontal Scaling and Vertical Scaling&lt;/p&gt;
&lt;p&gt;Horizontal Scaling (also called scaling out) is adding resources or servers or virtual machines as needed.&lt;/p&gt;
&lt;p&gt;Vertical Scaling (also called scaling up) is adding computing power, that is adding toexisting resources by adding more CPU, adding more memory.&lt;/p&gt;
&lt;h3 id=&quot;4-elasticity&quot;&gt;4. Elasticity&lt;/h3&gt;
&lt;p&gt;The ability to automatically increase or decrease resources as needed.&lt;/p&gt;
&lt;h3 id=&quot;5-global-reach&quot;&gt;5. Global reach&lt;/h3&gt;
&lt;p&gt;Accessing resources and adding resources around the world. like creating resources from anywhere to anywhere.&lt;/p&gt;
&lt;h3 id=&quot;6-customer-latency-capabilities&quot;&gt;6. Customer latency capabilities&lt;/h3&gt;
&lt;p&gt;User can be as close to our customers as possible to reduce latency for accessingtheir resources.&lt;/p&gt;
&lt;p&gt;Now with the cloud, with the global reach, we can put resources around the world. putting them as close to our customers as possible.&lt;/p&gt;
&lt;h3 id=&quot;7-agility&quot;&gt;7. Agility&lt;/h3&gt;
&lt;p&gt;The ability to quickly react to workload demands. like a sudden spike in traffic, allocate more resources. like down in traffic, deallocating resources.&lt;/p&gt;
&lt;h3 id=&quot;8-predictive-cost-considerations&quot;&gt;8. Predictive cost considerations&lt;/h3&gt;
&lt;p&gt;Almost every cloud service providers provide a calculator to calculate the estimated cost of the resources they what to use.&lt;/p&gt;
&lt;p&gt;So no surprise in the bills.&lt;/p&gt;
&lt;h2 id=&quot;cloud-expenditure-models&quot;&gt;Cloud Expenditure models&lt;/h2&gt;
&lt;p&gt;Capital Expenditure (CapEx)&lt;/p&gt;
&lt;p&gt;Operational Expenditure (OpEx)&lt;/p&gt;
&lt;h3 id=&quot;1-capital-expenditure-capex-&quot;&gt;1. Capital Expenditure (CapEx)&lt;/h3&gt;
&lt;p&gt;The up-front sending of money on physical infrastructure. That is when we what to create our own datacenter, we have to get budgets approved, buy or rent a space, get the physical resources, and network them together to build our own datacenter.&lt;/p&gt;
&lt;p&gt;The cost spent on Capital Expenditure reduces over time. As physical resources performance may reduce, may damage or become outdated.&lt;/p&gt;
&lt;p&gt;In the cloud, we don't need to do that.&lt;/p&gt;
&lt;h3 id=&quot;2-operational-expenditure-opex-&quot;&gt;2. Operational Expenditure (OpEx)&lt;/h3&gt;
&lt;p&gt;We spend as we needed. The spending and billing of services or products as needed. The Expenses are deducted in the same year and we are paying monthly or yearly for those expenses.&lt;/p&gt;
&lt;h2 id=&quot;consumption-based-model&quot;&gt;Consumption based model&lt;/h2&gt;
&lt;p&gt;Cloud service providers operate on the consumption-based model, which means the end-users only pay for the resources that they use.&lt;br&gt;
Think of it as our utility bill, we have a meter on it and we pay by what we actually used. Same thing for the cloud. We pay by what we actually use.&lt;/p&gt;
&lt;h3 id=&quot;advantages&quot;&gt;Advantages&lt;/h3&gt;
&lt;p&gt;Better cost prediction&lt;/p&gt;
&lt;p&gt;Prices for individual resources and services are provided&lt;/p&gt;
&lt;p&gt;Billing is based on actual usage&lt;/p&gt;
&lt;h3 id=&quot;cloud-services&quot;&gt;Cloud Services&lt;/h3&gt;
&lt;p&gt;Infrastructure-as-a-Service (IaaS)&lt;/p&gt;
&lt;p&gt;Platform-as-a-Service (PaaS)&lt;/p&gt;
&lt;p&gt;Software-as-a-Service (SaaS)&lt;/p&gt;
&lt;h3 id=&quot;1-infrastructure-as-a-service-iaas-&quot;&gt;1. Infrastructure-as-a-Service (IaaS)&lt;/h3&gt;
&lt;p&gt;Build pay-as-you-go IT infrastructure by renting servers, virtual machines, storage, networks, and operating systems from a cloud provider.&lt;/p&gt;
&lt;p&gt;IaaS is the most flexible cloud service. We can configure and manage hardware for our application.&lt;/p&gt;
&lt;p&gt;This flexibility helps in optimizing the application as per our needs as we have full access to hardware resources.&lt;/p&gt;
&lt;p&gt;User Manage: Data &amp;amp; Access, Application, Runtime, Operating System, Virtual Machines&lt;/p&gt;
&lt;p&gt;Cloud Service Provider Manage: Compute, Networking, Storage&lt;/p&gt;
&lt;p&gt;Example: Virtual Machines&lt;/p&gt;
&lt;h3 id=&quot;2-platform-as-a-service-paas-&quot;&gt;2. Platform-as-a-Service (PaaS)&lt;/h3&gt;
&lt;p&gt;Provides an environment for building, testing, and deploying software applications without focusing on managing underlying hardware/ infrastructure.&lt;/p&gt;
&lt;p&gt;They are responsible for managing servers, infrastructure, operating systems, Networks, Network firewalls, Network security, and even service configuration.&lt;/p&gt;
&lt;p&gt;This makes organizations more efficient and productive.&lt;/p&gt;
&lt;p&gt;Here we can focus on our application development rather than spending more time in hardware configuration, software configurations, etc.,&lt;/p&gt;
&lt;p&gt;User Manage: Data &amp;amp; Access, Application&lt;/p&gt;
&lt;p&gt;Cloud Service Provider Manage: Runtime, Operating System, Virtual Machines, Compute, Networking, Storage&lt;/p&gt;
&lt;p&gt;Example: App services or containers&lt;/p&gt;
&lt;h3 id=&quot;3-software-as-a-service-saas-&quot;&gt;3. Software-as-a-Service (SaaS)&lt;/h3&gt;
&lt;p&gt;Users connect to and use cloud-based apps over the internet. for example Google Suite, Google Drive, OneDrive, Google Docs, Google Sheets, Google Slides, etc.,&lt;/p&gt;
&lt;p&gt;It is basically like renting software monthly or yearly.&lt;/p&gt;
&lt;p&gt;The Cloud service providers manage everything else, the Servers, Networks, Operating Systems, Physical buildings, Infrastructure, Development Tools, and even hosted applications and apps.&lt;/p&gt;
&lt;p&gt;Users pay for the software they use on a subscription model.&lt;/p&gt;
&lt;p&gt;User Manage: Data &amp;amp; Access&lt;/p&gt;
&lt;p&gt;Cloud Service Provider Manage: Application, Runtime, Operating System, Virtual Machines, Compute, Networking, Storage&lt;/p&gt;
&lt;p&gt;Example: Microsoft Teams, Microsoft 365, Google Suite, Google Drive, OneDrive, Google Docs, Google Sheets, Google Slides, etc.,&lt;/p&gt;
&lt;p&gt;NOTE: WE CAN USE ANY COMBINATION OF THESE INFRASTRUCTURES&lt;/p&gt;
&lt;p&gt;Linkedin: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/khushi-dubey-6036a2305&quot;&gt;https://www.linkedin.com/in/khushi-dubey-6036a2305&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;thank-you-&quot;&gt;Thank you!&lt;/h3&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/1104/cloud-fundamentals</guid>
<pubDate>Mon, 17 Feb 2025 10:08:44 +0000</pubDate>
</item>
<item>
<title>Using Elastic Container Registry (ECR) as an image repository.</title>
<link>https://coderlegion.com/899/using-elastic-container-registry-ecr-as-an-image-repository</link>
<description>&lt;h2 id=&quot;introduction-3&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This article discusses using Elastic Container Registry (ECR) as an &lt;em&gt;image repository&lt;/em&gt;. AWS Elastic Container Registry is a fully managed container image registry service that Amazon Web Services (AWS) provides. It is used to store, manage, and deploy container images (Docker images) securely, making it an essential component of your containerized application development workflow.&lt;/p&gt;
&lt;h2 id=&quot;why-use-aws-ecr-&quot;&gt;Why Use AWS ECR?&lt;/h2&gt;
&lt;p&gt;Before diving into the setup, let’s understand why AWS ECR is a preferred choice over other container registries like Docker Hub, Google Container Registry (GCR), and Azure Container Registry (ACR).&lt;/p&gt;
&lt;h2 id=&quot;key-benefits-of-aws-ecr&quot;&gt;Key Benefits of AWS ECR&lt;/h2&gt;
&lt;p&gt;✔️ Fully Managed – No need to set up and maintain your own container registry. AWS handles scaling, security, and maintenance. &lt;br&gt;&lt;br&gt;
✔️ High Security – Supports IAM-based access controls and AWS KMS encryption for protecting images. &lt;br&gt;&lt;br&gt;
✔️ Deep Integration – Works seamlessly with AWS services like ECS, EKS, Lambda, and CodePipeline. &lt;br&gt;&lt;br&gt;
✔️ Automated Image Scanning – Identifies vulnerabilities in container images. &lt;br&gt;&lt;br&gt;
✔️ Lifecycle Policies – Automatically deletes old or unused images to save storage costs. &lt;br&gt;&lt;/p&gt;
&lt;h2 id=&quot;prerequisite&quot;&gt;Prerequisite&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Create an &lt;a rel=&quot;nofollow&quot; href=&quot;https://aws.amazon.com&quot;&gt;AWS account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.docker.com/desktop/setup/install/windows-install/&quot;&gt;Install docker&lt;/a&gt; on your local computer&lt;/li&gt;
&lt;li&gt;Install &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html&quot;&gt;AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Create an &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.aws.amazon.com/keyspaces/latest/devguide/create.keypair.html&quot;&gt;IAM user&lt;/a&gt; with an Access Key and Secret Access Key&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pushing-a-docker-image-to-ecr&quot;&gt;Pushing a Docker Image to ECR&lt;/h2&gt;
&lt;p&gt;After creating the repository, follow these steps to push your Docker image to AWS ECR.&lt;/p&gt;
&lt;h3 id=&quot;1-authenticate-docker-with-aws-ecr&quot;&gt;1. Authenticate Docker with AWS ECR&lt;/h3&gt;
&lt;p&gt;Run the following command to authenticate Docker with AWS ECR:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash

aws ecr get-login-password --region &amp;lt;your-region&amp;gt; | docker login --username AWS --password-stdin &amp;lt;aws-account-id&amp;gt;.dkr.ecr.&amp;lt;your-region&amp;gt;.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &amp;lt;your-region&amp;gt; (e.g., us-east-1) and &amp;lt;aws-account-id&amp;gt; with your actual AWS credentials.&lt;/p&gt;
&lt;p&gt; Note: If authentication fails, ensure your IAM user has the AmazonEC2ContainerRegistryFullAccess policy attached.&lt;/p&gt;
&lt;h3 id=&quot;2-build-the-docker-image&quot;&gt;2. Build the Docker Image&lt;/h3&gt;
&lt;p&gt;Navigate to your application’s directory and build a Docker image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash

docker build -t my-app .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will create a Docker image with the tag my-app.&lt;/p&gt;
&lt;h3 id=&quot;3-tag-the-image-for-aws-ecr&quot;&gt;3. Tag the Image for AWS ECR&lt;/h3&gt;
&lt;p&gt;Tag the Docker image to match your AWS ECR repository URL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash

docker tag my-app:latest &amp;lt;aws-account-id&amp;gt;.dkr.ecr.&amp;lt;your-region&amp;gt;.amazonaws.com/my-app-repo:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-push-the-image-to-ecr&quot;&gt;4. Push the Image to ECR&lt;/h3&gt;
&lt;p&gt;Finally, push the tagged image to the ECR repository:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash

docker push &amp;lt;aws-account-id&amp;gt;.dkr.ecr.&amp;lt;your-region&amp;gt;.amazonaws.com/my-app-repo:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once completed, your image will be available in AWS ECR for deployment.&lt;/p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Log in to your AWS dashboard, search for ECR, and click on it&lt;/li&gt;
&lt;li&gt;Create a repository -- note that the default repository for ECR is private. &lt;/li&gt;
&lt;li&gt;Provide a name for the repository, and click Create.&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=12455849816125894295&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=1593461852952190563&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Once the repository is created, click on the &quot;view push command&quot;&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=7839665018350358544&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow the commands to push your image to the created repository.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Authenticate the docker client&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=16745125154522609754&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build the image&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=7927730434954447450&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tag the image&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=17703486542633836686&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Push the image&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=7779946183066627708&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15524272404646242863&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;troubleshooting-common-issues&quot;&gt;Troubleshooting Common Issues&lt;/h2&gt;
&lt;p&gt;❌ Error: no basic auth credentials&lt;br&gt;
Solution: Run aws ecr get-login-password and ensure your IAM user has AmazonEC2ContainerRegistryFullAccess.&lt;/p&gt;
&lt;p&gt;❌ Error: AccessDeniedException&lt;br&gt;
Solution: Verify that your IAM role has the correct ECR permissions (ecr:PutImage, ecr:GetAuthorizationToken).&lt;/p&gt;
&lt;p&gt;❌ Docker Push Fails with 403 Error&lt;br&gt;
Solution: Ensure your AWS region and repository URL are correct.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-3&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AWS Elastic Container Registry (ECR) provides a secure, scalable, and fully managed solution for storing and managing container images. By following this guide, you can:&lt;/p&gt;
&lt;p&gt;✅ Set up an ECR repository &lt;br&gt;&lt;br&gt;
✅ Push and manage Docker images &lt;br&gt;&lt;br&gt;
✅ Integrate ECR with ECS, EKS, and AWS Lambda &lt;br&gt;&lt;br&gt;
✅ Automate deployments using AWS CodePipeline &lt;br&gt;&lt;/p&gt;
&lt;p&gt;With AWS ECR, managing containerized applications becomes seamless and efficient. &lt;/p&gt;
</description>
<category>azure</category>
<guid isPermaLink="true">https://coderlegion.com/899/using-elastic-container-registry-ecr-as-an-image-repository</guid>
<pubDate>Mon, 03 Feb 2025 09:07:04 +0000</pubDate>
</item>
<item>
<title>Differentiating Network Architecture: An Overview of 2-Tier and 3-Tier Network Architectures</title>
<link>https://coderlegion.com/864/differentiating-network-architecture-an-overview-tier-and-tier-network-architectures</link>
<description>&lt;p&gt;Hi Everyone, Today, we will explore network architectures, how companies utilize them, and the significance of these architectures in today's digital landscape. We will also highlight some major companies that implement these architectures, discuss the differences and similarities between traditional and modern architectures, and delve into the various types of network architectures.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ais-mn.com/wp-content/uploads/wireless-communication-cityscape-background.jpg&quot; alt=&quot;imgone&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is a Network?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A network is a collection of interconnected devices that communicate with each other to share resources and information. These devices can include computers, servers, switches, routers, and other hardware components. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is Network Architecture?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Network architecture refers to the structural design of a network, defining how devices, systems, and protocols interact to facilitate data transfer. It acts as a blueprint for organizing components like switches, routers, and servers to ensure efficient communication. Effective network architecture is vital for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Supporting growing demands. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt;: Ensuring low latency and high throughput.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Protecting data during transmission.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The 2-Tier Architecture: A Simple Cafe Setup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Imagine walking into a cafe where everything is straightforward. You place your order at the counter (the client), and the person behind the counter(the server) prepares your drink. This is the essence of 2-Tier Architecture, which consists of two layers: the &lt;strong&gt;Access Layer&lt;/strong&gt; (client tier) and the &lt;strong&gt;Core/Distribution Layer&lt;/strong&gt; (server tier).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=12644994726320639520&quot; alt=&quot;tier2&quot;&gt;&lt;/p&gt;
&lt;p&gt;Two-tier architecture, or client-server architecture, divides an application into two layers: the Client Tier and the Server Tier. The client tier handles the user interface and sends requests, while the server tier processes these requests, executes business logic, and interacts with the database. Communication occurs over a network using protocols like HTTP or TCP/IP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Advantages of 2-Tier Architecture&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: Easy to design, implement, and manage due to fewer components.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost-Effectiveness&lt;/strong&gt;: Requires less hardware, ideal for small businesses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low Latency&lt;/strong&gt;: Direct communication between clients and servers reduces delays.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations of 2-Tier Architecture&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scalability Issues&lt;/strong&gt;: Performance degrades as more clients connect to the server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single Point of Failure&lt;/strong&gt;: If the server fails, all client requests are disrupted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited Traffic Management&lt;/strong&gt;: Lacks advanced features like VLAN routing or QoS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The 3-Tier Architecture: A Corporate Office Setup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Imagine you entered a corporate office where tasks are divided among departments. You approach the front desk to make a request (the Access Layer), the management team processes your request and coordinates the work (the Distribution Layer), and all critical data is securely stored in the archive room (the Core Layer). This is the essence of 3-Tier Architecture, which consists of three layers: &lt;strong&gt;the Access Layer, the Distribution Layer, and the Core Layer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=16246059131023676144&quot; alt=&quot;tier3&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Three Layers of 3-Tier Architecture&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access Layer:&lt;/strong&gt; This layer is the entry point for users to interact with the system, much like the front desk in an office. In networking, this layer connects end-user devices to the network using switches or wireless access points.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distribution Layer:&lt;/strong&gt; Acting as the management team, this layer processes requests received from the Access Layer and determines how to handle them. In networking terms, it uses multi-layer switches or routers to manage traffic and apply filtering or routing rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core Layer:&lt;/strong&gt; The Core Layer is like the archive room where all important data is stored securely. It handles &lt;strong&gt;high-speed data&lt;/strong&gt; transfers and ensures reliable access to databases or storage systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Advantages of 3-Tier Architecture&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Separation of Responsibilities&lt;/strong&gt;: Each layer has a distinct role, making it easier to maintain and troubleshoot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; Each layer can be scaled independently based on demand, ensuring smooth performance during high traffic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Efficiency:&lt;/strong&gt; The Distribution Layer optimizes traffic flow and reduces bottlenecks by managing requests intelligently.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations of 3-Tier Architecture&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Designing and managing three separate layers requires expertise and careful planning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Higher Costs&lt;/strong&gt;: Additional infrastructure for each layer increases hardware and operational costs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2-Tier vs 3-Tier&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While 2-Tier Architecture directly connects clients to servers (or devices to a network), 3-Tier Architecture introduces a middle Distribution Layer that optimizes performance and scalability. For example:&lt;br&gt;
In a corporate network, if many users in the Access Layer try to communicate directly with the Core Layer (as in 2-Tier), it can lead to congestion.&lt;br&gt;
With 3-Tier Architecture, the Distribution Layer efficiently manages traffic between users (Access) and data storage (Core), ensuring smooth operations even during peak usage.&lt;/p&gt;
&lt;p&gt;As we wrap with 2-tier and 3-tier architectures, it's important to highlight the growing adoption of a third model—&lt;strong&gt;Spine-Leaf Design&lt;/strong&gt;. This architecture is particularly well-suited for data centers that manage high volumes of east-west traffic, which is becoming increasingly prevalent in today's digital landscape.&lt;br&gt;
Currently, around 80% of companies are leveraging some form of this innovative architecture, enabling them to achieve greater scalability, reduced latency, and more efficient traffic management compared to traditional models. The Spine-Leaf architecture simplifies network design by utilizing two layers: the Spine layer, which acts as the backbone connecting all Leaf switches, and the Leaf layer, which connects directly to servers and endpoints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spline Leaf Design&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Spine-Leaf Architecture is a modern two-layer network topology designed to optimize data center performance by addressing the limitations of traditional three-tier architectures. It consists of two main layers: the &lt;strong&gt;Spine Layer&lt;/strong&gt;, which acts as the backbone of the network, and the &lt;strong&gt;Leaf Layer&lt;/strong&gt;, which connects directly to servers and end-user devices. In this architecture, every leaf switch is interconnected with every spine switch in a full mesh topology, allowing for efficient east-west traffic flow—server-to-server communication within the same data center—while minimizing latency and reducing hop counts to a maximum of two. This design enhances scalability, as new spine or leaf switches can be added without disrupting existing connections, and improves redundancy by allowing multiple active links between switches, thus preventing bottlenecks. However, it does require more cabling due to the extensive interconnections and may have limitations on the number of hosts supported based on spine port counts. Overall, this architecture is increasingly favored in modern data centers for its ability to handle high volumes of traffic efficiently.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=363491439253574624&quot; alt=&quot;splineleaf&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At the end, understanding 2-Tier, 3-Tier, and Spine-Leaf architectures is essential for designing efficient and scalable networks tailored to organizational needs. 2-Tier Architecture offers simplicity and cost-effectiveness, making it ideal for smaller setups, while 3-Tier Architecture provides enhanced scalability, security, and flexibility for larger enterprises. Meanwhile, the modern Spine-Leaf Architecture is revolutionizing data centers by efficiently handling high volumes of east-west traffic with reduced latency and improved scalability. Each model serves a unique purpose, and choosing the right architecture depends on factors like application size, traffic demands, and future growth.&lt;/p&gt;
&lt;p&gt;Thank you for making it to the end! If you enjoyed the content, please consider sharing it with someone who might benefit from it.&lt;br&gt;
Feel free to reach out to me on &lt;a rel=&quot;nofollow&quot; href=&quot;https://x.com/harshit_rwt&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thankyou Once Again!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqo9utdt1vt5vth21fh8.png&quot; alt=&quot;Thankyou&quot;&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/864/differentiating-network-architecture-an-overview-tier-and-tier-network-architectures</guid>
<pubDate>Sun, 19 Jan 2025 10:01:32 +0000</pubDate>
</item>
<item>
<title>Check out this article for beginners on Kubernetes</title>
<link>https://coderlegion.com/842/check-out-this-article-for-beginners-on-kubernetes</link>
<description>&lt;h2 id=&quot;getting-started-with-kubernetes-a-beginner-s-guide&quot;&gt;Getting Started With Kubernetes: A beginner's guide&lt;/h2&gt;
&lt;h3 id=&quot;introduction-4&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;In today’s world of software development, applications are no longer created as one single large program. Instead, they’re broken into smaller pieces or units called microservices, which run inside containers. But as you start running more containers, managing them can quickly become challenging. That’s where Kubernetes comes in.&lt;/p&gt;
&lt;p&gt;This article introduces you to Kubernetes, covering what it is, explains why it’s essential, and how to get started with it!&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;A basic understanding on Containers and Docker basics, for this, you can check out my article on &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/onlyfave/understanding-docker-a-beginners-guide-to-containerization-3478&quot;&gt;Understanding Docker: A beginner's guide to containerization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Basic Command Line Knowledge, you should be comfortable using the terminal or command line interface (CLI)&lt;/li&gt;
&lt;li&gt;YAML basics and that's because Kubernetes configurations are written in YAML.&lt;/li&gt;
&lt;li&gt;Basic Networking Concepts. You should understand simple networking ideas, what an IP address is, and how ports work.&lt;/li&gt;
&lt;li&gt;A Willingness to Learn. Kubernetes introduces some new concepts, like pods, services, and deployments so having patience and a mindset to experiment will make the learning process enjoyable.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, let's dive right in!&lt;/p&gt;
&lt;h3 id=&quot;what-is-kubernetes--1&quot;&gt;What Is Kubernetes?&lt;/h3&gt;
&lt;p&gt;Kubernetes, often abbreviated as K8s, is an open-source container orchestration platform developed by Google. It's designed to automate the deployment, scaling, and management of containerized applications. With Kubernetes, developers can focus on writing code, while the platform handles the complexities of deploying and managing those applications in production.&lt;/p&gt;
&lt;h3 id=&quot;why-use-kubernetes-&quot;&gt;Why Use Kubernetes?&lt;/h3&gt;
&lt;p&gt;As applications become more complex and microservices-based architectures gain popularity, the need for efficient management tools has increased. Here are some reasons to consider using Kubernetes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Kubernetes provides powerful scaling options. You can easily scale your application up or down based on traffic or resource demand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Load Balancing&lt;/strong&gt;: It automatically distributes network traffic across multiple containers, ensuring no single container is overloaded.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-Healing&lt;/strong&gt;: Kubernetes detects when a container fails and automatically restarts it or schedules it on a different node, ensuring high availability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service Discovery&lt;/strong&gt;: It simplifies the process of managing communication between services, allowing them to find each other easily.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seamless Updates&lt;/strong&gt;: Kubernetes allows you to update your app with zero downtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;key-terms-and-components-in-kubernetes&quot;&gt;Key Terms and Components in Kubernetes&lt;/h3&gt;
&lt;p&gt;When understanding Kubernetes, you're required to be familiar with these terms or core components. Here’s a breakdown of its key concepts:&lt;/p&gt;
&lt;h4 id=&quot;1-cluster&quot;&gt;1. &lt;strong&gt;Cluster&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;A Kubernetes cluster is a set of machines (called nodes) that run containerized applications. Each cluster has at least one master node and multiple worker nodes.&lt;/p&gt;
&lt;h4 id=&quot;2-node&quot;&gt;2. &lt;strong&gt;Node&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;A node is a physical or virtual machine in the cluster that runs applications. There are two types of nodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Master Node&lt;/strong&gt;: Manages the cluster, coordinating tasks and distributing workloads to worker nodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Worker Node&lt;/strong&gt;: Executes the applications and services.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-pod&quot;&gt;3. &lt;strong&gt;Pod&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;A pod is the smallest deployable unit in Kubernetes. It can contain one or more containers that share storage and network resources. Pods are typically used to run tightly coupled applications.&lt;/p&gt;
&lt;h4 id=&quot;4-deployment&quot;&gt;4. &lt;strong&gt;Deployment&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;A deployment is a Kubernetes resource that manages the lifecycle of your application. It defines how many replicas (copies) of a pod should be running at any given time and ensures that the desired state of the application is maintained.&lt;/p&gt;
&lt;h4 id=&quot;5-service&quot;&gt;5. &lt;strong&gt;Service&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;A service is an abstract way to expose an application running on a set of pods. It provides a stable endpoint for users to access the application and can handle load balancing and failover.&lt;/p&gt;
&lt;h4 id=&quot;6-configmap-and-secret&quot;&gt;6. &lt;strong&gt;ConfigMap and Secret&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ConfigMap&lt;/strong&gt;: Used to store non-sensitive configuration data for your application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secret&lt;/strong&gt;: Used to store sensitive information, such as passwords or API keys, ensuring they are securely managed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-kubernetes-works&quot;&gt;How Kubernetes Works&lt;/h3&gt;
&lt;h5 id=&quot;let-s-walk-through-an-example-&quot;&gt;Let’s walk through an example:&lt;/h5&gt;
&lt;p&gt;You have a web app and want to run it in 3 containers.&lt;/p&gt;
&lt;p&gt;You create a deployment in Kubernetes, specifying the app’s configuration and that you want 3 replicas.&lt;/p&gt;
&lt;p&gt;Kubernetes starts 3 pods (each containing your app’s container) on the available worker nodes.&lt;/p&gt;
&lt;p&gt;A service is created to expose your app to users.&lt;/p&gt;
&lt;p&gt;If one pod fails, Kubernetes automatically starts a new one to maintain 3 replicas.&lt;/p&gt;
&lt;h3 id=&quot;getting-started-with-kubernetes&quot;&gt;Getting Started With Kubernetes&lt;/h3&gt;
&lt;p&gt;There are various ways to install Kubernetes, depending on your environment and requirements. Here are a few popular options for beginners:&lt;/p&gt;
&lt;h4 id=&quot;1-minikube&quot;&gt;1. Minikube&lt;/h4&gt;
&lt;p&gt;Minikube is a tool that allows you to run Kubernetes locally on your machine. It’s ideal for development and testing.&lt;/p&gt;
&lt;p&gt;To install Minikube:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install VirtualBox or another compatible virtualization tool.&lt;/li&gt;
&lt;li&gt;Install Minikube following the instructions on Minikube's official site.&lt;/li&gt;
&lt;li&gt;Start your local Kubernetes cluster with &lt;code&gt;minikube start&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;2-kubectl&quot;&gt;2. Kubectl&lt;/h4&gt;
&lt;p&gt;Kubectl is the command-line interface for interacting with your Kubernetes cluster. You can install it by following the instructions on the Kubernetes documentation site.&lt;/p&gt;
&lt;h4 id=&quot;3-cloud-providers&quot;&gt;3. Cloud Providers&lt;/h4&gt;
&lt;p&gt;If you want to use Kubernetes in production, consider cloud providers that offer managed Kubernetes services, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google Kubernetes Engine (GKE)&lt;/li&gt;
&lt;li&gt;Amazon Elastic Kubernetes Service (EKS)&lt;/li&gt;
&lt;li&gt;Azure Kubernetes Service (AKS)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;deploying-your-first-application&quot;&gt;Deploying Your First Application&lt;/h3&gt;
&lt;p&gt;Now that you have a basic understanding of Kubernetes, let’s deploy a simple application. We’ll use a basic Nginx web server as an example.&lt;/p&gt;
&lt;h4 id=&quot;create-a-deployment&quot;&gt;Create a Deployment&lt;/h4&gt;
&lt;p&gt;Create a file named &lt;code&gt;nginx-deployment.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: apps/v1  
kind: Deployment  
metadata:  
  name: nginx-deployment  
spec:  
  replicas: 2  
  selector:  
    matchLabels:  
      app: nginx  
  template:  
    metadata:  
      labels:  
        app: nginx  
    spec:  
      containers:  
      - name: nginx  
        image: nginx:latest  
        ports:  
        - containerPort: 80  
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;apply-the-deployment&quot;&gt;Apply the Deployment&lt;/h4&gt;
&lt;p&gt;Run the following command to create the deployment in your cluster:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f nginx-deployment.yaml  
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;expose-the-deployment-as-a-service&quot;&gt;Expose the Deployment as a Service&lt;/h4&gt;
&lt;p&gt;To make the Nginx deployment accessible, create a service:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl expose deployment nginx-deployment --type=NodePort --port=80  
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;access-your-application&quot;&gt;Access Your Application&lt;/h4&gt;
&lt;p&gt;Get the URL to access your application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;minikube service nginx-deployment --url  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open this URL in your web browser, and you should see the default Nginx welcome page!&lt;/p&gt;
&lt;p&gt;For further learning, here is a list of Kubernetes resources;&lt;br&gt;
✨ &lt;strong&gt;Kubernetes Documentation&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://kubernetes.io/docs/home/&quot;&gt;Kubernetes Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;Kubernetes Basics Interactive Tutorial&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://kubernetes.io/docs/tutorials/kubernetes-basics/&quot;&gt;Kubernetes Basics&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;Katacoda Kubernetes Scenarios&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.katacoda.com/courses/kubernetes&quot;&gt;Katacoda Kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;Play with Kubernetes&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://labs.play-with-k8s.com/&quot;&gt;Play with Kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;Kubernetes YouTube Channel&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/c/KubernetesCommunity&quot;&gt;Kubernetes YouTube&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;TechWorld with Nana&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/c/TechWorldwithNana&quot;&gt;TechWorld with Nana&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;Google Cloud Tech&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/c/GoogleCloudPlatform&quot;&gt;Google Cloud Tech&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;Coursera - Introduction to Kubernetes&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.coursera.org/learn/introduction-to-kubernetes&quot;&gt;Coursera Kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✨ &lt;strong&gt;Udemy - Kubernetes for Absolute Beginners&lt;/strong&gt;  &lt;/p&gt;
&lt;h3 id=&quot;conclusion-4&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In this article, you've learned what Kubernetes is, why we use it, its key terms and concepts, how to install and get started with Kubernetes, and finally, how to deploy your first application on it.&lt;/p&gt;
&lt;p&gt;Kubernetes is a powerful tool for managing containerized applications, offering numerous features for scaling, load balancing, and self-healing. While the learning curve may difficult at first, there are plenty of resources and a supportive community to help you along the way.&lt;/p&gt;
&lt;p&gt;Embrace the journey, and happy coding! If you have any questions or need further details on specific topics, feel free to ask or comment your thoughts!&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/842/check-out-this-article-for-beginners-on-kubernetes</guid>
<pubDate>Fri, 17 Jan 2025 19:34:28 +0000</pubDate>
</item>
<item>
<title>The Ultimate Beginner's Guide to Azure AI Fundamentals (AI-900)</title>
<link>https://coderlegion.com/629/the-ultimate-beginners-guide-to-azure-ai-fundamentals-ai-900</link>
<description>&lt;h2 id=&quot;introduction-5&quot;&gt;&lt;strong&gt;&lt;em&gt;Introduction&lt;/em&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The AI-900 certification is your entry ticket into the world of AI and Azure. As businesses embrace AI across industries, understanding Azure AI opens up diverse job opportunities. In this blog, we’ll break down tips, best practices, and how Azure AI Fundamentals can help you land exciting career prospects.&lt;/p&gt;
&lt;h3 id=&quot;1-what-is-azure-ai-fundamentals-ai-900-&quot;&gt;&lt;strong&gt;&lt;em&gt;1. What is Azure AI Fundamentals (AI-900)?&lt;/em&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Overview:&lt;/strong&gt; The AI-900 is an entry-level certification offered by Microsoft, designed to provide foundational knowledge of AI concepts and how they are implemented using Azure AI services.&lt;/p&gt;
&lt;h3 id=&quot;topics-covered-&quot;&gt;&lt;strong&gt;&lt;em&gt;Topics Covered:&lt;/em&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AI Concepts:&lt;/strong&gt; Overview of AI, machine learning, deep learning.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure AI Services:&lt;/strong&gt; Cognitive Services, Azure Machine Learning, Azure Bot Services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI Workloads:&lt;/strong&gt; Types of AI workloads and solutions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responsible AI:&lt;/strong&gt; Ethical considerations in AI development.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-best-practices-to-prepare-for-the-ai-900-exam&quot;&gt;&lt;strong&gt;&lt;em&gt;2. Best Practices to Prepare for the AI-900 Exam&lt;/em&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Start with the Basics:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Familiarize yourself with AI fundamentals before diving into Azure-specific tools.&lt;/li&gt;
&lt;li&gt;Learn about machine learning, deep learning, and AI model training.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Utilize Free Learning Resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft Learn provides structured, free courses aligned with the AI-900 exam.&lt;/li&gt;
&lt;li&gt;Hands-on labs to experiment with Azure AI services like Computer Vision and Language Understanding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Break Down the Exam Topics:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus on AI workloads: understand different AI models and use cases.&lt;/li&gt;
&lt;li&gt;Master the core Azure AI tools: Cognitive Services, Azure ML, and Bot Services.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Practice with Real-World Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Experiment with Azure AI tools using a free Azure account.&lt;/li&gt;
&lt;li&gt;Try building simple AI models using Azure Machine Learning Studio.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Take Practice Exams:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Use practice tests to familiarize yourself with the exam format and question types.&lt;br&gt;
Identify areas where you need more practice.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Practice Sets | AI 900: Microsoft Azure AI Fundamentals Exam &lt;a rel=&quot;nofollow&quot; href=&quot;https://courses.kloudsaga.com/courses/azure-ai-fundamentals&quot;&gt;https://courses.kloudsaga.com/courses/azure-ai-fundamentals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-key-tips-for-success-in-ai-900&quot;&gt;&lt;strong&gt;&lt;em&gt;3. Key Tips for Success in AI-900&lt;/em&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Stay Hands-On:&lt;/strong&gt; AI is best learned through experience. Try implementing what you learn using Azure's free-tier services.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Focus on Real-World Applications&lt;/strong&gt;: Understand how Azure AI tools solve business problems in real industries such as healthcare, finance, and customer service.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Study the Ethical Aspects&lt;/strong&gt;: The AI-900 exam covers responsible AI practices, including fairness, transparency, and accountability—don’t skip this section.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Time Management&lt;/strong&gt;: The AI-900 exam is time-constrained. Practice managing your time during the practice exams to ensure you can complete the questions within the allotted time.&lt;/p&gt;
&lt;h3 id=&quot;4-azure-ai-career-opportunities&quot;&gt;&lt;strong&gt;&lt;em&gt;4. Azure AI Career Opportunities&lt;/em&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The AI-900 certification is not just a credential; it unlocks a wide range of exciting career opportunities in AI and cloud computing. &lt;/p&gt;
&lt;p&gt;Here are some roles you can explore:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;AI Developer:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Skills Needed: Knowledge of machine learning models, programming (Python, C#), and Azure Bot Services.&lt;br&gt;
Roles: Building AI applications, developing chatbots, and integrating Azure AI into existing solutions.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Average Salary: $80,000 - $110,000.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Data Scientist/AI Engineer:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Skills Needed: Experience with Azure Machine Learning, data analysis, and predictive modeling.&lt;br&gt;
Roles: Analyzing data to create predictive models and using Azure to deploy machine learning solutions.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Average Salary: $100,000 - $130,000.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Cloud Solutions Architect:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Skills Needed: Understanding cloud architecture, AI solutions, and Azure services.&lt;br&gt;
Roles: Designing scalable AI solutions using Azure cloud infrastructure for enterprise clients.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Average Salary: $120,000 - $160,000.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;AI Consultant:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Skills Needed: Familiarity with Azure AI tools, client communication, and project management.&lt;br&gt;
Roles: Advising companies on how to implement AI-powered solutions and adopt Azure AI for their specific needs.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Average Salary: $90,000 - $130,000.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;5-best-practices-to-grow-your-ai-career-after-ai-900&quot;&gt;&lt;strong&gt;5. Best Practices to Grow Your AI Career After AI-900&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Build a Portfolio:&lt;/strong&gt; Start creating personal projects using Azure AI. Showcase chatbots, image recognition, or natural language processing models.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stay Updated&lt;/strong&gt;: AI is evolving rapidly. Subscribe to AI-related blogs, attend webinars, and stay on top of new features and tools in Azure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Network with Professionals&lt;/strong&gt;: Join AI communities, attend events like Microsoft Ignite, or engage in forums like Stack Overflow and LinkedIn groups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Explore Further Certifications&lt;/strong&gt;: After completing AI-900, you can pursue advanced certifications such as Azure AI Engineer (AI-102) or Microsoft Certified: Azure Data Scientist.&lt;/p&gt;
&lt;h3 id=&quot;6-key-takeaways&quot;&gt;&lt;strong&gt;6. Key Takeaways&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The AI-900 certification is an excellent starting point for anyone&lt;br&gt;
looking to break into the world of AI and cloud computing with Azure.&lt;br&gt;
Hands-on practice is critical. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Azure offers free tools and trial accounts to help you apply what you learn in real-world scenarios. After passing the AI-900 exam, explore various career roles,&lt;br&gt;
including AI developer, data scientist, and cloud architect.&lt;br&gt;
Networking and continuous learning will help you stay competitive in&lt;br&gt;
the fast-growing field of AI.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;conclusion-5&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The AI-900 certification is intiative into the world of artificial intelligence and Azure cloud services. By following the best practices, tips, and strategies outlined above, you’ll be well on your way to mastering Azure AI and unlocking new career opportunities in this fast-evolving field.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://learn.microsoft.com/en-us/training/courses/ai-900t00&quot;&gt;https://learn.microsoft.com/en-us/training/courses/ai-900t00&lt;/a&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://kloudsaga.com&quot;&gt;https://kloudsaga.com&lt;/a&gt;&lt;/p&gt;
</description>
<category>azure</category>
<guid isPermaLink="true">https://coderlegion.com/629/the-ultimate-beginners-guide-to-azure-ai-fundamentals-ai-900</guid>
<pubDate>Wed, 01 Jan 2025 22:59:07 +0000</pubDate>
</item>
<item>
<title>Cloud Computing Simplified: Models, Services, and the Future of Technology</title>
<link>https://coderlegion.com/580/cloud-computing-simplified-models-services-and-the-future-of-technology</link>
<description>&lt;p&gt;Cloud computing has changed how we store, access, and manage data. It offers flexible, affordable, and powerful solutions that help businesses and individuals focus on what matters most. As more organizations adopt cloud technologies, understanding the basics is becoming essential.  &lt;/p&gt;
&lt;p&gt;In this guide, I’ll explain cloud computing, break down its key models, introduce its services, and highlight how it’s shaping industries and innovation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Why Use Cloud Computing?&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cloud Deployment Models&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On-Premise Computing  &lt;/li&gt;
&lt;li&gt;Public Cloud  &lt;/li&gt;
&lt;li&gt;Private Cloud  &lt;/li&gt;
&lt;li&gt;Hybrid Cloud&lt;/li&gt;
&lt;li&gt;Community Cloud&lt;/li&gt;
&lt;li&gt;Multi-Cloud&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cloud Services&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IaaS  &lt;/li&gt;
&lt;li&gt;PaaS  &lt;/li&gt;
&lt;li&gt;SaaS  &lt;/li&gt;
&lt;li&gt;DaaS  &lt;/li&gt;
&lt;li&gt;STaaS  &lt;/li&gt;
&lt;li&gt;FaaS  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;Cloud computing lets you access computing power over the internet instead of relying on expensive, on-site hardware. Whether you’re a business owner or a tech enthusiast, the cloud helps reduce costs, increase flexibility, and speed up innovation.  &lt;/p&gt;
&lt;p&gt;Let’s explore how it works, step by step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Use Cloud Computing?&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;Here are five reasons why businesses are embracing cloud computing:  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cost Savings&lt;/strong&gt;: You only pay for what you use—no need to buy expensive hardware upfront.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Easily adjust resources as your needs grow or shrink.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility&lt;/strong&gt;: Work from anywhere with an internet connection.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Top providers offer advanced protections against cyber threats.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speed&lt;/strong&gt;: Quickly develop, test, and deploy projects to stay ahead.  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cloud computing simplifies IT so you can focus on building ideas instead of managing hardware.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud Deployment Models&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mdahu5f59pr1vbf00wdx.jpeg&quot; alt=&quot;Cloud deployment model&quot;&gt;&lt;/p&gt;
&lt;p&gt;Cloud computing can be set up in different ways, depending on your needs:  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. On-Premise Computing&lt;/strong&gt;&lt;br&gt;
This is the traditional approach where everything is managed in-house.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Full control over data; suitable for strict security needs.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Expensive and hard to scale.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Public Cloud&lt;/strong&gt;&lt;br&gt;
Public clouds are shared by multiple users and managed by providers like AWS or Google Cloud.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Cost-effective and scalable.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Less customization; potential security concerns.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. Private Cloud&lt;/strong&gt;&lt;br&gt;
A private cloud is dedicated to one organization, offering more control.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Highly secure and customizable.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Expensive and complex to maintain.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Hybrid Cloud&lt;/strong&gt;&lt;br&gt;
Mixing private and public clouds for flexibility.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Combines local security with public cloud scalability.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;5. Community Cloud&lt;/strong&gt;&lt;br&gt;
A community cloud is a shared cloud infrastructure tailored for a specific group of users or organizations with shared concerns, such as compliance, security, or mission-critical goals.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt; Costs are shared among participating organizations, enabling secure collaboration within the community, with access limited to members, making it more secure than public clouds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons:&lt;/strong&gt; Managing shared resources requires coordination among all parties and community clouds offer less scalability compared to public cloud solutions. Use Cases include healthcare with hospitals sharing patient data while ensuring HIPAA compliance, government agencies collaborating on secure joint initiatives, and education with universities sharing research infrastructure and tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;6. Multi-Cloud&lt;/strong&gt;&lt;br&gt;
Using services from multiple cloud providers.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Using services from multiple cloud providers avoids reliance on a single provider while offering increased reliability through fault tolerance, improved disaster recovery, and higher system availability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Managing multiple cloud providers can introduce complexity, lead to higher operational costs, and increase security risks due to varying security protocols across providers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud Services&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;Cloud computing isn’t just about storing data. Here are its main types of services:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67zekfoowzjyq6wwhawh.png&quot; alt=&quot;Cloud services&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jhs5ujltkyo9s7q62x74.png&quot; alt=&quot;cloud services&quot;&gt;&lt;br&gt;
&lt;strong&gt;1. Infrastructure as a Service (IaaS)&lt;/strong&gt;&lt;br&gt;
Think of IaaS as renting virtual servers and storage online.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Amazon EC2, Azure Virtual Machines.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uses&lt;/strong&gt;: Hosting websites, running applications.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Platform as a Service (PaaS)&lt;/strong&gt;&lt;br&gt;
PaaS provides tools to build and launch apps without managing the hardware.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Heroku, Google App Engine.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uses&lt;/strong&gt;: Streamlining app development.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. Software as a Service (SaaS)&lt;/strong&gt;&lt;br&gt;
SaaS delivers ready-to-use apps over the internet, often subscription-based.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Google Workspace, Salesforce.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uses&lt;/strong&gt;: Productivity tools, CRM software.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Desktop as a Service (DaaS)&lt;/strong&gt;&lt;br&gt;
DaaS provides virtual desktops that can be accessed from any device.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Amazon WorkSpaces, Citrix.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uses&lt;/strong&gt;: Remote work setups.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;5. Storage as a Service (STaaS)&lt;/strong&gt;&lt;br&gt;
STaaS offers flexible cloud storage for businesses and individuals.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Amazon S3, Google Cloud Storage.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uses&lt;/strong&gt;: Backups, disaster recovery.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;6. Function as a Service (FaaS)&lt;/strong&gt;&lt;br&gt;
FaaS is about running code without managing servers, also known as serverless computing.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Examples&lt;/strong&gt;: AWS Lambda, Azure Functions.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uses&lt;/strong&gt;: Event-driven apps like chatbots.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;Cloud computing is transforming industries by making technology accessible, affordable, and efficient. From IaaS to SaaS, these services empower businesses to innovate faster and smarter.  &lt;/p&gt;
&lt;p&gt;The future of computing is in the cloud. Whether you’re just starting or looking to dive deeper, there’s no better time to explore its potential.  &lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/580/cloud-computing-simplified-models-services-and-the-future-of-technology</guid>
<pubDate>Mon, 09 Dec 2024 23:37:48 +0000</pubDate>
</item>
</channel>
</rss>