docker / compose

Define and run multi-container applications with Docker
https://docs.docker.com/compose/
Apache License 2.0
33.76k stars 5.19k forks source link

docker-compose exec: the input device is not a TTY #7306

Closed carbolymer closed 2 years ago

carbolymer commented 4 years ago

Description of the issue

Cannot start interactive shell (e.g. /bin/bash) using docker-compose -f - exec

Context information (for bug reports)

Output of docker-compose version

docker-compose version 1.25.4, build unknown
docker-py version: 4.2.0
CPython version: 3.8.2
OpenSSL version: OpenSSL 1.1.1e  17 Mar 2020

Output of docker version

Client:
 Version:           19.03.8-ce
 API version:       1.40
 Go version:        go1.14
 Git commit:        afacb8b7f0
 Built:             Mon Mar 16 22:23:09 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          19.03.8-ce
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.14
  Git commit:       afacb8b7f0
  Built:            Mon Mar 16 22:22:53 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.3.3.m
  GitCommit:        d76c121f76a5fc8a462dc64594aea72fe18e1178.m
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

Steps to reproduce the issue

  1. Run the following commands:
    
    #!/bin/bash
    read -d '' COMPOSE_FILE << EOF
    version: '3'
    services:
    hello:
    image: "redis:alpine"
    EOF

echo "$COMPOSE_FILE" echo "$COMPOSE_FILE" | docker-compose -f - up -d echo "$COMPOSE_FILE" | docker-compose -f - exec hello /bin/sh


### Observed result
Command quits immediately with the following message:

the input device is not a TTY



### Expected result
Interactive shell starts
lingster commented 4 years ago

you can try either: export COMPOSE_INTERACTIVE_NO_CLI=1 or run: docker-compose exec -T ...

see discussion: #5696

carbolymer commented 4 years ago

@lingster neither of those works: export COMPOSE_INTERACTIVE_NO_CLI=1 results in error:

Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/dockerpty/pty.py", line 334, in start
    self._hijack_tty(pumps)
  File "/usr/lib/python3.8/site-packages/dockerpty/pty.py", line 373, in _hijack_tty
    pump.flush()
  File "/usr/lib/python3.8/site-packages/dockerpty/io.py", line 367, in flush
    read = self.from_stream.read(n)
  File "/usr/lib/python3.8/site-packages/dockerpty/io.py", line 121, in read
    return os.read(self.fd.fileno(), n)
  File "/usr/lib/python3.8/socket.py", line 718, in fileno
    self._checkClosed()
ValueError: I/O operation on closed file.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/bin/docker-compose", line 11, in <module>
    load_entry_point('docker-compose==1.25.4', 'console_scripts', 'docker-compose')()
  File "/usr/lib/python3.8/site-packages/compose/cli/main.py", line 72, in main
    command()
  File "/usr/lib/python3.8/site-packages/compose/cli/main.py", line 128, in perform_command
    handler(command, command_options)
  File "/usr/lib/python3.8/site-packages/compose/cli/main.py", line 519, in exec_command
    pty.start()
  File "/usr/lib/python3.8/site-packages/dockerpty/pty.py", line 338, in start
    io.set_blocking(pump, flag)
  File "/usr/lib/python3.8/site-packages/dockerpty/io.py", line 32, in set_blocking
    old_flag = fcntl.fcntl(fd, fcntl.F_GETFL)
  File "/usr/lib/python3.8/site-packages/dockerpty/io.py", line 351, in fileno
    return self.from_stream.fileno()
  File "/usr/lib/python3.8/site-packages/dockerpty/io.py", line 103, in fileno
    return self.fd.fileno()
  File "/usr/lib/python3.8/socket.py", line 718, in fileno
    self._checkClosed()
ValueError: I/O operation on closed file.

-T switch just silences the error and nothing happens

dobleme commented 4 years ago

Experiencing the same issue!

caugner commented 4 years ago

I'm experiencing this issue when running a docker-compose exec command from a crontab cronjob.

abranhe commented 4 years ago

I am trying to backup a database from MySQL image and I am getting the same issue.

docker-compose exec db-service mysqldump -u root -proot db > ./db.sql
caugner commented 4 years ago

I'm experiencing this issue when running a docker-compose exec command from a crontab cronjob.

docker-compose exec -T solved the issue for me.

Azatalion commented 4 years ago

Got similar problem, when was trying to run laravel schedule in docker via cron.

My solution is type in host terminal: crontab -e

add this line: * * * * * cd /path/to/docker.yml && docker exec <docker-container's name> php artisan schedule:run >> log.txt 2>&1

save and look at log.txt

mudlee commented 4 years ago

I ran into this problem in a GCP environment in a startup script, where I didn't even see the error. -T solved my problem.

jennydaman commented 3 years ago

@carbolymer is your description up to date with docker-compose version 1.27.4?

I also get ValueError: I/O operation on closed file. when using COMPOSE_INTERACTIVE_NO_CLI=1 but the docker-compose exec works correctly with -T

carbolymer commented 3 years ago

@jennydaman yes, it still does not work.

Everyone else commenting here that -T solves the problem, doesn't understand what "interactive shell" means.

kylrth commented 3 years ago

Yeah the original problem is not solved; those saying that -T solves it have come here from searching "docker-compose exec input device is not a TTY".

My guess is that echo "$COMPOSE_FILE" | docker-compose -f - exec -T hello /bin/sh silences the error but does nothing because the docker-compose process is forwarding its stdin (which is also from echo "$COMPOSE_FILE") to sh, and so sh reaches the end of its stdin and exits.

alaincao commented 3 years ago

Heylow, my 2 cents here. I don't think what you are asking here is possible "in the Unix sense". You cannot have a TTY/terminal device (ie. a combination of a screen(stdout) and a keyboard(stdin) ) at the same time as saying that 'stdin' (ie. the keyboard) is the output of an 'echo' command (and thus, not '/dev/stdin' anymore).
I think what you'd need to do is give a fixed name to the container with container_name: <mycontainername> in your docker-compose "file" and invoke directly docker exec -it <mycontainername> /bin/sh.
Possibly auto-generate a "unique" random 'mycontainername'

nb: I came here indeed searching for "docker-compose exec input device is not a TTY", therefore, my problem is solved, I was seaching for the "-T" parameter ;-)

carbolymer commented 3 years ago

@alaincao Well, you're right. But you can get around this using: (echo "$COMPOSE_FILE" && cat) | docker-compose -f - exec hello /bin/sh (vide: https://stackoverflow.com/a/5852578/1608594 ) - but it does not work in this case also. My understanding is that docker-compose isn't able to determine when yaml file ends and when user input starts.

alaincao commented 3 years ago

Well, I don't think that even in the case of && cat, 'stdin' would be a TTY.
It would be the output of cat instead which is not a TTY device, but just the piped stdout of a program.
Also, if you do (echo "A" && echo "B") | cat, there's no EOF between the "A" and "B". This is not the same thing ; it's just a concatenation.

alaincao commented 3 years ago

I really think you should invoke docker exec -it directly here.
eg.: docker exec -it $(docker-compose ps -q web) /bin/bash instead, if you don't want to give it a fixed name.

caugner commented 3 years ago

Just to add some practical perspective, I observed the following with a mysql:8.0 container (defined as mysql in my docker-compose.yml):

yashtodi94 commented 3 years ago

I really think you should invoke docker exec -it directly here. eg.: docker exec -it $(docker-compose ps -q web) /bin/bash instead, if you don't want to give it a fixed name.

I came here looking for a totally different purpose. Wanted to add docker commands to a pre-commit hook and got the error input device is not a tty

Solved it using: docker exec --tty $(docker-compose ps -q web) /bin/bash from this link

Thanks for the dynamic container id idea. :)

NguyenLamIT commented 3 years ago

you can try either: export COMPOSE_INTERACTIVE_NO_CLI=1 or run: docker-compose exec -T ...

see discussion: #5696

@lingster . Thank you very much. It resolved for me

ndeloof commented 3 years ago

Compose v2 automatically applies -T if process is not running within a terminal (https://github.com/docker/compose-cli/blob/main/cmd/compose/exec.go#L71)

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 2 years ago

This issue has been automatically closed because it had not recent activity during the stale period.

marcindulak commented 2 years ago

:eyes:

esnunes commented 2 months ago

I can think of two scenarios where this error may occur:

  1. you are running it in an input device that is not a TTY.
  2. you are piping something to docker compose, therefore the input becomes non-interactive (that was the scenario I was facing when I found this issue and to solve it you just need to tell docker compose that you are not longer expecting a TTY with the -T flag.