kubectl exec -it: Run Commands Inside a Pod
kubectl exec runs a command in a running container; -i keeps stdin open and -t allocates a pseudo-TTY for interactive shells.
For running a migration or a one-off check inside a live pod, exec is the tool. The TTY flags matter: -t is for humans, not pipelines.
What it does
kubectl exec runs a process inside an existing container and streams its output back. -i (--stdin) keeps stdin attached; -t (--tty) allocates a TTY for line editing and shells. Everything after -- is the command and its arguments, kept separate from kubectl flags.
Common usage
kubectl exec -it deploy/api -- sh
kubectl exec pod/api -c sidecar -- cat /etc/config/app.yaml
# non-interactive in CI: no -t
kubectl exec deploy/api -- ./manage.py migrate
# pipe a command in with -i only
echo "SELECT 1;" | kubectl exec -i pod/db -- psql -U appOptions
| Flag | What it does |
|---|---|
| -i, --stdin | Keep stdin open to the container |
| -t, --tty | Allocate a TTY (only for interactive terminals) |
| -c, --container | Target container in a multi-container pod |
| -- | Separator: everything after is the command |
| deploy/<name> | Exec into a pod selected from a workload |
In CI
Do not pass -t in a pipeline; there is no real terminal and you get "the input device is not a TTY" or a hang. Use -i alone when piping input, or no flags for fire-and-forget commands. The exit code of the remote command becomes kubectl exit code, so a failing migration fails the job.
Common errors in CI
"Unable to use a TTY - input is not a terminal or the right kind of file" means -t in a non-interactive runner; drop it. "error: unable to upgrade connection: container not found" means a wrong -c name or the pod restarted. "OCI runtime exec failed: ... executable file not found in $PATH" means the command (often bash) is not in the image; try sh or the binary path.