How to keep Docker container volume files?

Kirby picture Kirby · Nov 8, 2016 · Viewed 7.1k times · Source

I'd like to share ~/mydir directory with host, but not replace Docker container directory with host files. So, I have docker-compose.yml

version: '2'
services:
  app:
    container_name: mono
    build: .
    volumes:
      # save .composer files on host to keep cache warmed up
      - '/srv/mono/mydir:/root/mydir'
    command: sleep infinity

And Dockerfile

#/bin/bash
FROM php:5.6

RUN mkdir /root/mydir && echo '{}' > /root/mydir/myfile.json

VOLUME /root/mydir

Directory /srv/mono/mydir is empty. It was replaced with host directory. It's clear.

But how to keep original files?

For example it work for MySQL Percona containers:

version: '2'
services:
  percona-56:
    container_name: percona-56
    image: percona/percona-server:5.6
    volumes:
    - /srv/mysql/percona-56:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'

There are original files from the container:

$ ll /srv/mysql/percona-56
total 176220
    auto.cnf
    error.log
    ibdata1
    ib_logfile0
    ib_logfile1
    init.ok
    mysql
    performance_schema

I've tried to inspect Percona Dockerfile but didn't find something related to the volume sharing.

$ docker --version
Docker version 1.12.3, build 6b644ec

Answer

Paul Becotte picture Paul Becotte · Nov 8, 2016

When you add a VOLUME at docker run, what you are saying is to use the main host filesystem instead of the copy-on-write filesystem that Docker uses for images. There are two main options here:

  1. You bind-mount an actual filesystem location into the image. This is what you are doing here.
  2. You let Docker handle the location... in this case, Docker creates the location on the main filesystem, and then copies the contents of the image into that location to get things started.

You are looking to get both- you want a fixed location on your filesystem, but you want files from your image to be there. Now, there is a reason it doesn't work this way! What happens if 'auto.conf' already exists in that folder and you launch your container? What happens if you run two containers with different versions of that file pointed at the same location? That is why if you pick a real location, it does not attempt to guess what to do with conflicts between the image and the filesystem, it just goes with the filesystem.

You CAN achieve what you want though. There are really two options. The better one would be to have your app read from two seperate folders- one that is populated inside the image, and one that is on your filesystem. That completely avoids this problem ;) The second option is to go in and tell Docker how to handle individual files in your image.

version: '2'
services:
  app:
    container_name: mono
    build: .
    volumes:
      # save .composer files on host to keep cache warmed up
      - '/srv/mono/mydir:/root/mydir'
      # Marking a volume this way will tell Docker to use THIS file 
      # from the image, even though the parent directory is a regular
      # volume.  If you have an auto.cnf file in your directory, it
      # will be ignored. 
      - /root/mydir/auto.cnf
    command: sleep infinity

......