2
votes

I have my application running in docker and setting up Github Actions to run my tests. For running Behat tests I have a separate test db so also a separate .env to be used.

In .env.test

DATABASE_URL=mysql://root:emc@mysql:3306/emc_test?serverVersion=5.7

In docker-compose.test.yml

version: "3.7"
services:

  mysql:
    build:
      context: docker/mysql
      dockerfile: Dockerfile
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: emc
      MYSQL_USER: emc
      MYSQL_PASSWORD: emc
      MYSQL_DATABASE: emc
      TZ: Europe/Brussels
    ports:
      - "3306:3306"
    networks:
      - backend

  cli:
    image: christianvermeulen/itexperts:latest
    volumes:
      - .:/application:cached
      - app-cache:/application/var/cache
      - composer:/composer
    networks:
      - backend

volumes:
  composer:
  app-cache:
  mysql-data:

networks:
  backend:

As soon as I hit the database I get a connection refused. I have this testcommand set up in Symfony:

<?php
declare(strict_types=1);

namespace Development\Cli;

use Development\Fixtures\LoadFixtures;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class TestDBCommand extends Command
{
    protected static $defaultName = 'test:db';
    /**
     * @var Connection
     */
    private Connection $connection;

    public function __construct(Connection $connection)
    {
        parent::__construct();
        $this->connection = $connection;
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Testing Database');

        $io->note('Username: '.$this->connection->getUsername());
        $io->note('Password: '.$this->connection->getPassword());
        $io->note('Host: '.$this->connection->getHost());

        try {
            $st = $this->connection->executeQuery('show databases;');
            $result = $st->fetchAll(\PDO::FETCH_ASSOC);
            foreach ($result as $key => $value) {
                $io->note($value);
            }
        } catch (DBALException $e) {
            $io->warning('Failed: '.$e->getMessage());
        }

        $io->success('All good');

        return 0;
    }
}

Finally I want to also see some information so I run the following commands in Github Actions:

- name: Prepare Testing
  run: |
    cp docker-compose.test.yml docker-compose.yml
    docker-compose build
    docker-compose up -d
    docker-compose ps
    docker-compose run --rm cli ping -c 5 mysql
    docker-compose run --rm mysql env | sort
    docker-compose run --rm -e APP_ENV=test cli bin/console test:db

The output is:

   Name                 Command              State                  Ports              
---------------------------------------------------------------------------------------
emc_cli_1     docker-php-entrypoint php -a   Exit 0                                    
emc_mysql_1   docker-entrypoint.sh mysqld    Up       0.0.0.0:3306->3306/tcp, 33060/tcp


PING mysql (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.170 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.066 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.092 ms
64 bytes from 172.18.0.3: seq=3 ttl=64 time=0.100 ms
64 bytes from 172.18.0.3: seq=4 ttl=64 time=0.070 ms

--- mysql ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.066/0.099/0.170 ms


GOSU_VERSION=1.12
HOME=/root
HOSTNAME=7656ccf87670
MYSQL_DATABASE=emc_test
MYSQL_MAJOR=5.7
MYSQL_PASSWORD=emc
MYSQL_ROOT_PASSWORD=emc
MYSQL_USER=emc
MYSQL_VERSION=5.7.30-1debian10
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
SHLVL=0
TZ=Europe/Brussels

Testing Database
================

 ! [NOTE] Username: root                                                         

 ! [NOTE] Password: emc                                                         

 ! [NOTE] Host: mysql                                                           

 [WARNING] Failed: An exception occurred in driver: SQLSTATE[HY000] [2002]      
           Connection refused                                                   

 [OK] All good

So in short, I have validated:

  • Hostname is correct
  • Expected username + password is correct
  • Port 3306 is mapped (though it should not be necessary internally)
  • mysql container is running
  • mysql is reachable (pingable) from the cli container
  • mysql container does have the right environment vars for the setup

Finally, I have 2 runs on the exact code with different outcomes. What could be the variable problem on Github Actions?

Failure Success

Why on earth is my connection being refused?

1

1 Answers

5
votes

In case any one else might be breaking their heads over this, it turned out the mysql container was fired up neatly however mysql itself needs more time to start up and run.

Hence, ping was ok, env was ok, container was running, but the mysql service was not (yet).

When doing this in an automated environment (such as CI pipelines) it runs too fast compared to a manual environment like localhost.

Solution: Re-order your commands to give more time to mysql to start or add in a short sleep of a couple of seconds.