# Kubernetes 101 — Pods, Deployments, and Services Explained

URL: https://www.devopsness.com/blog/kubernetes-101-pods-deployments-services
Author: Kiril Urbonas
Published: 2026-04-29
Updated: 2026-08-22
Categories: DevOps
Tags: Kubernetes, Containers, DevOps, Tutorial, Beginner

Summary: Run your first three Kubernetes objects — Pod, Deployment, Service — on a local cluster, then understand why each one exists and how they fit together.

---
# Kubernetes 101: Pods, Deployments, and Services Explained

By the end of this post you'll have a Kubernetes cluster running on your laptop, three core objects deployed to it (Pod, Deployment, Service), and a working mental model for what each one does. About 30 minutes start to finish.

You'll need Docker installed, plus `kubectl` and a local cluster tool (we'll use `kind`). Skip ahead to install steps if you don't have them yet.

## The mental model

Kubernetes is a system for running container workloads across a fleet of machines. Three core objects show up first when you start using it:

- A **Pod** is one or more containers running together as a unit. The smallest deployable thing in Kubernetes. Usually one container per Pod.
- A **Deployment** manages a set of identical Pods. It says "I want N copies of this Pod running at all times." If a Pod dies, the Deployment makes another. If you change the image, it does a rolling update.
- A **Service** is a stable network endpoint for a set of Pods. Pods come and go (different IPs each time); a Service has one IP that load-balances to whichever Pods are alive.

Almost everything else in Kubernetes (Ingresses, ConfigMaps, StatefulSets, autoscalers, RBAC) is an optimization on top of these three. Master these and you can read most production manifests.

## Step 1: Install kubectl and kind

`kubectl` is the command-line tool that talks to the cluster. `kind` runs Kubernetes inside Docker so you can have a real cluster on your laptop in under a minute.

On Mac:

```bash
brew install kubectl kind
```

On Linux, follow the official docs for both. On Windows, use WSL2 or Docker Desktop's bundled Kubernetes.

Verify:

```bash
kubectl version --client
kind version
```

You should see version output for both.

## Step 2: Start a local cluster

```bash
kind create cluster --name k8s-101
```

`kind` boots a cluster inside Docker. Takes about 30 seconds. When it finishes:

```bash
kubectl get nodes
```

You should see one node listed with status `Ready`. That's the whole cluster — one fake "machine" that's really just a Docker container.

## Step 3: Run your first Pod

Save this as `pod.yaml`:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello
spec:
  containers:
    - name: app
      image: nginx:1.27-alpine
      ports:
        - containerPort: 80
```

Apply it:

```bash
kubectl apply -f pod.yaml
kubectl get pods
```

You should see `hello   1/1   Running   0   30s`. The Pod is now running an nginx container.

Test it from inside the cluster:

```bash
kubectl exec hello -- curl -s http://localhost:80 | head -5
```

You should see nginx's default welcome page HTML.

So that's a Pod. One container, running. But Pods don't restart themselves if they die, and you can't easily run multiple copies. That's what Deployments are for.

## Step 4: Replace the Pod with a Deployment

```bash
kubectl delete pod hello
```

Save this as `deployment.yaml`:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: app
          image: nginx:1.27-alpine
          ports:
            - containerPort: 80
```

Apply it:

```bash
kubectl apply -f deployment.yaml
kubectl get pods -l app=hello
```

You should see three Pods, each with `1/1 Running`. The Deployment manages them.

Try killing one:

```bash
kubectl delete pod -l app=hello | head -1
kubectl get pods -l app=hello
```

You'll see the count drop briefly, then the Deployment spins up a replacement. That's the self-healing behavior — you say "I want 3", Kubernetes makes sure there's always 3.

## Step 5: Add a Service

The three Pods each have their own IP, but those IPs are ephemeral — they change when Pods restart. A Service gives you one stable endpoint.

Save this as `service.yaml`:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello
  ports:
    - port: 80
      targetPort: 80
```

Apply it:

```bash
kubectl apply -f service.yaml
kubectl get service hello
```

You'll see a `ClusterIP` like `10.96.123.45`. That's the stable internal address. Anything in the cluster can hit that IP and reach one of your nginx Pods (load-balanced).

Test it:

```bash
kubectl run curl-test --image=curlimages/curl:latest -i --rm --restart=Never -- \
  curl -s http://hello.default.svc.cluster.local
```

You should see nginx HTML returned. The Service did the DNS resolution, picked one of your three Pods, and forwarded the request.

## Step 6: Clean up

```bash
kind delete cluster --name k8s-101
```

That deletes the whole cluster. No leftover state on your machine.

## Common mistakes

**Forgetting the label selector.** A Service uses `selector` to decide which Pods receive traffic. If your Service's selector doesn't match the Pod labels, traffic goes nowhere — silently. Always check `kubectl get endpoints <service>` to confirm Pods are linked.

**Editing a Pod created by a Deployment.** If you change a Deployment-managed Pod directly, the Deployment will overwrite your change on the next reconcile. Edit the Deployment, not the Pod.

**Confusing Pod and Container.** A Pod can have multiple containers (sidecars), but most Pods have one. The Pod is the scheduling unit; the container is what actually runs.

**Using `kubectl apply` without seeing the diff.** Run `kubectl diff -f <file>` before applying — it shows exactly what will change. Saves you from accidental destructive updates.

## What to read next

You've used the three core objects. The next levels:

- [Kubernetes networking deep dive: Pods, Services, and Ingress](/blog/kubernetes-networking-deep-dive-pods-services-ingress) — how the packets actually flow once Services and Ingresses are in play
- [Kubernetes autoscaling: HPA, VPA, and the cluster autoscaler](/blog/kubernetes-autoscaling-hpa-vpa-cluster-autoscaler) — when "I want 3 replicas" should turn into "scale based on load"
- [GitOps with Argo CD: automating Kubernetes deployments](/blog/gitops-argocd-automating-kubernetes-deployments) — how teams manage clusters at scale

Pods, Deployments, Services. Three objects, one mental model. Most production manifests are these three plus a handful of namespaces, configmaps, and secrets. Once they click, the rest is incremental.

