Kubernetes Concepts Explained Simply
Kubernetes can feel overwhelming with its own vocabulary and abstractions. But at its core, it solves a simple problem: how to run and manage containerized applications across multiple machines. Let's break down the essential concepts in plain terms.
Containers and Pods
You probably know containers: they package an app with its dependencies. Kubernetes runs containers, but it doesn't run them directly. Instead, it groups one or more containers into a Pod. A pod is the smallest deployable unit in Kubernetes. Think of a pod as a "logical host" for your containers. Containers in the same pod share the same network namespace and can communicate via localhost. They also share storage volumes.
Why pods? Sometimes you need a helper container (like a log shipper or a proxy) that lives alongside your main container. Those belong in the same pod because they are tightly coupled.
Nodes and Clusters
A node is a machine (physical or virtual) where pods run. A cluster is a set of nodes. You have at least one worker node that runs your pods, and a control plane that manages the cluster. The control plane makes global decisions (like scheduling), while the worker nodes actually run the workloads.
In production, you'd have multiple worker nodes for high availability and scalability.
Deployments and ReplicaSets
Running a single pod is not enough for production. You need to ensure the right number of replicas are running, and you want to roll out updates without downtime. That's where a Deployment comes in.
A Deployment describes a desired state (e.g., "run 3 replicas of nginx:1.19") and works to achieve it. Under the hood, it creates a ReplicaSet, which is responsible for maintaining the correct number of pod replicas. If a pod dies, the ReplicaSet starts a new one. When you update the Deployment (e.g., to nginx:1.20), it creates a new ReplicaSet and gradually scales it up while scaling the old one down.
Here's a minimal Deployment YAML:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19
ports:
- containerPort: 80
Services
Pods are ephemeral: they can be created, destroyed, and rescheduled. Their IPs are not stable. To provide a stable network endpoint, you use a Service. A Service is an abstraction that defines a logical set of pods (usually by label selector) and a policy to access them. It gets a stable cluster-internal IP and DNS name.
For example, a Service named my-service in the default namespace can be reached by other pods at my-service.default.svc.cluster.local. You can also expose a Service externally via a LoadBalancer or NodePort type.
Here's a simple Service definition:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
Ingress
While a Service can give you a stable IP, you often want HTTP-level routing, TLS termination, and path-based routing. That's the job of an Ingress. An Ingress is not a service type; it's a collection of rules that allow inbound connections to reach cluster services. You need an Ingress controller (like NGINX or Traefik) to implement those rules.
Example Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
ConfigMaps and Secrets
Applications often need configuration data that shouldn't be baked into the container image. ConfigMaps store non-sensitive configuration (like environment variables or config files). Secrets are similar but for sensitive data (like passwords or API keys). You can mount them as files or expose them as environment variables.
Example ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_URL: "postgres://db:5432/app"
Then in your pod spec, reference it:
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_URL
Namespaces
Kubernetes uses namespaces to divide cluster resources among multiple users or projects. They provide a scope for names. Resources inside a namespace must have unique names, but you can have the same name in different namespaces. They also help with resource quotas and access control.
Putting It All Together
A typical workflow: you write a Deployment YAML to define your app, create a Service to expose it internally, and maybe an Ingress to route external HTTP traffic. You store configuration in ConfigMaps and secrets in Secrets. Kubernetes takes care of the rest: scheduling pods, scaling replicas, and keeping the cluster healthy.
Start small: create a kind or minikube cluster locally, deploy a simple nginx Deployment, and expose it with a Service. Play with scaling and updates. Once you grasp these core objects, the rest of Kubernetes (like StatefulSets, Jobs, and Operators) will feel like natural extensions.
For more detail, check the official Kubernetes documentation.
Top comments (0)