0

I have 2 Laravel applications running in docker environment.

The first application docker-compose file (which called mobile app)

version: '3.8'

networks:
    laravel:

services:
    nginx:
        build:
            context: .
            dockerfile: dockers/nginx/Dockerfile
        container_name: mobile-server-nginx
        ports:
            - "8188:80"
        volumes:
            - ./:/var/www/
        depends_on:
            - php
            - mysql
        networks:
            - laravel
    mysql:
        image: mysql:8.0.28
        container_name: mobile-server-mysql
        tty: true
        ports:
            - "5306:3306"
        volumes:
            - ./mysql:/var/lib/mysql
        environment:
            MYSQL_DATABASE: ${DB_DATABASE}
            MYSQL_USER: ${DB_USERNAME}
            MYSQL_PASSWORD: ${DB_PASSWORD}
            MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
            SERVICE_TAGS: dev
            SERVICE_NAME: mysql
        networks:
            - laravel
    php:
        build:
            context: .
            dockerfile: dockers/php/Dockerfile
        container_name: mobile-server-php
        extra_hosts: 
            - "host.docker.internal:host-gateway"
        volumes:
            - ./:/var/www/
        ports:
            - "9001:9000"
        networks:
            - laravel
        depends_on:
            - mysql

The second application docker-compose file: (which called resident app)

version: '3.7'

networks:
    resident:

services:
    nginx:
        build:
            context: .
            dockerfile: dockers/nginx/Dockerfile
        container_name: resident-backend-nginx
        ports:
            - "8088:80"
        volumes:
            - ./:/var/www/
        depends_on:
            - php
            - mysql
        networks:
            - resident
    mysql:
        image: mysql:5.7.22
        container_name: resident-backend-mysql
        tty: true
        ports:
            - "6306:3306"
        volumes:
            - ./mysql:/var/lib/mysql
        environment:
            MYSQL_DATABASE: ${DB_DATABASE}
            MYSQL_USER: ${DB_USERNAME}
            MYSQL_PASSWORD: ${DB_PASSWORD}
            MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
            SERVICE_TAGS: dev
            SERVICE_NAME: mysql
        networks:
            - resident
    php:
        build:
            context: .
            dockerfile: dockers/php/Dockerfile
        container_name: resident-backend-php
        extra_hosts: 
            - "host.docker.internal:host-gateway"
        volumes:
            - ./:/var/www/
        ports:
            - "9002:9000"
        networks:
            - resident
        depends_on:
            - mysql

2 applications work separated perfectly. Now, in mobile application, I want to connect to resident application database to retrieve some data. In the mobile application:

  • In config/database.php, I added 1 more database connection:
        'resident_mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_RESIDENT_URL'),
            'host' => env('DB_RESIDENT_HOST', '127.0.0.1'),
            'port' => env('DB_RESIDENT_PORT', '3306'),
            'database' => env('DB_RESIDENT_DATABASE', 'forge'),
            'username' => env('DB_RESIDENT_USERNAME', 'forge'),
            'password' => env('DB_RESIDENT_PASSWORD', ''),
            'unix_socket' => env('DB_RESIDENT_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
  • Then, I set env variables in .env file:
DB_RESIDENT_HOST=127.0.0.1
DB_RESIDENT_PORT=6306 // exposed mysql port in `resident_app`
DB_RESIDENT_DATABASE={database name}
DB_RESIDENT_USERNAME={database_user}
DB_RESIDENT_PASSWORD={database_password}
  • Create an api to test in api.php:
Route::get('test', function () {
    $user = \DB::connection('resident_mysql')->select('select * from users');
    return $user;
});
  • Finally, test api with postman, but it shows error SQLSTATE[HY000] [2002] Connection refused (SQL: select * from users) enter image description here

I've searched for this error but cannot find any answer.

UPDATE

  • According from @David Maze, I've changed some config in docker-compose file in mobile app.
  • In docker-compose file, add external network
networks:
    laravel:
        driver: bridge
    residentbackend_resident: // this is network in `resident` app, which type is `bridge`
        external: true
  • Then add external network to php service in networks section:
        networks:
            - laravel
            - residentbackend_resident
  • In .env, change DATABASE_HOST to mysql service name of resident app
DB_RESIDENT_HOST=mysql1

But it still return the same error as above.

simpsons3
  • 880
  • 1
  • 11
  • 29
  • Does the setup in [Communication between multiple docker-compose projects](https://stackoverflow.com/questions/38088279/communication-between-multiple-docker-compose-projects) help you? As always in Docker, the special IPv4 address 127.0.0.1 means "this container" and it won't connect to one of the other containers, in either file. – David Maze Jul 04 '22 at 12:00
  • (You could simplify this setup without affecting its functionality by removing unnecessary options like `tty:`, `container_name:`, and `networks:`; you likely do not need the `extra_hosts:` block either.) – David Maze Jul 04 '22 at 12:01
  • @DavidMaze, Thank for your answer, I've tried to set up a external network (I've updated on my post) like your reference link but it still doesn't work. Can you check if I have any mistake in my config? – simpsons3 Jul 04 '22 at 16:08

2 Answers2

2

There are a couple of things to consider here.

First, each container is a separate node in a bigger network.
So setting DB_RESIDENT_HOST=127.0.0.1 will not work, as it does not reference your local machine, but the (PHP) container itself.

Second, each docker-compose.yml creates a separate network, where all the containers defined are attached too. They can only communicate with each other and the host.
You need to attach an external network to the containers, that should be able to communicate across the stacks. But that, it seems like, you have already done by now.

Third, you used the port 6306, which is the exposed port on your local machine. Internally, the container still uses the port 3306. And as those containers communicate now directly (through the external docker network), this is the port to use.

And another thing I noticed is, that those containers have the same names across each stack (compose definitions, not container names). When accessing the mysql container, it probably routes to the container in the same file.
Maybe the hostname keyword solves this, but I haven't used that.
What definitely works, is either renaming them or setting the config to the internal IP address of the container itself.
Run docker inspect resident_mysql (replace the name with the correct one), search for "NetworkSettings", then "Networks", find the external network, that is attached to both containers, and use the value in "IPAddress".

dallyger
  • 126
  • 1
  • 6
  • What a simple solution! Also, when looking for solution, I found another solution worked too. I changed host and port in `.env` to `DB_RESIDENT_HOST=host.docker.internal` & `DB_RESIDENT_PORT=6306` (`6306` is the mysql port of `resident` app) – simpsons3 Jul 05 '22 at 02:30
0

DB host cannot be 127.0.0.1, Since it is a separate docker container you have to add the mysql docker private IP or the name

DB_RESIDENT_HOST=mysql

example for your reference

Shamith Wimukthi
  • 468
  • 3
  • 12