docker / compose

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

MacOS + PHP + proc_open('docker-compose (v2)') = `read /dev/stderr: bad file descriptor` #9115

Closed CodeCasterNL closed 2 years ago

CodeCasterNL commented 2 years ago

Description Docker-compose v2 does something to stderr on macOS. We're using Monterey / Darwin / Intel, 12.1 (21C52), kernel 21.2.0 as our operating system, and Docker Desktop with a project with some Docker containers, tied together through (during development) multiple docker-compose.yml files. It repros with one compose file as well.

Steps to reproduce the issue:

  1. Have an Intel Mac
  2. Have a docker-compose orchestration running, name it for example "mysql". Minimal repro (but triggered on various containers/images):
    services:
    mysql:
    image: mysql:8.0
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=true
  3. Run this PHP code on your Mac, targeting said container named "mysql":
    
    $command = 'docker-compose exec mysql ls';

$descriptors = [ ['file', '/dev/tty', 'r'], // stdin ['file', '/dev/tty', 'w'], // stdout ['file', '/dev/tty', 'w'], // stderr ];

$handle = proc_open($command, $descriptors, $pipes);

echo proc_close($handle);


This is, very simplified, what Symfony's Process component does when you start a process. This Process in turn is instantiated by Deployer, used to execute commands locally and in a container.

**Describe the results you received:**
When the checkbox for "Use Docker Compose V2" is **off**, it works fine. Always has. You'll get a nice directory listing of the entrypoint of the mysql container (or the output of whatever other command you executed on whatever container), followed by the exit code of "0%".

However, when you do check the V2 checkbox in Docker Desktop and apply, you will still get the same output, but now it'll be followed by:

> read /dev/stderr: bad file descriptor
> 1%

This trips the Process component into thinking the execution of the command failed. It didn't, I can see long-running commands being started within the container, but the caller doesn't know that.

**Describe the results you expected:**
I would expect `docker-compose` in V2 mode not to give errors about /dev/stderr being a bad file descriptor.

**Additional information you deem important (e.g. issue happens only occasionally):**
This was ultimately discovered by our use of a filesystem syncing tool called [Mutagen](https://github.com/mutagen-io/mutagen), which recently released v0.13.0 out of beta, which now exclusively uses Compose V2.

**Output of `docker compose version`:**

$ docker compose version Docker Compose version v2.2.3


With V2 checkbox off (and `docker-compose`, not `docker compose`):

$ docker-compose version docker-compose version 1.29.2, build 5becea4c docker-py version: 5.0.0 CPython version: 3.9.0 OpenSSL version: OpenSSL 1.1.1h 22 Sep 2020


**Output of `docker info`:**

Client: Context: default Debug Mode: false Plugins: buildx: Docker Buildx (Docker Inc., v0.7.1) compose: Docker Compose (Docker Inc., v2.2.3) scan: Docker Scan (Docker Inc., v0.16.0)

Server: Containers: 39 Running: 19 Paused: 0 Stopped: 20 Images: 100 Server Version: 20.10.12 Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: true Native Overlay Diff: true userxattr: false Logging Driver: json-file Cgroup Driver: cgroupfs Cgroup Version: 2 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc Default Runtime: runc Init Binary: docker-init containerd version: 7b11cfaabd73bb80907dd23182b9347b4245eb5d runc version: v1.0.2-0-g52b36a2 init version: de40ad0 Security Options: seccomp Profile: default cgroupns Kernel Version: 5.10.76-linuxkit Operating System: Docker Desktop OSType: linux Architecture: x86_64



**Workarounds**
1. Use docker-compose V1, but we can't, we use `mutagen-compose` which is now irrevocably a V2 wrapper.
2. Change `['file', '/dev/tty', 'w'], // stderr` to .../dev/null, but then we won't get error output, and also, the code that builds that array is outside of our control.
xenoscopic commented 2 years ago

Does invoking docker-compose exec with -T have any effect on the outcome here?

Also, does invoking Compose V2 as a CLI plugin (i.e. docker compose exec) alter the behavior?

CodeCasterNL commented 2 years ago

@xenoscopic docker-compose exec -T, V1:

➜  ~/.../ComposeV2 $ php dc2test.php
bin
boot
dev
[...]
tmp
usr
var
0%

docker-compose exec -T, V2:

➜  ~/.../ComposeV2 $ php dc2test.php
bin
   boot
       dev
[...]
                                                                                                   usr
                                                                                                      var
                                                                                                         0%

docker compose exec displays the original behavior, ending with an exit code of 1 and the error about stderr.

rfay commented 2 years ago

I see "interesting" behavior like this from docker-compose v2.2.2 or docker-compose v2.2.3 with calling code like this:

    proc := exec.Command(path, arg...)
    proc.Stdout = stdout
    proc.Stdin = stdin
    proc.Stderr = stderr

    err = proc.Run()

It's calling docker-compose exec and docker-compose exits with an exitErr and "read /dev/stderr: bad file descriptor"

Related Stack Overflow link: https://stackoverflow.com/questions/20134095/why-do-i-get-bad-file-descriptor-in-this-go-program-using-stderr-and-ioutil-re

rfay commented 2 years ago

I seem to be past this. I note now that it was happening when debugging in Goland, so could be possible that Goland or delve does something funky to stderr.

But I do suspect that since this has been discovered in various contexts that it's misbehavior from composer when something has happened to stderr, or perhaps the issue in the stack overflow posting.

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.