Search code examples
dockerhyper-vdocker-volumedocker-for-windowsdocker-desktop

Docker for Windows: Accessing named volume mounts


Please note that this is not a duplicate of Locating data volumes in Docker Desktop (Windows) as back in 2017 the inner workings of docker on windows were quite different - e.g. docker volume inspect output is quite different nowadays.

I have trouble accessing data mounted to containers in docker for windows via named volume mounts.

docker inspect [vol-id]

[
{
    "CreatedAt": "2019-04-02T11:58:14Z",
    "Driver": "local",
    "Labels": {
        "com.docker.compose.project": "foo",
        "com.docker.compose.version": "1.24.0",
        "com.docker.compose.volume": "mongodata-foo"
    },
    "Mountpoint": "/var/lib/docker/volumes/foo_mongodata-foo/_data",
    "Name": "foo_mongodata-payoff",
    "Options": null,
    "Scope": "local"
}
]

--> Mountpoint is inside the HyperV VM used in Docker. How to get access to that data? Is there an easily manageable way to to this?

Note: I don't have C:\ProgramData\Docker\Volumes as described here. Instead, what was created with Docker Desktop 2.0.0.3, Engine 18.03.3, was C:\ProgramData\DockerDesktop. That does not contain any Volumes as far as I can tell.

Background: I need named mounts with default location inside HyperV, as mounting it manually via docker run -v or specifying the driver device location looks to be unsupported by mongodb (I have exactly the same behavior as described there. It looks like mongodb is incompatible with NTFS-originating volume mounts.


Solution

  • method using built-in docker cp

    Use docker cp [containername]:[path] [host-path] to e.g. copy data out - reverse the params to copy data in - it works just like scp. To get shell access to the data you can just attach to the running container.

    pro: nothing additional needed in docker compose

    con: no integration (that I know of) with a file explorer GUI like WinSCP. need to do a terminal based copy each time a file is to be updated between host and container.

    method using a dockerized ssh server

    pro: can integrate with any tool that can talk over ssh/sftp

    con: needs additional setup

    The following approach starts an ssh server within a service, setup with docker-compse such that it automatically starts up and uses public key encryption between host and container for authorization. This way, data can be uploaded/downloaded via scp or sftp.

    The full docker-compose.yml for a node.js (keystone) + mongodb app is below, together with some documentation on how to use ssh service:

    version: '3'
    services:
      foo:
        build: .
        image: localhost.localdomain/${repository_name}:${tag}
        container_name: ${container_name}
        ports:
          - "3333:3333"
        links:
          - mongodb-foo
        depends_on:
          - mongodb-foo
          - sshd
        volumes:
          - "${host_log_directory}:/var/log/app"
    
      mongodb-foo:
        container_name: mongodb-${repository_name}
        image: "mongo:3.4-jessie"
        volumes:
          - mongodata-foo:/data/db
        expose:
          - '27017'
    
      #since mongo data on Windows only works within HyperV virtual disk (as of 2019-4-3), the following allows upload/download of mongo data
      #setup: you need to copy your ~/.ssh/id_rsa.pub into $DOCKER_DATA_DIR/.ssh/id_rsa.pub, then run this service again
      #download (all mongo data): scp -r -P 2222 user@localhost:/data/mongodb [target-dir within /c/]
      #upload (all mongo data): scp -r -P 2222 [source-dir within /c/] user@localhost:/data/mongodb
      sshd:
        image: maltyxx/sshd
        volumes:
            - mongodata-foo:/data/mongodb
            - $DOCKER_DATA_DIR/.ssh/id_rsa.pub:/home/user/.ssh/keys/id_rsa.pub:ro
        ports:
            - "2222:22"
        command: user::1001
    
    #please note: using a named volume like this for mongo is necessary on Windows rather than mounting an NTFS directory.
    #mongodb (and probably most other databases) are not compatible with windows native data directories due ot permissions issues.
    #this means that there is no direct access to this data, it needs to be dumped elsewhere if you want to reimport something.
    #it will however be persisted as long as you don't delete the HyperV virtual drive that docker host is using.
    #on Linux and Docker for Mac it is not an issue, named volumes are directly accessible from host.
    volumes:
      mongodata-foo:
    

    note: for a fully working example, before any docker-compose call the following script needs to be run:

    #!/usr/bin/env bash
    set -o errexit
    set -o pipefail
    set -o nounset
    
    working_directory="$(pwd)"
    host_repo_dir="${working_directory}"
    repository_name="$(basename ${working_directory})"
    branch_name="$(git rev-parse --abbrev-ref HEAD)"
    container_name="${repository_name}-${branch_name}"
    host_log_directory="${DOCKER_DATA_DIR}/log/${repository_name}"
    tag="${branch_name}"
    
    export host_repo_dir
    export repository_name
    export container_name
    export tag
    export host_log_directory