I am currently attempting to promote my image including custom theme to Production using a custom Dockerfile, like so:
FROM wordpress:latest
COPY wp-content/ /usr/src/wordpress/wp-content
The resulting image will have the wp-content directory in the "distribution" directory, which is copied to /var/www/html on initialisation when the right conditions are met.
The right conditions being that the following files do not exist in /var/www/html:
The first time, this works as expected as the target volume mounted on /var/www/html will be empty still. However, any subsequent updates will detect that /var/www/html has content in it and therefore initialisation will be skipped. With it, any changes made to my custom theme are not applied.
The simplest solution would be to not map a volume on /var/www/html, so that initialisation takes place every time - as each startup would effectively end up with an empty directory. However, the downside of this is that I end up with tons of dangling volumes, as the provided Wordpress image has a VOLUME directive set for this directory, which results in Docker creating an unnamed Volume to map on the directory. This is the approach I'm currently taking, together with a cleanup script running on the hosts to remove the volumes.
This is obviously less than ideal. Why is /var/www/html a Volume in the first place? Considering that in a local development environment the necessary content is bind mounted and in a production image the data is copied to /usr/src/wordpress.
What about bind-mounting the /var/www/html/wp-content/themes/ folder?
https://github.com/docker-library/docs/tree/master/wordpress#include-pre-installed-themes--plugins
An approach to using a directory that's not a VOLUME: https://github.com/docker-library/wordpress/issues/232#issuecomment-420767663
Other discussions on removing inherent volumes in images https://github.com/docker-library/mongo/issues/306, https://github.com/docker-library/redis/issues/140, https://github.com/docker-library/postgres/issues/404
Specifically the discussion over in https://github.com/docker-library/mysql/issues/255: "Why is there volume for data in the first place?"
With https://github.com/docker-library/wordpress/pull/557, you can theoretically run completely stateless as long as you've got the appropriate environment variables and don't try to add anything that goes into wp-content like image uploads -- that should even allow running with --read-only (assuming you point the webserver at /usr/src/wordpress instead of /var/www/html), although I admit I haven't tested that use case.
Thanks for all the feedback and suggestions, however the question as to why this 'VOLUME' directive is there in the first place is still unclear to me?
Running with a bind mounted directory, you don't use the volume. Running a production image, you have the data copied in /usr/src/wordpress, which is copied to /var/www/html on init - to me it seems, at this point the VOLUME is just in the way. If someone still wants to mount something on /var/www/html, they can do it; you don't need to VOLUME directive for that.
The only thing the VOLUME directive does is:
a) make it clear this is where application data is stored.
b) explicitly decouple the state of the specified directory.
In case of b, if you want to persist, you can mount a volume regardless. If you don't mount a volume, you'll end up with an unnamed volume (exactly my problem), for which I can not come up with a use case.
The volume is the only reliable way to let users know where the mutable state is stored.
WordPress was not designed for containers and, as such, considers all of its installation mutable state (and applies security updates automatically). So we designed the WordPress image to reflect that; the initial start will fill the volume (whether a bind-mount or named/unnamed docker volume) with the install and WordPress would then take care of updates. You can even update the container around WordPress to get newer PHP without it effecting the WordPress install.
In the early days of docker, volumes did not exist without a contianer and so tools like fig/docker-compose used tricks to keep volumes for new containers and still does so for named or unnamed volumes.
I understand, however if the only reason is to point out where the "mutable state" is, is it worth the problems it introduces? As I described in my (which I think are the common use-cases) use-cases:
If you do not mount a volume on /var/www/html, an unnamed volume will be mounted on it by Docker - which results in pollution.
In case of a named volume, the volume is useless - since when you add the data to /usr/src/wordpress, it's copied to /var/www/html (your volume), meaning any new versions of your extended image (changes to themes etc.) are not copied to /var/www/html anymore.
So, what's a real use-case for wanting to persist /var/www/html, considering that it will be populated by the content of /usr/src/wordpress when it's empty?
Can we add a separate folder, let's say /usr/src/wordpress/themes or /themes (and plugins) that is always copied to /var/www/html upon startup to the default image? I can easily add this in my image, but I think this might benefit others as well.
Most helpful comment
I understand, however if the only reason is to point out where the "mutable state" is, is it worth the problems it introduces? As I described in my (which I think are the common use-cases) use-cases:
If you do not mount a volume on /var/www/html, an unnamed volume will be mounted on it by Docker - which results in pollution.
In case of a named volume, the volume is useless - since when you add the data to /usr/src/wordpress, it's copied to /var/www/html (your volume), meaning any new versions of your extended image (changes to themes etc.) are not copied to /var/www/html anymore.
So, what's a real use-case for wanting to persist /var/www/html, considering that it will be populated by the content of /usr/src/wordpress when it's empty?
Can we add a separate folder, let's say /usr/src/wordpress/themes or /themes (and plugins) that is always copied to /var/www/html upon startup to the default image? I can easily add this in my image, but I think this might benefit others as well.