What is the purpose of VOLUME in Dockerfile - docker

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.

Related

docker: get files from one container to another

I have 2 docker containers which I created from 2 Dockerfiles.
docker run container1 # It updates a txt (update.txt) file every minutes and store it in the same container
docker run container2 --link container1 # A web server which in intended to read the updated file in container1
Now I want to access the file update.txt in container2 but I can't do that. I don't want to just copy the file since it will become static but I want to read the dynamically updated file to read the latest updates. Can anyone suggest a way out?
Use named volume to store update.txt in that volume on host.
Mount this volume in both containers.
All changes that container 1 writes then will be accessible in container 2.
Firstly, create a docker volume by using the below command
$ docker volume create --name sharedVolume
sharedVolume
And then start the first container by mounting the above-created volume and write data in that location where volume will be mounted.
$ docker run -it -v sharedVolume:/dataToWrite ubuntu
root#1021d9260d7b:/# echo "DATA Written" >> /dataToWrite/Example.txt
root#1021d9260d7b:/# cat /dataToWrite/Example.txt
DATA Written
Now, start the second container and mount the same volume you created above and check whether the same file present in the second container or not
$ docker run -it -v sharedVolume:/dataToWrite alpine
/ # cat /dataToWrite/Example.txt
DATA Written
As you can see above, the first container is ubuntu and the second container is alpine. Contents which are written in the first container is present in second container.

How to create a file not a directory automatically when mount a host file from container

I'm writing a cli which will generate a markdown file when finished, and I build a docker image for that cli.
I want to mount the markdown file generated by the container to host machine.
docker -v will create a folder not a file automatically when the path not exist on host.
For example.
~/result.md not exist at first.
docker run -it --rm -v ~/result.md:/usr/src/work_dir/result.md cli:latest generate_markdown
After running, ~/result.md folder is created but not file, and the cli throw an exception because of write to a directory not a file.
To avoid this, I have to create a file at first, and run the docker cli subsequently. It works fine.
Is it possible to avoid create the file at the beginning ?
Try -
$docker volume create myvol
$docker run -it --rm -v myvol:/usr/src/work_dir/ cli:latest generate_markdown
Alternately, you can just
$docker run -it --rm -v myvol:/usr/src/work_dir/ cli:latest generate_markdown
Want an explanation ?
You are using a bind mount; in your case
docker run -it --rm -v ~/result.md:/usr/src/work_dir/result.md cli:latest generate_markdown
The solution to your problem might just be a volume mount.
For more info refer - https://docs.docker.com/storage/volumes/
First create a docker volume by-
$docker volume create myvol
. You can give any name instead of myvol.
This docker volume will be created, you can check if the volume was created successfully by-
$docker volume ls
This will give a list of your all your volumes, your newly created volume should be listed.
ak#ubuntu:~$ docker volume create myvol
myvol
ak#ubuntu:~$ docker volume ls
DRIVER VOLUME NAME
local myvol
Docker Volumes are stored in a separate area on the host file system and are completely managed by docker as opposed to bind mounts.Docker volumes store state outside of containers, so your data survives when you replace the container to update your app.
Docker volumes also get automatically created in case you specify a name instead of a directory path. In the following example a volume by the name myvol2 will be automatically created -
$docker run -it -v myvol2:/home/myfiles imagename:tag
Docker volumes are usually created in /var/lib/docker/volumes
in linux and in C:\ProgramData\docker\volumes in Windows.
Now here's the useful part. Any data/file/directories that already exist in the specified container directory are automatically copied or 'mounted' onto the docker volume. Therefore if the '''/usr/src/work_dir/''' directory mentioned in the above example contains any files (like a markup file in your case), they are copied onto the volume automatically.
Hope this helps.
The volume mount will assume a directory name passed in, not a file. You can either mount the volume ~ or have a directory created and mount that volume.
mkdir ~/markdown
docker run -it --rm -v ~/markdown/:/usr/src/work_dir/ cli:latest generate_markdown
You should avoid mounting files all together accordijg to best practices. That being said it is not possible to change the x fault behaviour that you describe.
The solution to you problem (to not create the file each time before running the container) is to mount the directories, omitting the file names.
docker run -it --rm -v ~/:/usr/src/work_dir/ cli:latest generate_markdown

docker volume and VOLUME inside Dockerfile

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.

Creating docker named volume pointing to folder on host

I think that my question is simple but I want to make sure I am taking the right approach. On my host computer, I have a path, e.g. /my/docs, which contains HTML files which get updated automatically.
I have a Docker container with a small web server these html files. I would like to create a named coker volume to called my-docs to point to /my/docs, so that I can start the container as docker run -v my-docs:/public ...
Is this the right approach, and if so, what is the docker create volume command?
The default "local" driver for named volumes places the data inside of the docker directories. The correct way to do what you want is to use the built in host volume, instead of a named volume:
docker run -v /my/docs:/public ...
Alternatively, you can first copy the contents from /my/docs into the named volume and then use that named volume:
docker run --rm \
-v /my/docs:/source -v my-docs:/target \
busybox cp -av /source/. /target/
docker run --rm -it -v my-docs:/public busybox /bin/sh
It's also possible that someone has created a driver for this, or for you to create one yourself. See the volume driver plugin docs for more details.

Mounting a single file from a Docker data volume in a Docker

I'm trying to mount a single file from a Docker volume in a container when using "docker run".
I've been able to mount an entire volume as a directory, e.g:
docker run -v my_volume:/root/volume my_container
I've also mounted single files from the physical machine, e.g:
docker run -v /usr/local/bin/docker:/usr/local/bin/docker
Is there a way?
Is there a way always destination path/file doesn't exist in the container, if you've created a named volume and a bind to its directory (similar to deprecated volumes_from)
docker run -v /var/lib/docker/volumes/my_volume/_data/MY_FILE.txt:/destination_folder/MY_FILE.txt
That's why when you create a named volume and run a service/container with docker run -v my_volume:/root/volume my_container, data is stored in /var/lib/docker/volumes/my_volume/_data

Resources