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 runwp 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
-
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.
-
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
- What command can i use to see the environment variable values that will be used by the Makefile?
- 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.
2
Answers
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.
If anyone else is struggling with a similar issue, Docker compose now allows you to add a condition to
depends on
:https://docs.docker.com/compose/compose-file/#depends_on
This allows you to tell Docker to wait for a specific condition to be met before the container is started.
I have used this in my
Docker-compose.yml
file to make sure the WordPress Database is up and running before I initialize the wp-cli container. I did this by adding a health check on my database (I use mariadb – it may be a bit different with other images):