Search code examples
dockerdocker-composedocker-volume

Specify origin of data for a shared volume


I have a task that I already solved, but where I'm not satisfied with the solution. Basically, I have a webserver container (Nginx) and a fast-CGI container (PHP-FPM). The webserver container is built on an off-the-shelf image, the FCGI container is based on a custom image and contains the application files. Now, since not everything is sourcecode and processed on the FCGI container, I need to make the application files available inside the webserver container as well.

Here's the docker-compose.yml that does the job:

version: '3.3'

services:
  nginx:
    image: nginx:1-alpine
    volumes:
      - # customize just the Nginx configuration file
        type: bind
        source: ./nginx.conf
        target: /etc/nginx/nginx.conf
      - # mount application files from PHP-FPM container
        type: volume
        source: www-data
        target: /var/www/my-service
        read_only: true
        volume:
          nocopy: true
    ports:
      - "80:80"
    depends_on:
      - php-fpm

  php-fpm:
    image: my-service:latest
    command: ["/usr/sbin/php-fpm7.3", "--nodaemonize", "--force-stderr"]
    volumes:
      - # create volume from application files
        # This one populates the content of the volume.
        type: volume
        source: www-data
        target: /var/www/my-service

volumes:
  # volume with application files shared between nginx and php-fpm
  www-data:

What I don't like here is mostly reflected by the comments concerning the volumes. Who creates and stores data should be obvious from the code and not from comments. Also, what I really dislike is that docker actually creates a place where it stores data for this volume. Not only does this use up disk space and increase startup time, it also requires me to never forget to use docker-compose down --volumes in order to refresh the content on next start. Imagine my anger when I found out that down didn't tear down what up created and that I was hunting ghosts from previous runs.

My questions concerning this:

  • Can I express in code that one container contains data that should be made available to other containers more clearly? The above code works, but it fails utterly to express the intent.
  • Can I avoid anything persistent being created to avoid above mentioned downsides?
  • I would have liked to investigate into things like tmpfs volumes or other volume options. My problem is that I can't find documentation for available volume drivers or even explore which volume drivers exist. Maybe I have missed some CLI for that, I'd really appreciate a nudge in the right direction here.

Solution

  • You can use the local driver with option type=tmpfs, for example:

    volumes:
      www-data:
        driver: local
        driver_opts:
          type: tmpfs
          device: tmpfs
    

    Which will follow your requirements:

    • Data will be shared between containers at runtime
    • Data should not be persisted, i.e. volumes will be emptied when container are stopped, restarted or destroyed

    This is CLI equivalent of

    docker volume create --driver local --opt type=tmpfs --opt device=tmpfs www-data
    

    Important note: this is NOT a Docker tmpfs mount, but a Docker volume using a tmpfs option. As stated in the local volume driver documentation it uses the Linux mount options, in our case --types to specify a tmpfs filesystem. Contrary to a simple tmpfs mount, it will allow you to share the volume between container while retaining classic behavior of a temporary filesystem

    I can't find documentation for available volume drivers or even explore which volume drivers exist

    Can I express in code that one container contains data that should be made available to other containers more clearly? The above code works, but it fails utterly to express the intent.

    I don't think so, your code is are already quite clear as to the intent of this volume:

    • That's what volume are for: sharing data between containers. As stated in the doc Volumes can be more safely shared among multiple container, furthermore only containers are supposed to write into volumes.
    • nocopy and read_only clearly express that nginx relies on data written by another container as it will only be able to read from this volume
    • Given your volume is not external, it is safe to assume only another container from the same stack can use it
    • A bit of logic and experience with Docker allow to quickly come to the previous point, but even for less experienced Docker users your comments gives clear indications, and your comments are part of the code ;)