Docker container can't connect to each other - php

I have two containers in a docker compose, a Postgres DB and a Symfony PHP app.
From within the backend-app (PHP Symfony) I would like to execute commands that handle the DB connection, but none of the configs I try seem to work.
I added expose (https://docs.docker.com/compose/compose-file/#expose) as hinted here and also added a default network as hinted here
docker-compose.yml
version: '3'
services:
database:
image: postgres:11
ports:
- 5431:5432
expose:
- "5431"
environment:
POSTGRES_PASSWORD: password
POSTGRES_USER: user
POSTGRES_DB: my_db
volumes:
- ./database:/var/lib/postgresql/data
frontend:
image: frontend-image:latest
ports:
- 8090:80
backend-app:
image: backend-app:latest
links:
- database
backend-web:
image: backend-web:latest
ports:
- 8091:80
depends_on:
- backend-app
- database
networks:
default:
Depending on the DB config in the Backend Container I get different error messages when executing php bin/console doctrine:schema:update --force inside backend-app:
DATABASE_URL="postgresql://user:password#database:5431/my_db?serverVersion=11&charset=utf8"
leads to
An exception occurred in driver: SQLSTATE[08006] [7] could not connect to server: Connection refused. Is the server running on host "database" (172.21.0.2) and accepting TCP/IP connections on port 5431?
and
DATABASE_URL="postgresql://user:password#localhost:5431/my_db?serverVersion=11&charset=utf8"
leads to
SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5431?
Where am I wrong in my approaches?

You don't get to choose what the container expose inside the internal docker network created by compose.
The postgress image exposes the port 5432, so your expose: 5431 instruction just exposes a port on which postgress is not listening, so it is useless.
So in between containers, you are stuck to using the port 5432 for postgress, unless you derive from the existing image, change the configuration there and expose the port you'd like.
The instruction below just change the port on which the container is exposed to the outside world, as pointed by the documentation
ports:
- 5431:5432
This means that you are exposing the port 5432 of the container to the port 5431 of your host.
Either specify both ports (HOST:CONTAINER), or just the container port (an ephemeral host port is chosen).
Source: https://docs.docker.com/compose/compose-file/#ports
To sum up:
your Symfony configuration should read:
DATABASE_URL="postgresql://user:password#database:5432/my_db?serverVersion=11&charset=utf8"
the expose directive in your compose file is useless
the ports directive as you wrote it there is only convenient if you want to connect from your host machine to the postgress container on a different port than the default one (i.e. because you already have a local postgress server running and, so the port is in use)

Related

Database connection from php container with host name "localhost" instead of container name

Our website-framework(s) are designed to work on both xampp and docker environments. We are recognizing our database hosts by host name/IP-address (dev, test, staging, live env). People who are working with xampp are using https://localhost, so they get the environment variable called Development. People who are working with docker are using https://docker as their host. They get the env-variable called Development/Docker. We need this differentiation because inside the php applications our xampp users are connecting to their mysql service with host localhost. Docker users have to connect via host called mysql (this is the container name of the mysql-service).
Because of the last occurred problems (not relevant to be mentioned here) we want a unique solution for both user-groups concerning the database connection: Docker users should be able to connect to their mysql service with host localhost.
docker-compose.yaml (shortened for better overview):
version: '2'
services:
#######################################
# PHP application Docker container
#######################################
app:
build:
context: .
dockerfile: Dockerfile.development
links:
- mail
- mysql
- redis
ports:
- "80:80"
- "443:443"
- "10022:22"
- "3307:3306"
volumes:
- ./app/:/app/
- ./:/docker/
cap_add:
- SYS_PTRACE
env_file:
- etc/environment.yml
- etc/environment.development.yml
environment:
- POSTFIX_RELAYHOST=[mail]:1025
#######################################
# MySQL server
#######################################
mysql:
build:
context: docker/mysql/
dockerfile: MariaDB-10.Dockerfile
ports:
- "3306"
volumes:
- mysql:/var/lib/mysql
env_file:
- etc/environment.yml
- etc/environment.development.yml
#######################################
# phpMyAdmin
#######################################
# /// #
#######################################
# Mail
#######################################
# /// #
#######################################
# Redis
#######################################
# /// #
# Volumes
volumes:
mysql:
phpmyadmin:
redis:
I tried a lot and played with the docker-compose but didn't find a solution for weeks. Tried with links, networks and so on. I think my docker skills are exhausted by now...
I also added to the mysql.conf:
bind-address = 0.0.0.0
Any ideas?
It is because of docker's networking structure.
docker creates 3 base interfaces. docker0 , host and none.
each container uses docker0 by default. then each container will have a virtual network interface for communicating between containers. so you can use your database with mysql address.
if you want to connect to database with address localhost you should config docker to use host network mode (you can do it by adding one line to defenition of your app service in docker compose file). it will be able to connect to every app which is running on your system. By the way you would loose communication with other container by their name. maybe you loose your connection with your redis (which is connected with redis address)
In this network mode, every dependency should be deployed or be exposed to your localhost.

Symfony 4 "Connection refused" while trying to connect to docker mysql container

My question is how to configure connection to mysql container.
Here is my docker-compose.yml
version: '3'
services:
php:
build: ./php-fpm
volumes:
- ./iym:/var/www/iym
- ./php-fpm/php.ini:/usr/local/etc/php/php.ini
depends_on:
- mysql
web:
build: ./nginx
ports:
- "8888:80"
volumes:
- ./iym:/var/www/iym
- ./nginx/iym.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
mysql:
image: mysql:5.6
restart: always
command: --default-authentication-plugin=mysql_native_password
volumes:
- ${DB_PATH_HOST}:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "symf0ny"
ports:
- "3306:3306"
And here is my DATABASE_URL in .env file
DATABASE_URL=mysql://root:symf0ny#127.0.0.1:3306/iym
When i try to run php bin/console doctrine:database:create i get an error like "SQLSTATE[HY000] [2002] Connection refused". OS - ubuntu 18.04. What should i do to connect to DB? Many thanks!
I assume you are trying to connect from another container/service defined in docker-compose and you are using current version of docker-compose (2.4 or 3.7)
You need to change
DATABASE_URL=mysql://root:symf0ny#127.0.0.1:3306/iym
to
DATABASE_URL=mysql://root:symf0ny#mysql:3306/iym
The reason is that 127.0.0.1 is refering to the localhost of the machine on which php runs. In this case it's the php's container localhost. But the db doesn't run there. It runs in another docker container, which can be reached under the service name, mysql in this case.
In docker-compose networking docs is written:
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.
but, the service is discoverable under the container name (which is automatically generated to projectName_serviceName_1 (project name begin by default folder name), but also under service name, link and service alias if defined. I would recommend using service name wherever possible.
More in docs: https://docs.docker.com/compose/networking/
In my case, the Docker variable overrides the parameter from .env file and I'm trying to connect to the wrong host. Found that via dd($this->constructPdoDsn($params)) in the Doctrine\DBAL\Driver\PDO\MySQL\Driver::connect, maybe it will be helpful

Docker-Symfony-Mysql: SQLSTATE[HY000] [2002] Connection refused

So I am new to docker and this is the first project I have tried to run using it. I am running into the issue of my php-apache container is not able to connect to my mysql container, but only in the browser. I can do:
docker exec -it <php container id> bash
and then run
composer install
and all of the
php bin/console doctrine:<>
commands just fine with no database errors or connection problems. When I try to actually load up the site in my browser I am met with the "SQLSTATE[HY000] [2002] Connection refused" error. I am not really sure why this is the case and no results I have found on the web seem to work. Here are my files:
docker-compose.yml
version: '3'
services:
db:
restart: always
container_name: hcp-db
build:
context: ../
dockerfile: docker/db/Dockerfile
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
- MYSQL_DATABASE=symfony
- MYSQL_USER=root
- MYSQL_PASSWORD=password
volumes:
- db:/var/lib/mysql
expose:
- 3306
ports:
- "4306:3306"
application:
container_name: hcp-symfony
build:
context: ../
dockerfile: docker/Dockerfile
working_dir: /app
expose:
- 80
ports:
- 8000:80
depends_on:
- db
volumes:
- ../:/app
environment:
- SYMFONY_ENV=dev
- SYMFONY_DEBUG=1
volumes:
db:
parameters.yml
parameters:
database_driver: pdo_mysql
database_host: db
database_port: 3306
database_name: symfony
database_user: root
database_password: null
I am also able to connect to the database just fine through Sequel Pro while my container is running using the same credentials I provide in the parameters, but with the host as "127.0.0.1", which I find interesting.
Any help with what could be wrong would be much appreciated.
Sup, I can't comment yet to ask a bit more of details since I'm kind of new so I will take a wild guess and assume there is no issues on your app.
This kind of issue is usually related to firewall stuff. Docker does a lot of firewall configuration for us so we don't have to deal with the ufw or IP tables ourselves, but that also means that we need to specify how each container will interact with each other ourselves withing our docker compose file.
You have to specify that your app container links to the database container in order to allow hostnaming access since docker modify the container /etc/hosts file everytime a container starts so it maps each container current IP, like this:
services:
...
application:
...
depends_on:
- db
links:
- db
With that done, you just need to make sure your parameters file is configured correctly as #dbrumann pointed out, the database_password should contains your password and not a null value.
It is also a good practice to create a custom network for your docker project so you can have a nice private lan between your containers without being open to any other container using docker's default network, a custom network with defaults can do nicely, like this:
services:
db:
...
networks:
- my_project_network
application:
...
depends_on:
- db
links:
- db
networks:
- my_project_network
networks:
my_project_network:
You don't really need to expose your database port to the host for this to work but having it exposed makes development way easier when checking the database so just remember to remove the database container ports statement when going to production environment to avoid security issues.
Hope this helps, here is a link to docker network documentation in case you want to learn more: https://docs.docker.com/compose/compose-file/#network-configuration-reference

Symfony + Docker, connection refused

I'm seasoned in Symfony but quite new to docker, and I have a "connection refused error" I don't manage to solve.
Pretty sure it is a beginner error and that the solution here is quite simple...
Here is the content of my docker-compose file:
version: '3.2'
services:
cg-demo:
build: docker/cg-demo
container_name: cg-demo
working_dir: /var/www/html
volumes:
- .:/var/www/html
- ./docker/demo/vhost.conf:/etc/apache2/sites-available/000-default.conf:ro
- ./docker/demo/php.ini:/usr/local/etc/php/php.ini:ro
- ~/.ssh:/var/www/.ssh
- ~/.composer:/var/www/.composer
environment:
- SYMFONY_ENV
- DOMAIN_NAME: cg-demo.docker
- VIRTUAL_HOST: cg-demo.docker
depends_on:
- database
env_file: .env
ports:
- 8000:80
database:
image: percona:5.6
ports:
- 3306:3306
expose:
- 3306
container_name: cg-demo-database
volumes:
- /docker/database:/etc/mysql/conf.d
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: demo
tmpfs:
- /var/lib/mysql
- /tmpfs:size=300M
This has been based from another project that works, but I'm not sure of all that's happening here...
I also have a phpmyadmin container, not shown here. PhpMyAdmin connects correctly to the database and can use it without problem from any web server. However when it comes to the symfony container, I have this whenever trying to use the database:
[Doctrine\DBAL\Exception\ConnectionException]
An exception occured in driver: SQLSTATE[HY000] [2002] Connection refused
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[HY000] [2002] Connection refused
[PDOException]
SQLSTATE[HY000] [2002] Connection refused
The connection information is the following, in a .env file:
# Database credentials
DATABASE_HOST=database
DATABASE_PORT=3306
DATABASE_USER=root
DATABASE_PASSWORD=root
DATABASE_DB=cg-demo
Calling docker ps gives me this:
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS NAMES
16a67dadeebb phpmyadmin/phpmyadmin "/run.sh phpmyadmin" 15 minutes ago Up 15 minutes 0.0.0.0:8001->80/tcp cg.phpmyadmin.docker
8bd783aa1dd1 cg_cg-demo "entrypoint.sh apa..." 15 minutes ago Up 15 minutes 0.0.0.0:8000->80/tcp cg-demo
2fc7cd9105ba percona:5.6 "docker-entrypoint..." 15 minutes ago Up 15 minutes (healthy) 3306/tcp cg-database
I've tried to ping database from the demo container and it works...
EDIT 1:
Added the following to the database container:
ports:
- 3306:3306
EDIT 2:
Removed the following from all containers:
networks:
- default
EDIT 3:
My doctrine configuration in app/config/config.yml:
dbal:
host: "%env(DATABASE_HOST)%"
port: "%env(DATABASE_PORT)%"
dbname: "%env(DATABASE_DB)%"
user: "%env(DATABASE_USER)%"
password: "%env(DATABASE_PASSWORD)%"
charset: UTF8
mapping_types:
enum: string
server_version: 5.6
EDIT 4:
Added the following to the database configuration:
expose:
- 3306
This answer is for docker-compose version 2 and it also works on version 3:
The problem is a Linking Containers problem. We need to define additional aliases that services can use to reach one another.
Expose 3306 port will not solve your problem. mysql or percona container will expose by deffault that port. Take a look to the docker hub of percona image.
. It's mentioned there:
Connect to MySQL from an application in another Docker container
This image exposes the standard MySQL port (3306), so container
linking makes the MySQL instance available to other application
containers. Start your application container like this in order to
link it to the MySQL container:
$ docker run --name some-app --link some-percona:mysql -d application-that-uses-mysql
So, you should links the database to you cg-demo container. There's tow solutions:
1) Add a link under configuration :
services:
cg-demo:
build: docker/cg-demo
container_name: cg-demo
.
.
.
links:
- mysql
The diffirence between depeds_on and links is that depends_on docker-compose up will start services in dependency order. In your following example, database will be started before web.
We can also access data. But this is not enough, because we want to make sure that your web container (cg-demo) always connect to the database container.
Links allow you to define extra aliases by which a service is reachable from another service.
In the following example, database is reachable from web (cg-demo) at the hostname database. This means that thecg-demo can connect the database contanier from the 3306 port.
2) The second solution, is to configure the default network instead of (or in addition to) customizing your own network. Simply define a default entry under networks:
networks:
bridge_name:
driver: bridge
And then you should link every container to that bridge via networks tag:
cg-demo:
.
.
networks:
- bridge_name
database:
.
.
networks:
- bridge_name

Unable to connect to socket server running inside docker container

I have a docker compose file which combines nginx and php like this:
nginx:
image: nginx
ports:
- "80:80"
- "2443:2443"
links:
- phpfpm
volumes:
- ./nginx/anonymous.conf:/etc/nginx/conf.d/anonymous.conf
- ./logs/nginx-error.log:/var/log/nginx/error.log
- ./logs/nginx-access.log:/var/log/nginx/access.log
- ./public:/usr/share/nginx/html
phpfpm:
image: php:fpm
expose:
- "2443"
volumes:
- ./public:/usr/share/nginx/html
I can see my website i.e index.php page on browser with the virtual host i have already made lets say anonymous.com
Now inside my phpfpm container i started a socket server based on Ratchet which is listening to port 2443
// bin/server.php
$webSocketServer = new WsServer(new Chat());
$server = IoServer::factory(
new HttpServer($webSocketServer), 2443);
$server->run();
This is how i run my server inside phpfpm container
php /usr/share/nginx/html/bin/server.php
My understanding is, since i have already exposed 2443 and my ngnix and phpfpm containers are linked. I would be able to connect to my socket server running on phpfpm container by going to telnet anonymous.com 2443
But its not getting connected. Here is the output
$ telnet anonymous.com 2443
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.
Please note that previously when i had both nginx and php-fpm were on single container, every thing was working fine. So i am sure that there is nothing wrong with PHP. It just i cannot figure out how to access the socket server from outside world.
Thanks
Update
If i use my phpfpm container ip and use it with port 2443 through browser, its working fine. but the thing is i cannot rely on container ip as its all dynamic.
I had a similar issue (same output) using a socket server based on Ratchet. Mine was only a PHP container (= no nginx/apache/...).
It was because of the 3rd parameter given to the factory :
$server = IoServer::factory(
new HttpServer($webSocketServer), 2443, '127.0.0.1'
);
Removing 127.0.0.1 (and then use the default 0.0.0.0 value) solved the problem.
You should use the name of the service as the hostname. So to connect from nginx to phpfpm use phpfpm:2443

Categories