drupal icon indicating copy to clipboard operation
drupal copied to clipboard

Is a Volume Needed?

Open jeden25 opened this issue 9 years ago • 74 comments

Drupal would require some local storage for images and the like, right? So in order for the container to be persistent wouldn't I need to include a volume as well as the database?

If it is needed, I'm confused as to why the official Wordpress Dockerfile specifies a volume while the official Drupal Dockerfile does not?

jeden25 avatar May 27 '15 14:05 jeden25

Yes, this is the main problem with this image. There should be a volume for the source code files as well so we can add our own Drupal codebase.

Drupal core by itself isn't going to cut it for most people.

jonpugh avatar Jul 08 '15 16:07 jonpugh

A VOLUME line is not necessary in the Dockerfile for --volumes-from or -v to work (yes, you would need a -v on the first container for --volumes-from to work to a second container), so docker run -v /local/images/path/:/drupal/path/to/images/ drupal will work fine But if you have a place that you think a VOLUME should be defined, a PR is welcome.

yosifkit avatar Jul 08 '15 17:07 yosifkit

Yeah, this one was a hard one for me since from what I understand, the "sites" directory is probably the best place for the volume to be, but it must be pre-seeded with the initial content or Drupal won't start up. I'd love to see this fixed somehow.

tianon avatar Jul 08 '15 17:07 tianon

D8 uses a different structure now. For example, contributed modules are downloaded at /modules/, unlike D7, contributed modules are located in /sites/*/modules/

I was thinking the same question. But, there are different ways people would use this image. For example, I can potentially use a docker d8 image for

  1. spin up sandboxes for testing. Then, I don't need Volume.
  2. start a new project. Then, I want the whole Drupal directory to be managed by Git (except user files). It doesn't matter D7 or D8, it's best practise to put the whole Drupal directory under Git. If we put the while Drupal directory in a Volume, then we don't we just use PHP container and a Data container to start with?

skyred avatar Aug 05 '15 14:08 skyred

In my opinion we do need volumes, so that this image is actually usable. We should define mount points for the following directories (in D8):

  • /var/www/html/modules
  • /var/www/html/profiles
  • /var/www/html/themes

These three are no-brainers, they are empty by default (besides a README.txt) and will ensure that the container can be upgraded by just bumping the image version.

We should also include /var/www/html/sites/default/files, which will make sure user content survives.

Much more difficult is the question on how to deal with settings.php and default.settings.php. From what I understand we can not just define volumes on these files, as docker would just overwrite them with directories and the drupal install expects them to be files in a certain state with a certain content.

I'd be interested in any ideas. If we just mount /var/www/html/sites/ or a subdirectory we also have the problem that the structure is lost and drupal will either not install at all or refuse installation.

alexanderjulo avatar Nov 04 '15 15:11 alexanderjulo

Actually, scratch that, you don't need it. You can run this fine without any volumes, by using a drupal:8 as the image for the storage, too. See the following docker-compose.yml for an example. This also fixes issues with settings.php and so on. We can bump the image for drupal without bumping storage-drupal:

drupal:
    image: drupal:8
    volumes_from:
        - storage-drupal
    links:
        - "db:mysql"
    ports:
        - "80:80"
db:
    image: mysql
    volumes_from:
        - storage-mysql
    environment:
        - MYSQL_USER=someuser
        - MYSQL_PASSWORD=thispasswordsucks
        - MYSQL_DATABASE=somedb
        - MYSQL_ROOT_PASSWORD=thispasswordsuckstoo
storage-drupal:
    image: drupal:8
    volumes:
        - /var/www/html/modules
        - /var/www/html/profiles
        - /var/www/html/themes
        - /var/www/html/sites
storage-mysql:
    image: mysql
    volumes:
        - /var/lib/mysql

alexanderjulo avatar Nov 04 '15 16:11 alexanderjulo

Volume for Drupal's root folder would be great!

eduarddotgg avatar Nov 14 '15 20:11 eduarddotgg

Then you could not upgrade anymore by upgrading the container, because the drupal core folder would be in the volume.

On 14 Nov 2015 21:46 +0100, [email protected], wrote:

Volume for Drupal's root folder would be great!

— Reply to this email directly orview it on GitHub(https://github.com/docker-library/drupal/issues/3#issuecomment-156745063).

alexanderjulo avatar Nov 15 '15 09:11 alexanderjulo

oh, i see. than this folders would be great: /var/www/html/modules /var/www/html/profiles /var/www/html/themes /var/www/html/sites/default/files that @alexex mentioned before

eduarddotgg avatar Nov 15 '15 09:11 eduarddotgg

Can't use this image with kubernetes, because after every restart, installation process start again.

aborilov avatar Nov 27 '15 16:11 aborilov

Interesting issue&thread! As a newcomer to Docker, I've been struggling to find definitive answers on data/volumes/volume containers management for drupal, let alone some kind of benchmark of the different options, so it's quite difficult to determine which one would apply better to my usecase... If there's some consensus, adding some pointers on the description page would be great!

juliencarnot avatar Dec 14 '15 20:12 juliencarnot

The problem is that there are no docker-entrypoint.sh, which have to copy /var/www/html to volume, if it is empty, like it does in WordPress Dockerfile.

aborilov avatar Dec 15 '15 08:12 aborilov

@alexex Your solution does fix the issue of upgrading to a new version. However what it does not fix, is the ability to sync your data with the host. "/var/www/html/sites" Can't still be mounted from host as they contain default settings that drupal wants.

So you are still prone to loose your data by removing the data container, or in the case of k8s users like in the previous comments loose your pod and by so loose your data.

Something still needs to be done here, so that drupal does become a real containerized application that can survive: stop & destroy

Update: Just noticed that on your example your are using for your storage ambassador container mariadb and drupal images and you are not passing a command to execute. This would have for effect to keep these containers up. It is a good idea to use the same images though, as those are already pulled and would not need extra space. You can change this by adding -> command: bash or using another image (busybox for example)

YvanDaSilva avatar Feb 18 '16 15:02 YvanDaSilva

I'd move the drupal core download and extract stuff into an entrypoint.sh (instead of the dockerfile,) with a VOLUME at /var/www/html, as part of entrypoint check to see if the core exists, and if not pull down the core and extract into place.

ahuffman avatar Feb 22 '16 20:02 ahuffman

You could also use Environment variables to pull in all the config stuff that might get lost on restarting a container. Check out the Wordpress or Joomla containers. There should be something like a DRUPAL_DB_HOST, DRUPAL_DB_PASSWORD, DRUPAL_DATABASE at minimum.

ahuffman avatar Feb 22 '16 20:02 ahuffman

@aborilov The copy doesn't have to be in entrypoint.sh. They need a VOLUME or multiple VOLUME entries in the Dockerfile. A VOLUME entry flushes the data to a bind mounted volume at runtime. I think this would solve image change concerns as well. Please see the reference here, as it explains perfectly: https://docs.docker.com/engine/reference/builder/#volume

ahuffman avatar Feb 24 '16 16:02 ahuffman

@ahuffman As you said here https://github.com/docker-library/drupal/issues/3#issuecomment-187377509, there must be VOLUME and extract(or copy) in entrypoint.sh. Usually, you can download and extract in dockerfile, but extract in some src dir, and copy to /var/www/html only if it empty. There is nothing new here, just see how it work in wordpress docker-entrypoint.sh

if ! [ -e index.php -a -e wp-includes/version.php ]; then
        echo >&2 "WordPress not found in $(pwd) - copying now..."
        if [ "$(ls -A)" ]; then
            echo >&2 "WARNING: $(pwd) is not empty - press Ctrl+C now if this is an error!"
            ( set -x; ls -A; sleep 10 )
        fi
        tar cf - --one-file-system -C /usr/src/wordpress . | tar xf -
        echo >&2 "Complete! WordPress has been successfully copied to $(pwd)"

This is it, and will work everywhere, with any storages.

aborilov avatar Feb 24 '16 19:02 aborilov

I've taken a crack at fixing this in my fork. I've almost got it, but could use some assistance troubleshooting, as I'm not too familiar with how the php-fpm image works/serves.

You can check out my fork here: https://github.com/ahuffman/drupal/tree/master/8/fpm

Made some changes to the Dockerfile build and created a 1/3 complete drupal_entrypoint.sh (seems to build out the settings.php properly from provided environment variables.)

I've only created one VOLUME at /var/www/html for now during testing.

Environment Variables to provide for MySQL: MYSQL_DB_PASS MYSQL_DB_HOST MYSQL_DB_USER (falls back to root if not provided) MYSQL_DB_PORT (falls back to 3306 if not provided) MYSQL_DB_NAME (falls back to drupal if not provided) DRUPAL_TBL_PREFIX (falls back to blank if not provided) DRUPAL_DB_TYPE (falls back to 'mysql' if not provided, choices are mysql, postgres, and sqlite ***I've only written MySQL so far)

ahuffman avatar Feb 25 '16 16:02 ahuffman

The docker run command initializes the newly created volume with any data that exists at the specified location within the base image. https://docs.docker.com/engine/reference/builder/#volume (emphasis added)

Just to ensure that it is understood, docker only copies files within a container's directory to new volumes created at docker run and this never happens on a bind mount.

  • -v /container/dir/ or VOLUME /container/dir/ will copy
  • -v /my/local/dir/:/container/dir/ will only contain what was in /my/local/dir/

It does seem like we need to define a VOLUME; but you should be able to get around it by defining them when it is run (using the folders suggested previously):

$ docker run -d -v /var/www/html/modules  -v /var/www/html/profiles -v /var/www/html/themes -v /var/www/html/sites/default/files drupal

yosifkit avatar Mar 01 '16 22:03 yosifkit

https://github.com/ahuffman/drupal/tree/master/8/apache

Check my fork there. I now have a working apache and MySQL setup with an entrypoint.sh and VOLUME at /var/www/html.

It can also do auto upgrades if the container drupal source changes.

For kubernetes support we need to add some code into my entrypoint script to check the DB for tables and if not there kick off the schema install. I need help on that piece, because I'm not a PHP guy so I don't really know what that would look like.

The entrypoint.sh builds the settings.php off of the provided environment variables. This seems to be working so far for MySQL, as I haven't written the postgres stuff yet.

Let me know what you think.

ahuffman avatar Mar 02 '16 17:03 ahuffman

@alexex How do you solve the permission issue with running 2 mysql containers that use the same database files? When I start my compose I get this:

[ERROR] InnoDB: Unable to lock ./ibdata1 error: 11
[Note] InnoDB: Check that you do not already have another mysqld process using the same InnoDB data or log files.

karelbemelmans avatar Mar 06 '16 19:03 karelbemelmans

@ahuffman Nice work there! Make a pull request on the main repo to get this into the hub image.

karelbemelmans avatar Mar 06 '16 19:03 karelbemelmans

@kbemelmans that's not a permissions issue, that would be two mysql server trying to store their databases in the same folder which will definitely lead to conflicts and not work. What are you trying to achieve?

alexanderjulo avatar Mar 07 '16 07:03 alexanderjulo

@alexex I literally copy/pasted your docker-compose.yml from this thread, where you use the mysql image for both the db and the storage-mysql container.

I've been reading up on it yesterday, and what you need is some kind of "do not actually start this container, just use it for data" option. But I wonder if that file actually worked for you like this?

karelbemelmans avatar Mar 07 '16 07:03 karelbemelmans

@kbemelmans ah, now I can see what you mean, just set /bin/true as command for the storage container. Also read up on the docker volume command and docker-compose v2 files, this is probably not the preferred method of storing data anymore. :-)

alexanderjulo avatar Mar 07 '16 08:03 alexanderjulo

@kbemelmans there's still a little bit of work that needs to be done here, which I need help on.

First, we need some php code written to be able to check the postgres/mysql db connections to see if the tables exist, and if not run through the table install procedure (similar to what the wordpress entrypoint does.)

The second piece is that we need to be able to see if there's a better (more drupal native way) to check on the drupal version, and if an upgrade is being performed automatically run the php code to upgrade the table schemas. I'm not familiar enough with the drupal code to know the answers to these questions. Other than that, my entrypoint script takes care of building the settings.php pretty well, and the drupal container can be scaled on a kubernetes environment.

I'm able to kill the running drupal containers (or their settings.php) and they return to normal after restarting.

ahuffman avatar Mar 07 '16 15:03 ahuffman

@ahuffman if you haven't explored drush that would be a good place to start. https://github.com/drush-ops/drush

Assuming you package drush with your Drupal container, it can already check the database health, check the Drupal version, or even perform full upgrades of core or packages.

'drush core-status' will dump you a response that looks like this:

Drupal version : 7.43 Site URI : http://default Database driver : mysql Database username : dbusername Database name : dbname Database : Connected Drupal bootstrap : Successful Drupal user : Anonymous Default theme : themename Administration theme : seven PHP executable : /usr/bin/php PHP configuration : /etc/php.ini PHP OS : Linux Drush version : 6.2.0 Drush configuration : Drush alias files : Drupal root : /path/to/drupal/root Site path : sites/default File directory path : sites/default/files Temporary file directory path : sites/default/tmp

Newer versions of drush support a '--format json' or '--format yaml' option to dump the above results in a format that is friendlier for parsing by other scripts or tools.

In nearly all cases you will want to package drush with drupal anyway, so this might kill a few birds with one stone. For example, drush can also be used to kick off the Drupal cron jobs that need to run periodically.

rjbrown99 avatar Mar 15 '16 16:03 rjbrown99

@rjbrown99 thanks, that looks like the best way to get this done. I'll start digging into it when I have more free time. If anyone else has some experience with drush and wants to add to the fork I have, please do. I have the script working up to recreating a missing settings.php off of environment variables. The next step is to check the db and if not there initialize it off of the env variables provided/settings.php.

ahuffman avatar Mar 17 '16 21:03 ahuffman

@ahuffman I'll look into it, but likely for Drupal 7 as opposed to 8 just based on my own current needs.

Ultimately, even if settings.php is auto-populated, in a large number of use cases there will be a need to otherwise modify that file beyond database settings. Not sure yet how to approach that, possibly through another set of environment variables.

One thing that the folks at Pantheon also did that I really like is to enable the setting of variables to show whether you are in a dev/test/prod environment. This link has details: https://pantheon.io/docs/settings-php. It's super useful as you can then configure if statements in the settings.php to, for example, enable/disable memcache or redis depending on which environment you are running the app.

Perhaps @davidstrauss would care to chime in with input as well as most of Pantheon is built on top of Docker if I'm not mistaken.

rjbrown99 avatar Mar 17 '16 23:03 rjbrown99

AFAIK pantheon uses LXC containers directly.

Re: volumes, i think this really should be up to the user. Using a compose file to also add a DB and relevant data containers is ideal (and easy). This is adapted from the stock drupal7 kalabox app so its built primarily for a local dev use case. You will obviously want to have better sql passwords.

data:
  image: busybox
  volumes:
    - /var/lib/mysql
    - /var/www/html

appserver:
  image: drupal:7
  volumes_from:
    - data
  links:
    - db:database
    - db:mysql
  ports:
    - "80"

db:
  image: mysql
  volumes_from:
    - data
  ports:
    - "3306"
  environment:
    MYSQL_USER: drupal
    MYSQL_PASSWORD: drupal
    MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    MYSQL_DATABASE: drupal

re: settings it would be a worthwhile effort to try and get drupal core to actually use ENV based db config a la pressflow (which is what pantheon uses). This is a fairly common model that is also used in wordpress.

pirog avatar Mar 20 '16 18:03 pirog