On my Ubuntu EC2 I host an application using docker containers. db data and upload data is being stored in volumes CaseBook-data-db and CaseBook-data-uploads which are being created with this commands:
docker volume create --name=CaseBook-data-db
docker volume create --name=CaseBook-data-uploads
Volumes being attached through docker-compose file:
version: '2'
services:
mongo:
container_name: "CaseBook-db"
restart: always
image: mongo:3.2.7
ports:
- "27017"
volumes:
- data_db:/data/db
labels:
- "ENVIRONMENT_TYPE=meteor"
app:
container_name: "CaseBook-app"
restart: always
image: "meteor/casebook"
build: .
depends_on:
- mongo
environment:
- MONGO_URL=mongodb://mongo:27017/CaseBook
ports:
- "80:3000"
volumes:
- data_uploads:/Meteor-CaseBook-Container/.uploads
labels:
- "ENVIRONMENT_TYPE=meteor"
volumes:
data_db:
external:
name: CaseBook-data-db
data_uploads:
external:
name: CaseBook-data-uploads
I need to store those docker volumes in different folder(for example /home/ubuntu/data/) of the host machine. How to change docker storage folder for volumes? Or there is a better way in doing this? Thank you in advance.
Named volumes will be stored inside docker's folder (/var/lib/docker). If you want to create a volume in a specific host folder, use a host volume with the following syntax:
docker run -v /home/ubuntu/data/app-data:/app-data my-image
Or from your compose file:
version: '2'
services:
mongo:
container_name: "CaseBook-db"
restart: always
image: mongo:3.2.7
ports:
- "27017"
volumes:
- /home/ubuntu/data/db:/data/db
labels:
- "ENVIRONMENT_TYPE=meteor"
app:
container_name: "CaseBook-app"
restart: always
image: "meteor/casebook"
build: .
depends_on:
- mongo
environment:
- MONGO_URL=mongodb://mongo:27017/CaseBook
ports:
- "80:3000"
volumes:
- /home/ubuntu/data/uploads:/Meteor-CaseBook-Container/.uploads
labels:
- "ENVIRONMENT_TYPE=meteor"
With host volumes, any contents of the volume inside the image will be overlaid with the exact contents of the host folder, including UID's of the host folder. An empty host folder is not initialized from the image the way an empty named volume is. UID mappings tend to be the most difficult part of using a host volume.
Edit: from the comments below, if you need a named volume that acts as a host volume, there is a local persist volume plugin that's listed on docker's plugin list. After installing the plugin, you can create volumes that point to host folders, with the feature that even after removing the named volume, the host directory is left behind. Sample usage from the plugin includes:
docker volume create -d local-persist -o mountpoint=/data/images --name=images
docker run -d -v images:/path/to/images/on/one/ one
docker run -d -v images:/path/to/images/on/two/ two
They also include a v2 compose file with the following volume example:
volumes:
data:
driver: local-persist
driver_opts:
mountpoint: /data/local-persist/data
One additional option that I've been made aware of in the past month is to use the local volume driver's mount options to manually create a bind mount. This is similar to a host volume in docker with the following differences:
If the directory doesn't exist, trying to start a container with a named volume pointing to a bind mount will fail. With host volumes, docker will initialize it to an empty directory owned by root.
If the directory is empty, a named volume will initialize the bind mount with the contents of the image at the mount location, including file and directory ownership/permissions. With a host volume, there is no initialization of the host directory contents.
To create a named volume as a bind mount, you can create it in advance with:
docker volume create --driver local \
--opt type=none \
--opt device=/home/user/test \
--opt o=bind \
test_vol
From a docker run command, this can be done with --mount:
docker run -it --rm \
--mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
foo
Or in a compose file, you can create the named volume with:
volumes:
data:
driver: local
driver_opts:
type: none
o: bind
device: /home/user/test
My preference would be to use the named volume with the local driver instead of the local-persist 3rd party driver if you need the named volume features.
Another way with build-in driver local:
docker volume create --opt type=none --opt device=/home/ubuntu/data/ --opt o=bind data_db
(This use DimonVersace example with: data_db declared as external named volume in docker-compose and /home/ubuntu/data/ as the folder on the host machine)
Related
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.
On an old server running docker I have a two containers running ipam and mysql. The mysql has mounted a volume and after stopping the containers, I copied the contents of the volume to a new server, into the directory:
/mnt/dockerdata/vols/ipam/phpipam-mysql
Next I create a volume on that new server: docker volume create --driver local --opt device=/mnt/dockerdata/vols/ipam/phpipam-mysql phpipam-mysql --opt type=volume
Next I created a docker-compose.yml file to try and make this repeatable. Not really needed here, but I want to learn for other projects. So I created this file: (I'm aware of the password, but it is just my lab)
services:
ipam-mysql:
container_name: ipamdb
image: mysql:5.6
environment:
- MYSQL_ROOT_PASSWORD=P#55F0rIP#M
restart: always
volumes:
- phpipam-mysql:/var/lib/mysql
ipam:
container_name: ipambase
depends_on:
- ipam-mysql
image: pierrecdn/phpipam
environment:
- MYSQL_ENV_MYSQL_USER=root
- MYSQL_ENV_MYSQL_ROOT_PASSWORD=P#55F0rIP#M
- MYSQL_ENV_MYSQL_HOST=mysql
ports:
- "192.168.0.10:80:80"
volumes:
phpipam-mysql:
external: true
name: phpipam-mysql
But this returns the following errors:
Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/
Creating ipamdb ... error
ERROR: for ipamdb Cannot create container for service ipam-mysql: failed to mount local volume: mount /mnt/dockerdata/vols/ipam/phpipam-mysql:/var/lib/docker/volumes/phpipam-mysql/_data: no such device
ERROR: for ipam-mysql Cannot create container for service ipam-mysql: failed to mount local volume: mount /mnt/dockerdata/vols/ipam/phpipam-mysql:/var/lib/docker/volumes/phpipam-mysql/_data: no such device
ERROR: Encountered errors while bringing up the project.
When I don't use the external:true option, a new empty volume is created which I don't want. I tried creating the volume with the type ext4 but that doesn't change the error.
Any tips?
The volume you create is set to mount a device, not a folder, therefore the no such device error.
To create a volume binded to a folder:
volume create --driver local --opt device=/mnt/dockerdata/vols/ipam/phpipam-mysql phpipam-mysql --opt type=none --opt o=bind
I need to mount a disk using docker-compose.
Currently I can assemble using docker service create, this way:
docker service create -d \
--name my-service \
-p 8888:80 \
--mount='type=volume,dst=/usr/local/apache2/htdocs,volume-driver=local,volume-opt=type=xfs,volume-opt=device=/dev/sdd' \
httpd
My docker-compose.yml looks like this:
version: '3.8'
services:
my-service:
image: httpd
ports:
- '80:80'
volumes:
- type: volume
source: my-vol
target: /usr/local/apache2/htdocs
volumes:
my-vol:
driver: local
driver_opts:
type: xfs
o: bind
device: '/dev/sdd'
When uploading the service with docker-compose up I get the error:
"failed to mount local volume: mount /dev/sdd:/var/lib/docker/volumes/apache_my-vol/_data, flags: 0x1000: not a directory"
How can I configure my docker-compose.yml to be able to mount a disk?
*Sorry, my bad english..
The o: line matches options you'd pass to the ordinary Linux mount(8) command. o: bind manually creates a bind mount that attaches part of the filesystem somewhere else; this is the mechanic behind Docker's bind-mount system. The important thing that changes here is that it causes the device: to actually be interpreted as a (host-system) directory to be remounted, and not a device.
Since you're trying to mount a physical device, you don't need the o: bind option. If you delete that option, the device: will be interpreted as a device name and you'll be able to mount your disk.
My goal is to simulate something like hard drive or USB, that you can prepopulate with data and then mount it to specific Docker container and access it from this container. Ideally, it should provide options such as mounting it in read-only mode.
I tried Docker volumes and the closest I got is something like shared host/container directory mounted as volume, docker-compose file looks like this:
...
image: image-name
container_name: container-name
volumes:
- ./data:/app/data
ports:
- "3000:3000"
Is there any way to do this or is there some better approach? Thanks.
If you want to populate a volume with data before using it, you can first create it:
docker volume create myapplicationdata
And then attach it to an ephemeral container in order to populate it with data:
tar -C /path/to/my/files -c -f- . | docker run --rm -i -v myapplicationdata:/data alpine tar -C /data -xv -f-
To use a pre-existing volume in your docker-compose.yml, declare it as an external volume:
version: "3"
services:
myapplication:
image: image-name
container_name: container-name
volumes:
- myapplicationdata:/app/data
ports:
- "3000:3000"
volumes:
myapplicationdata:
external: true
I have the following fragment of my yaml file.
version: '3'
services:
db:
image: dockerized_db
build: ./DB
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- 5432:5432
volumes:
pgdata:
How can I define size of my volume in docker-compose file for that volume used by db container?
The question is about docker-compose, so you are able to set Docker volumes size quota within docker-compose driver opts as the following way:
volumes:
tmpfs:
driver: local
driver_opts:
o: "size=100m,uid=1000"
device: tmpfs
type: tmpfs
For details, please go to see https://docs.docker.com/engine/reference/commandline/volume_create/#driver-specific-options
You can create a volume with a size limit and attach it to the container, a good example you can find here
The following example creates a tmpfs volume called foo with a size of 100 megabytes and uid of 1000.
docker volume create --driver local \
--opt type=tmpfs \
--opt device=tmpfs \
--opt o=size=100m,uid=1000 \
foo
read more