RKernel
RKernel

Reputation: 85

Share single files between docker containers

I want to share single files between docker containers

ContainerA:
- file-1
- file-2
- file-3
- shared-file

ContainerB
- file-a
- file-b
- file-c
- shared-file

It is not possible to share a complete volume for me. The path in the container is not the same.

Upvotes: 5

Views: 2293

Answers (3)

DerMaddi
DerMaddi

Reputation: 729

If containerA creates a file at a certain path and overwrites symlinks I don't think it's possible to do this with a "clean" approach (otherwise check acran's answer).

The only way I can come up with is:

  • start ContainerA
  • wait for the file to be created
  • get the file (e.g. docker cp)
  • start ContainerB with the seed

However there a few problems e.g. if ContainerA crashed ContainerB needs to be recreated as well or you need to copy the file again.

If you wrap it in a Makefile it could look like:

.DEFAULT_GOAL := run

run:
    docker-compose up -d containerA
    sleep 10
    docker cp containerA:/seed-file seed-file
    docker-compose up -d containerB

Upvotes: 0

acran
acran

Reputation: 9018

Since docker defaults to directories as volumes and only bind-mounts a file when the source is an existing file it is a bit harder to use.

With the file you want to share in your current directory you can use bind-mounts in docker-compose.yml

services:
  app1:
    # ...
    volumes:
      - ./file:/path/to/file1:rw
  app2:
    # ...
    volumes:
      - ./file:/path/to/file2:rw

This is requires the file to already exist outside the containers. See also the caveats with bind-mounting files in jubnzv's answer.

Depending on your use case maybe a better workaround could be using symlinks and mounting the shared file in a directory volume:

# tree layout in containers:
ContainerA:
|- shared/
|   ` shared-file
`- app_folder_a/
    |- file-1
    |- file-2
    |- file-3
    `- shared-file-a -> /shared/shared-file


ContainerB:
|- shared/
|   ` shared-file
`- app_folder_b/
    |- file-a
    |- file-b
    |- file-c
    `- shared-file-b -> /shared/shared-file
# docker-compose.yml
services:
  app1:
    # ...
    volumes:
      - ./shared/:/shared/:rw
  app2:
    # ...
    volumes:
      - ./shared/:/shared/:rw

Or if you do not want/can have the file or the shared directory on the host you can use named volumes with symlinks:

services:
  app1:
    # ...
    volumes:
      - shared:/app_folder_a
  app2:
    # ...
    depends_on:
      - app1
    volumes:
      - shared:/shared

volumes:
  shared:

and the shared file symlinked in containerB:

ContainerB:
|- shared/
|   ` ...
`- app_folder_b/
    |- file-a
    |- file-b
    |- file-c
    `- shared-file-b -> /shared/shared-file-a

The important part here is that when creating the new volume shared the first time docker will prepopulate it with the contents of the target directory in the container. So to work correctly app1 need to be started first so the shared volume is populated with the contents of app_folder_a - therefore the depends_on.

With this you then have the shared volume, populated with the contents of containerA's /app_folder_a/ and mounted to the same as well as on containerB's /shared/ while /app_folder_b/shared-file-b is a symlink to /shared/shared-file-a.

Upvotes: 4

jubnzv
jubnzv

Reputation: 1584

You can use volumes to share individual files, rather than directories. But in some cases, you can't write correctly to the mounted files.

Here is a minimal example:

echo 'Test.' > /tmp/1.txt
docker run -it --user $(id -u):$(id -g) --rm -v /tmp/1.txt:/tmp/2.txt:rw alpine 

Inside the container you can access /tmp/1.txt from the host system using in the /tmp/2.txt path:

/ $ cat /tmp/2.txt
Test.
/ $ echo '123' > /tmp/2.txt 
/ $ cat /tmp/2.txt
123

But some utilities will try to create a new inode when writing to the file. For example:

/ $ cp etc/sysctl.conf  /tmp/2.txt 
cp: can't create '/tmp/2.txt': File exists

The point is that mounting a file as a volume mounts a specific inode inside the container. Some tools that modify files replace the inode with a new one. But you can't do this because you mount a specific inode that points to your file.

Thus, you will need to mount a directory containing the inodes that you can modify inside the container. For more information, see the docker volumes documentation.

Upvotes: 0

Related Questions