docker-library / php

Docker Official Image packaging for PHP
https://php.net
MIT License
3.81k stars 2k forks source link

Podman php:cli with xdebug: Unable to debug php:cli in Visual Studio Code when using podman (Works in Docker) #1507

Open trymeouteh opened 5 months ago

trymeouteh commented 5 months ago

I am unable to get the VSCode debugger to work with PHP running in a podman container. I was able to set this up using Docker by following these steps...

  1. Create php.dockerfile (Dockerfile)
  2. Create php.ini
  3. Add VSCode debugging launch configuration to VSCode settings.json
  4. Create container in Docker
  5. Start container
  6. Open workspace folder of the PHP script in VSCode
  7. Add breakpoints in the PHP script in VSCode
  8. Start Debugger in VSCode
  9. Run PHP script in docker container which will trigger the debugger in VSCode

Dockerfile php.dockerfile

FROM docker.io/php:cli

# Install xdebug for nicer error messages
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug

php.ini

[PHP]

; xdebug settings for debugging
zend_extension=xdebug
xdebug.mode=debug
xdebug.client_host=xdebug://gateway

VSCode debugger launch config...

"launch": {
        "configurations": [
            {
                "name": "PHP (Container): Terminal",
                "type": "php",
                "request": "launch",
                "pathMappings": {
                    "/usr/src/app/": "${workspaceFolder}"
                }
            }
        ]
    },

Terminal commands to set this all up and run the script

$ docker image build -t my-php-image -f php.dockerfile .
$ docker container create --name my-container -v ./app/:/usr/src/app/ -v .:/usr/local/etc/php/ -w /usr/src/app/ -it my-php-image
$ docker container start my-container
$ docker container exec -it my-container php -d xdebug.start_with_request=yes test.php

I believe it is due to some networking setup with Podman which requires additional configuring for the debugger attach itself to the PHP script in the Podman container.

I fiddle around with podman some more and found that changing these two things will make debugging work with podman. However this will force the container to use the host network and therefore the container will not get its own network space.

Not sure if this is a good way to go about it for a PHP development environment or if there is a better way to achieve this. The problem with docker setup in the original post compared to podman is when using those steps for podman, the debugger cannot connect to the IDE (VSCode) since the podman container network is isolated as its own network.

Terminal command to create container

$ podman container create --name my-container -v ./app/:/usr/src/app/ -v .:/usr/local/etc/php/ -w /usr/src/app/ --network=host -it my-php-image

php.ini changes

xdebug.client_host = "host.containers.internal"

If anyone else knows of a better way to go about this, please do share how it can be done

LaurentGoderre commented 5 months ago

I notice the absence of a port when creating the container. I believe that xdebug2 uses port 9000 while xdebug3 uses 9003 so you might need to export that port for the debugger to connect.

trymeouteh commented 5 months ago

I notice the absence of a port when creating the container. I believe that xdebug2 uses port 9000 while xdebug3 uses 9003 so you might need to export that port for the debugger to connect.

When I add -p 9003:9003 to the container create command, it will cause port 9003 to be used, not allowing me to run the PHP debugger in VSCode which gives me the error that port 9003 is in use.

Is there another way to open a port but not use the port?

ssnepenthe commented 5 months ago

However this will force the container to use the host network

It shouldn't be necessary to set --network=host in order to use the host.containers.internal address.

trymeouteh commented 5 months ago

However this will force the container to use the host network

It shouldn't be necessary to set --network=host in order to use the host.containers.internal address.

For me it is on Manjaro using the latest version of podman

ssnepenthe commented 5 months ago

Strange - it looks like this was added way back in podman 3.2 (https://github.com/containers/podman/releases/tag/v3.2.0)

Podman now adds an entry to /etc/hosts, host.containers.internal, pointing to the current gateway (which, for root containers, is usually a bridge interface on the host system) (https://github.com/containers/podman/issues/5651).

I have used it for xdebug many times without setting --network=host - Maybe the manjaro package is doing something to disable this feature?

It should be easy to test, just check /etc/hosts in any container (https://github.com/containers/podman/issues/10878#issuecomment-877636625):

$ podman run docker.io/library/alpine grep host.containers.internal /etc/hosts
192.168.86.56   host.containers.internal host.docker.internal

Running podman 4.9.4 on fedora

trymeouteh commented 5 months ago

This is what I get when I run these commands in the terminal...

$ podman run docker.io/library/alpine grep host.containers.internal /etc/hosts
10.0.2.15   host.containers.internal host.docker.internal
$ ifconfig
enp0s3:
        inet 10.0.2.15

$ podman --version
podman version 4.8.2

I wish I can try this on Debian :( but the latest version of Podman available for Debian based distros is 3.4.4

I did try to reproduce this on Fedora inside a VirtualBox VM, but I keep getting an SELinux popup when I run the container and the PHP script in the container which maybe preventing me from using the debugger. I never used Fedora before.

trymeouteh commented 5 months ago

UPDATE:

I disabled SELinux in the Fedora VM by changing SELINUX=disabled in the /etc/selinux/config file. I was able to get the debugger to work with SELinux disabled, however I still needed to have --network=host as a flag when creating the container for VSCode debugging to work.

trymeouteh commented 5 months ago

UPDATE:

When I create the container without using the --network=host flag but set xdebug.client_host setting in the php.ini to my device local IP address xdebug.client_host = 172.16.1.123, it will work. I do not know why it does not work when set to "host.containers.internal" or xdebug://gateway

Why is this the case?

ssnepenthe commented 5 months ago

What is the default network mode podman is using? If you omit the --network option entirely when you create your container and then run:

$ podman container inspect my-container | grep NetworkMode

What is the output?

trymeouteh commented 5 months ago
$ podman container inspect my-container | grep NetworkMode
            "NetworkMode": "slirp4netns",
gnat42 commented 3 months ago

I'm on Fedora 40, podman 5.1.0 my container's NetworkMode is "bridge".

I did add the following to ~/.config/containers/containers.conf

[engine]
network_cmd_options=["allow_host_loopback=true"]

I have a multi-pod setup php-fpm,mysql,nginx etc. From a container I can connect to ports that were exposed and mapped to the host. So for example, I can do curl http://external-ip:8080 or http://nginx:8080 but I can't access anything that is only listening on the host.

I'm really curious @ssnepenthe how you have it working.

Also my containers don't have "host.containers.internal" added to the hosts file.

Not specifically tied to this product but I'm stuck and this is precisely the issue I'm facing.

ssnepenthe commented 3 months ago

I had asked about network mode because I knew there were still some outstanding issues wrt bridge network/pasta backend for rootless containers. e.g. after the switch to pasta by default in v5: https://github.com/containers/podman/issues/22653

While that specific issue has been closed as fixed, it looks like there are still lingering issues: https://github.com/containers/podman/issues/19213

See also the pasta section here: https://blog.podman.io/2024/03/podman-5-0-breaking-changes-in-detail/

There is also some brief discussion of xdebug in issue 19213 starting here: https://github.com/containers/podman/issues/19213#issuecomment-2079192968

It looks like the recommendation for now is to switch your default networking tool back to slirp4netns instead of pasta.

As for how I have it working - I assume it just works by default because I am still on F39/podman 4.9.4. I have been meaning to upgrade to F40 for a while now - I will report back here when I (eventually) get around to it.

gnat42 commented 3 months ago

@ssnepenthe Thank you for the very detailed response and even looking at some of the potential issues. I can confirm that when I change the network back to slirp4netns I can connect from containers to the host. I can continue with regular work now. So I very much appreciate it.