I am trying to connect from this docker container:
version: '3.8'
services:
vidslide-api:
image: php:8.1.17-apache
ports:
- "80:80"
volumes:
- ./htdocs:/var/www/html
command: >
sh -c "
docker-php-ext-install mysqli &&
docker-php-ext-enable mysqli &&
apache2-foreground
"
to this docker container:
version: '3.8'
services:
vidslide-db:
image: mysql:8.0.32
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: ***
ports:
- "3306:3306"
volumes:
- /var/lib/vidslide_mysql-db:/var/lib/mysql
volumes:
mysql_data:
I can connect to the mysql server with prisma and mysql workbench but not with php.
When I try to connect with mysqli:
$conn = mysqli_connect($host, $user, $pass, $dbname);
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
echo "Connected successfully";
I get: Fatal error: Uncaught mysqli_sql_exception: No such file or directory in /var/www/html/index.php:14 Stack trace: #0 /var/www/html/index.php(14): mysqli_connect(‘localhost’, ‘root’, ‘***’, ‘vidslide-db’) #1 {main} thrown in /var/www/html/index.php on line 14
my mysqli config from phpinfo();
I don’t understand the error message.
What do I have to do to make it work? Are the versions not compatible?
2
Answers
There is a lot to unpack here.
Consider each
docker-compose.yml
a different "project". For each project docker-compose will create its own virtual network. Without additional config in each project those virtual networks will not be able to talk to each otherThe declarations in the
ports:
section will map the port out to the host machine’slocalhost:port
but that is it."localhost" is only local to the individual container. Each container has its own, and none of them are the host machine’s "localhost" either.
Most mysql drivers [including PHP’s] map the name
localhost
to the local unix socket which is only available if you’re running the code on the same host [or container, in this case] as Mysql.#4 is why you’re getting the quizzical "file not found" error on connection, because it can’t find the socket file, and everything else is why it wouldn’t have worked anyway.
The simple solution is to combine the two services into a single
docker-compose.yml
and then use the mysql service’s hostname instead of localhost.Docker-compose creates local DNS names for each service, so your mysql hostname will be
vidslide-db
instead oflocalhost
.Additionally, you don’t want to be installing anything every time your container starts, unless you really like waiting for extensions to compile every time the container starts. For this you’ll want to build your own image that includes this, and Docker-compose makes it easy to build on demand.
Add this as
Dockerfile-php
in the same dir as yourdocker-compose.yml
:And change the
vidslide-api
service to simply:In this case,
localhost
is actually the container rather than your host. Therefore, the connection fails (because the PHP container doesn’t host a MySQL Database).To use your host in Docker Desktop, use
host.docker.internal
as the IP.If you want this solution to work on *nix as well, refer to this answer.
For production instances, you should definitely use docker networks to connect the container together and use
link
s orhostname
to access the database.