Introduction
The previous lab focused on logs and events. Those are the first signals, but sometimes you also need to inspect a running container or temporarily reach a Service from your terminal. Kubernetes provides two common tools for this: kubectl exec and kubectl port-forward.
In this lab, you will deploy a small web application, use kubectl exec to inspect files and processes inside one Pod, and use kubectl port-forward to open a temporary local connection to the Service. The workflow is intentionally small so you can focus on the debugging techniques instead of application complexity.
Prepare a Debugging Namespace
In this step, you will prepare a clean namespace for exec and port-forward practice.
Start in /home/labex/project. You will keep the application manifest in this directory.
mkdir -p /home/labex/project
cd /home/labex/project
Check that the Kubernetes API server is reachable. If the VM has just started and the node is not ready yet, wait a few seconds and run the command again.
kubectl get nodes --request-timeout=5s
Expected output includes:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
Wait until the cluster networking Pod is Ready. Port-forwarding uses the API server connection, but the application still needs a healthy Pod and Service.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
Expected output:
pod/calico-node-... condition met
Create a namespace named ckad-prep-debug and set it as the current namespace:
kubectl create namespace ckad-prep-debug
kubectl config set-context --current --namespace=ckad-prep-debug
Confirm the current namespace:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
Expected output:
ckad-prep-debug
Deploy a Small Web Application
In this step, you will deploy a simple application to inspect and access.
The Pod writes an index.html file and runs BusyBox httpd on port 8080. A Service named debug-web exposes the Pods inside the cluster on port 80. The Service is included because kubectl port-forward can target a Service as well as a Pod.
Create debug-web.yaml:
cat > debug-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: debug-web
spec:
replicas: 2
selector:
matchLabels:
app: debug-web
template:
metadata:
labels:
app: debug-web
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- |
mkdir -p /www
echo "debug-web-ready" > /www/index.html
httpd -f -p 8080 -h /www
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 1
periodSeconds: 2
---
apiVersion: v1
kind: Service
metadata:
name: debug-web
spec:
selector:
app: debug-web
ports:
- port: 80
targetPort: 8080
EOF
Apply the manifest and wait for the Deployment:
kubectl apply -f debug-web.yaml
kubectl rollout status deployment/debug-web --timeout=120s
Expected output includes:
deployment.apps/debug-web created
service/debug-web created
deployment "debug-web" successfully rolled out
Inspect the Pods and Service:
kubectl get pods -l app=debug-web
kubectl get service debug-web
Expected output includes two Running Pods and a ClusterIP Service:
debug-web-... 1/1 Running
debug-web ClusterIP
Inspect a Running Container with exec
In this step, you will use kubectl exec to run commands inside one application Pod.
kubectl exec is useful when the Pod is running but you need to inspect what the container sees. It is not a replacement for logs, and it should not be used to make hidden manual fixes during normal deployment. In a debugging workflow, it helps you confirm files, processes, environment, and local network behavior from inside the container.
Store one Pod name in a shell variable:
POD_NAME="$(kubectl get pods -l app=debug-web -o jsonpath='{.items[0].metadata.name}')"
echo "$POD_NAME"
Expected output is one Pod name:
debug-web-...
Run hostname inside the container. The output should match the Pod name because Kubernetes sets the container hostname from the Pod name.
kubectl exec "$POD_NAME" -- hostname
Expected output:
debug-web-...
List the running processes inside the container:
kubectl exec "$POD_NAME" -- ps
Expected output includes the httpd process:
PID USER TIME COMMAND
... root ... httpd -f -p 8080 -h /www
Read the file served by the web server:
kubectl exec "$POD_NAME" -- cat /www/index.html
Expected output:
debug-web-ready
Finally, test the web server from inside the same container:
kubectl exec "$POD_NAME" -- wget -qO- http://127.0.0.1:8080
Expected output:
debug-web-ready
Test the Service with Port Forwarding
In this step, you will use kubectl port-forward to access the Service from your terminal.
Port-forwarding creates a temporary tunnel from a local port to a Pod or Service in the cluster. It is useful for quick debugging because it does not require changing Service type, creating an Ingress, or opening external access. A foreground kubectl port-forward command keeps running until you stop it, so this lab starts it in the background, tests it, and then stops it.
Start a port-forward from local port 18080 to Service port 80. The output is written to /tmp/debug-web-port-forward.log so the terminal stays usable.
kubectl port-forward service/debug-web 18080:80 > /tmp/debug-web-port-forward.log 2>&1 &
PF_PID=$!
sleep 3
cat /tmp/debug-web-port-forward.log
Expected output includes:
Forwarding from 127.0.0.1:18080 -> 8080
Send a request through the local forwarded port:
wget -qO- http://127.0.0.1:18080
Expected output:
debug-web-ready
Stop the background port-forward process. This cleanup matters because otherwise the local port would remain in use.
kill "$PF_PID"
wait "$PF_PID" 2>/dev/null || true
Confirm the port-forward log recorded a handled connection:
cat /tmp/debug-web-port-forward.log
Expected output includes:
Handling connection for 18080
Summary
You practiced two practical debugging tools. You used kubectl exec to inspect a running container's hostname, processes, files, and localhost HTTP response. You also used kubectl port-forward to create a temporary local connection to a ClusterIP Service, tested it from the terminal, and stopped the background forwarding process cleanly.


