Kubernetes Lesson 13 – kubectl Introduction | Dataplexa
Kubernetes Fundamentals · Lesson 13
Hands-On Lesson — Open your cluster and follow along

kubectl Introduction

kubectl is the tool you will use every single day as a Kubernetes engineer. You have already been using it throughout this course — now we go deep. The full command structure, every essential flag, output formats, switching between clusters, and the shortcuts that save experienced engineers hours every week. Run every command in this lesson. Do not just read.

🖥️
Get your cluster ready — this lesson is all commands

Use Play with Kubernetes at labs.play-with-k8s.com or run minikube start. Every code block in this lesson is meant to be run. Seeing the output yourself is what makes it stick.

What kubectl Actually Is

kubectl (pronounced "kube-control") is a command-line tool that talks to your Kubernetes cluster's API Server. Every command you type becomes an HTTP request. When you type kubectl get pods, kubectl makes a GET request to the API Server and formats the JSON response into a readable table.

Anything kubectl can do, you could do with a plain curl command. kubectl is just a very convenient wrapper.

The Command Structure

Once you understand the structure, you can figure out almost any kubectl command without looking it up.

Anatomy of a kubectl Command
kubectl
the tool
+
get
the verb
+
pods
the resource type
+
payment-api
name (optional)
+
-n default
flags (optional)
Common verbs
get describe apply delete logs exec scale
Resource types and shortcuts
pods / po services / svc deployments / deploy nodes / no namespaces / ns

The get Command — Your Most-Used Command

The scenario: It is your first day on a new team. You need to quickly understand what is running in the cluster. These commands give you that picture in seconds.

# List all Pods in the current namespace
kubectl get pods

# List all Pods across every namespace
kubectl get pods -A

# List Pods with extra info — IP address and which node they are on
kubectl get pods -o wide

# Watch for live changes — updates every time something changes
kubectl get pods -w

# Filter Pods by label
kubectl get pods -l app=payment-api

# Get multiple resource types at once
kubectl get pods,services,deployments

# Get everything in the current namespace
kubectl get all
What to notice

RESTARTS: 2 on the auth-service — that Pod has crashed and restarted twice. Worth investigating with kubectl describe and kubectl logs --previous.

-o wide adds IP and NODE columns — useful when a specific node has problems and you need to see which Pods landed there.

Output Formats — Seeing More Than the Default Table

The scenario: You need the full YAML of a running object — to understand exactly how it is configured, debug an issue, or use it as a template for a new object.

# Full YAML of a running object — includes status Kubernetes wrote
kubectl get pod payment-api-7d9f8c6b4-x2p9k -o yaml

# Extract just the Pod IP with jsonpath — great for scripting
kubectl get pod payment-api-7d9f8c6b4-x2p9k -o jsonpath='{.status.podIP}'

# Get the container image name
kubectl get pod payment-api-7d9f8c6b4-x2p9k -o jsonpath='{.spec.containers[0].image}'

# List just names — useful for piping into other commands
kubectl get pods -o name

# Build a custom table showing exactly the columns you want
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,IP:.status.podIP
When each format is useful

-o yaml — the most useful debugging format. You see the full object as Kubernetes knows it, including the status it wrote. Great for seeing exactly why a Pod is in a certain state.

-o jsonpath — powerful for scripting. Extract exactly the field you need. Used constantly in CI/CD pipelines to get an image tag, an IP address, or a status field without parsing everything.

Namespaces — Staying in the Right Place

The scenario: Your company runs dev, staging, and production in the same cluster. You need to check what is happening in production without switching your default context.

# See all namespaces
kubectl get namespaces

# Run any command in a specific namespace with -n
kubectl get pods -n production
kubectl get pods -n kube-system

# Run across ALL namespaces
kubectl get pods -A

# Create a namespace
kubectl create namespace staging

# Set default namespace for your session
kubectl config set-context --current --namespace=production

# Switch back to default
kubectl config set-context --current --namespace=default

# Always check which namespace you are in before any destructive command
kubectl config view --minify | grep namespace
The most common and most costly kubectl mistake

Running a command in the wrong namespace. You think you are deleting a test Pod in staging but you are actually in production. Before any destructive command, always confirm which namespace you are in. Many engineers install kubens (part of the kubectx package) which shows your current namespace in the terminal prompt at all times — highly recommended.

Contexts — Switching Between Clusters

In real life you will have multiple clusters — local Minikube, a dev cluster, a production cluster. A context is a named combination of cluster, user and namespace stored in your kubectl config file. Switching context switches which cluster your commands go to.

# See all available contexts
kubectl config get-contexts

# Which context are you currently using?
kubectl config current-context

# Switch to a different cluster
kubectl config use-context production-gke

# Your config file lives at ~/.kube/config
# Cloud CLIs add new contexts here automatically:
# aws eks update-kubeconfig --name my-cluster --region us-east-1
# gcloud container clusters get-credentials my-cluster --zone us-central1-a
The star marks your active cluster

Every kubectl command you run goes to the cluster marked with *. Switching is instant. The kubeconfig file stores all credentials — when you configure a new EKS or GKE cluster, that cloud CLI automatically adds a new context to this file.

apply vs create — Which One to Use

Two commands create objects from YAML. They work differently in one important way.

# kubectl apply — CREATE if not exists, UPDATE if it does exist
# Use this almost always — it is the declarative approach
kubectl apply -f payment-deployment.yaml

# Apply everything in a directory
kubectl apply -f ./k8s/

# kubectl create — only CREATES. Errors if the object already exists
# Good for one-time setup like namespaces
kubectl create namespace test-ns

# Create objects from the command line without a YAML file
kubectl create deployment test-app --image=nginx:1.25 --replicas=2

# THE MOST USEFUL TRICK — generate YAML without applying anything
# Use this to bootstrap your YAML files instead of writing from scratch
kubectl create deployment test-app --image=nginx:1.25 --dry-run=client -o yaml

# Save it directly to a file, then edit and apply
kubectl create deployment test-app --image=nginx:1.25 --dry-run=client -o yaml > deployment.yaml
The --dry-run=client trick — use this constantly

Run kubectl create ... --dry-run=client -o yaml, redirect the output to a file, edit it to add resource limits, env variables, or labels. This is faster than writing YAML from scratch and the structure is always correct. Every experienced Kubernetes engineer does this.

describe — Your Best Debugging Command

The scenario: A Pod is stuck in Pending. A Deployment is not rolling out. In every one of these situations, kubectl describe is your first move. It shows the Events section that tells you exactly what happened.

# Describe a Pod — always read the Events section at the very bottom
kubectl describe pod payment-api-7d9f8c6b4-x2p9k

# Describe a Deployment
kubectl describe deployment payment-api

# Describe a Service — shows Endpoints (real Pod IPs behind it)
kubectl describe service payment-service

# Describe a Node — shows conditions, capacity, running Pods, events
kubectl describe node worker-node-01
Always read the Events section

Warning events mean something went wrong. Normal events are informational. When a Pod is stuck in Pending, the Events section explains exactly why — "0/3 nodes available: insufficient memory" or "no matching nodeSelector." The answer is almost always right there in plain English.

logs — Seeing What Your App Is Printing

The scenario: Users are reporting payment failures. You need to see what the payment API is printing to understand what is going wrong.

# Get logs from a Pod
kubectl logs payment-api-7d9f8c6b4-x2p9k

# Stream logs live — keep watching as new lines appear
kubectl logs payment-api-7d9f8c6b4-x2p9k -f

# Only the last 50 lines
kubectl logs payment-api-7d9f8c6b4-x2p9k --tail=50

# Logs from the last 1 hour
kubectl logs payment-api-7d9f8c6b4-x2p9k --since=1h

# THE MOST IMPORTANT ONE — logs from the PREVIOUS crashed container
# When a Pod is in CrashLoopBackOff, this shows you why it crashed
kubectl logs payment-api-7d9f8c6b4-x2p9k --previous

# Get logs from ALL Pods matching a label at once — no need to check each one
kubectl logs -l app=payment-api --all-containers=true
What the logs reveal

The logs show the problem immediately: Database connection refused. Now you know exactly where to look next — is the database Pod running? Does its Service exist?

kubectl logs -l app=payment-api streams logs from all matching Pods at once — far faster than checking each Pod individually when you have a scaled Deployment.

exec — Getting Inside a Running Container

The scenario: You want to check from inside the payment container whether it can reach the database. Running the check from your laptop will not work — networking inside the cluster is different.

# Open a bash terminal inside a running container
kubectl exec -it payment-api-7d9f8c6b4-x2p9k -- /bin/bash

# If bash is not available, use sh
kubectl exec -it payment-api-7d9f8c6b4-x2p9k -- /bin/sh

# Run a single command without opening a full terminal
kubectl exec payment-api-7d9f8c6b4-x2p9k -- env
kubectl exec payment-api-7d9f8c6b4-x2p9k -- cat /etc/nginx/nginx.conf

# In a multi-container Pod, specify which container with -c
kubectl exec -it payment-api-7d9f8c6b4-x2p9k -c payment-api -- /bin/bash
What this reveals

Running env shows all environment variables — including auto-injected Service host variables Kubernetes adds for every Service in the namespace. Quick way to confirm your container is receiving the config you expect.

port-forward — Testing Without Exposing

The scenario: You want to test a ClusterIP Service from your laptop without creating a LoadBalancer or NodePort. port-forward creates a secure tunnel.

# Forward local port 8080 to port 80 on a Service
kubectl port-forward service/payment-service 8080:80

# Forward to a specific Pod
kubectl port-forward pod/payment-api-7d9f8c6b4-x2p9k 8080:80

# Test it from another terminal while it is running
curl http://localhost:8080
When to use port-forward

Brilliant for local development testing — hit an internal database UI, test a ClusterIP API, check a monitoring dashboard — all without changing any Service types or creating security risks. The tunnel only exists while the command is running.

The Complete kubectl Cheat Sheet

Command What it does
Reading and Inspecting
kubectl get <resource> List resources as a table
kubectl get <resource> -o wide Table with extra columns — IPs, nodes
kubectl get <resource> -o yaml Full YAML including Kubernetes-written status
kubectl get <resource> -w Watch live — streams updates as they happen
kubectl describe <resource> <name> Human-readable details and Events section
kubectl logs <pod> -f Stream container logs live
kubectl logs <pod> --previous Logs from the last crashed container instance
Creating and Changing
kubectl apply -f file.yaml Create or update from YAML — use this always
kubectl create ... --dry-run=client -o yaml Generate YAML template without creating anything
kubectl edit <resource> <name> Open live object in editor — applies on save
kubectl scale deployment <name> --replicas=5 Change replica count immediately
kubectl delete <resource> <name> Delete an object
Debugging
kubectl exec -it <pod> -- /bin/bash Open terminal inside container
kubectl port-forward svc/<name> 8080:80 Tunnel a Service port to your laptop
kubectl run debug --image=busybox -it --rm -- sh Temporary debug Pod — auto-deletes on exit
kubectl top pods Live CPU and memory usage per Pod
Cluster and Config
kubectl config get-contexts List all clusters you can connect to
kubectl config use-context <name> Switch to a different cluster
kubectl api-resources List every resource type Kubernetes knows about
The three commands you will use 80% of the time

Day to day, Kubernetes work comes down to three commands over and over: kubectl apply to deploy, kubectl get to check what is running, and kubectl describe or kubectl logs to debug when things go wrong. Everything else is situational.

The best way to get fast with kubectl is muscle memory from using it every day. Run every command in this lesson on your own cluster right now.

👨‍💻 Your kubectl workout — do all three of these
1
Run kubectl create deployment nginx-test --image=nginx:1.25 --replicas=3 --dry-run=client -o yaml. Save the output to a file, add resource requests and limits, then apply it.
2
Deploy something broken: kubectl create deployment broken --image=nginx:this-does-not-exist. Diagnose it using only kubectl get pods and kubectl describe. Fix it with kubectl set image deployment/broken nginx=nginx:1.25.
3
Create a ClusterIP Service for your nginx-test Deployment. Then use kubectl port-forward svc/nginx-test 8080:80 and open http://localhost:8080 in your browser to confirm the full chain works.

Practice Questions

Type from memory.

1. A Pod is in CrashLoopBackOff. You want to see the logs from the previous crashed instance — not the one that just started. What command do you run?



2. You want to generate a Deployment YAML template without creating anything in the cluster. Which two flags do you add to kubectl create?



3. You have multiple clusters configured. You want to switch kubectl to the production GKE cluster whose context is named production-gke. What command do you run?



Knowledge Check

Pick the best answer.

1. A Pod has been in Pending for 10 minutes. What is the best first command to understand why?


2. What is the key difference between kubectl apply and kubectl create?


3. You want to test a ClusterIP Service from your laptop without changing it to NodePort or LoadBalancer. What do you do?


Up Next · Lesson 14

Kubernetes YAML Basics

Every Kubernetes object lives in a YAML file. We break down the full anatomy — apiVersion, kind, metadata, spec — and you will write real YAML for multiple object types from scratch. One lesson away from your first full end-to-end deployment.