docker volume and VOLUME inside Dockerfile - docker

I'm confused with what is different between creating docker volume create my-vol and VOLUME ["/var/www"].
My understanding is:
1) docker volume create my-vol creates a persistent volume on our machine and each container could be linked to my-vol.
2) VOLUME ["/var/www"] creates a volume inside its container.
And when I create another container, I could link my-vol as follows:
when running a container
$ docker run -d --name devtest --mount source=myvol2,target=/app nginx:latest
At that time, if I added VOLUME ["/var/www"] in my Dockerfile, all data of this docker file will be stored in both myvol2 and /var/www?

The Dockerfile VOLUME command says two things:
If the operator doesn't explicitly mount a volume on the specific container directory, create an anonymous one there anyways.
No Dockerfile step will ever be able to make further changes to that directory tree.
As an operator, you can mount a volume (either a named volume or a host directory) into a container with the docker run -v option. You can mount it over any directory in the container, regardless of whether or not there was a VOLUME declared for it in the Dockerfile.
(Since you can use docker run -v regardless of whether or not you declare a VOLUME, and it has confusing side effects, I would generally avoid declaring VOLUME in Dockerfiles.)
Just like in ordinary Linux, only one thing can be (usefully) mounted on any given directory. With the setup you describe, data will be stored in the myvol2 you create and mount, and it will be visible in /var/www in the container, but the data will only actually be stored in one place. If you deleted and recreated the container without the volume mount the data would not be there any more.

There are two types of persistent storage used in Docker,the first one is Docker Volumes and the second one is bind mounts. The differebce between them is that volumes are internal to Docker and stored in the Docker store (which is usually all under /var/lib/docker) and bind mounts use a physical location on your machine to store persistent data.
If you want to use a Docker Volume for nginx:
docker volume create nginx-vol
docker run -d --name devtest -v nginx-vol:/usr/share/nginx/html nginx
If you want to use a bind mount:
docker run -d --name devtest -v [path]:/usr/share/nginx/html nginx
[path] is the location in which you want to store the container's data.

Related

Docker start a container with already created volume

How would I go about starting a container with a volume that's already created? I have a volume for example named 'data' and 'docker volume ls' will show this. Now I need to start a container by attaching this existing volume.
Mounting a Data Volume
To mount a data volume to a container add the --mount flag to the docker run command. It adds the volume to the specified container, where it stores the data produced inside the virtual environment.
To run a container and mount a data volume to it, follow the basic syntax:
docker run --mount source=[volume_name],destination=[path_in_container]
Replace [path_in_container] with the path where you want to place the data volume in the container. Everything stored in that directory automatically gets saved on the data volume on the host as well.
For example, to launch an Ubuntu container and mount the data volume to it, run:
docker run -it --name=example1 --mount source=data,destination=/data ubuntu

docker -v option with only one field

From the doc docker volume
-v or --volume: Consists of three fields, separated by colon characters (:). The fields must be in the correct order, and the meaning of each field is not immediately obvious.
But I have seen someone using -v flag which only consists of one field:
docker run -v /data ubuntu
What does this option mean? Is this a bind mounts or volume type?
Docker support three type volume and the one above is anonymous volume
anonymous volume
An anonymous volume is useful for when you would rather have Docker
handle where the files are stored. It can be difficult, however, to
refer to the same volume over time when it is an anonymous volumes. To
create an anonymous volume:
docker run -v /path/in/container ...
To find this volume you need to the following step to check the long ID of volumes.
docker inspect container_id
look into Mounts and then run
docker volume ls | grep volume_id
You will see the volume is created.
host volume
A host volume lives on the Docker host's filesystem and can be
accessed from within the container. To create a host volume:
docker run -v /path/on/host:/path/in/container ...
named volume
A named volume is similar to an anonymous volume. Docker manages where
on disk the volume is created, but you give it a volume name. To
create a named volume:
docker volume create somevolumename
docker run -v name:/path/in/container ...
docker-different-types-of-volumes
All three fields are not mandatory
"docker run -v /data ubuntu" creates a new volume mounted to /data in a ubuntu container.

Docker volume persistent

I have two questions about docker volume.
First : When I run my docker with a volume which it creates with docker volume create or with docker-compose, new files on the default directory are not appended to the volume. I give an example :
docker volume create testdock-logs
docker run -d -p 80:80 --name testdock --restart=on-failure -v testdock-logs:/var/www/logs testdock:latest -s
After that when I create a new file or directory on /var/www/logs and build my image testdocker, I don't find my new file on the volume.
What am I doing wrong?
Docker doesn't replace files in a volume with those in a modified image. Doing so would defeat the purpose of a volume, this is the one persistent location you have to store data that isn't reverted back to the image state when the container is recreated.
If you need the files from your image instead of the files in your volume, then reconsider whether you actually need a volume.

Sharing volume between Docker containers

I am using Docker to deploy some services and I want to share the Docker volumes between different containers.
Suppose I have a Docker container A which mounts a volume at /data. Here is its Dockerfile:
VOLUME /data
From my understanding, this will attach a volume to the container but it will not mount a host directory to the container. So the data inside this volume is still inside the container A.
I have another container B which provides an FTP service. It accesses the data under volume /public. Its Dockerfile is:
VOLUME /public
Now I want to link them together so that I can use B to manage A's data. From the Docker doc https://docs.docker.com/engine/userguide/containers/dockervolumes/ I shall use the --volumes-from flag to mount A's data volume to B. But this command will mount A's data to /data in B instead of /public, and in this case, the container B is not able to access the data. I didn't see any way to rename the mount point.
Any suggestions or best practices to handle this case?
The data-only container gives a good solution for this case. But if you want to use volumes-from and mount the data to different mount point, this question may be helpful!
How to map volume paths using Docker's --volumes-from?
You may find a lot of pointers mentioning data-only containers and --volumes-from. However, since docker 1.9, volumes have become first class citizens, they can have names, and have more flexibility:
It's now easy to achieve the behavior you want, here's an example :
Create a named data volume with name service-data:
docker volume create --name service-data
You can then create a container that mounts it in your /public folder by using the -v flag:
docker run -t -i -v service-data:/public debian:jessie /bin/bash
For testing purpose we create a small text file in our mapped folder:
cd public
echo 'hello' > 'hello.txt'
You may then attach your named volume to a second container, but this time under the data folder:
docker run -t -i -v service-data:/data debian:jessie /bin/bash
ls /data #-->shows "hello.txt"
Just remember, if both containers are using different images, be careful with ownership and permissions!

What is the purpose of VOLUME in Dockerfile

I'm trying to go deeper in my understanding of Docker's volume, and I'm having an hard time to figure out the differences / use-case of:
The docker volume create command
The docker run -v /path:/host_path
The VOLUME entry in the Dockerfile file
I particularly don't understand what happens if you combine the VOLUME entry with the -v flag.
A volume is a persistent data stored in /var/lib/docker/volumes/...
You can either declare it in a Dockerfile, which means each time a container is started from the image, the volume is created (empty), even if you don't have any -v option.
You can declare it on runtime docker run -v [host-dir:]container-dir.
combining the two (VOLUME + docker run -v) means that you can mount the content of a host folder into your volume persisted by the container in /var/lib/docker/volumes/...
docker volume create creates a volume without having to define a Dockerfile and build an image and run a container. It is used to quickly allow other containers to mount said volume.
If you had persisted some content in a volume, but since then deleted the container (which by default does not deleted its associated volume, unless you are using docker rm -v), you can re-attach said volume to a new container (declaring the same volume).
See "Docker - How to access a volume not attached to a container?".
With docker volume create, this is easy to reattached a named volume to a container.
docker volume create --name aname
docker run -v aname:/apath --name acontainer
...
# modify data in /apath
...
docker rm acontainer
# let's mount aname volume again
docker run -v aname:/apath --name acontainer
ls /apath
# you find your data back!
VOLUME instruction becomes interesting when you combine it with volumes-from runtime parameter.
Given the following Dockerfile:
FROM busybox
VOLUME /myvolume
Build an image with:
docker build -t my-busybox .
And spin up a container with:
docker run --rm -it --name my-busybox-1 my-busybox
The first thing to notice is you will have a folder in this image named myvolume. But it is not particularly interesting since when we exit the container the volume will be removed as well.
Create an empty file in this folder, so run the following in the container:
cd myvolume
touch hello.txt
Now spin up a new container, but share the same volume with my-busybox-1:
docker run --rm -it --volumes-from my-busybox-1 --name my-busybox-2 my-busybox
You will see that my-busybox-2 contains the file hello.txt in myvolume folder.
Once you exit both containers, the volume will be removed as well.
#radium226
Specifying VOLUME in Dockerfile makes sure the folder is to be treated as a volume(i.e., outside container) at runtime, as opposed to be a regular directory inside the container. Note the performance and accessibility implications.
If having forgot to specify "-v" in "docker run" command line, the above is still true. It's just the volume name becomes anonymous. But there are still ways to access or recover data from such anonymous volumes.
Using MYSQL from docker hub:
Running the below command as an example:
$ docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
The -v /my/own/datadir:/var/lib/mysql part of the command mounts the /my/own/datadir directory from the underlying host system as /var/lib/mysql inside the container, where MySQL by default will write its data files.
Therefore, a directory that persists when the container is killed is mounted is available that also provided higher performance for some operations like databases actions.

Resources