Introduction
Kubernetes, often abbreviated as K8s, is an open-source container orchestration platform that automates the deployment, scaling, and management of containerized applications. Originally developed by Google, Kubernetes has become the de facto standard for container orchestration in the industry, enabling organizations to efficiently manage their applications in a cloud-native environment.Kubernetes Core Concepts
This guide covers the essential building blocks of Kubernetes, organized chronologically from environment setup to production-ready service exposure. Every section includes not just the command, but the reasoning behind it — what is happening inside the cluster, what problems the feature solves, and what pitfalls to avoid.Table of Contents
- Namespaces: Logical Isolation
- Deployments and ReplicaSets
- Pods: The Atomic Unit
- Scaling and Node Resilience
- Services: Stable Networking
- Node Management
- Port Forwarding Techniques
- Common Workflow Summary
1. Namespaces: Logical Isolation
What is a Namespace?
A namespace is a virtual cluster inside a physical Kubernetes cluster. Think of it as a folder in a filesystem — it groups related resources together and provides a boundary for names, access control, and resource limits. Kubernetes creates three namespaces by default:default: Where resources go if you do not specify a namespace.kube-system: Reserved for Kubernetes control plane components (API server, scheduler, DNS, etc.).kube-public: A readable namespace for cluster-wide public resources.
Why Namespaces Matter
In a real-world organization, a single Kubernetes cluster often serves multiple teams, environments, or clients. Without namespaces, every resource lives in a flat global space, leading to collision and chaos.What Happens If You Skip Namespaces
Working exclusively in thedefault namespace works for a single-person lab, but it collapses quickly in any collaborative or multi-environment setup:
-
Naming Collisions
Two pods cannot share the same name, even if they belong to different teams or applications. Indefault, you quickly run into names likenginx-1,nginx-2,nginx-final,nginx-final-v2. -
Resource Chaos
Without resource quotas, a single misconfigured deployment (e.g., a memory leak or an infinite loop) can consume all available CPU or memory, starving other applications. -
Security Gaps
RBAC rules and NetworkPolicies are scoped to namespaces. Indefault, you cannot easily say “Team A can only see their own pods.” Everyone sees everything. -
Management Overhead
Runningkubectl get podsindefaultreturns every pod in the cluster. Debugging becomes noisy, and accidental deletions are more likely. -
No Clean Teardown
Without namespaces, deleting an environment means tracking down and deleting every individual pod, service, deployment, config map, and secret manually.
Creating a Namespace
Behind the scenes: The API server creates a Namespace object in etcd. From this point forward, any resource created with -n portainer is stored under this logical boundary. The Kubernetes scheduler still places pods on physical nodes based on resource availability — namespaces do not pin workloads to specific hardware.
Deploying Into a Namespace
Important: If the YAML file does not explicitly declaremetadata.namespace, the-nflag overrides the default. If the YAML does declare a namespace, it must match the-nflag or the command will fail.
Watching Pods Come Up
What-wdoes: It opens a watch stream to the API server. The server pushes updates to your terminal as pod statuses change — fromPendingtoContainerCreatingtoRunning. This is more efficient than repeatedly runningkubectl get pods.
Inspecting Pods Inside a Namespace
The-o wideoutput adds columns for:
- NODE: Which physical/virtual node the pod is running on
- IP: The pod’s internal cluster IP (not accessible from outside)
- NOMINATED NODE: If the scheduler pre-empted another pod to make room
- READINESS GATES: Custom conditions defined by the user
The Nuclear Option: Deleting a Namespace
⚠️ Warning: Namespace deletion is asynchronous. The namespace enters aTerminatingstate while the controller garbage-collects all child resources. If a finalizer is stuck (e.g., an external resource like a cloud load balancer cannot be released), the namespace may hang indefinitely. You can check the status with:
2. Deployments and ReplicaSets
What is a Deployment?
A Deployment is a declarative way to manage stateless applications. You tell Kubernetes: “I want 3 replicas of this container image running.” The Deployment controller then creates a ReplicaSet, which in turn creates and monitors the actual Pods.- Deployment handles rolling updates, rollbacks, and declarative scaling.
- ReplicaSet ensures the correct number of pods are always running.
- Pod is the actual running instance.
Creating a Deployment
What happens internally:
- The Deployment object is created in the API server.
- The Deployment controller notices the new object and creates a ReplicaSet with
replicas=3.- The ReplicaSet controller creates 3 Pod objects.
- The Scheduler assigns each Pod to a suitable node based on resource requests, taints, tolerations, and affinity rules.
- The Kubelet on each node pulls the
nginximage (if not cached) and starts the container.
Inspecting Deployments
kubectl describereveals:
- StrategyType: Usually
RollingUpdate(default) orRecreate- RollingUpdateStrategy:
maxUnavailableandmaxSurgepercentages- OldReplicaSets: Previous ReplicaSets kept for rollback
- Events: Recent scaling, image pulls, failures, and scheduling issues
Deleting a Deployment
Cascading behavior: By default,kubectl delete deploymentuses--cascade=background, meaning child objects are deleted by the garbage collector asynchronously. If you use--cascade=orphan, the ReplicaSet and Pods are left behind and become “orphaned.”
The Scaling Unit: Pod vs. Container
This is one of the most commonly misunderstood concepts in Kubernetes:Scaling occurs at the Pod level, not the Container level.If a pod contains multiple containers (e.g., an app container + a sidecar log shipper), scaling the deployment from 1 to 5 replicas creates 5 pods, each containing both containers. The containers inside a pod are not distributed across nodes — they are co-located, co-scheduled, and share the same network namespace and storage volumes. Implication: If you have a web server and a database in the same pod, scaling the deployment replicates both. This is usually wrong. Databases should be managed by StatefulSets, not Deployments, and should live in separate pods.
3. Pods: The Atomic Unit
What is a Pod?
A Pod is the smallest deployable unit in Kubernetes. It encapsulates:- One or more containers
- Shared storage volumes
- A unique cluster IP address
- Rules for how the containers run
Single-Container vs. Multi-Container Pods
Multi-Container Pod Example (Sidecar Pattern)
This example demonstrates a classic sidecar pattern: annginx web server serves content, while a debian container continuously writes timestamp data to a shared volume.
Deep dive into the components:emptyDirvolume: This is an ephemeral directory created when the pod is scheduled on a node. It exists for the lifetime of the pod. Both containers mount it at different paths (/usr/share/nginx/htmlfor nginx,/datafor debian), but they see the same underlying files. When the pod dies, theemptyDiris permanently deleted.commandandargs: These override the container’s default entrypoint. Here, we run a shell loop that appends a timestamp every 5 seconds. If this container crashes, Kubernetes restarts it according to the pod’srestartPolicy(default:Always). Shared network namespace: Both containers sharelocalhost. If the debian container needed to reach nginx, it could curlhttp://localhost:80.
When to Use Multi-Container Pods
Use multi-container pods only when containers are tightly coupled:- They must share a filesystem (like the example above).
- They must communicate over
localhostwith minimal latency. - They share the same lifecycle — if one dies, both should be restarted.
Inspecting Container Details
Key fields indescribeoutput:
- QoS Class:
Guaranteed,Burstable, orBestEffort— determines eviction priority under memory pressure- Conditions:
PodScheduled,ContainersReady,Initialized,Ready- Events: Image pull status, scheduling decisions, volume mount errors, OOMKills
4. Scaling and Node Resilience
Exposing a Deployment (Preparing for Traffic)
Before scaling, you need a Service so that traffic can reach your pods. A Service provides a stable endpoint that load-balances across all healthy pods matching its selector.Parameter breakdown:
--type=NodePort: Exposes the service on a static port (30000–32767) on every node’s IP--port=80: The port the Service listens on internally--target-port=80: The port the container actually exposes- The Service automatically selects pods with labels matching the deployment’s selector
Verifying Endpoints
What this shows: The actual pod IPs that the Service is forwarding traffic to. If endpoints are empty, the Service selector does not match any running pods — usually a labeling issue.
Scaling Up
Behind the scenes:Watch the scaling event:
- The Deployment’s
spec.replicasis updated to 6.- The Deployment controller notices the change and updates the ReplicaSet.
- The ReplicaSet controller creates 3 new Pod objects.
- The Scheduler places them on nodes with available resources.
- The Kubelet starts the containers.
Node Failure Behavior
Kubernetes is designed to be self-healing, but recovery is not instant. Here is the exact timeline when a worker node fails:
Simulate a node failure (KinD/Docker environment):
Why the delay? Kubernetes assumes network partitions are temporary. If it rescheduled pods immediately after every missed heartbeat, a brief network blip would cause unnecessary churn. The 5-minute eviction grace period is configurable via the --pod-eviction-timeout flag on the controller manager.
Ghost Pods
During node failure, pods on the lost node enterUnknown or Terminating states. These are sometimes called ghost pods because they appear in listings but are not actually running.
Find non-running pods:
Field selectors filter objects at the API server level, reducing the amount of data transferred. Valid phases:Force-delete stuck pods:Pending,Running,Succeeded,Failed,Unknown.
⚠️ Danger: --force --grace-period=0 bypasses graceful shutdown. The pod is removed from the API server immediately, but if the node was only partitioned (not dead), the actual container may keep running as an orphan. Use this only when you are certain the node is gone.
Forcing a Rolling Restart
If pods seem stale (e.g., stale configuration, memory fragmentation, or suspected corruption), trigger a controlled restart without changing the deployment spec:
How it works: Kubernetes adds an annotation (kubectl.kubernetes.io/restartedAt) to the pod template. Because the template changed, the Deployment creates a new ReplicaSet and performs a rolling update — one pod at a time by default — ensuring zero downtime.
5. Services: Stable Networking
The Problem Services Solve
Pods are ephemeral. Their IPs change when they:- Are rescheduled to a different node
- Are restarted after a crash
- Are scaled up or down
- Are replaced during a rolling update
How Services Select Pods
Services use label selectors. The Service maintains an EndpointSlice (or legacy Endpoints) object listing all pod IPs that match the selector. The kube-proxy component on each node configures iptables/IPVS rules to load-balance traffic across these IPs.Service Types Explained
Creating a NodePort Service
Sample output columns:
- CLUSTER-IP: Internal virtual IP (e.g.,
10.96.123.45)- EXTERNAL-IP: For LoadBalancer, the cloud-assigned public IP
- PORT(S):
80:31234/TCPmeans port 80 internally, port 31234 on every node externally
Accessing NodePort Services
Once created, you can reach the service via any node’s IP address:Security note: NodePort opens the port on every node in the cluster, even nodes not running the pod. kube-proxy routes the traffic to a healthy pod, potentially on a different node.
Headless Services
A Headless Service is used when you need direct pod-to-pod communication without load balancing — common with StatefulSets (databases, message queues).DNS behavior: Instead of returning a single ClusterIP, DNS returns A records for each matching pod:pod-0.my-headless-service.namespace.svc.cluster.local,pod-1.my-headless-service.namespace.svc.cluster.local, etc.
6. Node Management
Understanding Node Roles
A Kubernetes cluster consists of:- Control plane nodes: Run the API server, scheduler, controller manager, and etcd. These manage the cluster state.
- Worker nodes: Run user workloads (pods). They run the Kubelet, container runtime, and kube-proxy.
Viewing Cluster Nodes
Key columns inget nodes:
- STATUS:
Ready,NotReady,SchedulingDisabled- ROLES:
control-plane,worker,<none>- AGE: How long the node has been in the cluster
- VERSION: Kubernetes version running on the node
Labeling Nodes
Explicitly label worker nodes for clarity and scheduling control:What this does: Adds a label to the node object. The keynode-role.kubernetes.io/workeris a convention. The valueworkeris arbitrary but descriptive. This label can then be used in:
- Node selectors: Force a pod to run on worker nodes only
- Taints and tolerations: Prevent control-plane pods from scheduling on workers
- Affinity rules: Prefer or require certain node characteristics
Checking Pod Placement
To see which physical node hosts each pod:
Use case: If a pod is stuck in Pending, check if any node has sufficient resources. If pods are unevenly distributed, consider Pod Topology Spread Constraints or cluster autoscaler.
7. Port Forwarding Techniques
Port forwarding is essential when running local or private clusters (e.g., KinD, Minikube, or on-premise clusters without cloud load balancers). It tunnels traffic from your local machine into the cluster.Foreground Port Forwarding
Parameter breakdown:
-n portainer: Target namespacesvc/portainer: Target service named “portainer”9443:9443: Local port : Service port--address 0.0.0.0: Listen on all network interfaces (not just localhost), allowing other machines on your network to access it
How it works: The kubectl client opens a connection to the API server, which proxies the traffic to the service. The service then load-balances to a healthy pod. This is not suitable for production — it is a debugging and development tool.
Background Port Forwarding
Run the forwarder as a background process so it does not block your terminal:Command breakdown:
nohup: Prevents the process from terminating when you close the terminal> /dev/null: Discards stdout (connection logs)2>&1: Redirects stderr to stdout (so both are discarded)&: Runs the entire command in the background
Stopping Background Port Forwarding
Caution:pkill -fmatches the full command line. If you have multiple port-forwards running, this kills all of them. To target a specific one, usepgrep -f port-forwardto find the PID, thenkill <PID>.
Alternative: Using kubectl proxy
For API server access (not pod/service access), use:
http://localhost:8080.
8. Common Workflow Summary
Here is a complete, repeatable workflow for deploying a stateless application:Key Takeaways
Further Reading
- Kubernetes Documentation — Namespaces
- Kubernetes Documentation — Deployments
- Kubernetes Documentation — Pods
- Kubernetes Documentation — Services
- Kubernetes Documentation — Node