364

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
  • 345
  • 1
  • 3
  • 12
drubb
  • 10,047
  • 6
  • 13
  • 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
  • 2
    what about `docker-compose run myapp` ? – ivoba Mar 27 '16 at 17:07
  • 2
    @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
  • @codentary It is just YAML, so quotes are optional in this particular case. – Gogowitsch Jan 22 '21 at 21:47

9 Answers9

486

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
  • 525
  • 4
  • 6
Leon Carlo Valencia
  • 5,333
  • 1
  • 8
  • 12
  • 3
    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
  • 18
    @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 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
  • 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
  • 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
283

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

docker-compose run --rm myapp

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.

Daryn
  • 3,917
  • 2
  • 30
  • 42
dnephin
  • 19,351
  • 8
  • 44
  • 38
  • 21
    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
  • 10
    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
  • 7
    This should be the top answer. This is what I was looking for when I came here. – mkasberg Jan 25 '17 at 18:38
  • 9
    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
77

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

version: '3'
services:
  web:
    build: .
    ports:
     - "5000:5000"
  redis:
    image: "redis:alpine"

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

docker-compose exec redis sh
docker-compose exec web sh 
clay
  • 13,176
  • 19
  • 65
  • 150
58

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,434
  • 2
  • 26
  • 42
  • 5
    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
  • 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
32

If anyone from the future also wanders up here:

docker-compose exec container_name sh

or

docker-compose exec container_name bash

or you can run single lines like

docker-compose exec container_name php -v

That is after you already have your containers up and running

Tim Fletcher
  • 5,784
  • 1
  • 31
  • 33
  • 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
25

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
  • 911
  • 10
  • 12
  • 1
    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
  • 4
    @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
5

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,327
  • 11
  • 21
4

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

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
  • 3,179
  • 11
  • 44
  • 72
Yu N.
  • 725
  • 5
  • 7