skip to Main Content

I think I do not understand how Docker volumes work. I have a docker compose file with an app service running a laravel app, a postgres service, and a memcached service. I have named volumes for the laravel storage and for postgres, but nothing is persisted to those volumes. If I look in my file finder there are no files in the folder and when I shut down the db container the data is lost.

docker-compose.yaml:

services:
  app:
    build:
      context: .
    entrypoint: php artisan octane:frankenphp
    ports:
      - "80:8000"
      - "443:443"
      - "443:443/udp" # HTTP/3
      - "5173:5173"
    depends_on:
      - db
      - cache
    volumes:
      - storage:/path/to/laravel/base/storage
      - ../:/app
    networks:
      - storefront
      - backroom
  db:
    image: postgres:latest
    restart: unless-stopped
    volumes:
      - data:/path/where/I/want/db/data
    environment:
      POSTGRES_USER: user
      POSTGRES_DB: db
      POSTGRES_PASSWORD: "password"
    networks:
      - backroom

  cache:
    image: memcached:latest
    restart: unless-stopped
    networks:
      - backroom

networks:
  storefront:
  backroom:

volumes:
  data:
  storage:

This line appears to work:

  • ../:/app
    When I do things inside the app service container, I can see the changes in my local file system. For instance, if I use composer to add a package, I can look at composer.json in VS Code later and the new package is there. But the two named volumes do not appear to do anything.

The containers communicate – php artisan migrate and php artisan db:seed create tables and records in postgres – but the data does not persist.

Thank you

2

Answers


  1. Chosen as BEST ANSWER

    I posted this same issue over at Docker forums and my man Rimelek guided me to the answer.

    https://forums.docker.com/t/volumes-in-docker-compose-not-persisting/141107/8

    I simply was not understanding how volumes work. As he pointed out, my bind mount in the db container was wrong. This line here:

    • data:/path/where/I/want/db/data

    Was not the folder in the db container where Postgres actually put its data. So I was mounting to an empty folder. Once I changed that line to be the actual Postgres data directory, it all worked.

    I could have had the same effect by setting the PGDATA environment variable to "/path/where/I/want/db/data" so that Postgres was putting the database there.

    Thanks to Snor for his answer which is accurate but not quite going all the way to the specific problem I had.


  2. In Docker there are two different types of "volumes" that are specified under that heading. One is actually a docker volume, and the other is a "bind mount".

    This is a docker volume:

      - storage:/path/to/laravel/base/storage
    

    They are not a part of your regular filesystem, but are instead managed by docker. When the first part is just a name without a / anywhere, it will be a volume.

    This is a bind mount:

      - ../:/app
    

    They are basically mappings between your docker container and your file system. They specify a path, rather than just being a volume name.

    Conclusion

    What you are seeing is correct. And your data in the volumes will actually be persisting, just not inside directories that you can view and manage on your normal filesystem.

    Which type you use for various things is ultimately up to you, but I recommend reading about the volumes, their purpose, how to work with them, and any pros/cons so that you can make a sensible choice.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search