Kubernetes Architecture Series – Part 2: Designing Scalable and Resilient Applications


This is the second part of our three-part Kubernetes architecture series. In Part 1, we explored Kubernetes from the infrastructure and orchestration perspective. We discussed the control plane, data plane, and core components that make Kubernetes the go-to orchestrator for cloud-native workloads.
In this part, we’ll shift gears and explore Kubernetes from the application perspective. Whether you’re a developer, architect, or platform engineer, your job doesn’t end with writing code—your applications need to run in a scalable, cost-effective, and secure manner. They should be resilient, self-healing, and capable of recovering from failures with minimal disruption.
That’s where Kubernetes really shines—and we’ll explore how using some of its built-in primitives.
Our focus in this article will be on scaling and resilience, two of the biggest challenges when running applications at scale. You’ll see how Kubernetes objects like Pods, ReplicaSets, Deployments, Services, and Ingress help us build robust application architectures.
Throughout the post, we’ll also show examples of Kubernetes YAML configurations to ground the theory in real-world usage.
Deploying Your Application with Pods
As we discussed in Part 1, the Pod is the smallest deployable unit in Kubernetes. But what exactly is a Pod? And how does it differ from a container?
Think of a Pod as a wrapper around one or more containers that need to run together. While a container is a single isolated environment to run an application, a Pod groups containers that are tightly coupled and share the same network and storage namespace.
You might wonder why a Pod would contain multiple containers. One common reason is when you use sidecar containers. These are utility containers that support the main container and have a tightly linked lifecycle. For example, a sidecar might collect logs, proxy traffic, or sync configuration files. If the main container stops, the sidecar should stop too—and vice versa.
Example: Pod with Single Container (nginx)
apiVersion: v1
kind: Pod
metadata:
name: music
spec:
containers:
- name: musicContainer
image: nginx
Example: Pod with Sidecar Logging Container
apiVersion: v1
kind: Pod
metadata:
name: music
spec:
containers:
- name: musicContainer
image: nginx
- name: log-sidecar
image: busybox
args: ['/bin/sh', '-c', 'tail -f /var/log/nginx/access.log']
Scaling Pods
A single Pod is not resilient. If it crashes, traffic is lost. If demand spikes, it can’t scale on its own. In early container deployments, we used to manually spin up additional containers—which worked at a small scale but quickly became unsustainable. Worse, because Pods are ephemeral, they're more likely to disappear than a traditional server—so manual scaling is actually riskier than before.
This is where ReplicaSets come in. A ReplicaSet ensures that a specified number of Pod replicas are always running. If a Pod crashes, the ReplicaSet spins up a replacement. If demand increases and we change the desired number of replicas, the ReplicaSet adjusts accordingly.
However, ReplicaSets don’t offer features like versioning, rolling updates, or rollback. They are powerful, but not application-aware.
Example: ReplicaSet for the Music Pod
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: musicReplica
spec:
replicas: 3
selector:
matchLabels:
app: music
template:
metadata:
labels:
app: music
spec:
containers:
- name: musicContainer
image: nginx
Scaling and Deploying with Deployments
To bridge the gap between operational automation and application lifecycle management, Kubernetes provides Deployments.
Deployments manage ReplicaSets under the hood but offer critical functionality like versioned updates, rolling deployments, and rollback. When you update a Deployment, Kubernetes creates a new ReplicaSet with the updated specification and gradually shifts traffic to the new Pods—ensuring zero downtime during the rollout.
Example: Music Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: music-deployment
spec:
replicas: 3
selector:
matchLabels:
app: music
template:
metadata:
labels:
app: music
spec:
containers:
- name: musicContainer
image: nginx:1.25
Adding Resiliency to Kubernetes Deployments
In distributed systems, failure domains are critical. Kubernetes allows us to spread Pods across nodes, availability zones, or even regions using anti-affinity rules.
For example, you can ensure that Pods of the same deployment do not land on the same node using a topologyKey
such as kubernetes.io/hostname
.
Example: Anti-Affinity for Spreading Pods Across Nodes
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- music
topologyKey: 'kubernetes.io/hostname'
Kubernetes also supports other topology keys like:
topology.kubernetes.io/zone
topology.kubernetes.io/region
This allows for even higher levels of fault tolerance across zones or cloud regions.
Deployment Strategies
Kubernetes supports two built-in deployment strategies:
RollingUpdate (Default)
RollingUpdate gradually replaces old Pods with new ones, minimizing downtime.
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
Pros: No downtime, graceful transition Cons: If something breaks, users might get a mix of old and new versions before rollback
Recreate
Recreate stops all old Pods before starting new ones.
strategy:
type: Recreate
Pros: Simpler, useful when app cannot handle multiple versions running concurrently Cons: Downtime during deployment
Exposing Applications Using Services
Your Deployment may be running multiple Pods—but how do clients (internal or external) find and connect to them?
Kubernetes Services act as stable frontends for Pods, abstracting away the ephemeral nature of Pods by load-balancing traffic to healthy instances.
There are several service types:
- ClusterIP (default): Internal-only access within the cluster
- NodePort: Exposes the service on a static port on each node’s IP
- LoadBalancer: Provisions an external load balancer (on supported cloud providers)
Example: ClusterIP Service for Music App
apiVersion: v1
kind: Service
metadata:
name: music-service
spec:
selector:
app: music
ports:
- port: 80
targetPort: 80
type: ClusterIP
This allows any other Pod in the cluster to access the service via music-service
.
Ingress: The Gatekeeper to Your Cluster
While Services expose individual Deployments, Ingress allows you to route external traffic to the appropriate Service using rules based on domain names or paths.
Ingress also handles TLS encryption, authentication, and centralized routing. Think of Ingress as the security guard and traffic cop combined.
An Ingress Controller like NGINX or Traefik implements the logic defined in your Ingress resource and ensures only the right traffic reaches your services.
Advanced Deployment Strategies: Blue/Green and Canary
As we saw earlier, Kubernetes supports RollingUpdate
and Recreate
, but Blue/Green and Canary deployments are more advanced strategies. Kubernetes doesn’t support them natively—but you can build them using Deployments + Services + Ingress or extend them with tools like Argo Rollouts or Flagger.
Blue/Green Deployment
In a Blue/Green deployment, you have two versions of the application (blue = current, green = new). You deploy the new version (green), test it, and then switch the Service or Ingress to point to green once it's verified.
# Two deployments: music-blue and music-green
# Service initially routes to music-blue
# Once green is verified, update the selector in music-service to route to music-green
This allows zero-downtime deployments with easy rollback (just switch back to blue).
Canary Deployment
In Canary deployments, a small percentage of traffic is sent to the new version to monitor behavior before gradually increasing the traffic.
# Two deployments: music (stable) and music-canary (new)
# Use Ingress rules or service weight-based routing to control traffic flow
This approach is excellent for A/B testing and minimizing blast radius during rollouts.
Conclusion
In this post, we’ve taken a deep dive into how Kubernetes helps you scale, deploy, and expose your applications reliably and efficiently.
We explored how:
- Pods are the foundational unit of deployment.
- ReplicaSets and Deployments add resilience and automation.
- Services and Ingress enable internal and external traffic routing.
- Kubernetes lets you implement powerful deployment strategies, including rolling updates, Blue/Green, and Canary models.
In the final part of this series, we’ll explore the configuration management side of Kubernetes. We’ll look at handling application Secrets, managing multi-tenancy with Namespaces, and storing data persistently using Volumes, Persistent Volumes, and Persistent Volume Claims.
Stay tuned—because running containers is just the beginning. Making them stateful, secure, and tenant-aware is what we’ll tackle next.