Search code examples
dockerdocker-composedocker-volume

How to use directory with files as volume in Docker


I'm trying to create a docker image from code that I download from a github repository. This is all done in the Dockerfile. Next, I want to make this directory accessible from the host machine. But when I specify it as a volume, the directory remains empty on the host machine after starting the container. But inside the container, the directory contains files.

Here is docker-compose.yml, but folder empty

services:
  p_parser:
    container_name: p_parser
    hostname: p_parser
    image: local/parser:1.0
    working_dir: /var/www/parser
    build:
      context: ./build/parser/
      dockerfile: Dockerfile
      args:
        - SSH_PRIVATE_KEY
    restart: unless-stopped
    networks:
      - default
    volumes:
      - p_parser_volume:/srv/var/www/p_parser
      - ./configs/p_parser/php.ini:/etc/php/8.1/cli/php.ini:delegated
volumes:
  p_parser_volume:
    driver: local
    driver_opts:
      device: ./data/p_parser
      o: bind
      type: none


Solution

  • This can be a bit tricky. The key is to create a named volume, as those will be populated by the data in the container file system if they are empty.

    Additionally, you can create a named volume with options such that it is effectively a bind mount. But it still gets populated with container data like named volume.

    #!/usr/bin/env sh
    
    mkdir -p data
    
    docker volume create \
        --driver local \
        -o o=bind \
        -o type=none \
        -o device="$PWD/data" \
        example-volume
    
    docker run -d --rm \
        --mount source=example-volume,destination=/usr/share/nginx/html \
        nginx:latest sh -c "exit 0"
    

    You can have a read here. https://docs.docker.com/storage/volumes/#populate-a-volume-using-a-container.

    The same config with compose looks like the below. Note the absolute path for the volume device.

    Also note that, this will only be populated once when the volume is new and empty. So if you don't see it getting populated, do a docker compose down -v to remove the volume so that it gets created the next time you do up.

    services:
      nginx:
        image: nginx:latest
        command: sh -c "exit 0"
        volumes:
          - example-volume:/usr/share/nginx/html
    
    volumes:
      example-volume:
        driver: local
        driver_opts:
          type: none
          o: bind
          device: "$PWD/data"