I'm getting started working with Docker. I'm using the WordPress
base image and docker-compose
.
I'm trying to ssh into one of the containers to inspect the files/directories that were created during the initial build. I tried to run docker-compose run containername ls -la
, but that didn't do anything. Even if it did, I'd rather have a console where I can traverse the directory structure, rather than run a single command. What is the right way to do this with Docker?
docker attach
will let you connect to your Docker container, but this isn't really the same thing as ssh
. If your container is running a webserver, for example, docker attach
will probably connect you to the stdout of the web server process. It won't necessarily give you a shell.
The docker exec
command is probably what you are looking for; this will let you run arbitrary commands inside an existing container. For example, to run bash
inside a container:
docker exec -it <mycontainer> sh
Of course, whatever command you are running must exist in the container filesystem; if your container doesn't have sh
, this will fail with something like:
OCI runtime exec failed: exec failed: unable to start container process:
exec: "sh": executable file not found in $PATH: unknown
[If your container doesn't have sh
-- which is a common case for minimal images -- you may need to investigate other ways to explore the container filesystem.]
In the above command <mycontainer>
is the name or ID of the target container. It doesn't matter whether or not you're using docker compose
; just run docker ps
and use either the ID (a hexadecimal string displayed in the first column) or the name (displayed in the final column). E.g., given:
$ docker ps
d2d4a89aaee9 larsks/mini-httpd "mini_httpd -d /cont 7 days ago Up 7 days web
I can run:
$ docker exec -it web ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
18: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever
I could accomplish the same thing by running:
$ docker exec -it d2d4a89aaee9 ip addr
Similarly, I could start a shell in the container;
$ docker exec -it web sh
/ # echo This is inside the container.
This is inside the container.
/ # exit
$
In commands shown in this answer, the -i
and -t
options (combined as -it
) are necessary to get an interactive shell:
-i
keeps stdin connected; if you don't specify -i
, the shell will simply exit.
-t
allocates a tty device; if you don't specify -t
, you won't have a very pleasant interactive experience (there will be no shell prompt or job control, for example).
If you're specifically using docker compose
, there is a convenience docker compose exec
command that works very much like the docker exec
command, except:
-i
and -t
compose.yaml
file.For example, if you have a compose.yaml
like this:
services:
web:
image: docker.io/alpinelinux/darkhttpd
Then you can run:
docker compose exec web sh
The equivalent docker exec
command would be something like:
docker exec -it myproject-web-1 sh