0

I'm trying to run a Docker container based on:

  • PHP 8.1
  • Apache 2.4
  • MariaDB (latest official docker image)

Dockerfile:

FROM php:8.1-apache

WORKDIR /var/www/html/

RUN pecl install xdebug \
    && apt update \
    && apt install libzip-dev -y \
    && docker-php-ext-enable xdebug \
    && a2enmod rewrite \
    && docker-php-ext-install zip \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-install pdo pdo_mysql

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY composer.json .

RUN groupadd -r user && useradd -r -g user user
USER user
RUN composer install --no-dev

COPY . .

EXPOSE 80

CMD [ "sh", "-c", "php src/init.php" ]

docker-compose.yml:

services:

  php:
    build: ./php
    depends_on:
      - db
      - adminer
    container_name: php-apache
    ports:
      - 80:80
    volumes:
      # setup xdebug to be able to use PHP step debugger, if needed
      - ./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
      - ./php/conf.d/error_reporting.ini:/usr/local/etc/php/conf.d/error_reporting.ini
      # apache config (server name)
      - ./apache/apache2.conf:/etc/apache2/apache2.conf
      # apache config (rewrite rule to reroute all requests to unknown resources through to REST controller)
      - ./apache/000-default.conf:/etc/apache2/sites-enabled/000-default.conf
      # Source code
      - ./php/src:/var/www/html/src
      # unbind local composer components
      - /php/vendor
      - /php/composer.lock
      - /php/composer.phar
    environment:
      MARIADB_HOST: db
      MARIADB_USER: root
      MARIADB_PASSWORD: top_very_secret
      MARIADB_DB: apidb

  adminer:
    image: adminer
    depends_on:
      - db
    restart: always
    ports:
      - 8080:8080

  db:
    image: mariadb
    container_name: db
    volumes:
      - maria-db-storage:/var/lib/mysql
    environment:
      MARIADB_ROOT_PASSWORD: top_very_secret
      MARIADB_DATABASE: apidb
    ports:
      - 3306:3306

volumes:
  maria-db-storage:

src/init.php connects with the DB and creates tables the application needs, if they do not already exist. To connect, I use the environment variables like so:

new PDO(
    "mysql:host={$_ENV['MARIADB_HOST']};dbname={$_ENV['MARIADB_DB']}",
    $_ENV['MARIADB_USER'],
    $_ENV['MARIADB_PASSWORD'],
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]
);

And for the first time I docker-compose up, I always get:

SQLSTATE[HY000] [2002] Connection refused.

At the top of the src/init.php script, I can successfully echo out all of the environment variables used in Docker. So they are all defined.

I'm really confused with this, as docker-compose up and the DB connection only work after failing on the first time docker-compose up fails (with the above-mentioned error). When then calling docker-compose down, then do docker-compose up again in the subsequent times, things all work flawlessly. Any idea why this happens?

I've been digging a little further, and I noticed that, wehn the mariadb image is built (e.g. when you first run docker-compose up with the above mentioned file contents), I get the above-mentioned error plus the output:

PLEASE REMEMBER TO SET A PASSWORD FOR THE MariaDB root USER

So it seems that, at the moment of the image being built; the MARIADB_ROOT_PASSWORD is for some reason not applied, but aftewards it is, and that that's the reason for the failed connection?

Currently, I suppose that this is due to this ?:

If there is no database initialized when the container starts, then a default database will be created. While this is the expected behavior, this means that it will not accept incoming connections until such initialization completes. This may cause issues when using automation tools, such as docker-compose, which start several containers simultaneously.

2
  • 1
    My guess would be that the environment variables are not available to the command executed by the Dockerfile's CMD directive. You can add some commands to your init.php to log the variables prior to establishing the database connection. In any case, this seems to be a Docker problem and not something related to MySQL.
    – mustaccio
    Commented Nov 16, 2022 at 20:46
  • I’ll check and (hopefully) verify that tomorrow, cheers!
    – DevelJoe
    Commented Nov 16, 2022 at 23:05

1 Answer 1

0

Ok now I got it. The reason indeed seems to be that, when the container was initiated for the first time, the mariadb and the php apache image were being generated at the same time. That's why I got the error only at the first docker-compose up; I've tried to connect with the DB when the db container wasn't fully initialized. In most of the subsequent docker-compose up, this did not happen. Most likely because docker grabbed the already pulled mariadb image from the cache, and the db container was ready much faster.

I've found this and have chosen the wait-for-it solution to execute the init.php only after waiting until the db:3306 is available in the container. All finally perfectly working now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.