Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
CodeCasterNL opened this issue Jan 19, 2022 · 6 comments
Labels

Comments

@CodeCasterNL
Copy link

CodeCasterNL commented Jan 19, 2022

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
  1. 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, 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
Copy link

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
Copy link
Author

CodeCasterNL commented Jan 21, 2022

@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
Copy link
Contributor

rfay commented Feb 16, 2022

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
Copy link
Contributor

rfay commented Feb 16, 2022

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
Copy link

stale bot commented Sep 21, 2022

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 stale bot added the stale label Sep 21, 2022
@stale
Copy link

stale bot commented Nov 2, 2022

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

@stale stale bot closed this as completed Nov 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants