How to mount multiple subfolders inside named cifs volume in docker-compose? - docker

I have a docker compose stack of several containers that all need to access the same network drive shared via cifs. The applications need access to several subfolders within this drive and the mount points cannot be changed, because they expect the folders to reside in specific locations.
I know it's not possible to access subfolders of named volumes such as named_vol:/subdir:/container_path, but I cannot seem to find a way around that. The only thing I can think of is to manually mount each folder as a network drive, but I would like to avoid that, as I would end up with 15-20 mounted network drives. Below is a partial example of what I need to achieve, were it possible to access subdirs of a named volume. How can I fix the below get the desired volume mapping?
node1:
...
volumes:
# - shared_vol:/data/media:/media
# - shared_vol:/tmp/:/tmp
...
node10:
...
volumes:
# - shared_vol:/data/media:/media
# - shared_vol:/data/config:/config
volumes:
shared_vol:
driver_opts:
type: "cifs"
o: "username=xxx,password=xxx,uid=xxx,gid=xxx,vers=3.0"
device: "//192.168.1.69/shared_vol"

Related

Named volumes on desired location

I need to store the project on the mounted drive using the docker-compose file, placed at the root of that drive. I want to use docker volumes, not as bounded folders, but as named volumes. But I do not want to store it physically on the default location (/var/lib/docker/volume), because the system drive is small. How can I set up named volumes in docker-compose and ask the docker to create volumes in the same place where the docker-compose file is located?
Recommended: If system drive is small then you should move the docker data-root to some other location. This will keep compose file same across all users/systems.
Not Recommended: For having a named volume on desired location, you can specify driver_opts for the volume driver.
e.g. for local driver, declare top level volumes in compose file as
volumes:
my_volume:
driver: local
driver_opts:
type: none
device: "/full/host/path/"
o: bind
This change will apply to all systems your docker compose is used, with small system drives or large.

invalid mount config for type "bind": bind source path does not exist: /container/tdarr-server/server

I am trying to use an nfs share to use docker swarm with a single endpoint server for a drive, the NFS share its self does work as i can create files on it, however when trying to use it on a stack i get a bind source path error. my nfs share is set to /container on both machines so each machine can find it at the same location. here is what i have as a volume in my docker compose file:
volumes:
- /container/tdarr-server/server:/app/server
- /container/tdarr-server/configs:/app/configs
- /container/tdarr-server/logs:/app/logs
- /container/plex/media:/media
- /container/tdarr-server/transcode:/transcode
There are two ways to do this:
On each server mount a nfs share. Assuming you have a nfs server sharing a volume "docker_volumes" you could mount that as "/mnt/volumes"
Then your stack file could look like this:
version: "3.9"
volumes:
prometheus:
driver: local
driver_opts:
o: bind
type: none
device: /mnt/volumes/prometheus-data
services:
prometheus:
image: prom/prometheus:latest
volumes:
- prometheus:/data
NB. Docker will NOT create missing volumes for you. Each missing directory (e.g. ./prometheus-data) needs to be manually created on the nfs share before docker will start the service.
As an alternative you can - rather than pre-mounting the nfs volume in a defined location - provide docker with the nfs connection details so it can mount the nfs share on the fly:
volumes:
data:
driver_opts:
type: "nfs"
o: "addr=10.40.0.199,nolock,soft,rw"
device: ":/docker/example"
Again, if you provide a path into the nfs share as part of the device description, docker will not create it if it does not exist. The admin must pre-create any specific sub folders referenced before services or containers will be able to use the volume definition.

docker-compose volumes not mounting directories, only files inside directory

Might sound weird, but I am trying to get docker-compose to mount directories to a volume I created
volumes:
- backend-data:/app/migrations/autogen-migrations
- backend-data:/app/seeds/autogen-seeds
- backend-data:/app/server/public
- backend-data:/app/server/src/services/location
Only problem is, that instead of simply mapping the folders to the volume, it's mounting the content inside the volume. Is there any way to tell docker-compose to copy/map the folder itself?
Edit:
Already tried doing
backend-data/autogen-migrations:/app/migrations/autogen-migrations
And I get the following error:
Named volume "backend-data/autogen-migrations:/app/migrations/autogen-migrations:rw" is used in service "backend" but no declaration was found in the volumes section.
Btw this is how my volumes are declared
volumes:
backend-data:
driver: local
When you need mount a local directory as Docker volume, you have use this syntax in your service:
volumes:
- ./your/local/path:/app/migrations/autogen-migrations
In this way, Docker create a local path "./your/local/path" in the same folder where docker-compose.yml file is, to store the data of mounted volume. In this case you don't need specify the volume section in the docker-compose.yml because you manage the volumes by yourself.
If you need mount more than one folder, remember also to mount more than one local folder:
volumes:
- ./your/local/migrations/or/whatever/you/want:/app/migrations/autogen-migrations
- ./your/local/seeds:/app/seeds/autogen-seeds
- ./your/local/server/public:/app/server/public
- ./your/local/server/src:/app/server/src/services/location
You can also aggregate mounts folder under the same folder:
volumes:
- ./your/local/migrations:/app/migrations/autogen-migrations
- ./your/local/seeds:/app/seeds/autogen-seeds
- ./your/local/server:/app/server
In this case into './your/local/server' you found all '/app/server/' content.
If you use the syntax:
volumes:
backend-data:
driver: local
you tell Docker: "Docker, please, mount the folder which correspond to backend-data: (in your case backend-data:/app/migrations/autogen-migrations) when you want and store my data!". In this case, Docker manage the "local" folder by itself without use the the same folder where docker-compose.yml file is.

Mounting a single file from an NFS docker volume into a container

Example (many options omitted for brevity):
version: "3"
volumes:
traefik:
driver: local
driver_opts:
type: nfs
o: "addr=192.168.1.100,soft,rw,nfsvers=4,async"
device: ":/volume/docker/traefik"
services:
traefik:
volumes:
- traefik/traefik.toml:/traefik.toml
This errors out as there is no volume with the name traefik/traefik.toml meaning that the volume name must be the full path to the file (i.e. you can't append a path to the volume name)?
Trying to set device: ":/volume/docker/traefik/traefik.toml" just returns a not a directory error.
Is there a way to take a single file and mount it into a container?
You cannot mount a file or sub-directory within a named volume, the source is either the named volume or a host path. NFS itself, along with most filesystems you'd mount in Linux, require you to mount an entire filesystem, not a single file, and when you get down to the inode level, this is often a really good thing.
The options remaining that I can think of are to mount the entire directory somewhere else inside your container, and symlink to the file you want. Or to NFS mount the directory to the host and do a host mount (bind mount) to a specific file.
However considering the example you presented, using a docker config would be my ideal solution, removing the NFS mount entirely, and getting a read only copy of the file that's automatically distributed to whichever node is running the container.
More details on configs: https://docs.docker.com/engine/swarm/configs/
I believe I found the issue!
Wrong:
volumes:
- traefik/traefik.toml:/traefik.toml
Correct:
volumes:
- /traefik/traefik.toml:/traefik.toml
Start the volume with "/"

What's the difference between declaring in docker-compose.yml volume as section and under a service?

What's the difference between declaring in the docker-compose.yml file a volume section and just using the volumes keyword under a service?
For example, I map a volume this way for a container:
services:
mysqldb:
volumes:
- ./data:/var/lib/mysql
This will map to the folder called data from my working directory.
But I could also map a volume by declaring a volume section and use its alias for the container:
services:
mysqldb:
volumes:
- data_volume:/var/lib/mysql
volumes:
data_volume:
driver: local
In this method, the actual location of where the mapped files are stored appears to be somewhat managed by docker compose.
What are the differences between these 2 methods or are they the same? Which one should I really use?
Are there any benefits of using one method over the other?
The difference between the methods you've described is that first method is a bind mount, and the other is a volume. These are more of Docker functions (rather than Docker Compose), and there are several benefits volumes provide over mounting a path from your host's filesystem. As described in the documentation, they:
are easier to back up or migrate
can be managed with docker volumes or the API (as opposed to the raw filesystem)
work on both Linux and Windows containers
can be safely shared among multiple containers
can have content pre-populated by a container (with bind mounts sometimes you have to copy data out, then restart the container)
Another massive benefit to using volumes are the volume drivers, which you'd specify in place of local. They allow you to store volumes remotely (i.e. cloud, etc) or add other features like encryption. This is core to the concept of containers, because if the running container is stateless and uses remote volumes, then you can move the container across hosts and it can be run without being reconfigured.
Therefore, the recommendation is to use Docker volumes. Another good example is the following:
services:
webserver_a:
volumes:
- ./serving/prod:/var/www
webserver_b:
volumes:
- ./serving/prod:/var/www
cache_server:
volumes:
- ./serving/prod:/cache_root
If you move the ./serving directory somewhere else, the bind mount breaks because it's a relative path. As you noted, volumes have aliases and have their path managed by Docker, so:
you wouldn't need to find and replace the path 3 times
the volume using local stores data somewhere else on your system and would continue mounting just fine
TL;DR: try and use volumes. They're portable, and encourage practices that reduce dependencies on your host machine.

Resources