Auto populate empty host folders with container content? - docker

In Docker Compose, when I mount an empty host volume to a location that already has data in the container, than this data is copied to the empty host volume on the first run.
E.g. if I use the nginx image and mount my empty host volume nginx-config to /etc/nginx in the nginx container then on the first start of the container everything from /etc/nginx is copied to my host volume nginx-config.
Meanwhile I am using Kubernetes and wondering how that's done in kubernetes? When I mount a empty PersistentVolume to an container at /etc/nginx, nothing is automatically copied to it ):

You need to use an initContainer, mount the volume on a different path and do the copy explicitly.

Related

Is it possible to mount the host path or docker volume to the path in the image from dockerfile?

I want to mount my host path (or docker volume) to the path in the image from dockerfile.
Dockerfile can copy the host data or directory to the data or directory in the image.
But I want to bind or mount not copy!
It is similar to "docker run -v" option but I wonder that it is done by creating the image from dockerfile.
Is any solution for this issue?
No, as far as I am aware, a host path cannot be mounted via the Dockerfile due to the portability of docker images and the different host architectures/directory layouts etc. See dockerfile volumes note 4.
Using VOLUME within the dockerfile will create a docker volume on the host at run-time of the container, but it cannot be specified to be a host directory. This answer explains the use of dockerfile VOLUME quite well. To use a host directory, you will need to do it at run time.

How does volume mount from container to host and vice versa work?

docker run -ti --rm -v DataVolume3:/var ubuntu
Lets say I have a volume DataVolume 3 which pulls the contents of /var in the ubuntu container
even after killing this ubuntu container the volume remains and I can use this volume DataVolume3 to mount it to other containers.
This means with the deletion of container the volume mounts are not deleted.
How does this work ?
Does that volume mount mean that it copies the contents of /var into some local directory because this does not look like a symbolic link ?
If I have the container running and I create a file in the container then the same file gets copied to the host path ?
How does this whole process of volume mount from container to host and host to container work ?
Volumes are used for persistent storage and the volumes persists independent of the lifecycle of the container.
We can go through a demo to understand it clearly.
First, let's create a container using the named volumes approach as:
docker run -ti --rm -v DataVolume3:/var ubuntu
This will create a docker volume named DataVolume3 and it can be viewed in the output of docker volume ls:
docker volume ls
DRIVER VOLUME NAME
local DataVolume3
Docker stores the information about these named volumes in the directory /var/lib/docker/volumes/ (*):
ls /var/lib/docker/volumes/
1617af4bce3a647a0b93ed980d64d97746878564b141f30b6110d0818bf32b76 DataVolume3
Next, let's write some data from the ubuntu container at the mounted path var:
echo "hello" > var/file1
root#2b67a89a0050:/# cat /var/file1
hello
We can see this data with cat even after deleting the container:
cat /var/lib/docker/volumes/DataVolume3/_data/file1
hello
Note: Although, we are able to access the volumes like shown above but it not a recommended practice to access volumes data like this.
Now, next time when another container uses the same volume then the data from the volume gets mounted at the container directory specified as part of -v flag.
(*) The location may vary based on OS as pointed by David and probably can be seen by the docker volume inspect command.
Docker has a concept of a named volume. By default the storage for this lives somewhere on your host system and you can't directly access it from outside Docker (*). A named volume has its own lifecycle, it can be independently docker volume rm'd, and if you start another container mounting the same volume, it will have the same persistent content.
The docker run -v option takes some unit of storage, either a named volume or a specific host directory, and mounts it (as in the mount(8) command) in a specific place in the container filesystem. This will hide what was originally in the image and replace it with the volume content.
As you note, if the thing you mount is an empty named volume, it will get populated from the image content at container initialization time. There are some really important caveats on this functionality:
Named volume initialization happens only if the volume is totally empty.
The contents of the named volume never automatically update.
If the volume isn't empty, the volume contents completely replace what's in the image, even if it's changed.
The initialization happens only on native Docker, and not for example in Kubernetes.
The initialization happens only on named volumes, and not for bind-mounted host directories.
With all of these caveats, I'd avoid relying on this functionality.
If you need to mount a volume into a container, assume it will be empty when your entrypoint or the main container command starts. If you need a particular directory layout or file structure there, an entrypoint script can create it; if you're expecting it to hold particular data, keep a copy of it somewhere else in your image and copy it in if it's not already there (or, perhaps, always).
(*) On native Linux you can find a filesystem location for it, but accessing this isn't a best practice. On other OSes this will be hidden inside a virtual machine or other opaque storage. If you need to directly access the data (or inject config files, or read log files) a docker run -v /host/path:/container/path bind mount is a better choice.
Volumes are part of neither the container nor the host. Well, technically everything resides in the host machine. But the docker directories are only accessible by users in "docker" group. The files in these directories are separately managed by docker.
"Volumes are stored in a part of the host filesystem which is managed by Docker (/var/lib/docker/volumes/ on Linux)."
Hence volumes are like the union of files under the docker container and the host itself. Any addition on either end will be added to the volume(/var/lib/docker/volumes), not hard copy, rather something like symbol link
As volumes can be shared across different containers, deleting a container does not cascade to the volumes associated with it.
To remove unused volumes:
docker volume prune .

How can I mount a container file to my Docker host?

I'd like to mount a file from a Docker's container to my docker host.
Data volumes is not the solution for me, as these are mounts from the docker host to docker containers, and I need the opposite way around.
Thanks
When docker mounts a volume, it overlays the directory inside the container with that of the volume. There is an exception where it will initialize a named volume with the content of that directory in the image. There's no other built in method to copy files out of the image to the volume.
Therefore, to go the other direction and copy the contents of the image directory out to the host with a host volume, you'll need to add your own copy command inside the container. That can be part of your entrypoint script that runs in the container.
An example of the entrypoint script is the volume caching scripts in my base image. One script moves the files to a cached location inside the image during the build, and a second script copies files from the image cached location to the volume mount in the entrypoint.

Dockerfile vs. docker-compose VOLUME

This experiment tries to build a container using this Docker file:
FROM lambdalinux/baseimage-amzn:2016.09-000
COPY ./bundle /opt/bundle/
VOLUME /bundle
Then inside the container, create a /opt/bundle/file.txt and put some text in it. But that file did not show up in the bundle directory on the host as I expected after reading Should I include my code with COPY/ADD or a volume last paragraph:
There may be cases where you’ll want to use both. You can have the image include the code using a COPY, and use a volume in your Compose file to include the code from the host during development. The volume overrides the directory contents of the image.
Doesn't Dockerfile VOLUME do the same as docker-compose.yml VOLUME? If so, how can this be done so that changes in the host directory is reflected inside the container directory in this case?
I also created a file on the host bundle/play.txt but that did not show up inside the container /opt/bundle/...
A VOLUME instruction in the dockerfile creates a mount point but initially only maps it to Docker's internal data directory.
In order to map the volume to the host filesystem, you need to specify which path on the host should be mapped to the volume. You can do this in the docker-compose file using the volumes parameter. (Note: you can create volumes using docker-compose without declaring them in the Dockerfile.)
Note that when mapping a directory from the host to a container, the directory contents on the host will replace the contents in the container, not vice versa.

Specify location of volumes in docker

I need to create a container specifying the location of volumes (not a bind mount).
The container has a volume /var/www, is possible to choose the location on the host machine? (i want to save in /data/www not in /var/lib/docker....). I can't do with -v (bind mount) the /var/www folder has data.
I can't do with -v (bind mount) the /var/www folder has data.
The first order of business would be to get those data on your host (in your host /data/www): run your container, and docker inspect it in order to get the path of the volume it uses (the one in /var/lib/docker/volumes/...): you can copy those files onto your host.
Then you can bind mount that host /var/www folder to your container.
But the better practice remains to use volumes (with the new 1.9+ docker volumes API), and mount it with --volumes-from.

Resources