简体   繁体   中英

docker compose - how to wait for a file to appear or a folder to appear before another service starts to build?

Background Information

I am trying to dockerize a wordpress development environment. All the containers work except the wp-cli. When I docker compose up -d --build command, the wp-cli container attempts to start but then exits with this error message:

Error: This does not seem to be a WordPress installation.

Pass --path= path/to/wordpress or run wp core download .

I'm not a wordpress developer so I've been poking around to see how to fix this. But it seems to be related to a timing issue. the wordpress cli server is checking a shared volume called wordpress:/var/www/html and when it doesn't find the files it needs, it dies.

Relevant section in docker-compose.yml

version: '3.6'
services:
 #Set Debian GNU/Linux 11 (bullseye)
  wordpress:
    container_name: ${WORDPRESS_CONTAINER_NAME}
    build: ./wpserver/
    volumes:
      - ./config/php.conf.ini:/usr/local/etc/php/conf.d/conf.ini
      - ./wordpress:/var/www/html
    environment:
      - WORDPRESS_DB_NAME=${WORDPRESS_DB_NAME}
      - WORDPRESS_TABLE_PREFIX=${WORDPRESS_TABLE_PREFIX}
      - WORDPRESS_DB_HOST=${WORDPRESS_DB_HOST}
      - WORDPRESS_DB_USER=${WORDPRESS_DB_USER}
      - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
    depends_on:
      - mysql
    restart: always

  wpcli:
    container_name: ${WPCLI_CONTAINER_NAME}
    build: 
      context: ./
      dockerfile: Dockerfile-wpcli
    volumes:
      - ${WORDPRESS_DATA_DIR:-./wordpress}:/var/www/html
    working_dir: /var/www/html
    environment:
      - WORDPRESS_DB_NAME=${WORDPRESS_DB_NAME}
      - WORDPRESS_TABLE_PREFIX=${WORDPRESS_TABLE_PREFIX}
      - WORDPRESS_DB_HOST=${WORDPRESS_DB_HOST}
      - WORDPRESS_DB_USER=${WORDPRESS_DB_USER}
      - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
    depends_on:
      - wordpress


    user: "33"

Dockerfile-wpcli

FROM wordpress:cli

# Install make tool
USER root
RUN apk add --no-cache make

# Make docker-compose wait for container dependencies be ready
# Add the wait script to the image
ENV WAIT_VERSION 2.7.2
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/$WAIT_VERSION/wait /wait
RUN chmod +x /wait

# Add Makefile to scripts dir
ADD Makefile entrypoint.sh /scripts/
ADD entrypoint.sh /scripts/
RUN ls -lah /scripts
RUN chmod +x /scripts/entrypoint.sh

ENTRYPOINT [ "/scripts/entrypoint.sh" ]
USER 33:33
CMD ["wp", "shell"]

entrypoint.sh

#!/bin/sh
set -euo pipefail
# Based on wordpress:cli entrypoint
# https://github.com/docker-library/wordpress/blob/master/php7.2/cli/docker-entrypoint.sh

# If the first arg is `--some-option` then execute wp-cli
if [ "${1#-}" != "$1" ]; then
    set -- wp "$@"
fi

# if our command is a valid wp-cli subcommand (say plugin), let's invoke it through wp-cli instead
# (this allows for "docker run wordpress:cli help", etc)
# documenation of the subcommand is shown
if wp --path=/dev/null help "$1" > /dev/null 2>&1; then
    set -- wp "$@"
fi

# Execute aliases in the make file or directly the provided command
if [ "$1" == "install" ] || [ "$1" == "configure" ]; then
  make -f /scripts/Makefile $1
else
  exec "$@"
fi

Makefile

install: configure

configure:

    @echo "Configuring Wordpress parameters..."
    wp core install \
        --path=${WORDPRESS_WEBSITE_URL_WITHOUT_HTTP} \
        --title=$(WORDPRESS_WEBSITE_TITLE) \
        --admin_user=${WORDPRESS_ADMIN_USER} \
        --admin_password=${WORDPRESS_ADMIN_PASSWORD} \
        --admin_email=${WORDPRESS_ADMIN_EMAIL}

    wp option update siteurl ${WORDPRESS_WEBSITE_URL}

What I've tried So Far

  1. As noted earlier I tried to using the -f and config options to see what variables are being substituted in from the.env file and everything looks ok.

  2. I've logged into a container that does build / run properly and tried to ping the WORDPRESS_DB_HOST ( which is widgets_mysql ) to prove that I don't have a finger fumble.

    docker exec -it -u 0 widgets_wordpress /bin/bash

     root@ef8daaed9a25:/var/www/html# ping widgets_mysql PING widgets_mysql (172.27.0.2) 56(84) bytes of data. 64 bytes from widgets_mysql.wp-docker-local_default (172.27.0.2): icmp_seq=1 ttl=64 time=0.130 ms 64 bytes from widgets_mysql.wp-docker-local_default (172.27.0.2): icmp_seq=2 ttl=64 time=0.047 ms 64 bytes from widgets_mysql.wp-docker-local_default (172.27.0.2): icmp_seq=3 ttl=64 time=0.047 ms 64 bytes from widgets_mysql.wp-docker-local_default (172.27.0.2): icmp_seq=4 ttl=64 time=0.046 ms ^C --- widgets_mysql ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3053ms rtt min/avg/max/mdev = 0.046/0.067/0.130/0.036 ms root@ef8daaed9a25:/var/www/html#

Questions

  1. What command can i use to see the environment variable values that will be used by the Makefile?
  2. Although the name of the wordpress container is is widgets_wordpress, the nginx configuration is set up such that I can browse to https://localhost on my host machine and launch the wordpress site. It's not clear to me what value I should plug in for the WORDPRESS_WEBSITE_URL_WITHOUT_HTTP or the WORDPRESS_WEBSITE_URL variables in the Makefile. From the hosts perspective the web address is https://localhost. But from other containers on the same docker network what should I use? I am currently going to see how to always assign the same IP address to the wordpress container and then see if I can plug that value into my nginx configuration. But any tips would be appreciated.

Here's the list of containers that I have running:

   CONTAINER ID   IMAGE                   COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
    02097ccd3a8b   wp-docker-local_nginx   "/docker-entrypoint.…"   30 minutes ago   Up 30 minutes   0.0.0.0:443->443/tcp, 80/tcp, 0.0.0.0:8085->8085/tcp   widgets_nginx
    d1d683822612   adminer                 "entrypoint.sh docke…"   30 minutes ago   Up 30 minutes   0.0.0.0:8080->8080/tcp                                 widgets_adminer
    ef8daaed9a25   wordpress:php7.3-fpm    "docker-entrypoint.s…"   30 minutes ago   Up 30 minutes   9000/tcp                                               widgets_wordpress
    a8a4e4ecbe27   mariadb:10.6.4-focal    "docker-entrypoint.s…"   30 minutes ago   Up 30 minutes   3306/tcp                                               widgets_mysql

And in case it helps, here's the first few lines from default.conf on my nginx server that serves up the PHP files from the wordpress container:

server {
    listen      8085;
    listen [::]:8085;
    server_name FQDN_OR_IP;

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }

    location ^~ /.well-known {
        allow all;
        root  /data/letsencrypt/;
    }
}

server {
    listen      443           ssl http2;
    listen [::]:443           ssl http2;
    include /etc/nginx/conf.d/self-signed.conf;

    server_name               FQDN_OR_IP www.FQDN_OR_IP;

    add_header                Strict-Transport-Security "max-age=31536000" always;

I'm currently in the process of adding all the relevant variables defined in the.env file in the "environment" section of the wpcli service in docker compose to see if that helps.

EDIT 1

I just tried to change the value of the variable in.env to look like this:

 WORDPRESS_WEBSITE_URL_WITHOUT_HTTP=widgets_wordpress:/var/www/html

cuz maybe I'm supposed to give it location of the installation of wordpress. But i'm still seeing the same error message in the container logs.

EDIT 2

I think I figured out the problem. There seems to be a timing issue. The wordpress cli server / container needs the wordpress container to be up and running in order to connect to it.
Although I have a "depends_on" clause, what's NOT happening in a timely manner is that the "/var/www/html" folder on the wordpress server isn't being populated in a timely manner. So by the time the set up on the wordpress cli starts, it checks the /var/www/html folders for the files it needs and then when it doesn't find them, it dies.

To test this theory - I build everything in my docker compose... and then when I know the wordpress /var/www/html is finally created, I manually run all the same commands to set up wordpress cli and it just works. Another symptom I'm seeing that seems to support the theory that I have a timing issue is that in my Dockerfile that set ups the wordpress server, I have a copy commands. All the copy commands that try to copy files into the /var/www/html fail. But the other ones work

So in the code below, the first two COPY commands are ok. But the last 2 never work.

COPY msmtprc /etc/msmtprc
COPY php.ini /usr/local/etc/php/php.ini
COPY phpinfo.php /var/www/html/phpinfo.php
COPY install-wp-cli.sh /var/www/html/install-wp-cli.sh

So really, what this boils down to is that I need somehow to bake in a wait that will wait until a specific folder or a file is present before I consider the wordpress service set up to be complete. I'm going to rename the question so it more accurately reflects this finding.

I just read about healthchecks in docker.. so i'm going to read up on that. I found an example:

healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:15672"]
    interval: 30s
    timeout: 10s
    retries: 5

Thanks for reading.

The fundamental problem is that I have a timing issue. The wordpress server isn't ready / done setting up by the time the wp-cli server tries to connect. And although I have a depends_on clause that's not enough. I need to add a healthcheck clause in the wordpress service definition to check for the specific files that wp-cli looks for.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM