Skip to content

[BUG] Race condition when populating volumes with nested volumes #11663

Open
@benibr

Description

@benibr

Description

We have a customer setup where a volume is bind mounted into a container and the container populates it with some files on first start.
Later another volume was added which is a subdirectory inside the first volume. This subdirectory gets created by the file population of the container at first start.
Now I'm aware this is not a really self consistent concept and therefore might be bad practice, however the problem is that is sometimes fails and sometime succeeds which is worse then just getting a error.

Steps To Reproduce

I tried to stay a close to the original setup as possible while removing everything which is not necessary. This is what I came up with to reproduce:

# parameters
NO_VARS=255
NO_RUNS=99
NO_INC_SIZE=3
TEST_PATH=/tmp

cd $TEST_PATH

cat << EOF > Dockerfile
FROM debian:latest

# create dirs to populate
RUN mkdir -p /foo/bar /foo/baz
RUN touch /foo/bar/iamhere

# create a larger container size
RUN for i in \$(seq 1 $NO_INC_SIZE); do \
        cp -rv /usr /foo/baz/$i/ >/dev/null 2>&1; \
    done

CMD sleep .1
EOF

cat << EOF > docker-compose.yml
services:
  test:
    container_name: test
    image: race:condition
    network_mode: "host"
    volumes:
      - type: volume
        source: parent
        target: /foo
      - type: volume
        source: subdir
        target: /foo/bar
        read_only: true

volumes:
  parent:
    driver: local
    driver_opts:
      type: none
      device: \${TEST_PATH}/parent
      o: bind

  subdir:
    driver: local
    driver_opts:
      type: none
      device: \${TEST_PATH}/parent/bar
      o: bind,ro
EOF

# build container
docker build -t race:condition .

# create a larger env file
rm -f .env
for i in $(seq 0 $NO_VARS); do
        echo "VAR$i=$i" >> .env
done
echo "TEST_PATH=$TEST_PATH" >> .env

# loop to reproduce
rm -f debug.log
for no in $(seq 0 $NO_RUNS); do
        # prepare clean state
        docker compose down >/dev/null 2>&1
        mkdir -p parent >/dev/null 2>&1
        rm -rf parent/* >/dev/null 2>&1
        docker volume rm -f tmp_parent tmp_subdir >/dev/null 2>&1
        # test & report
        docker compose up test >> debug.log 2>&1 && echo "$no: success" || echo "$no: failed"
done

Since this is a race condition it might behave differently on other systems depending on CPU,IO,etc.
You can play around with the parameters in search for the "sweet spot". I did not find any config that always fails, but some that are more likely to succeed more often %)

Compose Version

Docker Compose version v2.25.0

Used on RHLE 9.3

Installed Packages
Name         : docker-compose-plugin
Version      : 2.25.0
Release      : 1.el9
Architecture : x86_64
Size         : 59 M
Source       : docker-compose-plugin-2.25.0-1.el9.src.rpm
Repository   : @System
From repo    : Default_Organization_docker-ce-stable_docker-ce-stable_el9_x86_64
Summary      : Docker Compose (V2) plugin for the Docker CLI
URL          : https://github.com/docker/compose/
License      : ASL 2.0
Description  : Docker Compose (V2) plugin for the Docker CLI.
             :
             : This plugin provides the 'docker compose' subcommand.
             :
             : The binary can also be run standalone as a direct replacement for
             : Docker Compose V1 ('docker-compose').

Docker Environment

Client: Docker Engine - Community
 Version:    26.0.0
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.13.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.25.0
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 2
 Server Version: 26.0.0
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc version: v1.1.12-0-g51d5e94
 init version: de40ad0
 Security Options:
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 5.14.0-284.11.1.el9_2.x86_64
 Operating System: Red Hat Enterprise Linux 9.3 (Plow)
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 1.736GiB
 Name: dstorweb01tl.unicph.domain
 ID: dfe1b231-0a99-45e5-8c16-93edec96d0b2
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

Anything else?

I'm posting this here because I'm not able to reproduce this with Docker alone. Eg.
mkdir -p state; rm -rf state/* state/.*; docker run --rm -ti -v ./state/log:/var/log -v state:/var debian bash

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions