docker execRun a command inside a running container
docker exec starts an extra process inside a container that is already running: a shell to look around, a one-off check like nginx -t, or a database client. It joins the container's namespaces and cgroup, so it sees exactly what the app sees.
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]nginx is serving the wrong page. You want to look at the config files it's actually using, from inside the container.
docker execStart a new process inside an existing, running container.
The CLI calls POST /containers/<id>/exec to register the command (user, env, working dir, TTY) and then POST /exec/<id>/start. dockerd passes it to containerd, whose shim runs runc exec. runc does not create anything new: it setns() into the container's existing pid, mount, network, ipc and uts namespaces, joins its cgroup, applies the same capabilities, seccomp and AppArmor profile, and execs your command. So the process sees the container's filesystem, its localhost and its processes, and its memory counts against the container's limit. It is not PID 1: when the container stops, exec'd processes are killed, and nothing restarts them. The command must exist in the image, which is why minimal images often have no shell.
-i, --interactiveKeep STDIN open (needed to pipe input in)-t, --ttyAllocate a pseudo-terminal (needed for shells; breaks pipes)-u, --user USER[:GROUP]Run as another user, e.g. -u 0 for root-w, --workdir DIRWorking directory inside the container-e, --env KEY=VALExtra environment variables for this process only-d, --detachStart the command in the background and return--privilegedGive this process extended privileges (avoid)Fixing a bug by editing files with docker exec in productionThe change lives only in that container's writable layer. The next deploy or restart from the image loses it, and other replicas never get it.
Fix the image or the mounted config, rebuild and redeploydocker exec -it in a cron job or CI stepThere is no terminal there: it fails with 'the input device is not a TTY'.
docker exec (or -i only when piping input) in scriptsdocker exec api sh -c "echo $HOME"Double quotes let your local shell expand $HOME before docker ever runs, so you see the host's value.
docker exec api sh -c 'echo $HOME'Using exec to start the main service: docker exec web nginxExec'd processes aren't supervised: nothing restarts them, and their logs don't go to docker logs.
Make the service the container's command, with a restart policyTry these on a Linux machine of your own. Each task has a hint and a solution.
Open an interactive shell as root in the api container (its image runs as the non-root user node) and check who you are.
Write a command that restores ~/data/backup.sql into the Postgres container db as user shop.
In the sandbox, see the same quoting trap: compare sh -c "echo $HOME" and sh -c 'echo $HOME' when run as another user with sudo -u nobody.
docker execRun a command inside a running container
docker exec starts an extra process inside a container that is already running: a shell to look around, a one-off check like nginx -t, or a database client. It joins the container's namespaces and cgroup, so it sees exactly what the app sees.
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]nginx is serving the wrong page. You want to look at the config files it's actually using, from inside the container.
docker execStart a new process inside an existing, running container.
The CLI calls POST /containers/<id>/exec to register the command (user, env, working dir, TTY) and then POST /exec/<id>/start. dockerd passes it to containerd, whose shim runs runc exec. runc does not create anything new: it setns() into the container's existing pid, mount, network, ipc and uts namespaces, joins its cgroup, applies the same capabilities, seccomp and AppArmor profile, and execs your command. So the process sees the container's filesystem, its localhost and its processes, and its memory counts against the container's limit. It is not PID 1: when the container stops, exec'd processes are killed, and nothing restarts them. The command must exist in the image, which is why minimal images often have no shell.
-i, --interactiveKeep STDIN open (needed to pipe input in)-t, --ttyAllocate a pseudo-terminal (needed for shells; breaks pipes)-u, --user USER[:GROUP]Run as another user, e.g. -u 0 for root-w, --workdir DIRWorking directory inside the container-e, --env KEY=VALExtra environment variables for this process only-d, --detachStart the command in the background and return--privilegedGive this process extended privileges (avoid)Fixing a bug by editing files with docker exec in productionThe change lives only in that container's writable layer. The next deploy or restart from the image loses it, and other replicas never get it.
Fix the image or the mounted config, rebuild and redeploydocker exec -it in a cron job or CI stepThere is no terminal there: it fails with 'the input device is not a TTY'.
docker exec (or -i only when piping input) in scriptsdocker exec api sh -c "echo $HOME"Double quotes let your local shell expand $HOME before docker ever runs, so you see the host's value.
docker exec api sh -c 'echo $HOME'Using exec to start the main service: docker exec web nginxExec'd processes aren't supervised: nothing restarts them, and their logs don't go to docker logs.
Make the service the container's command, with a restart policyTry these on a Linux machine of your own. Each task has a hint and a solution.
Open an interactive shell as root in the api container (its image runs as the non-root user node) and check who you are.
Write a command that restores ~/data/backup.sql into the Postgres container db as user shop.
In the sandbox, see the same quoting trap: compare sh -c "echo $HOME" and sh -c 'echo $HOME' when run as another user with sudo -u nobody.