I've run into an interesting issue where there seems to be a difference between the docker run
command and using docker-compose
.
I have two Docker containers, one is an Apache website with PHP, the other a MySQL. I use the following commands to run the containers:
Website:
docker run -p 8080:80 -d website_local
MySQL:
docker run -e MYSQL_ROOT_PASSWORD=RamaLamaDingDong --name=mysql5725 -d mysql:5.7.25
Looking at the Docker ecosystem I can see them both running:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
849c421e750b website_local "/usr/sbin/apache2ct…" 19 minutes ago Up 19 minutes 0.0.0.0:8080->80/tcp pedantic_tesla
ccebba95693b mysql:5.7.25 "docker-entrypoint.s…" 23 minutes ago Up 23 minutes 3306/tcp, 33060/tcp mysql5725
I have setup a PDO connection to the database, using the name for the MySQL Docker container:
PHP: (the USER
and PASS
are correct and yes, I know I shouldn't use the root's credentials)
try {
$dbh = new PDO('mysql:host=mysql5725;dbname=grocery;charset=utf8', USER, PASS);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
echo $e->getMessage();
$errorCode = $e->getCode();
}
When attempting to connect to the database I get the following error:
SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known
If I replace host
in the connections string with the Docker IP address (172.17.0.3) of the container it connects properly.
Now it gets interesting. If I bring up the containers using Docker Compose:
version: '3'
services:
db:
image: mysql:5.7.25
container_name: mysql5725
environment:
MYSQL_ROOT_PASSWORD: RamaLamaDingDong
ports:
- "3306:3306"
web:
image: website_local:latest
container_name: website_local
depends_on:
- db
volumes:
- ./website/www:/var/www/html/
ports:
- "8080:80"
The PHP function connects correctly using the name of the Docker container (mysql5725
), but cannot connect using the IP address of the Docker container.
Many times in a testing environment I only want to stop and rebuild certain containers, especially when dealing with more than two Docker images. I should only have to use the resource's name when making a connection because there is no guarantee the network will assign the same IP addresses to containers every time.
Why should these two methods of launching Docker containers produce different results? Is there a way to 'normalize' this, so connecting by name will work no matter how the container is launched?
Docker Compose automatically sets up a network for you:
By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
The default bridge network that Docker creates on its own doesn't provide DNS so you can't use it to connect to containers using their names. You'll probably want to set up a network yourself, e.g. with
docker network create mynetwork
and then connect your containers to it, e.g. with
docker network connect mynetwork mysql5725
docker network connect mynetwork php-container
Note that this isn't the only difference between Docker Compose and manually running containers.