Search code examples
laravelpostgresqldocker

How to reference another docker service from Dockerfile


I have 2 services in docker-compose.yml (here is excerpt; file mostly generated by Laravel Sail):

services:
    laravel.test:
        build:
            context: .
            dockerfile: ./docker/8.3/Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: 'sail-8.3/app'
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '800:80'
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - pgsql
    pgsql:
        image: 'postgres:15'
        ports:
            - '${FORWARD_DB_PORT:-5432}:5432'
        environment:
            ...
        volumes:
            - 'sail-pgsql:/var/lib/postgresql/data'
            - './docker/pgsql/create-testing-database.sql:/docker-entrypoint-initdb.d/10-create-testing-database.sql'
        networks:
            - sail
networks:
    sail:
        driver: bridge

Referenced Dockerfile here contains the following lines near the end:

COPY --link . /var/www/html
WORKDIR /var/www/html
RUN php artisan migrate --seed

Unfortunately, migration ends with the error: SQLSTATE[08006] [7] could not translate host name "pgsql" to address: Name or service not known

Service laravel.test depends on pgsql service, so it knows about it. But Dockerfile in laravel.test seems has another scope and cannot see service pgsql, right?

Whether the way to make migration in docker exists?


Solution

  • Your laravel.test container doesn't seem to be able to access the pgsql service during the build phase because Docker's service discovery (i.e., how containers communicate via service names like pgsql) only works once the containers are running. The build process in a Dockerfile doesn't have access to the network of running services defined in docker-compose.yml.

    In your case, the migration command (php artisan migrate --seed) is being executed during the build phase in the Dockerfile.

    My suggestion is that you execute the migration happens after both containers are up and running.

    You can follow an approach like this:

    • Remove the migration command from your Dockerfile to avoid running it during the build phase:
    # Original lines
    COPY --link . /var/www/html
    WORKDIR /var/www/html
    # RUN php artisan migrate --seed (remove this line)
    
    • You can also add a post-start script to your docker-compose.yml to run the migration after the services are up:
    services:
        laravel.test:
            ...
            depends_on:
                - pgsql
            command: >
                sh -c "php artisan migrate --seed && php artisan serve --host=0.0.0.0 --port=8000"
    
        pgsql:
            ...
    

    With these changes, the Laravel service will run the migration automatically on startup and then continues to run the development server.

    One key thing to note by the way: Ensure that your application waits for the PostgreSQL service to be ready before running migrations. You can either use Laravel’s built-in retry mechanism for database connections, or a tool like dockerize to wait for the PostgreSQL service before running the migration.