Docker on Windows
上QQ阅读APP看书,第一时间看更新

Sharing data between containers with volumes

Volumes are defined in an image with the VOLUME instruction, specifying a directory path. When you run a container with a volume defined, the volume is mapped to a physical location on the host, which is specific to that one container. More containers running from the same image will have their volume mapped to a different host location.

In Windows, volume directories need to be empty - in your Dockerfile, you can't create files in a directory and then expose it as a volume. Volumes also need to be defined on a disk that exists in the image. In the Windows base images, there is only a C drive available, so volumes need to be created on the C drive.

The Dockerfile for dockeronwindows/ch02-volumes creates an image with two volumes:

# escape=`
FROM microsoft/nanoserver

VOLUME C:\app\config
VOLUME C:\app\logs

ENTRYPOINT powershell

When I run a container from that image, Docker creates a virtual filesystem from three sources. The image layers are read-only, the container's layer is writeable, and the volumes can be set to read-only or writeable:

Because volumes are separate from the container, they can be shared with other containers even if the source container isn't running. I can run a task container from this image, with a command to create a new file in the volume:

docker container run --name source dockeronwindows/ch02-volumes "echo 'start' > c:\app\logs\log-1.txt"

Docker starts the container, which writes the file, and then exits. The container and its volumes haven't been deleted, so I can connect to the volumes in another container using the --volumes-from option and by specifying my first container's name:

docker container run -it --volumes-from source dockeronwindows/ch02-volumes

This is an interactive container, and when I list the contents of the C:\app directory, I'll see the two directories logs and config, which are volumes from the first container:

> ls C:\app

Directory: C:\app

Mode LastWriteTime Length Name
---- ------------- ------ ----
d----l 6/22/2017 8:11 AM config
d----l 6/22/2017 8:11 AM logs

The shared volume has read and write access, so I can see the file created in the first container and append to it:

PS C:\> cat C:\app\logs\log-1.txt
start

PS C:\> echo 'more' >> C:\app\logs\log-1.txt

PS C:\> cat C:\app\logs\log-1.txt
start
more

Sharing data between containers like this is very useful - you can run a task container that takes a backup of data or log files from a long-running background container. The default access is for volumes to be writeable, but that's something to be wary of, as you could edit data and break the application running in the source container.

Docker lets you mount volumes from another container in the read-only mode instead by adding the :ro flag to the name of the container in the --volumes-from option. This is a safer way to access data if you want to read it without making changes. I'll run a new container, sharing the same volumes from the original container in read-only mode:

> docker container run -it --volumes-from source:ro dockeronwindows/ch02-volumes

PS C:\> cat C:\app\logs\log-1.txt
start
more

PS C:\> echo 'more' >> C:\app\logs\log-1.txt
out-file : Access to the path 'C:\app\logs\log-1.txt' is denied.
At line:1 char:1
+ echo 'more' >> C:\app\logs\log-1.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], UnauthorizedAccessException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

In the new container, I can't write to the log file. However I can see the content in the log file from the original container, and the line appended by the second container.