Definition
- Pod – the smallest deployable unit in Kubernetes, wrapping one or more tightly-coupled containers that share a network address and storage volumes.
- Deployment – a controller that manages a set of identical Pods through a ReplicaSet, handling scaling, rolling updates, and self-healing.
- Service – a stable virtual IP and DNS name that load-balances across the Pods behind it, in three types: ClusterIP (internal), NodePort (per-node port), and LoadBalancer (cloud external).
- Ingress – an HTTP-layer router that directs external traffic to Services by hostname and URL path and terminates TLS.
- ConfigMap – a key-value store for non-secret configuration, injected into Pods as environment variables or mounted files.
- Secret – a key-value store for sensitive data like passwords and API keys, base64-encoded and optionally encrypted at rest.
Think of National Bank of India's call centre. A Pod is one agent at a desk handling calls. A Deployment is the workforce manager who keeps exactly twenty agents on the floor, replacing anyone who goes home sick. A Service is the single phone number customers dial that quietly routes to whichever agent is free. An Ingress is the front switchboard that sends loan queries to the loans team and card queries to the cards team. A ConfigMap is the shared handbook of non-secret procedures, and a Secret is the sealed envelope with the vault combination.
Understanding the Concepts
What is a Pod?
A Pod is the atom of scheduling in Kubernetes. It wraps one or more containers that must run together on the same node, sharing an IP address, network namespace, and often a volume. A Pod is ephemeral: when it dies, Kubernetes creates a brand-new one with a new IP.
# A simple Pod running the Transfer Service
apiVersion: v1
kind: Pod
metadata:
name: transfer-service-pod
labels:
app: transfer-service
spec:
containers:
- name: transfer-service
image: registry.nbi.com/transfer-service:2.5.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: production
# You almost never create Pods directly in production
# Instead you create a Deployment that manages Pods
kubectl apply -f transfer-deployment.yaml
kubectl get pods -l app=transfer-service
NAME READY STATUS RESTARTS AGE
transfer-service-7f8d4b5c6-abc12 1/1 Running 0 5m
transfer-service-7f8d4b5c6-def34 1/1 Running 0 5m
transfer-service-7f8d4b5c6-ghi56 1/1 Running 0 5m
What is a Deployment?
A Deployment is the object you actually declare in production. It wraps a ReplicaSet that ensures a specified number of identical Pods are always running. When you change the pod template, the Deployment performs a controlled rolling update and can roll back.
apiVersion: apps/v1
kind: Deployment
metadata:
name: transfer-service
namespace: banking
spec:
replicas: 3
selector:
matchLabels:
app: transfer-service
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: transfer-service
spec:
containers:
- name: transfer-service
image: registry.nbi.com/transfer-service:2.5.0
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
# Scale the Deployment
kubectl scale deployment/transfer-service --replicas=5 -n banking
# Check the rollout
kubectl rollout status deployment/transfer-service -n banking
What is a Service and what are its types?
A Service provides a stable virtual IP and DNS name and load-balances requests across all healthy Pods matching its label selector. Pod IPs are unstable because Pods come and go; a Service solves that.
# ClusterIP Service -- internal only
apiVersion: v1
kind: Service
metadata:
name: transfer-service
namespace: banking
spec:
type: ClusterIP
selector:
app: transfer-service
ports:
- port: 80
targetPort: 8080
---
# NodePort Service -- accessible on every node's IP
apiVersion: v1
kind: Service
metadata:
name: transfer-service-nodeport
spec:
type: NodePort
selector:
app: transfer-service
ports:
- port: 80
targetPort: 8080
nodePort: 30080
---
# LoadBalancer Service -- cloud external LB
apiVersion: v1
kind: Service
metadata:
name: transfer-service-lb
spec:
type: LoadBalancer
selector:
app: transfer-service
ports:
- port: 443
targetPort: 8080
| Type | Reachable from | Use case |
|---|---|---|
| ClusterIP | Inside cluster only | Microservice-to-microservice calls |
| NodePort | Outside via node IP:port | Simple external access, development |
| LoadBalancer | Outside via cloud LB | Production external traffic |
What is an Ingress?
An Ingress operates at the HTTP layer above Services. Instead of exposing many LoadBalancers, you run one Ingress controller and declare rules that route by hostname and URL path.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: banking-ingress
namespace: banking
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- api.nbi.com
secretName: nbi-tls-cert
rules:
- host: api.nbi.com
http:
paths:
- path: /transfers
pathType: Prefix
backend:
service:
name: transfer-service
port:
number: 80
- path: /accounts
pathType: Prefix
backend:
service:
name: account-service
port:
number: 80
What are ConfigMap and Secret?
A ConfigMap stores non-sensitive configuration as key-value pairs. A Secret stores sensitive data like database passwords. Both are injected into Pods as environment variables or mounted files, keeping configuration out of the image.
# ConfigMap for feature flags
apiVersion: v1
kind: ConfigMap
metadata:
name: transfer-config
namespace: banking
data:
LOG_LEVEL: "INFO"
FRAUD_CHECK_ENABLED: "true"
MAX_TRANSFER_AMOUNT: "1000000"
---
# Secret for database credentials
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: banking
type: Opaque
data:
DB_USERNAME: cmFqZXNo # base64 of 'rajesh'
DB_PASSWORD: c2VjdXJlcGFzcw== # base64 of 'securepass'
# Injecting ConfigMap and Secret into a Pod
spec:
containers:
- name: transfer-service
image: registry.nbi.com/transfer-service:2.5.0
envFrom:
- configMapRef:
name: transfer-config
- secretRef:
name: db-credentials
Why are Pods cattle, not pets?
A pet is a server you name, care for individually, and nurse back to health when sick. Cattle are a herd of identical, numbered animals; if one is unwell you replace it. Kubernetes Pods are cattle: identical, disposable, and replaceable. The practical consequence is that applications must be stateless or externalise their state.
package com.bank.service;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Service
public class TransferService {
private final TransferRepository repository; // state in DB, not in Pod
private final AccountClient accountClient; // calls via Service DNS
public TransferService(TransferRepository repository,
AccountClient accountClient) {
this.repository = repository;
this.accountClient = accountClient;
}
// Stateless: any Pod can handle any request
public TransferResult transfer(String fromAccount,
String toAccount,
BigDecimal amount) {
accountClient.debit(fromAccount, amount);
accountClient.credit(toAccount, amount);
return repository.save(new Transfer(fromAccount, toAccount, amount));
}
}
What about self-healing and the reconciliation loop?
The entire Kubernetes model is declarative and reconciliation-driven. You declare the desired end state in YAML, and controllers continuously work to make the actual state match. If a Pod crashes or a node dies, the ReplicaSet notices the count has fallen and creates replacements.
# Delete a pod -- Kubernetes recreates it automatically
kubectl delete pod transfer-service-7f8d4b5c6-abc12 -n banking
# Watch the self-healing
kubectl get pods -l app=transfer-service -n banking -w
NAME READY STATUS RESTARTS AGE
transfer-service-7f8d4b5c6-abc12 1/1 Terminating 0 10m
transfer-service-7f8d4b5c6-xyz99 0/1 Pending 0 1s
transfer-service-7f8d4b5c6-xyz99 1/1 Running 0 5s
What are common mistakes?
The most common mistake is creating bare Pods without a Deployment. When a bare Pod dies, nothing recreates it.
# WRONG: bare Pod -- no self-healing
apiVersion: v1
kind: Pod
metadata:
name: transfer-service
spec:
containers:
- name: transfer-service
image: registry.nbi.com/transfer-service:2.5.0
# CORRECT: Deployment manages the Pod lifecycle
apiVersion: apps/v1
kind: Deployment
metadata:
name: transfer-service
spec:
replicas: 3
selector:
matchLabels:
app: transfer-service
template:
metadata:
labels:
app: transfer-service
spec:
containers:
- name: transfer-service
image: registry.nbi.com/transfer-service:2.5.0
What should a senior engineer know?
A senior engineer understands that the declarative reconciliation model is the foundation of Kubernetes resilience. You never tell Kubernetes the steps; you describe the end state, and controllers converge reality toward it. When genuine per-instance identity is needed, such as a database cluster, you use a StatefulSet, precisely because ordinary Pods have no durable identity.
Visual Overview
External Traffic
│
▼
┌──────────┐ host/path rules ┌───────────────┐
│ Ingress │ ───────────────────→ │ Service (LB) │
└──────────┘ └───────┬───────┘
│ label selector
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Pod 1 │ │ Pod 2 │ │ Pod 3 │
│ [app] │ │ [app] │ │ [app] │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
ConfigMap Secret Volume
(env vars) (credentials) (storage)
┌───────────────────────────────────────────┐
│ Deployment │
│ desired: 3 replicas │
│ strategy: RollingUpdate │
│ │
│ ┌────────────────────────────────────┐ │
│ │ ReplicaSet │ │
│ │ actual: 3 → reconcile if < 3 │ │
│ └────────────────────────────────────┘ │
└───────────────────────────────────────────┘
Key Takeaway
The core Kubernetes objects each solve a specific problem. A Pod wraps containers, a Deployment manages Pods and handles updates, a Service gives a stable address, an Ingress routes HTTP traffic, and ConfigMap and Secret inject configuration. Pods are cattle, not pets: identical, disposable, and replaceable, which is why applications must externalise state to a database or object store.
The model is declarative: you describe the desired end state in YAML and controllers continuously reconcile reality toward it. That is why self-healing, scaling, and rolling updates all emerge from the same core idea. When a Pod dies, the ReplicaSet notices and creates a replacement, and the Service absorbs the churn because it always routes to whatever Pods are live.
At National Bank of India, the Transfer Service survived a midnight node failure with no human intervention because the Deployment's reconciliation loop replaced the lost Pod within seconds and the Service in front absorbed the churn completely.
Remember one sentence: Deployments keep disposable Pods running, Services give them a stable address, and no individual Pod is ever precious.
---