Lab¶
Duration: 10 minutes
Objectives¶
- Verify cluster is running correctly
- Practice basic kubectl commands
- Create and interact with a Pod
- Explore using k9s
Prerequisites¶
- Workshop container running
- Inside the
/workspaces/compose-to-kubernetesdirectory
Tasks¶
Task 1: Cluster Verification¶
- List all nodes in the cluster
- Verify both nodes show
STATUS: Ready - Display cluster information
- View your kubeconfig (redacted for security)
Expected Output:
- 2 nodes:
workshop-control-planeandworkshop-worker; both withReadystatus - Cluster API server address displayed
Solution
# List all nodes
kubectl get nodes
# Output:
# NAME STATUS ROLES AGE VERSION
# workshop-control-plane Ready control-plane 5m v1.28.0
# workshop-worker Ready <none> 5m v1.28.0
# Display cluster information
kubectl cluster-info
# Output:
# Kubernetes control plane is running at https://127.0.0.1:45697
# CoreDNS is running at https://127.0.0.1:45697/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
# View kubeconfig
kubectl config view
# Output shows cluster, user, and context information
Task 2: Create and Inspect a Pod¶
-
Create a Pod named
test-busyboxusing thebusybox:latestimage that runs the commandsleep 3600Hint
Use
kubectl runwith--to specify the command:For sleep, the command is
sleepand the arg is3600. -
Wait for the Pod to be in
Runningstate - Get detailed information about the Pod (describe)
-
Execute the command
echo "Hello from inside the Pod!"in the PodHint
Use
kubectl exec:For echo, the full command is
echo "Hello from inside the Pod!"but you may need to handle quotes. -
Check the Pod's logs (even though it's just sleeping, there shouldn't be much)
- Get an interactive shell into the Pod and run:
hostname(should show Pod name)ls /-
exitHint
Use
kubectl execwith-itflags:Note: busybox uses
/bin/sh, not/bin/bash. -
Delete the Pod
Expected Outcomes:
- Pod successfully created and running
- Commands executed successfully
- Pod cleanly deleted
Solution
# 1. Create a Pod running busybox with sleep command
kubectl run test-busybox --image=busybox:latest -- sleep 3600
# Output:
# pod/test-busybox created
# 2. Wait for Pod to be Running
kubectl get pods -w
# Press Ctrl+C when you see:
# NAME READY STATUS RESTARTS AGE
# test-busybox 1/1 Running 0 5s
# Alternative: Wait until Running
kubectl wait --for=condition=Ready pod/test-busybox --timeout=60s
# 3. Get detailed information about the Pod
kubectl describe pod test-busybox
# Output shows:
# - Pod IP address
# - Node it's running on
# - Container details
# - Events (image pull, container started, etc.)
# 4. Execute a command in the Pod
kubectl exec test-busybox -- echo "Hello from inside the Pod!"
# Output:
# Hello from inside the Pod!
# 5. Check the Pod's logs
kubectl logs test-busybox
# Output:
# (empty or minimal, since sleep doesn't produce output)
# 6. Get an interactive shell
kubectl exec -it test-busybox -- /bin/sh
# Inside the Pod:
/ # hostname
test-busybox
/ # ls /
bin dev etc home proc root sys tmp usr var
/ # exit
# 7. Delete the Pod
kubectl delete pod test-busybox
# Output:
# pod "test-busybox" deleted
# Verify deletion
kubectl get pod test-busybox
# Output:
# Error from server (NotFound): pods "test-busybox" not found
Task 3: Explore with k9s¶
- Launch k9s
- Navigate to view Pods (
:pods) - Navigate to view Nodes (
:nodes) - Select the worker node and describe it (press
d) - Navigate to
kube-systemnamespace and view system Pods: - Type
:podsthen press Enter - Type
/kube-systemto filter - Browse the system Pods
- Exit k9s
Hint for k9s namespace filtering
In k9s, you can filter by namespace by typing / followed by search text, or use 0-9 keys to select namespace, or type : followed by resource type and namespace like :pods default.
Solution
# 1. Launch k9s
k9s
# 2. Navigate to Pods
# Type: :pods
# Press: Enter
# 3. Navigate to Nodes
# Type: :nodes
# Press: Enter
# 4. Describe a node
# Use arrow keys to select workshop-worker
# Press: d (for describe)
# Press: Esc (to go back)
# 5. View system Pods in kube-system
# Type: :pods
# Press: Enter
# Use namespace selector (press 0-9 or type namespace)
# Or type: :pods kube-system
# You should see Pods like:
# - coredns-XXXXX
# - etcd-workshop-control-plane
# - kube-apiserver-workshop-control-plane
# - kube-controller-manager-workshop-control-plane
# - kube-proxy-XXXXX
# - kube-scheduler-workshop-control-plane
# 6. Exit k9s
# Type: :q
# Or press: Ctrl+C
Task 4: Context and Namespaces¶
-
List all available contexts
-
Display the current context (should show
kind-workshop) -
List all namespaces in the cluster
Expected Output:
- Context:
kind-workshop - Namespaces:
default,kube-system,kube-public,kube-node-lease
Solution
# 1. List all contexts
kubectl config get-contexts
# Output:
# CURRENT NAME CLUSTER AUTHINFO NAMESPACE
# * kind-workshop kind-workshop kind-workshop
# 2. Display current context
kubectl config current-context
# Output:
# kind-workshop
# 3. List all namespaces
kubectl get namespaces
# or
kubectl get ns
# Output:
# NAME STATUS AGE
# default Active 10m
# kube-node-lease Active 10m
# kube-public Active 10m
# kube-system Active 10m
Bonus Challenges¶
1. Create multiple Pods: Create 3 Pods with different names but same image. Delete them all at once.
Solution
# Create 3 Pods
kubectl run pod1 --image=busybox:latest -- sleep 3600
kubectl run pod2 --image=busybox:latest -- sleep 3600
kubectl run pod3 --image=busybox:latest -- sleep 3600
# Verify they're running
kubectl get pods
# Delete all at once (by label would be better, but these don't have common labels)
kubectl delete pod pod1 pod2 pod3
# Or delete by pattern (if you have many)
kubectl get pods -o name | grep pod | xargs kubectl delete
2. Port forwarding: Create an nginx Pod, forward port 8080 locally to port 80 in the Pod, and curl it.
Solution
# Create nginx Pod
kubectl run nginx --image=nginx:latest
# Wait for it to be ready
kubectl wait --for=condition=Ready pod/nginx --timeout=60s
# Forward local port 8080 to Pod port 80
kubectl port-forward pod/nginx 8080:80 &
# Test it (in same or different terminal)
curl http://localhost:8080
# Output:
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# ...
# Stop port forwarding
kill %1 # If running in background
# Clean up
kubectl delete pod nginx
3. Resource inspection: Find out how much CPU and memory the workshop-worker node has allocated.
Solution
# Describe the worker node and look for capacity
kubectl describe node workshop-worker | grep -A 5 "Capacity:"
# Output:
# Capacity:
# cpu: X
# memory: XXXXKi
# pods: 110
# Allocatable:
# cpu: X
# memory: XXXXKi
# Or get all node resources in table format
kubectl get nodes -o custom-columns=NAME:.metadata.name,CPU:.status.capacity.cpu,MEMORY:.status.capacity.memory
4. System exploration: Use kubectl get all -n kube-system to see all resources in the system namespace. What do you notice?
Solution
# Get all resources in kube-system
kubectl get all -n kube-system
# Output shows:
# - Pods (system components)
# - Services (kube-dns, etc.)
# - DaemonSets (kube-proxy)
# - Deployments (coredns)
# - ReplicaSets (coredns-XXXXX)
# What you notice:
# 1. System Pods run on control-plane node (most of them)
# 2. DaemonSets ensure Pods run on every node (like kube-proxy)
# 3. CoreDNS uses Deployments (like regular apps)
# 4. Everything is a Pod at some level!
Common Mistakes¶
Using /bin/bash instead of /bin/sh¶
# WRONG (busybox doesn't have bash)
kubectl exec -it test-busybox -- /bin/bash
# CORRECT
kubectl exec -it test-busybox -- /bin/sh
Forgetting the -- separator¶
# WRONG
kubectl run test --image=busybox sleep 3600
# CORRECT
kubectl run test --image=busybox -- sleep 3600
Not waiting for Pod to be ready¶
# Might fail if Pod isn't ready yet
kubectl exec test-busybox -- echo hello
# Wait first
kubectl wait --for=condition=Ready pod/test-busybox
kubectl exec test-busybox -- echo hello
Troubleshooting¶
| Issue | Solution |
|---|---|
Pod stays in Pending |
Check: kubectl describe pod <name> for events |
| "command not found" error | Verify you're using /bin/sh not /bin/bash for busybox |
| Can't delete Pod | Use kubectl delete pod <name> --force --grace-period=0 |
| k9s won't start | Verify cluster is running: kubectl get nodes |
Key takeaways¶
- kubectl run is the quickest way to create a single Pod
- kubectl describe shows detailed information and events
- kubectl exec lets you run commands or get a shell inside Pods
- k9s provides a visual way to explore the cluster
- Contexts let you switch between different clusters
- Namespaces provide logical separation of resources
Next section¶
Once you've reviewed the content and completed the lab, proceed to the next section.