Mount OpenMediaVault NFS in docker-compose.yml volume for Docker Swarm - docker

I am trying to externalise my runtime data from my applications to be saved in OpenMediaVault shared folder.
I was able to create shared folder and configure NFS or at least I think so. The config I see in OMV/Services/NFS/Shares is:
Shared folder: NasFolder[on /dev/sda1, nas/]
Client: 192.168.50.0/24
Privelage: Read/Write
Extra options: subtree_check,insecure
Now in that shared folder I have this structure(I checked it using windows SMB/CIFS config)
\\nfs-ip\NasFolder
|- mysql
| \- some my sql folders...
|- TEST.txt
I want to use this mysql folder to store MariaDB runtime data(I know names are messed up I am in a middle of a migration to Maria...). And meaby create some other folders for other services. This is my config from docker-compose.yml:
version: '3.2'
services:
mysqldb:
image: arm64v8/mariadb:latest
ports:
- 3306:3306
restart: on-failure:3
volumes:
- type: volume
source: nfs-volume
target: /mysql
volume:
nocopy: true
environment:
- MYSQL_ROOT_PASSWORD=my-secret-pw
command: --character-set-server=utf8 --collation-server=utf8_general_ci
volumes:
nfs-volume:
driver: local
driver_opts:
type: "nfs"
o: addr=192.168.50.70,nolock,soft,rw
device: ":/NasFolder"
Now when I run docker stack deploy -c docker-compose.yml --with-registry-auth maprealm on my manager node I get error on maprealm_mysqldb.1 that looks like this:
"Err": "starting container failed: error while mounting volume '/var/lib/docker/volumes/maprealm_nfs-volume/_data': failed to mount local volume: mount :/NasFolder:/var/lib/docker/volumes/maprealm_nfs-volume/_data, data: addr=192.168.50.70,nolock,soft: permission denied",
I am pretty new to integration stuff. This is my home server and I just can't find good tutorials that 'get through my thick skull' how to configure those NFS paths and permissions or at least how can I debug it beside just getting this error. I know that volumes.nfs-volume.driver_opts.device is supposed to be a path but I am not sure what path should that be.
I was trying to adapt config from here: https://gist.github.com/ruanbekker/4a9c0d250bce9f84482f2a788ce92131
Edit1) Few additional details:
Docker swarm has 3 nodes and only one node is manager with availability pause.
OMV is running on a separet machine that is not a part of a cluster

Ok so if someone would be looking for solution:
OMV by default has /export/ for NFS so volume needed to be updated. I needed to update volume for mysql and update volumes.mysql-volume.driver_opts.device to include that /export/ prefix and I also added path to mysql folder to have volume for mysqldb service use only:
volumes:
mysql-volume:
driver: local
driver_opts:
type: "nfs"
o: addr=192.168.50.70,nolock,soft,rw
device: ":/export/NasFolder/mysql"
After those changes there was need to update volume config on mysql/mariadb:
mysqldb:
image: arm64v8/mariadb:latest
ports:
- 3306:3306
restart: on-failure:3
volumes:
- type: volume
source: mysql-volume
target: /var/lib/mysql
volume:
nocopy: true
environment:
- MYSQL_ROOT_PASSWORD=my-secret-pw
command: --character-set-server=utf8 --collation-server=utf8_general_ci
mysqldb.volumes.source points to name of your volume defined in step 1 - mysql-volume
mysqldb.volumes.target is where inside container runtime data is stored. In mysql/mariadb databases runtime data is stored in /var/lib/mysql so you want to point to that and you can only use full path.
Since I used default OMV config there were problems with permissions. So I updated OMV/Services/NFS/Shares to this:
Shared folder: NasFolder[on /dev/sda1, nas/]
#here you can see note 'The location of the files to share. The share will be accessible at /export/.'
Client: 192.168.50.0/24
Privelage: Read/Write
Extra options: rw,sync,no_root_squash,anonuid=1000,anongid=1000,no_acl

Related

mount a directory from docker container to the linux ubuntu host machine

I would like to mount a directory from inside a docker to my linux Ubuntu host machine using docker-compose.yml.
The directory in the docker container is /usr/local/XXX and I want to mount it on /home/Projects/XX
How can I make it happen?
This is my docker-compose.yml file:
version: '3'
services:
MyContainer:
image: XX.XXX.XXX.XXX:XXXX/XXX/MyContainer:latest
restart: always
container_name: MyContainer
hostname: MyContainer_docker
privileged: true
ports:
- "XXXX:XX"
volumes:
- /home/Project/workspace/XXX/XXXX:/home/XX
environment:
- ...
extra_hosts:
- ...
networks:
net_plain3:
ipv4_address: ...
networks:
# ...etc...
It is possible with the right driver options.
Technically, you still mount the host directory to the container, but the result is that the host directory is populated with the data in the container directory. Usually it's the other way around. That's why you need those driver options.
services:
somebox:
volumes:
- xx-vol:/usr/local/XXX
volumes:
xx-vol:
driver: local
driver_opts:
type: none
o: bind
device: /home/Projects/XX
Empty named volumes are initialized with the content of the image at the mount location when the container is created.
- bmitch
So the key here is to create a named volume that uses as device the desired location on the host.
As a full working demonstration.
I create the following Dockerfile to add text file in the /workspace dir:
FROM busybox
WORKDIR /workspace
RUN echo "Hello World" > hello.txt
Then a compose.yaml to build this image and mount a volume with these driver options:
services:
databox:
build: ./
volumes:
- data:/workspace
volumes:
data:
driver: local
driver_opts:
type: none
o: bind
device: /home/blue/scrap/vol/data
Now I run the below commands:
$ mkdir data
$ docker-compose up
[+] Running 1/0
⠿ Container vol-databox-1 Created 0.0s
Attaching to vol-databox-1
vol-databox-1 exited with code 0
$ cat /home/blue/scrap/vol/data/hello.txt
Hello World
As you can see, the hello.txt file ended up on the host. It was not created after container startup but was already inside the container's file system when the container started, since it has been added during build.
That means, it is possible to populate a host directory with data from a container in such a way that the data doesn't have to be generated after volume mount, which is usually the case.

How to configure external bind volumes specified in .env for docker-compose

Trying to figure out a flexible bind mount, that survives a docker compose down
Setup
I have a docker-compose.yml:
version: "3.9"
services:
redis:
image: "redis:alpine"
restart: always
command: redis-server --requirepass ${REDIS_PASSWORD}
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
volumes:
- type: volume
source: redis_data
target: /data
ports:
- ${REDISPORT}:6379
volumes:
redis_data:
external: true
name: "redis_data"
driver: local
driver_opts:
type: "none"
o: "bind"
device: ${VOLUME_REDIS}
and an .env file:
#Docker Test
REDIS_PASSWORD=supersecret
REDISPORT=6379
VOLUME_REDIS=/Users/stephan/temp/redis
The problem
When I start docker-compose up I get the error:
conflicting parameters "external" and "driver" specified for volume "redis_data"
However the documentation seems to suggest, that parameter are supported in the current version:
For version 3.3 and below of the format, external cannot be used in conjunction with other volume configuration keys (driver, driver_opts, labels). This limitation no longer exists for version 3.4 and above.
When I remove the driver entry, the error changes to:
conflicting parameters "external" and "driver_opts" specified for volume "redis_data"
Environment
Docker version 20.10.6, build 370c289
docker-compose version 1.29.1, build c34c88b2 (but I used docker compose on macOS)
OS: macOS Catalina & Ubuntu 20.04 (tested on both)
What I'm trying to achieve
Have all variables in .env files, so I can start the same docker-compose.yml multiple times by specifying different env files
Avoid that a docker-compose down wipes my volumes
use host bind, so I can process data (with Docker stopped) with host apps
Stuff I looked at
Conditionalizing bind mounted volumes for Docker Compose
How to specify site-specific volumes for docker-compose
What do I miss?

How to specify volume host path in docker-compose?

I want to share a volume among multiple containers, and specify the path for this volume on the host.
I used the following settings:
version: '3'
services:
service1:
image: image1
volumes:
- volume1:/volume1
service2:
image: image2
volumes:
- volume1:/volume1
volumes:
volume1:
driver: local # meaning?
driver_opts:
o: bind # meaning?
type: none # meaning?
device: /volume1 # the path on the host
But I am not sure of the driver: local, type: none and o: bind options.
I would like to have a regular volume (like without specifying any driver nor driver_opts), just being able to specify the path on the host.
You're looking for a bind mount. Specifying the volumes key means that you're creating a volume in the Docker machine for persistent storage. Despite the name, a volume is not necessarily related to volumes.
Use something like:
version: '3'
services:
service1:
image: image1
volumes:
- type: bind # Host and Docker machines have identical views to the same directory; changes propagate both ways
source: . # Host machine directory to mount
target: /app # Docker machine directory to be mapped to

Docker Named Volumes

What's the right way to mix named volumes with and without local host path in docker compose v3?
This way I'm getting YML error:
volumes:
/mnt/volume-part1:/volume
conf:
vhost:
html:
certs:
Then I'd like to refer to volume inside containers...
For named volumes, you need to declare the volume name under the dedicated volumes section in the compose file. For a mount, you don't declare it in that section:
Consider the following compose file:
version: "3"
services:
db:
image: db
volumes:
- data-volume:/var/lib/db
- /mnt/volume-part1:/volume
volumes:
data-volume:
As you can see the named volume data-volume needes to be declared in the volumes section before being assiged to the container.
Whereas the directory mount is directly mounted onto the container.
UPDATE
If you don't want to replicate the machine path on all the container, you can use a clever trick to specify where exactly the named volume will be created as such:
version: "3"
services:
db:
image: db
volumes:
- data-volume:/var/lib/db
- volume-part1:/volume
volumes:
data-volume:
volume-part1:
driver_opts:
type: none
device: /mnt/volume-part1
o: bind
As you can see above, we have created a named volume volume-part1 and specified where this volume will be backuped on the host machine.

how to define a general mount point in docker compose

I would like to define a general mount volume - along with all the options I would like to have it associated - that can be reused across multiple services. In fact, I'm developing a project which uses the same source for several microservices.
That way, the volume will be simpler to manage and modify.
To start off, I used the old way which took advantage of volumes_from:
shared:
image: phusion/baseimage
volumes:
- ./code:/var/www/html
nginx:
build: docker/nginx
ports:
- "8080:80"
links:
- php
volumes_from:
- shared
This works, but I had to define a shared service to make it work. As of the 3.0 version, volumes can be used, so I would like to define a general volume and use it into my nginx service, but I'm not finding the right syntax:
version: '3.3'
volumes:
vol_test:
type: bind
source: ./code
target: /var/www/html
volume:
nocopy: true
services:
nginx:
build: docker/nginx
ports:
- "8080:80"
volumes:
- vol_test
Update
I've found that defining a volume the way I want could not be possible, since the following definition:
volumes:
data-volume:
type: bind
source: ./code
target: /var/www/html
volume:
nocopy: true
will produce this output when calling docker-compose up:
ERROR: The Compose file './docker-compose.yml' is invalid because:
volumes.data-volume value Additional properties are not allowed ('volume', 'source', 'type', 'target' were unexpected)
I guess I still have to use the volumes_from way then. Can anybody confirm that?
I can confirm your observation: If you want to mount a host directory, you'll have to use the bind mount syntax.
You do not have to use volume_from anymore. Form
https://docs.docker.com/compose/compose-file/#volumes:
But, if you want to reuse a volume across multiple services, then
define a named volume in the top-level volumes key. Use named volumes
with services, swarms, and stack files.
They even specifically address your issue:
Note: The top-level volumes key defines a named volume and references it from each service’s volumes list. This replaces
volumes_from in earlier versions of the Compose file format. See Use
volumes and Volume Plugins for general information on volumes.
So, for a MWE I defined an empty volume and referenced it in two services. This is the compose file:
version: '3.3'
volumes:
vol_test:
services:
reader:
image: ubuntu
tty: true
command: bash -c "sleep 1; cat /volume/file;exit 0"
volumes:
- vol_test:/volume
writer:
image: ubuntu
tty: true
command: bash -c "date | tee /volume/file; exit 0"
volumes:
- vol_test:/volume
This gives us the following behavior:
$ date; docker-compose up
So 27. Aug 11:54:13 CEST 2017
Creating network "dockercomposetest_default" with the default driver
Creating dockercomposetest_writer_1 ...
Creating dockercomposetest_reader_1 ...
Creating dockercomposetest_writer_1
Creating dockercomposetest_reader_1 ... done
Attaching to dockercomposetest_writer_1, dockercomposetest_reader_1
writer_1 | 27 09:54:15 UTC 2017
reader_1 | 27 09:54:15 UTC 2017
Gracefully stopping... (press Ctrl+C again to force)

Resources