I'm trying to set up php debugging with VSCode and xDebug, but xDebug can't connect to the host. Thus, VSCode doesn't hit any breakpoints either.
When I start the debug listener in VSCode, run a Bash shell in the php-fpm container and try to connect to the host, it fails:
$ docker-compose exec php-fpm bash
root#178ba0224b37:/application# nc -zv 172.20.0.1 9001
172.20.0.1: inverse host lookup failed: Unknown host
(UNKNOWN) [172.20.0.1] 9001 (?) : Connection refused
I'm confused about the IP addresses, because in the Docker settings the Virtual Switch subnet is set to 10.0.75.0, and the network adapter vEthernet (DockerNAT) uses the IP 10.0.75.1. How do the containers get the IP range 172.20.0.x?
From my desktop I am unable to request the webpage using 172.20.0.1.
It works fine with 10.0.75.1, which shows the phpinfo() as expected, but the breakpoint is not triggered.
phpinfo() shows xDebug is configured and the settings match what I have in the php-ini-overrides.ini config.
I've disabled the firewall, tried different IP's, and checked the port and various xDebug, php, docker-compose, and VSCode debug settings.
I've been searching far and wide, but I guess I'm still missing something. My guess is that it has to do with the network connection, but I don't know what else I can change to fix this issue.
Setup
Host is Windows 10 with docker-compose and VSCode.
I got the docker debug-test directory from https://phpdocker.io/generator
Basically it uses two docker containers: nginx:alpine and phpdocker/php-fpm
My VSCode workspace looks like this:
(The readme files come from the phpdocker.io generator and contain some basic Docker info)
index.php contents:
<?php
phpinfo(); // <-- VSCode breakpoint here
echo 'hello there';
?>
The IP addresses for the containers:
/debug-test-php-fpm - 172.20.0.3
/debug-test-webserver - 172.20.0.2
$_SERVER['REMOTE_ADDR']: 172.20.0.1 <- the host?
Configs and logs
launch.json contents:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"pathMappings": {
"/application/public": "${workspaceRoot}/public"
},
"log": true,
"port": 9001,
"xdebugSettings": {
"max_data": 65535,
"show_hidden": 1,
"max_children": 100,
"max_depth": 5
}
},
{
"name": "Launch currently open script",
"type": "php",
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"port": 9001
}
]
}
docker-compose.yml contents:
###############################################################################
# Generated on phpdocker.io #
###############################################################################
version: "3.1"
services:
webserver:
image: nginx:alpine
container_name: debug-test-webserver
working_dir: /application
volumes:
- .:/application
- ./phpdocker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8000:80"
php-fpm:
build: phpdocker/php-fpm
container_name: debug-test-php-fpm
working_dir: /application
volumes:
- .:/application
- ./phpdocker/php-fpm/php-ini-overrides.ini:/etc/php/7.2/fpm/conf.d/99-overrides.ini
php-ini-overrides.ini contents:
upload_max_filesize = 100M
post_max_size = 108M
# added for debugging with Docker and VSCode
xdebug.remote_enable=1
xdebug.remote_connect_back=On
xdebug.remote_autostart=1
# xdebug.remote_host=172.20.0.1 # using remote_connect_back instead, which should work for any IP
xdebug.remote_connect_back=1
xdebug.remote_port=9001
xdebug.profiler_enable=0
xdebug.var_display_max_depth = 5
xdebug.var_display_max_children = 256
xdebug.var_display_max_data = 1024
xdebug.remote_log = /application/xdebug.log
xdebug.idekey = VSCODE
xdebug.log contents after one visit to the page:
Log opened at 2019-01-30 12:37:39
I: Checking remote connect back address.
I: Checking header 'HTTP_X_FORWARDED_FOR'.
I: Checking header 'REMOTE_ADDR'.
I: Remote address found, connecting to 172.20.0.1:9001.
W: Creating socket for '172.20.0.1:9001', poll success, but error: Operation now in progress (29).
E: Could not connect to client. :-(
Log closed at 2019-01-30 12:37:39
Log opened at 2019-01-30 12:37:39
I: Checking remote connect back address.
I: Checking header 'HTTP_X_FORWARDED_FOR'.
I: Checking header 'REMOTE_ADDR'.
I: Remote address found, connecting to 172.20.0.1:9001.
W: Creating socket for '172.20.0.1:9001', poll success, but error: Operation now in progress (29).
E: Could not connect to client. :-(
Log closed at 2019-01-30 12:37:39
This is no paste error, it actually logs the request two times for some reason.
Debug console in VSCode after starting the debug listener:
<- launchResponse
Response {
seq: 0,
type: 'response',
request_seq: 2,
command: 'launch',
success: true }
Any thoughts? I'm lost..
Perhaps it has to do with the DockerNAT setup?
Sorry for the long post. I'm still new to Docker, I hope this has all the info needed.
Edit: solved
See my answer below.
After some coding I stumbled upon the solution.
The IP address in the php debug settings was incorrect. Since my system has VPN connections, multiple ethernet adapters, multiple virtual switches, and multiple virtual machines, it's a bit tricky to find out what's used where.
I discovered the IP by accident when I ran netstat on the php container during a request:
$ docker-compose ps --services
php
app
$ docker-compose exec php sh
/var/www/html # netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 08674b3fd785:58060 192.168.137.12:http TIME_WAIT
tcp 0 0 08674b3fd785:58062 192.168.137.12:http TIME_WAIT
[...]
udp 0 0 08874b3cd785:35298 192.168.65.1:domain ESTABLISHED
I tried the 192.168.65.1 IP first, but that didn't work.
The 192.168.137.12 is the IP of a Hyper-V Virtual Machine that the php script connects to. Apparently the php container can connect to that, so maybe then it could also connect to the Windows adapter that's bound to that virtual switch, in other words: 192.168.137.1 .
Adding this to the xDebug settings solved the problem:
xdebug.remote_host = 192.168.137.1.
Related
I'm trying to connect to host OS MySQL via host.docker.internal, I'm able to connect if i directly mention my internal IP in Laravel application hosted inside docker container.
OS / ENVIRONMENT:
Host operating system and version: MacOS Monterey 12.5.1
Docker desktop version: 4.12.0 (85629)
Docker desktop engine: Engine: 20.10.17
Docker desktop compose version: v2.10.2
Problem:
These are the steps i took to connect my Laravel application inside docker to my host OS MySQL. I successfully managed to connect my application via internal IP address of my Host OS, but the internal IP keep changing and its kind of getting dificult to keep changing the DB_HOST inside laravel .env each time the IP change. so i want to use host.docker.internal but i won't work.
Steps:
1: docker-compose down (Delete all the containers)
2: I removed the devilbox .env port HOST_PORT_MYSQL=
3: I changed the port of my host OS MySQL to 3306 and using sequel ace i successfully connected to mysql with these credentials
Host: 127.0.0.1
user: root
database: hanger
port: 3306
4: In order to connect from docker to my Host OS MySQL i had to edit my my.cnf file OR in this case created a new one for MySQL here the my.cnf
[mysqld]
bind_address = 0.0.0.0 # default is 127.0.0.1 Change to 0.0.0.0 to allow remote connections
5: Restarted the MySQL server and confirmed that MySQL can now listen to all IP's and NOT just localhost
6: used this command
netstat -anp tcp | grep 3306 OR netstat -ap tcp | grep -i "listen"
tcp4 0 0 127.0.0.1.3306 127.0.0.1.52469 ESTABLISHED
tcp4 0 0 127.0.0.1.52469 127.0.0.1.3306 ESTABLISHED
tcp4 0 0 127.0.0.1.3306 127.0.0.1.52468 ESTABLISHED
tcp4 0 0 127.0.0.1.52468 127.0.0.1.3306 ESTABLISHED
tcp4 0 0 127.0.0.1.3306 127.0.0.1.52464 ESTABLISHED
tcp4 0 0 127.0.0.1.52464 127.0.0.1.3306 ESTABLISHED
tcp4 0 0 *.3306 . LISTEN
tcp46 0 0 *.33060 . LISTEN
tcp4 0 0 192.168.18.190.3306 192.168.18.190.52566 TIME_WAIT
tcp4 0 0 192.168.18.190.3306 192.168.18.190.52567 TIME_WAIT
tcp4 0 0 192.168.18.190.3306 192.168.18.190.52568 TIME_WAIT
7: Once its confirmed that 3306 is listeing need to create a MySQL user which would be connected from other than localhost
8: In mysql shell i executed these queries, since I'm using MySQL 8.0.27 the creating user and granting previliges must be in seperate queries.
CREATE USER 'root'#'%' IDENTIFIED BY 'root'; // remember this root password we will use it in Laravel .env
GRANT ALL PRIVILEGES ON *.* TO 'root'#'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
9: To make sure the root#% user is created type
SELECT User, Host FROM mysql.user; there are two root users one with host set to localhost and second one is %
10: Now its time to Edit Laravel .env MySQL section
DB_CONNECTION=mysql
DB_HOST=192.168.18.190 // my host machine internal ip (host.docker.internal not working)
DB_PORT=3306
DB_DATABASE=hanger
DB_USERNAME=root
DB_PASSWORD=root
Note: my DB_HOST did not work with 127.0.0.1 OR host.docker.internal so i thought it may work with my local IP, which it did.
11: To find out my local IP on MAC go to system preferences > network > My wifi connection > advanced > TCP/IP > under IPv4 192.168.43.182
The thing I'm concerned about is that my local IP keep changing, and as per the documentation The following sections will give you the IP address and/or the CNAME where the host os can be reached from within a container. https://devilbox.readthedocs.io/en/latest/advanced/connect-to-host-os.html#docker-18-03-0-ce-and-docker-compose-1-20-1 The docker should be able to connect through host.docker.internal to my Host machine, which it does not and i don't know why. Can you please anyone please point me in the direction what should i do to figure out this issue ?
Don't know the exact reasoning why does it work on some mac machines and doesn't on some, but you can force docker to map host.docker.internal by adding "host.docker.internal:host-gateway" under extra_hosts in your docker-compose. You should be able to use it post this.
Same problem here, the "host.docker.internal" is for development purpose and does not work in a production environment outside of Docker Desktop.
https://docs.docker.com/desktop/networking/#use-cases-and-workarounds-for-all-platforms
Suggested solution:
The database port (typically 3306 for mysql, mariadb, etc.) must be available on the host, you must check the firewall and open the port.
If you use ufw, the command is the following:
sudo ufw allow 3306
Bind_address should be change in the database configuration.
Access to the file can be found in general: /etc/my.cnf
bind_address = 0.0.0.0
In your case you have already do this.
After that, you have to look at the IP address of the gateway of the docker bridge network and enter this value as the host access value of the database. This is usually the IP address: 172.17.0.1
To check the bridge network details run following command:
docker network inspect bridge
Result will be a JSON where you will find the IP of bridge gateway:
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
}
If everything is set up correctly, you can access the database on the host machine from the docker container.
When I run ddev start, I get the following error in the command line:
Failed to start amdocs-stage: Unable to listen on required ports, port 443 is already in use,
Troubleshooting suggestions at https://ddev.readthedocs.io/en/stable/users/troubleshooting/#unable-listen
I went to my configuration file, replaced port 443 for 8443, and port 80 for 8000. However after I run ddev restart, I still see the same error. All instructed here
I don't have lando, and stopped all the services running through brew.
My Docker desktop is running, and the config.yaml inside .ddev looks like this:
name: cohesion-test
type: drupal8
docroot: web
php_version: "7.4"
webserver_type: nginx-fpm
router_http_port: "8000"
router_https_port: "8443"
xdebug_enabled: false
additional_hostnames: []
additional_fqdns: []
mariadb_version: "10.3"
mysql_version: ""
use_dns_when_possible: true
composer_version: ""
web_environment: []
How can I fix this?
You probably have more than one project active (or perhaps "paused") and the other projects still use port 443 (router_https_port is not a global setting). Do a ddev poweroff to stop all projects and then ddev start. If that doesn't do it, remove any additional containers that ddev may not know about with docker rm -f $(docker ps -aq).
You also may want to look at https://github.com/drud/ddev/issues/2981, which explains that there is a bug in current Docker Desktop for Mac v3.3.3, which regularly creates problems with port access that require ddev poweroff and a docker restart.
I'm doing a PoC using dockers and .net 5. The idea is to create a console app or worker service that opens a TCP port and start listening for some specific traffic. If i test it outside of dockers it works but when i try to debug using dockers, the container is run without any port binding. Without the port binding the program does not receive any connection.
This happens with Background workers or Console Apps projects. Meanwhile i tried using the project "Container Application for Kubernetes" and removed all the web code and put mine own code. With this project, VS binds a random port to the exposed port.
Is there anyway i can add a port binding manually to a visual studio debugging process?
When working on docker there are always 2 networks
host machine network
docker's own private network docker network ls
For a port mapping --ports <left side>:<right side> if you are debugging from withing docker container you'll have to use port on the right side of the mappings. If you are accessing from host machine use the one of the left hand side
Not sure if this is what you need.
I created a docker-compose with multiple port bindings, like so:
version: '3.4'
services:
consoleapp2:
image: ${DOCKER_REGISTRY-}consoleapp2
ports:
- "8080:80"
- "8081:81"
- "8082:82"
build:
context: .
dockerfile: ConsoleApp2/Dockerfile
And this is what I see when I debug the app:
You can also use container port 80 and then map it via the httpPort in launchSettings.json
Dockerfile
FROM mcr.microsoft.com/dotnet/runtime:5.0-buster-slim AS base
WORKDIR /app
EXPOSE 80
...
launchSettings.json
{
"profiles": {
"TerminalService": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
},
"dotnetRunMessages": "true"
},
"Docker": {
"commandName": "Docker",
"httpPort": 9003,
"useSSL": false
}
}
}
This binds container port 80 to host port 9003.
Then in the code of my Worker I have a TCP listener listening on port 80:
TcpListener listener = new TcpListener(IPAddress.Any, 80);
Looks like you can also do it via DockerfileRunArguments in the project file (I did not test this):
<PropertyGroup>
<DockerfileRunArguments>-p 8883:8883</DockerfileRunArguments>
</PropertyGroup>
See:
https://github.com/microsoft/DockerTools/issues/206
I installed the docker-beata (https://beta.docker.com/) for osx.
Next, I created a folder with this file docker-compose.yml :
web:
image: nginx:latest
ports:
- "8080:80"
After, I used this command : docker-compose up.
Container start with success.
But the problem is to access in my container. I don't know what ip use.
I try to find ip with docker ps and docker inspect ...:
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "6342cefc977f260f0ac65cab01c223985c6a3e5d68184e98f0c2ba546cc602f9",
"EndpointID": "8bc7334eff91d159f595b7a7966a2b0659b0fe512c36ee9271b9d5a1ad39c251",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
So I try to use http://172.17.0.2:8080/ to access, but I have a ERR_CONNECTION_TIMED_OUT error.
But, if I usehttp://localhost:8080/, I can access to my container !
(But my localhost is already use by my native config on my mac, so if I want use localhost I must stop my native apache).
Why it's doesn't work with the ip ?
As #Javier-Segura mentioned, on with native Docker on Linux you should be able to hit the container via it's IP and port, so in your case http://172.17.0.2:80 - the 8080 port would be on the host IP.
With Docker for Mac Beta it does not appear to work the same way for the container. It changes a bit with every release but right now it appears you can not reach a container by ip via conventional means.
Unfortunately, due to limtations in OSX, we’re unable to route traffic
to containers, and from containers back to the host.
Your best bet is to use a different non-conflicting port as mentioned. You can use different Compose config files for different environments, so as in the example above, use 8081 for development and 8080 for production, if that is the desire. You would start Compose in production via something like docker-compose -f docker-compose.yml -f production.yml up -d where production.yml has the overrides for that environment.
When you map a port (like done with "8080:80") you are basically saying that "Forward the port 8080 on my localhost to the 80 port on the container".
Then you can access your nginx via:
http://localhost:8080
http://172.17.0.2:80/ (depending on the network configuration)
If the port 8080 is already used by apache on your mac, you can change your configuration to "8081:80" and nginx will be available on 8081
Here is one more tip to add to the good ones already provided. You can use the -p option to include IP mapping in addition to your port mapping. If you include no IP (something like -p 8080:80), then your telling docker to route traffic entering all interfaces on port 8080 to your docker internal network (172.17.0.2 in your case). This includes, but is not limited to, localhost. If you'd like this mapping to apply to only a certain IP, for example an IP dynamically assigned to your workstation through DHCP, you can specify the IP in the option as -p 10.11.12.13:8080:80 (where 10.11.12.13 is a fictional IP). Then localhost or any other interface would not be routed.
Likewise, you could use the option to restrict to localhost with -p 127.0.0.1:8080:80 so that other interface traffic is not routed to your docker container's 172.17.0.2 interface.
#pglezen is right. Providing full IP within compose file is solving the issue.
Image IP addresses that were generated by docker-compose dose not work (now) on MAC OSX.
Providing specific ip within compose file allowed to access container image:
nginx:
image: nginx:latest
ports:
- "127.0.0.1:80:80"
links:
- php-fpm
docker-compose still assigned generic 172.* IP address to image that was not accessable. But real hardcoded 127.0.0.1 was working and returns correct container response.
The server works fine locally, but I can't access the server from outside when I'm entering the hostname in my mobile browser (webpage not available). I my Gruntfile.js i have
connect: {
options: {
port: 9000,
hostname: '130.236.124.57',
livereload: 35729
},//...
where hostname is the ip (inet) adress I get when I'm running ifconfig in the terminal.
You should change your hostname to 0.0.0.0 to allow external requests and restart your grunt server.
Next, access your external server with your machine specific hostname/IP