kubectl exec

Execute a command in a container. Provides interactive shell access for debugging running containers.

kubectl exec [POD] [-c CONTAINER] -- [COMMAND] [args...]

Common Flags

FlagShortDescription
--stdin-iPass stdin to the container
--tty-tAllocate a TTY for the session
--container-cContainer name. If omitted, uses the first container in the pod
--namespace-nNamespace of the pod
--quiet-qOnly print output from the remote session

Examples

Run a command in a pod

kubectl exec my-pod -- ls /app

Open an interactive shell

kubectl exec -it my-pod -- /bin/bash

Execute in a specific container

kubectl exec -it my-pod -c sidecar -- /bin/sh

Check environment variables

kubectl exec my-pod -- env

Test network connectivity from inside a pod

kubectl exec my-pod -- curl -s http://other-service:8080/health

Check DNS resolution

kubectl exec my-pod -- nslookup kubernetes.default.svc.cluster.local

View file contents inside a container

kubectl exec my-pod -- cat /etc/nginx/nginx.conf

When to Use kubectl exec

kubectl exec runs commands inside a container, giving you direct access to the running environment. It is the Kubernetes equivalent of docker exec and is essential for interactive debugging, inspecting the container filesystem, and testing connectivity from inside the cluster network.

Interactive Shell Access

The most common use is opening an interactive shell:

# Bash shell (if available)
kubectl exec -it my-pod -- /bin/bash

# Bourne shell (more broadly available)
kubectl exec -it my-pod -- /bin/sh

# In a specific namespace
kubectl exec -it my-pod -n production -- /bin/bash

The -i flag keeps stdin open for interaction, and -t allocates a pseudo-TTY so you get a proper terminal experience with command history and line editing.

The Double Dash Separator

Always use -- before the command you want to execute:

# Correct: -- separates kubectl flags from the container command
kubectl exec my-pod -- ls -la /app

# Without --, the -l flag confuses kubectl
# BAD: kubectl exec my-pod ls -la /app

This separator is critical when your command includes flags that could conflict with kubectl's own flags.

Debugging Network Issues

exec is invaluable for testing connectivity from inside the cluster:

# Test service discovery
kubectl exec my-pod -- nslookup my-service.default.svc.cluster.local

# Test HTTP connectivity
kubectl exec my-pod -- curl -s -o /dev/null -w "%{http_code}" http://api-service:8080/health

# Test TCP connectivity
kubectl exec my-pod -- nc -zv database-host 5432

# Check routing
kubectl exec my-pod -- traceroute external-host.com

# View network interfaces and IPs
kubectl exec my-pod -- ip addr show

Inspecting Container State

Examine the running environment to understand how the container is configured:

# View environment variables
kubectl exec my-pod -- env | sort

# Check mounted volumes
kubectl exec my-pod -- df -h

# View mounted secrets or configmaps
kubectl exec my-pod -- ls /var/run/secrets/kubernetes.io/serviceaccount/

# Check the service account token
kubectl exec my-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

# View process list
kubectl exec my-pod -- ps aux

# Check resource usage
kubectl exec my-pod -- top -bn1

Multi-Container Pods

For pods with sidecars or multiple containers, specify the target:

# List container names
kubectl get pod my-pod -o jsonpath='{.spec.containers[*].name}'

# Exec into the application container
kubectl exec -it my-pod -c app -- /bin/bash

# Exec into the sidecar
kubectl exec -it my-pod -c istio-proxy -- /bin/sh

# Check sidecar logs from inside
kubectl exec my-pod -c fluentd -- tail -20 /var/log/app.log

Running One-Off Commands

Exec can run single commands without an interactive session:

# Database operations
kubectl exec my-pod -- mysqldump -u root mydb > backup.sql

# Run a Django management command
kubectl exec my-pod -- python manage.py migrate

# Clear application cache
kubectl exec my-pod -- redis-cli FLUSHALL

# Run a health check script
kubectl exec my-pod -- /app/healthcheck.sh

Security Considerations

kubectl exec is a powerful capability that should be restricted in production:

# RBAC rule to deny exec access
# In a Role or ClusterRole:
# rules:
# - apiGroups: [""]
#   resources: ["pods/exec"]
#   verbs: []  # empty = no access

Audit logs capture exec events, so security teams can track who accessed which containers. For production debugging, prefer kubectl debug with ephemeral containers over exec, as it provides a controlled debugging environment without modifying the running container.

Limitations

Exec requires the container to have the command binary installed. Distroless and minimal images may lack shells and common utilities. In these cases:

# Use kubectl debug instead
kubectl debug my-pod -it --image=busybox --target=app

# Or copy a static binary into the container
kubectl cp ./diagnostic-tool my-pod:/tmp/diagnostic-tool
kubectl exec my-pod -- /tmp/diagnostic-tool

Changes made via exec are ephemeral. Any files created, packages installed, or configurations changed inside the container are lost when the pod restarts. Never use exec to make persistent production changes. Instead, update the container image or use ConfigMaps and Secrets.

Interview Questions About This Command

Why should you use -- before the command in kubectl exec?
The double dash separates kubectl flags from the command to execute. Without it, flags like -l in ls -l might be interpreted as kubectl flags, causing unexpected behavior.
How do you troubleshoot a container that does not have a shell installed?
Use kubectl debug to attach an ephemeral debug container with debugging tools, or use kubectl cp to copy diagnostic tools into the container. Distroless images have no shell by default.
Is it safe to use kubectl exec in production?
It should be used cautiously. exec bypasses normal change management, can modify state in ways that are hard to track, and poses security risks. Use RBAC to restrict exec access in production namespaces.

Common Mistakes

  • Forgetting the -- separator before the command, causing kubectl to misinterpret command arguments as its own flags.
  • Trying to exec into a container based on a distroless image that has no shell, which fails. Use kubectl debug instead.
  • Making changes inside a running container and expecting them to persist. Container filesystem changes are lost when the pod restarts.

Related Commands