Changing the location of docker named volumes

A few weeks ago I was presenting at SQL Saturday Raleigh and was asked a question that I didn’t know the answer to.

The question was, “can you change the location of named volumes in docker?”

This is one of the things that I love about presenting, being asked questions that I don’t know the answer to. They give me something to go away and investigate (many thanks to Dave Walden (b|t) for his help!)

N.B. – I’ve previously written about persisting data using named volumes here

First let’s have a look at a named volume. To create one, run: –

docker volume create sqlserver

And now let’s have a look at it: –

docker volume inspect sqlserver

You can see above where the named volume lives on the host. But what if we want to change that location?


UPDATE – February 2022

This article originally only talked about using a docker volume plugin called Local Persist to change the location of a named volume.

However, you can do this without using a plugin by using the docker local driver and the bind option, which I’ll go through here.

I’ve left the details of how to use the plugin below as it does work to move a named volume but the plugin has not been updated for a while so using the local driver is the preferred way.


So let’s create a directory to point our named volume to: –

mkdir /sqlserver

And now create the named volume using the local driver and the bind option, setting the device to our custom location: –

docker volume create --driver local -o o=bind -o type=none -o device=/sqlserver sqlserver

Let’s have a look at it: –

docker volume inspect sqlserver

There we can see the device listed, /sqlserver, and the mount point, /var/lib/docker/volumes/sqlserver/_data.

What will happen when this named volume is used in a container is that /sqlserver will be mounted to /var/lib/docker/volumes/sqlserver/_data

And there you have it, a named volume in a custom location


Original post using the docker volume plugin – 2018

Well, in order to do so we need to use a docker volume plugin. Which unfortunately means that this functionality is not available on Windows or on Macs (as plugins aren’t supported on those platforms). The workaround is to run the plugin from a container but I would just mount a volume from the host (see here).

The plugin that I’m going to use is the Local Persist Plugin

Really simple to install: –

curl -fsSL https://raw.githubusercontent.com/CWSpear/local-persist/master/scripts/install.sh | sudo bash

And we are good to go!

Ok, let’s create a directory to point our named volume to: –

mkdir /sqlserver

And now we can create our named volume: –

docker volume create -d local-persist -o mountpoint=/sqlserver --name=sqlserver2

Let’s have a look at it: –

docker volume inspect sqlserver2

And there you have it, the named volume pointing to a custom location.

Thanks for reading!

7 thoughts on “Changing the location of docker named volumes

    • you can use the mountpoint option in a compose file. For example

      version: "3.7"
      services:
        sqlserver:
          image: mcr.microsoft.com/mssql/server:2019-CU4-ubuntu-16.04
          ports:  
          - "15789:1433"
          environment:
            MSSQL_SA_PASSWORD: "Testing1122"
            ACCEPT_EULA: "Y"
          volumes: 
          - sqlsystem:/var/opt/mssql/
      
      volumes:
        sqlsystem:
          driver: local-persist
          driver_opts:
            type: none
            mountpoint: /sqlserver
            o: bind
      

      That’ll create a named volume mounted from /sqlserver on the host.

  1. Hi. Thank you for this post. I have a question with regards to your February 2022 update:

    I am trying to figure out how to create a volume with the following properties:
    – Custom volume directory on host. I would like to choose the directory myself so that I can easily modify things like configuration files that the containers are using.
    – Named volume. I would like to refer to it by a name rather than a path, so that it is easier to maintain the docker-compose file. Suppose I am sharing a volume with 50 containers; if I need to change the path of the host directory, now I need to modify the path in 50 places. If it is named in a `volume:` section, then I only need update it in one place.
    – The container populates this named+custom_host_location volume with its own files that it otherwise would if I had not created a volume. In my case, I would like a named volume with a custom host directory for the container’s internal /etc/nginx. The problem is that the container does not populate the volume with the default files that would otherwise exist within /etc/nginx (or perhaps it does, but gets mounted-over in-place).

    Perhaps what I’m trying to do is not possible, but if you have any insight, I would appreciate it!

    Thanks,

    Ed

    • Sorry if I’m getting this wrong but you would like to mount a directory from the host containing custom nginx files to /etc/nginx into a container using a named volume?

      I ran through this, firstly by creating a location on the host: –

      mkdir /nginx
      

      Then created a named volume using the local driver and the bind option: –

      docker volume create --driver local -o o=bind -o type=none -o device=/nginx nginx
      

      That’ll create a named volume bound to /nginx. When mapped to a container it’ll be mounted to a location in /var/lib/docker/volumes (I’m not sure you can change that).

      Then I tested using the custom location by running a container with the directory referenced by the named volume: –

      docker container run -d -p 80:80 --name nginx1 --volume nginx:/etc/nginx nginx
      

      That worked, the directory was initially empty but was then populated with the default nginx files/directories.

      So drop your custom nginx files to /nginx on the host and then run another container with the named volume mapped.

      This can also be done in a docker compose file (this is a really basic docker compose example): –

      version: "3.3"
      
      services:
         nginx1:
          image: nginx
          ports:
            - "80:80"
          volumes:
            - nginx:/etc/nginx
        
        nginx2:
          image: nginx
          ports:
            - "8080:80"
          volumes:
            - nginx:/etc/nginx
      	  
      volumes:
        nginx:
          driver: local
          driver_opts:
            type: none
            device: /nginx
            o: bind
      

      So if you want to make any changes, you can just update the device location in the volumes section.

      Hope that helps!

Leave a Reply to dbafromthecold Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s