578

Is there any way to start an interactive shell in a container using Docker Compose only? I've tried something like this, in my docker-compose.yml:

myapp:
  image: alpine:latest
  entrypoint: /bin/sh

When I start this container using docker-compose up it's exited immediately. Are there any flags I can add to the entrypoint command, or as an additional option to myapp, to start an interactive shell?

I know there are native docker command options to achieve this, just curious if it's possible using only Docker Compose, too.

Ahmed Nour Eldeen
  • 351
  • 1
  • 4
  • 13
drubb
  • 14,533
  • 7
  • 15
  • 11
  • 1
    This is not supposed to work. For example, if you have multiple images with `/bin/sh` entrypoint in your compose file, what should it do? – Xiongbing Jin Mar 27 '16 at 16:38
  • 2
    Hmh, why not just start multiple shells? For example, a shell into a mysql container to work with mysql cli, and a shell into a backup container to run backup commands? – drubb Mar 27 '16 at 17:06
  • 5
    what about `docker-compose run myapp` ? – ivoba Mar 27 '16 at 17:07
  • 3
    @ibova The problem is with `docker-compose run myapp` is that it won't expose the ports. So you have to use `docker-compose run --service-ports myapp` but still its not very convenient. – The Fool Oct 04 '18 at 12:35
  • `entrypoint: /bin/sh` should be `entrypoint: "/bin/sh"` – codentary May 21 '20 at 05:36
  • 2
    @codentary It is just YAML, so quotes are optional in this particular case. – Gogowitsch Jan 22 '21 at 21:47

13 Answers13

748

You need to include the following lines in your docker-compose.yml:

version: "3"
services:
  app:
    image: app:1.2.3
    stdin_open: true # docker run -i
    tty: true        # docker run -t

The first corresponds to -i in docker run and the second to -t.

Cellcore
  • 824
  • 6
  • 8
Leon Carlo Valencia
  • 7,979
  • 1
  • 11
  • 12
  • 4
    that `stdin_open` is the missing link, for simply providing me the expected behavior when I attach to one of my containers that is already running a shell. – Charney Kaye Dec 07 '16 at 20:50
  • 41
    @TheFool, Even I got the same issue. Its better to run `docker-compose run ` – Aswath K Mar 05 '19 at 06:13
  • 4
    Where exactly is this added? Inside the service? – problemofficer - n.f. Monica Dec 11 '19 at 20:49
  • 1
    This seems to be the best answer to the OP's question.. since the issue is that the container exits immediately otherwise, so getting a shell using `docker exec` on it is not going to work. – RoyM Dec 31 '19 at 17:15
  • 1
    This gives me an error on Windows: `colorama\win32.py, line 152, in SetConsoleTitle: ctypes.ArgumentError: ‘ValueError’: embedded null character` – cowlinator Apr 29 '20 at 01:54
  • 1
    the only thing missing here is how to get *out* of the shell without exiting the process and stopping the container. Press CTRL-P-Q to detach. – user3504575 Feb 17 '21 at 20:43
  • 10
    This still does not work if I use `docker-compose up` and entrypoint `["/bin/sh"]`. Although the container does not exist immediately. Is the input attached to the entrypoint? – doraemon Jan 13 '22 at 09:34
  • Same issue as @doraemon dockerfile is just FROM debian:bullseye-slim; entrypoint ["/bin/bash"]; these options prevent it from exiting immediatly, and container says it's up, but there is no input/output. docker run -it {image} works as expected. – user1169420 Jul 11 '22 at 23:09
  • 4
    Works well with docker attach – Alexander Aug 24 '22 at 15:29
  • This saved my day for different issue with high CPU usage of python interpreter even being in idle, stdin_open: true helped for this problem. – Ilay Sep 09 '22 at 05:07
  • Any chance to get container shell right in same docker-compose call? I mean going each time to another terminal to call docker-compose exec is a bit annoying... – bodich Mar 14 '23 at 07:25
432

The canonical way to get an interactive shell with docker-compose is to use:

docker-compose run --rm myapp

(With the service name myapp taken from your example. More general: it must be an existing service name in your docker-compose file, myapp is not just a command of your choice. Example: bash instead of myapp would not work here.)

You can set stdin_open: true, tty: true, however that won't actually give you a proper shell with up, because logs are being streamed from all the containers.

You can also use

docker exec -ti <container name> /bin/bash

to get a shell on a running container.

questionto42
  • 7,175
  • 4
  • 57
  • 90
dnephin
  • 25,944
  • 9
  • 55
  • 45
  • 30
    Note you need to add `--service-ports` if you expose any ports(ie for a web server) – epelc Aug 21 '16 at 19:22
  • 1
    This creates a new container every time you run the above command. If you want a more space efficient use the approach given by @lynx0123. – Casper Sep 01 '16 at 12:46
  • 13
    I've updated my answer to provide more information and add the `--rm` flag so that the container is removed. The answer by @lynx0123 is not correct. You will not get an interactive shell if you run `docker-compose up`. – dnephin Sep 01 '16 at 16:17
  • 2
    To get this to work using Docker for Windows, I needed docker-compose v. 1.9.0 (see Github [issue](https://github.com/docker/compose/issues/3194) and [PR](https://github.com/docker/compose/pull/3980)). As of 12/19/16, this only ships with beta versions of Docker for Windows. Then `docker-compose run` works. You'll also want to add `command: /bin/bash` to docker-compose.yml. – Joseph238 Dec 20 '16 at 00:14
  • 9
    This should be the top answer. This is what I was looking for when I came here. – mkasberg Jan 25 '17 at 18:38
  • 10
    docker-compose up -d && docker attach – Aaron McMillin Apr 24 '17 at 02:34
  • docker attach is exactly what I've been looking for to connect to my python pdb debugger, thanks! But it won't always help get a shell on the container unless there is an interactive shell running already. Containers are probably already running something more useful. – Joseph Sheedy Oct 25 '18 at 22:29
  • When using docker exec -ti /bin/bash, you do need the tty: true in docker-compose.yml, otherwise you receive a message that the container is not a tty – Alex Apr 15 '19 at 12:44
  • @dnephin is there a way to supply the value for '--rm' in the compose yml file? – refriedjello May 18 '22 at 22:36
136

The official getting started example (https://docs.docker.com/compose/gettingstarted/) uses the following docker-compose.yml:

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

After you start this with docker-compose up, you can shell into either your redis container or your web container with:

docker-compose exec redis sh
docker-compose exec web sh 
clay
  • 18,138
  • 28
  • 107
  • 192
  • And why with other images I can't do it, I just asked here https://stackoverflow.com/questions/66638731/why-do-i-need-tty-true-in-docker-compose-yml-and-other-images-do-not – jcarlosweb Mar 15 '21 at 14:54
87

docker-compose run myapp sh should do the deal.

There is some confusion with up/run, but docker-compose run docs have great explanation: https://docs.docker.com/compose/reference/run

Alex Povar
  • 4,890
  • 3
  • 29
  • 44
  • 7
    Thank you so much. Just a little add to clarify. docker-compose run [your-service-name-defined-in-docker-compose.yml] [sh or bash]. – theeranitp Dec 19 '19 at 10:08
  • 1
    I think this is the most straightforward of answers. I needed to verify the environment is correct for the service by going `docker-compose run sh` as suggested. – Nae Nov 13 '20 at 11:13
  • 1
    To override the `entrypoint` configured in `docker-compose.yml` I had to use: `docker-compose run --entrypoint /bin/bash myapp` – hfs Feb 27 '21 at 19:28
  • This really did the trick, when working with docker-compose!! – Vincent Jun 06 '21 at 15:05
  • Great alternative command Instead of docker-compose up later running interactive shell from the container. I do use `docker-compose -f other-compose-file.yml run myapp sh` to run specific version of node with alpine image. where -f specifies yml file that declares myapp service. – chisim Sep 12 '22 at 17:09
59

If anyone from the future also wanders up here:

docker-compose exec service_name sh

or

docker-compose exec service_name bash

or you can run single lines like

docker-compose exec service_name php -v

That is after you already have your containers up and running.

The service_name is defined in your docker-compose.yml file

rmcsharry
  • 5,363
  • 6
  • 65
  • 108
  • 1
    This is incorrect it is: `docker-compose exec `, not `docker-compose exec `. – loicgasser Dec 19 '20 at 00:02
  • And why with other images I can't do it, I just asked here https://stackoverflow.com/questions/66638731/why-do-i-need-tty-true-in-docker-compose-yml-and-other-images-do-not – jcarlosweb Mar 15 '21 at 14:55
38

Using docker-compose, I found the easiest way to do this is to do a docker ps -a (after starting my containers with docker-compose up) and get the ID of the container I want to have an interactive shell in (let's call it xyz123).

Then it's a simple matter to execute docker exec -ti xyz123 /bin/bash

and voila, an interactive shell.

David Hersey
  • 1,049
  • 11
  • 13
  • 2
    Not sure why this was down-voted - it's a great way to get debugging in case anything goes wrong, and I used this method with success, like, within a minute of reading this solution. – ericmjl Aug 31 '17 at 17:30
  • 6
    @ericmjl Because it's a two step process where the question asked specifically about using docker-compose features, and was already stated in the other answer – OneCricketeer Sep 02 '17 at 04:34
10

This question is very interesting for me because I have problems, when I run container after execution finishes immediately exit and I fixed with -it:

docker run -it -p 3000:3000 -v /app/node_modules -v $(pwd):/app <your_container_id>

And when I must automate it with docker compose:

version: '3'
services:
    frontend:
        stdin_open: true
        tty: true
        build: 
            context: .
            dockerfile: Dockerfile.dev
        ports: 
            - "3000:3000"
        volumes: 
            - /app/node_modules
            - .:/app

This makes the trick: stdin_open: true, tty: true

This is a project generated with create-react-app

Dockerfile.dev it looks this that:

FROM node:alpine

WORKDIR '/app'

COPY package.json .
RUN npm install

COPY . . 

CMD ["npm", "run", "start"]

Hope this example will help other to run a frontend(react in example) into docker container.

Carnaru Valentin
  • 1,690
  • 17
  • 27
  • Hey @Carnaru can you tell me the reason of using "- /app/node_modules" command under the volume section – aashir khan Jan 15 '22 at 08:24
  • @aashirkhan it's related to using volumes and having the container use the node_modules in the container rather than your local files – A.com Feb 15 '22 at 04:21
9

I prefer

docker-compose exec my_container_name bash
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
alec vinent
  • 99
  • 1
  • 4
8

If the yml is called docker-compose.yml it can be launched with a simple $ docker-compose up. The corresponding attachment of a terminal can be simply (consider that the yml has specified a service called myservice):

$ docker-compose exec myservice sh

However, if you are using a different yml file name, such as docker-compose-mycompose.yml, it should be launched using $ docker-compose -f docker-compose-mycompose.yml up. To attach an interactive terminal you have to specify the yml file too, just like:

$ docker-compose -f docker-compose-mycompose.yml exec myservice sh

Cleber Jorge Amaral
  • 1,316
  • 13
  • 26
5

A addition to this old question, as I only had the case last time. The difference between sh and bash. So it can happen that for some bash doesn't work and only sh does.

So you can: docker-compose exec CONTAINER_NAME sh

and in most cases: docker-compose exec CONTAINER_NAME bash

use.

If you have time. The difference between sh and bash is well explained here: https://www.baeldung.com/linux/sh-vs-bash

Maik Lowrey
  • 15,957
  • 6
  • 40
  • 79
3

You can do docker-compose exec SERVICE_NAME sh on the command line. The SERVICE_NAME is defined in your docker-compose.yml. For example,

services:
    zookeeper:
        image: wurstmeister/zookeeper
        ports:
          - "2181:2181"

The SERVICE_NAME would be "zookeeper".

J. Scott Elblein
  • 4,013
  • 15
  • 58
  • 94
Yu N.
  • 1,765
  • 11
  • 9
2

According to documentation -> https://docs.docker.com/compose/reference/run/

You can use this docker-compose run --rm app bash

[app] is the name of your service in docker-compose.yml

MrBB
  • 131
  • 1
  • 2
  • 11
0

I found the following steps can open an interactive shell, although it's not directly with docker-compose:

  • After running docker-compose up
  • Check the name of the container using docker ps -a
  • Choose the container name you want to open an interactive bash shell for
  • Run docker exec -it containerName bash

Your terminal should now be in the bash shell of the container and you can interact with its content.

Hope this helps.

IK Cheng
  • 11
  • 1
  • 3