Back to Kubernetes: Core Concepts
Q1Question 1 of 16

Core Kubernetes objects: Pod, Deployment, Service, Ingress, ConfigMap, Secret: and why Pods are "cattle, not pets"

Key Concepts
  • A Pod is the smallest deployable unit, wrapping one or more containers that share a network address and storage.
  • A Deployment manages identical Pods through a ReplicaSet, handling scaling, rolling updates, and self-healing.
  • A Service provides a stable virtual IP and DNS name, load-balancing across Pods: ClusterIP for internal, NodePort for per-node, LoadBalancer for external.
  • An Ingress routes external HTTP traffic to Services by host and path and terminates TLS.
  • ConfigMap holds non-secret configuration; Secret holds sensitive values like passwords, both injected into Pods as env vars or files.
  • Pods are cattle, not pets: identical, disposable, and replaceable, so applications must externalise state.

Definition

Deployments keep interchangeable Pods running, Services give them a stable address, Ingress routes outside traffic in, ConfigMaps and Secrets feed them configuration, and no Pod is ever precious.
  • 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.

YAML
# 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
BASH
# 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
TEXT
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.

YAML
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"
BASH
# 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.

YAML
# 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.

YAML
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.

YAML
# 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'
YAML
# 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.

JAVA
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.

BASH
# 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
TEXT
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.

YAML
# 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
YAML
# 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

DIAGRAM
  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.

---

Share
Use ← → arrow keys to navigate