666

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.

6
  • 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? Commented Mar 27, 2016 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? Commented Mar 27, 2016 at 17:06
  • 6
    what about docker-compose run myapp ? Commented Mar 27, 2016 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. Commented Oct 4, 2018 at 12:35
  • 2
    @codentary It is just YAML, so quotes are optional in this particular case. Commented Jan 22, 2021 at 21:47

14 Answers 14

834

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.

Sign up to request clarification or add additional context in comments.

12 Comments

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.
@TheFool, Even I got the same issue. Its better to run docker-compose run <service_name>
Where exactly is this added? Inside the service?
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?
Works well with docker attach <container_name>
|
497

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. For 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.

10 Comments

Note you need to add --service-ports if you expose any ports(ie for a web server)
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.
To get this to work using Docker for Windows, I needed docker-compose v. 1.9.0 (see Github issue and PR). 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.
This should be the top answer. This is what I was looking for when I came here.
docker-compose up -d && docker attach <container_name>
|
151

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 

2 Comments

And why with other images I can't do it, I just asked here stackoverflow.com/questions/66638731/…
This works like charm! I was trying with docker exec -it <container name> sh and it failed once and other again. running through docker-compose exec really works!
94

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

5 Comments

Thank you so much. Just a little add to clarify. docker-compose run [your-service-name-defined-in-docker-compose.yml] [sh or bash].
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 <service-name> sh as suggested.
To override the entrypoint configured in docker-compose.yml I had to use: docker-compose run --entrypoint /bin/bash myapp
This really did the trick, when working with docker-compose!!
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.
73

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

3 Comments

This is incorrect it is: docker-compose exec <service_name>, not docker-compose exec <container_name>.
And why with other images I can't do it, I just asked here stackoverflow.com/questions/66638731/…
It is now docker compose btw. If anyone is still using the v1 aka docker-compose, you should update to v2: docs.docker.com/compose/migrate
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.

2 Comments

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 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
13

You can get an interactive shell with docker-compose using the following command (considering that the yml has specified a service called myservice):

$ docker-compose exec myservice sh

In the case of using a different yml file name, such as docker-compose-mycompose.yml, to get the interactive terminal, it is necessary to specify the yml, like:

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

1 Comment

This requires, that the container is already running. A prerequisite for that is, that Dockerfile has a CMD [...] line, that does not exit immediately, which seems to be the case in the question.
11

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.

2 Comments

Hey @Carnaru can you tell me the reason of using "- /app/node_modules" command under the volume section
@aashirkhan it's related to using volumes and having the container use the node_modules in the container rather than your local files
9

I prefer

docker-compose exec my_container_name bash

Comments

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

Comments

4

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".

Comments

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

Comments

2

You can execute the shell through docker compose run.

compose.yml:

services:
  myapp:
    build: .

Dockerfile

FROM alpine:latest

Commandline on host

docker compose run --rm myapp sh -c "/bin/sh"

You might also want to mount some volumes in the compose file to persist whatever you are doing inside the container in compose.yml:

services:
  myapp:
    build: .
    volumes:
      - .:/app

I have mounted the current directory on host to the directory /app inside the container.

1 Comment

I also follow this approach with docker compose: docker compose run --rm --service-ports myapp sh
1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.