skip to Main Content

I have a wordpress docker-compose, which contains 3 services.

1 – php,apache

2 – mysql

3 – phpmyadmin

what I want to do is install wordpress core and plugins at build time,
and the reason is obvious I don’t want everytime I restart my containers I goes to all steps all over again and install plugins and … . so I need connection to database but It seems that build time I can’t access my mysql container.
I read somewhere that I need to specify network on build stage but I couldn’t make it work.
and here is my docker-compose file :

version: '3.8'

volumes:
  mhndev_systems_mysql_data:
  mhndev_systems_wp_uploads:

networks:
  mhndev_network:


services:
  ## --------------------------------------------
  ## | 1: WordPress
  ## --------------------------------------------
  mhndev_systems_wp:
    build:
      context: .
      dockerfile: docker/Dockerfile
      args:
        WP_VERSION: ${WP_VERSION}
        MYSQL_HOST: ${MYSQL_HOST}
        MYSQL_PORT: ${MYSQL_PORT}
        MYSQL_DATABASE_NAME: ${MYSQL_DATABASE_NAME}
        MYSQL_USERNAME: ${MYSQL_USERNAME}
        MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        SITE_URL: ${SITE_URL}
        DB_TABLE_PREFIX: ${DB_TABLE_PREFIX}
        ENV: ${ENV}
        UID: ${UID}
        GID: ${GID}
        SITE_TITLE: ${SITE_TITLE}
        SITE_ADMIN_USERNAME: ${SITE_ADMIN_USERNAME}
        SITE_ADMIN_PASSWORD: ${SITE_ADMIN_PASSWORD}
        SITE_ADMIN_EMAIL: ${SITE_ADMIN_EMAIL}
      network: "mhndev_network"
    ports:
      - 8191:80
    env_file:
      - .env
    volumes:
      - ./themes/dt-the7-child:/var/www/html/wp-content/themes/dt-the7-child
      - ./plugins/teamcity:/var/www/html/wp-content/plugins/teamcity
      - mhndev_systems_wp_uploads:/var/www/html/wp-content/uploads
    depends_on:
      - mhndev_systems_mysql
    networks:
      - mhndev_network

  ## --------------------------------------------
  ## | 2: Mysql
  ## --------------------------------------------
  mhndev_systems_mysql:
    image: mysql:5.7.21
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE_NAME}
      MYSQL_USER: ${MYSQL_USERNAME}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mhndev_systems_mysql_data:/var/lib/mysql
    networks:
      - mhndev_network

  ## --------------------------------------------
  ## | 3: PhpMyAdmin
  ## --------------------------------------------
  mhndev_systems_phpmyadmin:
    image: phpmyadmin/phpmyadmin:5.0.2
    depends_on:
      - mhndev_systems_mysql
    ports:
      - "7191:80"
    environment:
      PMA_HOST: mhndev_systems_mysql
    networks:
      - mhndev_network

here is my Dockerfile :

FROM php:7.4-apache

ARG WP_VERSION=5.5.1

RUN apt-get update && apt-get install -y 
    sendmail 
    libpng-dev 
    libjpeg-dev 
    libfreetype6-dev 
    netcat 
    gnupg 
    libzip-dev 
    zip 
    && docker-php-ext-configure gd --with-freetype --with-jpeg 
    && docker-php-ext-install gd pdo_mysql zip 
    && docker-php-ext-install mysqli && docker-php-ext-enable mysqli

ADD ./docker/apache.conf /etc/apache2/sites-enabled/000-default.conf

RUN 
    printf "nServerName localhost" >> /etc/apache2/apache2.conf &&
    a2enmod rewrite expires

### install wp cli
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar &&
    chmod +x wp-cli.phar &&
    mv wp-cli.phar /usr/local/bin/wp

WORKDIR /var/www/html
RUN wp core download --allow-root

### copy plugins and themes and php config files to container
COPY ["./plugins/*.zip", "/docker/plugins/"]
COPY ["./themes/*.zip", "/docker/themes/"]
COPY ./themes/dt-the7-child /var/www/html/wp-content/themes/dt-the7-child
COPY ./plugins/teamcity /var/www/html/wp-content/plugins/teamcity
COPY ./docker/php.ini /usr/local/etc/php/php.ini
COPY ./docker/wp-config.php /var/www/html/wp-config.php
COPY ["./plugins/plugins_*.txt", "/docker/plugins/"]
COPY ["./uploads/", "/docker/uploads/"]
COPY ["./docker/commands/*.sh", "/docker/bin/"]

RUN chmod a+x /docker/bin/*.sh

RUN /bin/bash -c "source /docker/bin/setup-theme-plugins.sh"

RUN chown -R www-data:www-data /var/www/html/

CMD apachectl -D FOREGROUND

and here is a bash file (setup-theme-plugins.sh), which is responsible for installing wordpress core and plugins.

#!/bin/bash

echo '-------------------whoami--------------------'
echo $(whoami)
echo '---------------------------------------------'

printf "33[0;32m > Waiting for mysql  ...x1b[0m n"
until nc -z -v -w30 "$MYSQL_HOST" "$MYSQL_PORT"
do
echo "Waiting for database connection..."
# wait for 5 seconds before check again
sleep 1
done

printf "33[0;32m >Mysql is ready ...x1b[0m n"
echo '---------------------------------------------'

printf "33[0;32m > Copy wordpress uploads if not exists (usually first time ) x1b[0m n"

FILE=/var/www/html/wp-content/uploads/2020/01/dell.jpg

if [ -f "$FILE" ]; then
echo "$FILE exists, so no need to copy uploads"
else
echo "$FILE does not exist, copying ..."
cp -r /docker/uploads/* /var/www/html/wp-content/uploads
fi
echo '---------------------------------------------'


sed -i s/__DB_NAME__/"${MYSQL_DATABASE_NAME}"/g /var/www/html/wp-config.php
sed -i s/__DB_USER__/"${MYSQL_USERNAME}"/g /var/www/html/wp-config.php
sed -i s/__DB_PASSWORD__/"${MYSQL_PASSWORD}"/g /var/www/html/wp-config.php
sed -i s/__DB_HOST__/"${MYSQL_HOST}"/g /var/www/html/wp-config.php
sed -i s/__SITE_URL__/"${SITE_URL}"/g /var/www/html/wp-config.php


if [[ -n "${DB_TABLE_PREFIX}" ]]; then
sed -i s/__DB_TABLE_PREFIX__/"${DB_TABLE_PREFIX}"/g /var/www/html/wp-config.php
else
sed -i s/__DB_TABLE_PREFIX__/"${DB_TABLE_PREFIX}"/g /var/www/html/wp-config.php
fi

### set WP_DEBUG, SCRIPT_DEBUG based on DEV environment variable
if [ "${ENV}" = "dev" ]; then
sed -i s/__WP_DEBUG__/true/g /var/www/html/wp-config.php
sed -i s/__SCRIPT_DEBUG__/true/g /var/www/html/wp-config.php
else
sed -i s/__WP_DEBUG__/false/g /var/www/html/wp-config.php
sed -i s/__SCRIPT_DEBUG__/false/g /var/www/html/wp-config.php
fi



wp option update home "${SITE_URL}" --allow-root
wp option update siteurl "${SITE_URL}" --allow-root

### set WP_DEBUG_LOG to php://stdout to always output logs to stdout so be available for docker logs
old_string='__WP_DEBUG_LOG__'
new_string='php://stdout'
sed -i "s%$old_string%$new_string%g" /var/www/html/wp-config.php


if [[ -n "${SITE_ADMIN_USERNAME}" ]]; then
DASHBOARD_USER_NAME="${SITE_ADMIN_USERNAME}"
else
DASHBOARD_USER_NAME="admin"
fi

if [[ -n "${UID}" ]]; then
usermod -u "${UID}" www-data
groupmod -g "${GID}" www-data
fi

chown -R www-data:www-data /var/www/html/

### install wordpress
printf "33[0;32m > Checking if wordpress core installed, if not Installing it  ...x1b[0m n"
wp core is-installed --allow-root
retVal=$?
if [ "$retVal" == "1" ];then
printf "33[0;32m > Trying to Install wordpress ...x1b[0m n"
printf "33[0;32m > Command to execute is : wp core install --url="${SITE_URL}" --title="${SITE_TITLE}" --admin_user="${DASHBOARD_USER_NAME}" --admin_password="${SITE_ADMIN_PASSWORD}" --admin_email="${SITE_ADMIN_EMAIL}" --allow-root ...x1b[0m n"
wp core install --url="${SITE_URL}" --title="${SITE_TITLE}" --admin_user="${DASHBOARD_USER_NAME}" --admin_password="${SITE_ADMIN_PASSWORD}" --admin_email="${SITE_ADMIN_EMAIL}" --allow-root
fi
echo '---------------------------------------------'

### install The7 theme from zip file
# shellcheck disable=SC2059
printf "33[0;32m > Checking if theme: $FILE installed, if not Installing it  ...x1b[0m n"

wp theme is-installed The7 --allow-root
is_theme_installed=$?
if [[ is_theme_installed -eq 1 || ! -d /var/www/html/wp-content/themes/dt-the7 ]]; then
rm -rf /var/www/html/wp-content/themes/dt-the7
wp theme install /docker/themes/dt-the7.zip --force --allow-root;
fi
echo '---------------------------------------------'

### install plugins from plugins_dev.txt or plugins_prod.txt based on environment
# shellcheck disable=SC2162
while read line; do
IFS='=' read -r -a array <<< "$line"
printf "33[0;32m > Checking if plugin:%s  is installed else Installing %s:%s ...x1b[0m n" "${array[0]}" "${array[0]}" "${array[1]}"

#  if wp plugin is-installed "${array[0]}" --allow-root; then
wp plugin install "${array[0]}" --version="${array[1]}" --activate --force --allow-root
#  fi
echo '---------------------------------------------'
done < /docker/plugins/plugins_"${ENV}".txt


### install plugins from zip file
for FILE in /docker/plugins/*.zip;
do
# shellcheck disable=SC2059
printf "33[0;32m > Installing plugin $FILE ...x1b[0m n"
wp plugin install "$FILE" --force --allow-root;
echo '---------------------------------------------'
done

printf "33[0;32m > Checking if hello plugin exist and if so uninstall it ...x1b[0m n"
#if ! wp plugin is-installed hello --allow-root; then
wp plugin uninstall hello  --allow-root
#fi

echo '---------------------------------------------'

printf "33[0;32m > Checking if akismet plugin exist and if so uninstall it ...x1b[0m n"
#if ! wp plugin is-installed akismet --allow-root; then
wp plugin uninstall akismet --allow-root
#fi
echo '---------------------------------------------'

printf "33[0;32m > activating the7 child theme  ...x1b[0m n"
wp theme activate dt-the7-child --allow-root
echo '---------------------------------------------'

printf "33[0;32m > Uninstalling initial themes  ...x1b[0m n"
#if ! wp theme is-installed twentynineteen --allow-root; then
wp theme delete twentynineteen --allow-root
#fi
echo '---------------------------------------------'

#if ! wp theme is-installed twentyseventeen --allow-root; then
wp theme delete twentyseventeen --allow-root
#fi
echo '---------------------------------------------'

#if ! wp theme is-installed twentytwenty --allow-root; then
wp theme delete twentytwenty --allow-root
#fi
echo '---------------------------------------------'

As you can see in my bash file I’m connecting to mysql container.
How can I achieve this ?

3

Answers


  1. My guess is that you are unable to connect because the database service started but is not ready. In the docker documentation on depends_on it states this (and I too have had this problem):

    depends_on does not wait for db and redis to be “ready” before starting web – only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.

    (emphasis mine)

    In my case I solved it in a very ugly way (have a sleep() for 10 seconds in my python script), but if this is no solution for you, maybe the official strategy documentation found here might help.

    [edit]
    What do you use as the host variable name? When using a network in docker compose, machines should be able to communicate to each other using their container names (i.e. mhndev_systems_mysql in your case). Can you try that?

    Login or Signup to reply.
  2. You cannot connect to the database from the Dockerfile at all.

    Part of this is the basic Docker model of how images work. A Docker image contains only a filesystem and some metadata describing how to start a container from it; it is something you could copy to a different system and run there. If you built an image and tried to update a database as part of it, and then ran the same image on a different system, it wouldn’t have the database setup; similarly, you can delete and recreate the local database without rebuilding the image, and you won’t have any database content.

    Mechanically, the docker build step (or its Compose equivalent) runs in a restricted environment. Most notably here, it is not attached to any Compose network, so there’s no network setup for it to resolve hostnames like mhndev_systems_mysql. (Technically it is on the default bridge network, as distinct from the Compose default network or any networks: you specify for the built container.)

    In a typical application you’d want to separate "the application code" from "the database setup". You have to run the database-setup part (often, "migrations") when the application starts up, or separately from starting the application; but you can’t do it at build time.

    Login or Signup to reply.
  3. There is a simple misunderstanding between build time and runtime; all the containers will be available in runtime, not build time. So there is no way to access your MySQL container, in build time.
    My suggestion is that to remove all the steps which needs MySQL from your Dockerfile and move them to your entrypoint, then set a boolean ENV in your Dockerfile and check that value at the beginning of your entrypoint which will run your commands, if you set that ENV to true; now if you need to run your entrypoint (aka setting up your WP & MySQL), simply pass that ENV in build time.

    docker build --build-arg var_name=${VARIABLE_NAME}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search