On this page
  1. Before you start
  2. Step 1 — Write the Deployment
  3. Step 2 — Write the Service
  4. Step 3 — Apply and verify
  5. Step 4 — Reach the app
  6. Step 5 — See self-healing in action
  7. Where AI coding assistants get this wrong
  8. Checklist
  9. FAQ
    1. What is the difference between a Deployment and a Pod?
    2. Why can’t I reach my app after applying?
    3. Do I need a Service to reach my pods?
  10. Related topics
  11. Sources
tutorial

How to Deploy Your First App to Kubernetes

A step-by-step tutorial to deploy a containerized app to Kubernetes with a Deployment and Service, using minikube and kubectl.

Quick answer

  • Deploying to Kubernetes means applying a Deployment (what to run) and a Service (how to reach it).
  • Run a local cluster with minikube, kubectl apply your manifests, and port-forward to see the app.
  • A working deploy shows Running pods and a reachable endpoint; that is your success signal.

Before you start

You need Docker or another container tool, kubectl, and a local cluster. Install minikube, then start a cluster:

minikube start
kubectl cluster-info

How to verify it worked: cluster-info prints your control-plane and CoreDNS URLs without errors.

Step 1 — Write the Deployment

Create deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: hello
          image: nginxdemos/hello:plain-text
          ports:
            - containerPort: 80

This declares two replicas of a small demo web server. The selector and the pod labels must match, or the Deployment cannot manage its pods.

Step 2 — Write the Service

Create service.yaml:

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

The Service selects the pods labeled app: hello and exposes their port 80.

Step 3 — Apply and verify

kubectl apply -f deployment.yaml -f service.yaml
kubectl get pods
kubectl get service hello-service

How to verify it worked: get pods shows two pods in Running state, and get service lists hello-service with a port mapping. If a pod is stuck in ImagePullBackOff, the image name or tag is wrong.

Step 4 — Reach the app

For a local cluster, forward a port to the Service:

kubectl port-forward service/hello-service 8080:80

Open http://localhost:8080 in a browser. You should see the demo server’s plain-text response.

Step 5 — See self-healing in action

Delete one pod and watch Kubernetes replace it:

kubectl delete pod -l app=hello
kubectl get pods -w

A new pod appears to restore the declared replica count — the reconciliation loop from What Is Kubernetes? working as designed.

Where this bites vibecoders

The classic AI-generated deploy uses latest tags, no resource limits, and no readiness probe, so it appears to deploy but serves 502s or gets evicted under load. After your first apply, check kubectl describe pod — not just get pods — to see events, image errors, and probe failures that explain what is actually wrong.

Where AI coding assistants get this wrong

  • Using latest image tags that make rollbacks impossible to reason about.
  • Omitting resource requests/limits, inviting eviction or node starvation.
  • Mismatching the Service selector and the pod labels so nothing routes.
  • Forgetting a readiness probe, sending traffic before the app can respond.

Checklist

  • Pin exact image tags and make the image available to the cluster.
  • Match the Deployment selector and pod labels exactly.
  • Set resource requests and limits on every container.
  • Add readiness and liveness probes.
  • Verify with kubectl describe and kubectl logs, not just a green apply.

FAQ

What is the difference between a Deployment and a Pod?

A pod runs containers; a Deployment manages pods, declaring how many replicas should exist and which image they run. You almost never create pods directly — you create a Deployment and let it own the pods.

Why can’t I reach my app after applying?

The most common causes are a Service selector that does not match pod labels, a pod not yet Running, or a port mismatch. Check kubectl get pods and kubectl describe service to trace the path.

Do I need a Service to reach my pods?

Pods have their own IPs, but those change when pods are replaced. A Service gives a stable address that load-balances across matching pods. Always expose pods through a Service.

Sources

Share: