docker-compose mounted volume is empty, but other volumes created during Docker image build are populated

2.9k views Asked by At

Starting with an empty directory, I created this docker-compose.yml:

version: '3.9'
services:
  neo4j:
    image: neo4j:3.2
    restart: unless-stopped
    ports:
      - 7474:7474
      - 7687:7687
    volumes:
      - ./conf:/conf
      - ./data:/data
      - ./import:/import
      - ./logs:/logs
      - ./plugins:/plugins
    environment:
      # Raise memory limits
      - NEO4J_dbms_memory_pagecache_size=1G
      - NEO4J_dbms.memory.heap.initial_size=1G
      - NEO4J_dbms_memory_heap_max__size=1G

Then I add the import directory, which contains data files I intend to work with in the container.

At this point, my directory looks like this:

0 drwxr-xr-x   9 cc  staff  288 Dec 11 18:57 .
0 drwxr-xr-x   5 cc  staff  160 Dec 11 18:15 ..
8 -rw-r--r--   1 cc  staff  458 Dec 11 18:45 docker-compose.yml
0 drwxr-xr-x  20 cc  staff  640 Dec 11 18:57 import

I run docker-compose up -d --build, and the container is built. Now the local directory looks like this:

0 drwxr-xr-x   9 cc  staff  288 Dec 11 18:57 .
0 drwxr-xr-x   5 cc  staff  160 Dec 11 18:15 ..
0 drwxr-xr-x   2 cc  staff   64 Dec 11 13:59 conf
0 drwxrwxrwx@  4 cc  staff  128 Dec 11 18:08 data
8 -rw-r--r--   1 cc  staff  458 Dec 11 18:45 docker-compose.yml
0 drwxr-xr-x  20 cc  staff  640 Dec 11 18:57 import
0 drwxrwxrwx@  3 cc  staff   96 Dec 11 13:59 logs
0 drwxr-xr-x   3 cc  staff   96 Dec 11 15:32 plugins

The conf, data, logs, and plugins directories are created.

data and logs are populated from the build of the Neo4j image, and conf and plugins are empty, as expected.

I use docker exec to look at the directory structures on the container:

     8 drwx------    1 neo4j    neo4j         4096 Dec 11 23:46 .
     8 drwxr-xr-x    1 root     root          4096 May 11  2019 ..
    36 -rwxrwxrwx    1 neo4j    neo4j        36005 Feb 18  2019 LICENSE.txt
   128 -rwxrwxrwx    1 neo4j    neo4j       130044 Feb 18  2019 LICENSES.txt
    12 -rwxrwxrwx    1 neo4j    neo4j         8493 Feb 18  2019 NOTICE.txt
     4 -rwxrwxrwx    1 neo4j    neo4j         1594 Feb 18  2019 README.txt
     4 -rwxrwxrwx    1 neo4j    neo4j           96 Feb 18  2019 UPGRADE.txt
     8 drwx------    1 neo4j    neo4j         4096 May 11  2019 bin
     4 drwxr-xr-x    2 neo4j    neo4j         4096 Dec 11 23:46 certificates
     8 drwx------    1 neo4j    neo4j         4096 Dec 11 23:46 conf
     0 lrwxrwxrwx    1 root     root             5 May 11  2019 data -> /data
     4 drwx------    1 neo4j    neo4j         4096 Feb 18  2019 import
     8 drwx------    1 neo4j    neo4j         4096 May 11  2019 lib
     0 lrwxrwxrwx    1 root     root             5 May 11  2019 logs -> /logs
     4 drwx------    1 neo4j    neo4j         4096 Feb 18  2019 plugins
     4 drwx------    1 neo4j    neo4j         4096 Feb 18  2019 run

My problem is that the import directory in the container is empty. The data and logs directories are not empty though.

The data and logs directories on my local have extended attributes which the conf and plugins do not:

xattr -l data
com.docker.grpcfuse.ownership: {"UID":100,"GID":101}

The only difference I can identify is that those directories that had data created by docker-compose when it grabbed the Neo4j image.

Does anyone understand what is happening here, and tell me how I can get this to work? I'm using Mac OS X 10.15 and docker-compose version 1.27.4, build 40524192.

Thanks.

1

There are 1 answers

0
David Maze On BEST ANSWER

TL;DR: your current setup probably works fine.


To walk through the specific behavior you're observing:

  1. On container startup, Docker will create empty directories on the host if they don't exist, and mount-point directories inside the container. (Which is why those directories appear.)

  2. Docker never copies data from an image into a bind mount. This behavior only happens for named volumes (and only the very first time you use them, not on later runs; and only on native Docker, not on Kubernetes).

  3. But, the standard database images generally know how to initialize an empty data directory. In the case of the neo4j image, its Dockerfile ends with an ENTRYPOINT directive that runs at container startup; that docker-entrypoint.sh knows how to do various sorts of first-time setup. That's how data gets into ./data.

  4. The image also declares a WORKDIR /var/lib/neo4j (via an intermediate environment variable). That explains, in your ls -l listing, why there are symlinks like data -> /data. Your bind mount is to /import, but if you docker-compose exec neo4j ls import, it will look relative to that WORKDIR, which is why the directory looks empty.

  5. But, the entrypoint script specifically looks for a /import directory inside the container, and if it exists and is readable, it sets an environment variable NEO4J_dbms_directories_import=/import.

This all suggests to me that your setup is correct, and if you try to execute an import, it will work correctly and see your host data. You are looking at a /var/lib/neo4j/import directory from the image, and it's empty, but the image startup knows to also look for /import in the container, and your mount points there.