| Topology | Best Used For | Complexity | Writes Scalable? |
|---|---|---|---|
| Standalone (e.g. apt setup) | Local development / testing. | Very Low | No |
| Leader-Follower (Our next step) | Small/Medium apps needing read-scalability. | Medium | No (Only 1 Leader) |
| Sentinel | High Availability (Auto-failover) for Leader-Follower. | High | No (Only 1 Leader) |
| Cluster Mode | Massive datasets that don't fit on one machine. | High | Yes (Shards data across masters) |
| Active-Passive | Disaster Recovery across different cloud regions. | Very High | No (Only Main Region) |
| Active-Active | Global apps requiring ultra-low latency worldwide. | Extremely High | Yes (Write anywhere globally) |
RS Chandras Tech Blog | AI, ML, Agentic AI
Monday, May 25, 2026
Redis Topologies
Understanding the React ESLint Warning: “Avoid Calling setState() Directly Within an Effect”
While working with React, I encountered an interesting ESLint warning related to useEffect.
The application itself was running perfectly fine, but ESLint still flagged the code with an error.
At first glance, the warning looked confusing because useEffect is supposed to handle side effects like fetching data.
This article explains:
- what the warning actually means,
- why ESLint complained,
- why the corrected version passed,
- and the deeper React concepts involved.
The Original Code
// Helper function to fetch messages from the backend API
const fetchEntries = async () => {
try {
const res = await fetch(API_URL);
if (!res.ok) {
throw new Error('Backend failed to respond');
}
const data = await res.json();
setEntries(data);
setError(null);
} catch (err) {
setError('Could not fetch guestbook entries. Is the backend running?');
console.error(err);
}
};
// Fetch entries automatically when the page loads
useEffect(() => {
fetchEntries();
}, []);
The ESLint Error
ESLint produced the following warning:
Avoid calling setState() directly within an effect
This warning came from:
The Corrected Version
The corrected version moved the async function inside the effect.
useEffect(() => {
const fetchEntries = async () => {
try {
const res = await fetch(API_URL);
if (!res.ok) {
throw new Error('Backend failed to respond');
}
const data = await res.json();
setEntries(data);
setError(null);
} catch (err) {
setError('Could not fetch guestbook entries. Is the backend running?');
console.error(err);
}
};
fetchEntries();
}, []);
Interestingly, this version passed ESLint successfully.
Was the Original Code Actually Wrong?
Not really.
Both versions are almost identical in runtime behavior.
The application worked because the state update was not actually synchronous.
The important line is:
That await creates an asynchronous boundary.
So the sequence is actually:
↓
fetch request starts
↓
effect completes
↓
network response arrives later
↓
setState executes
This is very different from:
useEffect(() => {
setCount(count + 1);
}, []);
where the state update happens immediately during the effect execution.
Then Why Did ESLint Complain?
The answer lies in static analysis.
ESLint does not execute the program like a browser does. Instead, it analyzes the source code structure and tries to detect potentially dangerous patterns.
In the original code, ESLint saw:
useEffect(() => {
fetchEntries();
}, []);
and noticed that:
fetchEntries()
contains:
- setEntries(...)
- setError(...)
From ESLint’s perspective:
So it assumed:
The linter could not safely prove that the state updates only happen after an asynchronous operation.
The complete error as received was:
error Error: Calling setState synchronously within an effect can trigger cascading renders
Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:
* Update external systems with the latest state from React.
* Subscribe for updates from some external system, calling setState in a callback function when external state changes.
Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).
npm vs npx
The primary difference is that npm (Node Package Manager) is used to install and manage packages, while npx (Node Package Execute) is used to run packages without permanently installing them.
Think of npm as your project's storage manager and npx as a "one-off" execution tool.
Key Comparison
| Feature | npm | npx |
|---|---|---|
| Primary Goal | Installs and manages project dependencies. | Executes Node packages on the fly. |
| Storage | Packages are installed locally or globally on your machine. | Runs packages without cluttering local or global storage. |
| Workflow | You typically install a package before you can use it. | You can run a package directly from the registry without prior installation. |
| Version Control | Manages specific versions via the package.json file. | Often used to ensure you are running the latest version of a tool. |
When to Use Each
Use npm: For long-term project dependencies that you need to use repeatedly, like a web framework (React) or a utility library (Lodash).
Use npx: For one-time tasks or scaffolding new projects. For example, create-react-app is commonly run with npx so you don't have to keep an outdated version of the installer globally on your system.
Practical Example
If you want to create a new React application:
Using npm
You would first run npm install -g create-react-app to install it globally, then run create-react-app my-app .
Using npx
You simply run npx create-react-app my-app . It downloads what it needs, runs the setup, and finishes without leaving the tool installed on your computer
Sunday, May 24, 2026
SSoT for the K8s Project
Architectural Design Specifications
1. Core Architecture & Local Runtime Environment
The entire platform is built as a distributed microservice system running inside an enterprise-grade local sandbox. The underlying infrastructure uses k3d to spin up a multi-node, lightweight K3s (Kubernetes) cluster directly inside Docker on your laptop. To eliminate external internet dependencies and network bottlenecks, a built-in local container registry is bound directly to the k3d cluster nodes. The local development life cycle is orchestrated entirely by Skaffold, which watches local source directories, coordinates container builds, injects live code updates via hot-reloading directly into running containers, and automates local manifest application.
2. Service Breakdown & Polyglot Storage Strategy
The business logic is decoupled into distinct, containerized microservices to ensure individual scalability and fault isolation:
- Frontend Service (React): The client-side user interface responsible for store browsing, user authentication, and shopping cart interactions.
- Product Catalog Service: A read-intensive microservice managing item definitions, technical specifications, and merchant inventory counts. It relies on a document-oriented MongoDB database cluster due to its highly flexible, schema-less properties.
- Order Processing Service: A highly transactional microservice handling secure checkout states, billing, and customer invoices. It relies on PostgreSQL to enforce strict ACID compliance and relational integrity.
3. Data Sovereignty & Geographic Infrastructure Sharding
To strictly comply with global data protection regulations (such as GDPR, CCPA, and DPDP), the system uses Geographic Sharding to ensure sensitive user data is physically stored within its region of origin.
- Implementation: The system leverages a composite shard key consisting of [tenant_id, country_code].
- Database Layers: MongoDB automates horizontal scaling using its native mongos routing query routers and config servers. PostgreSQL implements true multi-node horizontal sharding across independent physical cloud clusters by using the Citus open-source database extension.
4. Complex Multi-Tenancy Strategy
The platform supports multiple commercial merchants (tenants) sharing a unified, cost-efficient infrastructure via a Hybrid Multi-Tenancy Architecture:
- Compute Tier: All tenants share the same running microservice container pods inside the Kubernetes cluster. The system dynamically identifies the active tenant by decoding a tenant_id claim baked directly into the user’s cryptographically signed identity token.
- Product Storage Tier (Shared Catalogue, Private Overlay): To prevent duplicate entries of universal products, the platform separates data. The core products collection holds global, shared item details (SKU, brand, images). A separate merchant_listings collection stores tenant-specific commercial overrides (price, current stock, active flag) tied to a unique tenant_id.
- Order Storage Tier (Isolated Shards): Financial and customer transaction histories are isolated across independent database shards managed by Citus and MongoDB clustering based on the tenant's risk profile and scale.
5. Application-Level Geo-Fencing (Country Restrictions)
When compliance or licensing restricts specific products from being sold in certain countries, the system avoids infrastructural sharding for public catalog data and handles rules at the application layer.
- An explicit geo_restrictions schema matrix containing inclusion or exclusion lists (e.g., whitelist or blacklist arrays of ISO country codes) is attached directly to the global product or merchant listing document.
- At runtime, the cluster edge (API Ingress) captures the user's origin country via GeoIP or profile data and passes an X-User-Country header down to the Product Service. The backend appends a dynamic mongo filter (e.g., $ne: userCountry) to eliminate blocked items before delivering responses to the client.
6. Scalable Redis Caching Strategy
To protect the primary databases from intensive read operations, an ultra-fast Redis in-memory data cache sits directly in front of MongoDB.
- Key Namespacing: To prevent data leaks across distinct merchants and countries, Redis uses strict composite composite keys following a colon-separated namespace:
tenant:<tenant_id>:country:<country_code>:catalog - Cache Patterns: The system enforces a Cache-Aside (Lazy Loading) pattern with a mandatory Time-To-Live (TTL) expiration limit of 1 hour.
- Day-2 Operational Safety: The Product Service implements a Mutex Lock mechanism to block "Cache Stampedes" by ensuring only one backend worker can re-query MongoDB on a cache miss while parallel concurrent requests wait. Whenever a merchant alters an item or a country rule, the backend executes targeted cache eviction using background scans matching
tenant:<tenant_id>:country:*:catalog.
7. Eventual Data Synchronization & Change Data Capture (CDC)
- Instead of forcing application code to double-write to multiple networks, the system implements a modern Change Data Capture (CDC) model.
- The Debezium framework hooks directly into the database transaction logs (the Postgres Write-Ahead Log [WAL] and the MongoDB Oplog) in real-time, translating row modifications into structured JSON event streams. These streams are safely fed into an Apache Kafka cluster, allowing reporting data warehouses or regional caches to sync automatically.
8. API Gateway Management & Versioning Strategy
- Ingress & Validation: Traefik acts as the API Gateway. It validates incoming JSON Web Tokens (JWT) signatures at the cluster edge, dropping unauthorized traffic instantly.
- API Evolution: The platform enforces strict URL Path Versioning (e.g., /api/v1/orders vs. /api/v2/orders). Breaking structural API payload changes require incrementing the major path version, allowing Traefik to route legacy and modern variants cleanly to distinct Kubernetes deployment groups.
9. Unified Identity Provider (IdP) & Application RBAC
- Authentication (AuthN): Handled completely outside the custom microservices by deploying Keycloak (OpenID Connect / OIDC provider). Users register, authenticate, and manage passwords against Keycloak, which hands back a secure JWT.
- Authorization (AuthZ): Inside our custom application code, granular Role-Based Access Control (RBAC) is evaluated by decoding the roles array contained within the token (e.g., separating standard customer reading routes from inventory-manager mutation actions).
10. Left-Shift Security & Automated Quality Gates
- Pre-Commit / Early CI: ESLint/Ruff/Golangci-lint checks syntax, while TruffleHog/Gitleaks blocks commits if high-entropy cloud secrets are exposed in plain text.
- Static Security & Dependencies: SonarQube/Semgrep executes Static Application Security Testing (SAST), while Snyk/Dependabot reviews open-source application dependency trees for Software Composition Analysis (SCA).
- Container Security: During image creation, Trivy audits the operating system container base layers for vulnerabilities (CVEs).
- Manifest Auditing: Before manifests are committed to Git, Datree/Kube-linter scans the Kubernetes YAML files to block infrastructure misconfigurations (e.g., missing resource limits, privilege escalation vectors).
- Runtime Security: Automated OWASP ZAP runs Dynamic Application Security Testing (DAST) web vulnerability injection attacks against running staging namespaces.
11. Tiered Testing Strategy
- Unit Tests: Handled natively via modern test runners (Vitest/PyTest/Go Test) to check decoupled pure business logic and algorithms with zero dependencies.
- Integration Tests: Enabled by Testcontainers. During test execution, Testcontainers invokes the local Docker API to spin up real, ephemeral, completely pristine instances of Redis, MongoDB, and PostgreSQL. The microservice test suite runs its queries against these short-lived native databases, ensuring integration testing accurately mirrors true cloud environments before disposing of the containers.
12. GitOps Delivery & Infrastructure Control
- Environment Orchestration: Managing differing requirements across development, staging, and production environments is isolated using Kustomize. Kustomize maintains a single source base/ configuration file structure and maps changes (replicas, ingress domains, configuration values) through declarative, non-destructive overlays/.
- Continuous Deployment (CD): The platform rejects manual push actions (kubectl apply) in favor of a pull-based GitOps engine powered by Argo CD running inside the cluster. Argo CD constantly checks the state of your infrastructure Git repository against the active state of the cluster, pulling, validating, and auto-correcting drift instantly.
Architectural Design Matrix
| Category | Component Layer | Chosen Technology | Architectural Function & Single Source of Truth Rules |
|---|---|---|---|
| Runtime | Local Cluster Infrastructure | k3d (K3s in Docker) + Local Registry | Provisions a local multi-node cluster and secure loopback repository to eliminate external cloud network lag. |
| Workflow | Developer Inner Loop | Skaffold | Automates container tracking, handles image orchestration, and triggers live hot-reloading into k3d. |
| Microservices | Frontend Core | React | Client browser rendering engine managing secure sessions and UI visual flows. |
| Microservices | Catalog Backend | Node.js / Go / Python | Controls item inventories and references. Pairs strictly with unstructured storage. |
| Microservices | Transactional Backend | Node.js / Go / Python | Processes state-driven consumer purchase checkouts and compliance-driven invoicing. |
| Data Layer | Product Storage | MongoDB (Cloud-Ready) | Document database housing global reference products alongside multi-tenant listings. |
| Data Layer | Order Ledger | PostgreSQL + Citus | Sharded relational engine executing horizontal table partitioning and row routing across servers. |
| Data Layer | Distributed Fast Cache | Redis | Accelerates data reads via lazy-loading. Resolves cache stampedes via Mutex locks. |
| Architecture | Data Sovereignty | Geo-Sharding via [tenant_id, country_code] | Restricts sensitive relational transaction logs to country boundaries via database-level shards. |
| Architecture | Multi-Tenancy | Composite JWT Token Mapping | Leverages a single shared compute container layer while using logical document IDs and Postgres tables to segregate clients. |
| Architecture | Geo-Fencing | API X-User-Country Header Matrix | Filters catalog displays by querying a blacklist/whitelist array inside item metadata to meet geographic constraints. |
| Data Flow | Asynchronous Sync | Debezium + Apache Kafka | Executes infrastructure-level Change Data Capture (CDC) via live log tracking to sync remote data analytics. |
| Traffic Gate | API Gateway & Routing | Traefik | Performs URL path validation, checks edge JWT signatures, and separates /v1 and /v2 microservice endpoints. |
| Identity | AuthN & AuthZ | Keycloak (OIDC) | Decouples core systems from user credentials by centralizing authentication and providing cryptographically signed JWT tokens. |
| Quality/QA | Code Linters | ESLint / Ruff / Golangci-lint | Enforces structural code patterns and identifies structural code smells before code review. |
| Quality/QA | Secret Interception | TruffleHog / Gitleaks | Evaluates local git histories and blocks commits if unencrypted security tokens are caught. |
| Quality/QA | Logic Testing | Vitest / PyTest / Go Test | Executes ultra-fast, local testing of functions without firing external infrastructure networks. |
| Quality/QA | Environment Testing | Testcontainers | Spins up live Docker containers of real databases (Mongo/Postgres/Redis) for clean integration tests. |
| Quality/QA | Static Code Security | SonarQube / Semgrep (SAST) | Audits codebase syntax trees for OWASP top-10 programming vulnerabilities during pull requests. |
| Quality/QA | Dependency Audit | Snyk / Dependabot (SCA) | Discovers and alerts developers to security issues in open-source third-party application modules. |
| Quality/QA | Container Integrity | Trivy | Reviews target container base filesystems for known CVE vulnerability patches during the build process. |
| Quality/QA | Runtime Testing | OWASP ZAP (DAST) | Fires automated pen-testing payload injections against live staging application endpoints. |
| Quality/QA | Manifest Evaluation | Datree / Kube-linter | Evaluates local Kubernetes configuration YAML layouts for misconfigurations before application. |
| Deployment | Environment Variant Overlay | Kustomize | Declares a standard base configurations directory and merges targeted environment patches natively. |
| Deployment | GitOps Delivery | Argo CD | Automates the complete delivery loop by monitoring Git changes and auto-correcting active cluster drift. |
Demystifying Kubernetes: Scaling, NodePorts, and the Myth of the "Chosen Pod"
Kubernetes has become the de facto orchestration platform for modern cloud-native applications. While containerization platforms like Docker solve packaging and deployment problems, Kubernetes solves the far more difficult challenges of scalability, resiliency, orchestration, and traffic management.
However, once developers move beyond basic tutorials and begin working with production-grade workloads, several practical questions emerge:
- How can an application automatically handle sudden spikes in traffic?
- How does Kubernetes distribute traffic among pods?
- Can a request be routed to one exact pod instance?
- What architectural patterns should be used for stateful applications?
This article provides a detailed and practical explanation of how Kubernetes scaling and networking work internally, including Horizontal Pod Autoscaling (HPA), NodePort services, StatefulSets, sticky sessions, and direct pod routing architectures.
Quick Reference Guide
| Component / Concept | Primary Function | Traffic Control Capability | Best Used For |
|---|---|---|---|
| Deployment | Manages application pod lifecycles and rolling updates. | None. Focuses on maintaining desired replica count. | Stateless web applications, APIs, microservices. |
| Service (NodePort) | Exposes an application port externally on cluster nodes. | Round-robin or random load balancing. | External access during development and testing. |
| StatefulSet | Provides stable pod identities and persistent naming. | Supports exact pod targeting with headless services. | Databases, Kafka clusters, distributed systems. |
| HPA | Automatically scales pods using metrics. | Scales based on CPU, memory, or custom metrics. | Traffic spikes and dynamic workloads. |
Part 1: Understanding Kubernetes Scaling
Consider a web application that normally operates with 3 pods handling approximately 100 requests per second. During high traffic periods, such as marketing campaigns or viral events, traffic may surge beyond 200 requests per second. In such scenarios, Kubernetes can automatically scale the application to additional pods using the Horizontal Pod Autoscaler (HPA).
The Default HPA Behavior
By default, HPA monitors CPU and memory consumption. When average resource utilization crosses configured thresholds, Kubernetes increases or decreases the number of pod replicas accordingly.
To scale based on request volume or other business metrics, Kubernetes supports Custom Metrics. This is commonly implemented using:
- Prometheus
- Prometheus Adapter
- KEDA (Kubernetes Event-Driven Autoscaling)
The HPA Scaling Formula
HPA periodically evaluates workload metrics and calculates the required replica count using the following formula:
Practical Example
Suppose:
- 3 pods comfortably handle 100 requests per second
- Target per-pod throughput is approximately 33 requests per second
- Traffic suddenly increases to 210 requests per second
Kubernetes computes:
Kubernetes therefore increases the deployment replica count from 3 to 7 pods in order to distribute the increased workload safely.
Example HPA Manifest
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-awesome-app-scaler
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app-deployment
minReplicas: 3
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 33m
Part 2: Understanding NodePort Services
A common misconception among Kubernetes beginners is the belief that a specific pod can be targeted directly through a NodePort service.
How NodePort Works
When a NodePort service is created:
- Kubernetes allocates a port from the NodePort range (typically 30000–32767).
- The port becomes accessible on every node in the cluster.
- kube-proxy intercepts incoming traffic.
- Traffic is forwarded to one available backend pod using load balancing.
↓
Traffic hits Node on Port 32500
↓
[kube-proxy Load Balancer]
↙ ↓ ↘
[Pod 1] [Pod 2] [Pod 3]
As a result, requests are distributed automatically, and clients cannot choose a specific pod through the NodePort alone.
Why Kubernetes Prevents Direct Pod Addressing
Pods are intentionally ephemeral. If a pod crashes, Kubernetes replaces it with a new pod having a different IP address. Directly exposing pod-specific networking to clients would make applications fragile and tightly coupled to infrastructure details.
The Service abstraction ensures:
- Stable networking endpoints
- Automatic failover
- Simplified service discovery
- Transparent load balancing
Part 3: Architectures for Targeting Specific Pods
Certain workloads require communication with a specific pod instance. Common examples include:
- Multiplayer gaming servers
- Sticky WebSocket sessions
- Distributed databases
- Kafka brokers
- Partition-aware applications
Option A: StatefulSet + Headless Service
This is the recommended approach for stateful distributed systems.
- Pods receive stable deterministic names.
- Example names: my-app-0, my-app-1, my-app-2
- A headless service exposes direct DNS entries for each pod.
- Applications can directly communicate with specific pod identities.
Option B: Dedicated Service per Pod
In scenarios where external traffic must target exact pods, a dedicated Kubernetes Service can be created for each pod using unique label selectors.
- Service A → NodePort 32501 → Pod 1
- Service B → NodePort 32502 → Pod 2
- Service C → NodePort 32503 → Pod 3
This bypasses generic load balancing and routes requests deterministically.
Option C: Ingress Controller with Session Affinity
For web applications requiring sticky sessions, an Ingress Controller such as NGINX Ingress can maintain affinity between a client and a backend pod using cookies.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "SERVERID"
Subsequent requests from the same browser are routed consistently to the same backend pod.
Frequently Asked Questions
What is the difference between a Pod, ReplicaSet, and Deployment?
| Component | Purpose |
|---|---|
| Pod | Runs the actual application container. |
| ReplicaSet | Maintains the required number of pod replicas. |
| Deployment | Manages ReplicaSets and rolling updates. |
How does Kubernetes prevent rapid scaling fluctuations?
Kubernetes prevents excessive scaling oscillations using stabilization windows and cooldown periods. After scaling up, the HPA intentionally waits before scaling back down, ensuring system stability during temporary traffic spikes.
Is NodePort obsolete?
No. NodePort remains useful for:
- Local Kubernetes environments (Minikube, Kind)
- Bare-metal clusters
- Internal development environments
- Testing and debugging
However, production systems typically use:
- Ingress Controllers
- Cloud LoadBalancers
- Service Meshes
Troubleshooting Checklist
- Verify HPA Metrics: Run kubectl get hpa. If the TARGETS column shows <unknown>, the metrics pipeline is failing.
- Check Service Endpoints: Run kubectl get endpoints <service-name>. Empty endpoints indicate label selector mismatches.
- Inspect NodePort Allocation: Run kubectl describe service <service-name> to confirm valid NodePort allocation.
Conclusion
Kubernetes abstracts enormous operational complexity behind relatively simple APIs. However, understanding the internal mechanics of scaling, service routing, traffic distribution, and pod identity is essential for building reliable cloud-native systems.
Horizontal Pod Autoscaling allows applications to react dynamically to changing workloads. Services and NodePorts provide stable networking abstractions, while StatefulSets and advanced ingress configurations enable deterministic routing for stateful applications.
Selecting the correct Kubernetes architecture depends heavily on whether the workload is stateless or stateful, internal or internet-facing, and whether exact pod targeting is required.
- "How do I make my app handle a sudden viral spike in traffic without waking me up at 3:00 AM?"
- "If I expose a port to the outside world, how on earth do I talk to one specific instance of my app?"
The Quick-Reference Guide
| Component / Concept | Primary Function | Traffic Control Capability | Best Used For |
|---|---|---|---|
| Deployment | Manages application pod lifecycles and rolling updates. | None. It focuses entirely on keeping the specified number of containers alive. | Stateless web apps, APIs, microservices. |
| Service (NodePort) | Exposes an application port on every cluster server (Node). | Random/Round-robin load balancing. You cannot pick a specific pod. | Basic external traffic entry points, development, testing. |
| StatefulSet | Manages pods with unique, permanent identities. | Highly specific. Paired with a Headless Service, you can target exact pods. | Databases (Mongo, Postgres), Kafka, distributed storage. |
| HPA (Horizontal Pod Autoscaler) | Dynamically scales pods up and down based on resource metrics. | Triggers scaling based on thresholds (CPU or request volume via Prometheus). | Handling unpredictable traffic surges automatically. |
Part 1: The Magic of Scaling (Or, How to Math Your Way to 6 Pods)
The Default Problem: CPU vs. The Real World
The Math Behind the Curtain
Step 1: Establish Your Baseline Target
Step 2: The Traffic Spike (Hitting 210 Requests)
- Current Replicas: 3
- Current Total Value: 210 requests (which averages to 70 requests per pod across the current 3 pods)
- Target Metric Value: 33 requests per pod
The Configuration Blueprint
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-awesome-app-scaler
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app-deployment
minReplicas: 3
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 33m # 'm' stands for milli-units in K8s; 33m represents our targeted average value
Part 2: The NodePort Dilemma (And Why You Can't Talk to Pod 2)
32500 externally, which maps to port 5000 inside your pods). You want to send a request specifically to Pod #2. How do you do it using only the port number?Understanding the NodePort Flow
[ External Internet User ]
│
▼
Traffic hits Node 1 on Port 32500
│
[ Kube-Proxy ] <── (The invisible referee)
│
┌───────────────────┼───────────────────┐
│ (Random) │ (Random) │ (Random)
▼ ▼ ▼
[ Pod 1 ] [ Pod 2 ] [ Pod 3 ]
32500 on any node, an internal network component called kube-proxy intercepts the traffic. kube-proxy looks at the available endpoints (your 3 pods), randomly selects one (using a round-robin style load-balancing algorithm), and forwards the traffic.Why Does Kubernetes Do This?
Part 3: Architectures to Target Specific Pods
Option A: The StatefulSet + Headless Service Pattern (Recommended)
Deployment, you deploy it as a StatefulSet.How it works:
- Predictable Identity: Instead of generating random hashes for pod names (like
my-app-7mz8x), a StatefulSet names its pods deterministically:my-app-0,my-app-1, andmy-app-2. Your "Pod 2" will permanently be known asmy-app-1(zero-indexed). - The Headless Service: You create a companion Service but set its cluster IP configuration field to
clusterIP: None.
http://cluster.localOption B: The "Dedicated Service per Pod" Pattern
How it works:
- Unique Labels: When writing your pod templates, ensure each pod receives a distinct metadata label distinguishing it from its siblings (e.g.,
app: my-app, instance: pod-1,app: my-app, instance: pod-2). - Multiple Services: You write separate service configuration manifests:
- Service 1: Listens on NodePort
32501and targets pods with the labelinstance: pod-1. - Service 2: Listens on NodePort
32502and targets pods with the labelinstance: pod-2.
- Service 1: Listens on NodePort
32502, the request will bypass the generic pool and route directly to Pod 2.Option C: The Ingress Controller with Cookie Affinity
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "SERVERID"
SERVERID cookie from their browser headers and guarantees that their subsequent requests are consistently routed back to the exact same backend pod.Technical Deep Dive: A Frequently Asked Questions Breakdown
Q: What is the difference between a Pod, a Deployment, and a ReplicaSet?
Q: If my metric value fluctuates wildly every few seconds, won't Kubernetes constantly scale up and down like crazy?
behavior section where you can define stabilization windows.Q: Why would anyone use NodePort if it lacks advanced routing capabilities? Is it obsolete?
Summary Troubleshooting Checklist
- Verify Metric Flow: Run
kubectl get hpa. If you see<unknown>under the TARGETS column, your HPA cannot communicate with your metrics server or custom adapter.
kubectl get endpoints <service-name>. If the list is empty, your Service's label selector does not match the labels declared in your Deployment template.Inspect Cluster Traffic: Use
kubectl describe service <service-name> to verify that your NodePort is allocated cleanly within the valid 30000–32767 range and hasn't conflicted with another app.Friday, May 22, 2026
kubernetes controllers and workloads
In Kubernetes, Workloads are the applications you run on the cluster, while Controllers are the background control loops that watch the state of your cluster and make changes to move the current state closer to the desired state.
Think of it this way: a Workload defines what you want to run, and a Controller is the mechanism that ensures it stays running exactly how you specified.
1. Kubernetes Workloads
A workload is an application running on Kubernetes. Whether it is a single component or several working together, you run it inside a set of Pods.
Because managing individual Pods manually is tedious and risky (if a Pod dies, it doesn't self-heal), Kubernetes uses higher-level workload resources to manage them for you.
Core Workload Types
Deployments: The most common workload type. Best suited for stateless applications (e.g., web servers, microservices).
It allows you to define how many identical replicas of a Pod you want, handles rolling updates, and lets you roll back to previous versions smoothly. StatefulSets: Tailored for stateful applications that require unique identities and persistent storage (e.g., databases like PostgreSQL, MySQL, or Kafka).
Unlike Deployments, Pods in a StatefulSet have a sticky identity (e.g., pod-0,pod-1) and pair with specific persistent volumes that persist even if a Pod is rescheduled.DaemonSets: Ensures that all (or some) Nodes run a copy of a Pod.
As nodes are added to the cluster, Pods are automatically started on them. This is ideal for infrastructure-level apps like log collectors (Fluentd), monitoring agents (Prometheus Node Exporter), or networking plugins. Jobs & CronJobs: Designed for ephemeral, run-to-completion tasks.
A Job creates one or more Pods and ensures that a specified number of them successfully terminate (e.g., a database migration script).
A CronJob runs Jobs on a time-based schedule, exactly like a traditional Linux cron job (e.g., nightly backups).
2. Kubernetes Controllers
A Controller is a tracking process that watches the shared state of the cluster through the API server and makes changes attempting to move the current state toward the desired state.
+-----------------------+ Watches +-----------------------+
| Desired State | <------------------ | |
| (YAML Configs) | | Kubernetes |
+----------------------+ | Controller Loop |
| (Reconciliation) |
+---------------------+ Modifies | |
| Current State | <--------------------| |
| (Actual Cluster) | | |
+---------------------+ +---------------------- -+
How They Work Together
Every workload mentioned above is actually driven by its own corresponding controller inside the Kubernetes control plane:
| Workload Resource | Managing Controller | What It Responsibly Watches |
| Deployment | DeploymentController | Watches ReplicaSets and Pods; handles rolling out updates without downtime. |
| StatefulSet | StatefulSetController | Maintains strict ordering and unique network/storage identifiers for its Pods. |
| DaemonSet | DaemonSetController | Listens for new nodes joining the cluster and ensures the daemon pod is scheduled onto them. |
| Job / CronJob | JobController | Tracks Pod exits codes to ensure tasks complete successfully; cleans up old pods. |
The Built-in Controller Manager
Most of these core loops are packed into a single binary running in the control plane called the kube-controller-manager.
Summary of Use Cases
Choose a Deployment if your app is a stateless API backend or frontend website.
Choose a StatefulSet if you are deploying a database or distributed system that cares about index order and identity.
Choose a DaemonSet if you need a utility tool running on every single server blade in your data center.
Choose a Job / CronJob if you want to run a batch processing script once or every Sunday at midnight.
Redis Topologies
Topology Best Used For Complexity Writes Scal...