I am learning Docker and I have doubts about when and where to use ADD
and VOLUME
. Here is what I think both of these do:
ADD
Copy files to the image at build time. The image has all the files so you can deploy very easily. On the other hand, needing to build every time doesn't look like a good idea in development because building requires the developer to run a command to rebuild the container; additionally, building the container can be time-consuming.
VOLUME
I understand that using docker run -v
you can mount a host folder inside your container, this way you can easily modify files and watch the app in your container react to the changes. It looks great in development, but I am not sure how to deploy my files this way.
The
VOLUME
instruction creates a data volume in your Docker container at runtime. The directory provided as an argument toVOLUME
is a directory that bypasses the Union File System, and is primarily used for persistent and shared data.If you run
docker inspect <your-container>
, you will see under theMounts
section there is aSource
which represents the directory location on the host, and aDestination
which represents the mounted directory location in the container. For example,Here are 3 use cases for
docker run -v
:docker run -v /data
: This is analogous to specifying theVOLUME
instruction in your Dockerfile.docker run -v $host_path:$container_path
: This allows you to mount$host_path
from your host to$container_path
in your container during runtime. In development, this is useful for sharing source code on your host with the container. In production, this can be used to mount things like the host's DNS information (found in/etc/resolv.conf
) or secrets into the container. Conversely, you can also use this technique to write the container's logs into specific folders on the host. Both$host_path
and$container_path
must be absolute paths.docker run -v my_volume:$container_path
: This creates a data volume in your container at$container_path
and names itmy_volume
. It is essentially the same as creating and naming a volume usingdocker volume create my_volume
. Naming a volume like this is useful for a container data volume and a shared-storage volume using a multi-host storage driver like Flocker.Notice that the approach of mounting a host folder as a data volume is not available in Dockerfile. To quote the docker documentation,
Now if you want to copy your files to containers in non-development environments, you can use the
ADD
orCOPY
instructions in your Dockerfile. These are what I usually use for non-development deployment.ADD
The fundamental difference between these two is that
ADD
makes whatever you're adding, be it a folder or just a file actually part of your image. Anyone who uses the image you've built afterwards will have access to whatever youADD
. This is true even if you afterwards remove it because Docker works in layers and theADD
layer will still exist as part of the image. To be clear, you onlyADD
something at build time and cannot everADD
at run-time.A few examples of cases where you'd want to use
ADD
:ADD ./requirements.txt /requirements.txt
followed byRUN pip install -r /requirements.txt
You want to use your app code as context in your Dockerfile, for example, if you want to set your app directory as the working dir in your image and to have the default command in a container run from your image actually run your app, you can do:
ADD ./ /usr/local/git/my_app
WORKDIR /usr/local/git/my_app
CMD python ./main.py
VOLUME
Volume, on the other hand, just lets a container run from your image have access to some path on whatever local machine the container is being run on. You cannot use files from your
VOLUME
directory in your Dockerfile. Anything in your volume directory will not be accessible at build-time but will be accessible at run-time.A few examples of cases where you'd want to use
VOLUME
:/var/log/my_app
. You want those logs to be accessible on the host machine and not to be deleted when the container is removed. You can do this by creating a mount point at/var/log/my_app
by addingVOLUME /var/log/my_app
to your Dockerfile and then running your container withdocker run -v /host/log/dir/my_app:/var/log/my_app some_repo/some_image:some_tag
VOLUME /etc/settings/my_app_settings
to your Dockerfile, run your container withdocker run -v /host/settings/dir:/etc/settings/my_app_settings some_repo/some_image:some_tag
, and make sure the /host/settings/dir exists in all environments you expect your app to be run.