Kubernetes how-to
kubectl exec: Run Commands and Open a Shell in a Pod
kubectl exec runs a command inside a running container. Add -it and a shell opens in the pod, which is the quickest way to check a file, an environment variable or a network route from inside the workload. If the image has no shell, the command fails, and the fix is an ephemeral debug container.
By Muhammad Soliman, Founder at SeaGit
·
Key takeaways
- Syntax: kubectl exec POD -c CONTAINER -- COMMAND. The -- separates kubectl flags from the command you run in the pod.
- Use -i -t for an interactive shell. Without them the command runs once and prints the output.
- A distroless or minimal image often has no sh. The error is "executable file not found in $PATH". Use kubectl debug with a busybox container instead of installing tools into a production image.
- Exec runs in the container filesystem. Anything you change is lost when the container restarts, so exec is for inspection, not for fixing the image.
Syntax, the -- separator, and container selection
The reference gives the form kubectl exec (POD or TYPE/NAME) with a container flag, other flags, and then -- COMMAND. The double dash is not optional when the command has its own flags. Without it, kubectl reads ls -t as its own flag.
# Run one command in the first container of a pod
kubectl exec my-api-7c9f -n prod -- date
# Pick a container in a multi-container pod
kubectl exec my-api-7c9f -n prod -c ruby-container -- date
# Interactive shell (-i keeps stdin open, -t allocates a terminal)
kubectl exec -it my-api-7c9f -n prod -c my-api -- sh
# Target a Deployment or Service: kubectl picks one pod
kubectl exec -it deploy/my-api -n prod -- shUse the deploy/ form when you do not care which replica answers. Use the pod name when you are comparing replicas, because a random pick hides a bad node or a stale pod.
The image has no shell: the exact error and the fix
The Kubernetes debugging page demonstrates this with a minimal image. Trying to exec a shell into it fails like this:
OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknownThe fix in the official page is an ephemeral debug container. kubectl debug adds a container to the running pod, with its own tools, and --target shares the process namespace of the container you are debugging. It does not restart the pod.
# Attach a busybox debug container targeting the app container
kubectl debug -it my-api-7c9f -n prod --image=busybox:1.28 --target=my-api
# Inside it, look at the app's processes and files
ps aux
ls /proc/1/root/Do not patch the image in production to add a shell
Adding curl or bash to a production image to make exec work changes what runs in prod and the next build will remove it. An ephemeral container leaves the image alone and goes away with the pod.
Useful patterns for inspection
Most exec sessions are checks: is the config file the one I expect, does the process resolve the right hostname, is the disk full. These one-liners answer those questions without an interactive shell, so they are easy to put in a runbook.
# What environment does the app see?
kubectl exec deploy/my-api -n prod -- env | sort
# Can the pod resolve and reach a dependency?
kubectl exec deploy/my-api -n prod -- getent hosts db.internal
# Disk use inside the container
kubectl exec deploy/my-api -n prod -- df -h- env inside exec shows the variables the container runs with. Compare it with the manifest when a value looks stale.
- Exec into a crash-looping pod fails because the container is not running. Use kubectl logs --previous or kubectl debug on a copy of the pod instead.
- Writing files with exec is a change to a running container, which the next restart erases. Use it to test a fix, then put the fix in the manifest.
Access control: exec is a powerful permission
A user who can exec into a pod can read its secrets from the environment and its mounted volumes, and can reach its network. Treat the exec permission as production access. In Kubernetes RBAC the permission is granted on the pods/exec subresource, so check which roles and service accounts hold it before you hand out cluster-wide read access.
On a shared cluster, pair exec permissions with an audit log, and use a namespace-scoped role for developers rather than a cluster role.