Docker-Compose “No Such File” Error: Troubleshooting When the File Exists


3 views

When Docker-Compose throws a "No such file or directory" error despite the file physically existing, this typically indicates a permission or path resolution issue at the system level rather than a simple file-not-found scenario. Let's examine the key symptoms from the case:

ERROR: compose.cli.main.main: .IOError: [Errno 2] No such file or directory: '/etc/docker/docker-compose.d/20-registry.yaml'

Yet the file verification shows:

root@srv-backup:/# ll /etc/docker/docker-compose.d/20-registry.yaml
-rwxrwxr-x+ 1 root root 842 Jan 24 15:19 /etc/docker/docker-compose.d/20-registry.yaml*

In Linux environments, several factors could cause this behavior:

  • ACLs or Extended Attributes: The + in permissions (-rwxrwxr-x+) indicates existing ACLs
  • Namespace Isolation: Docker daemon might be running in a different mount namespace
  • SELinux/AppArmor: Security contexts preventing access
  • Symbolic Link Resolution: The path might contain symlinks that resolve differently for the daemon

First, verify the actual path visibility to the Docker daemon:

docker exec -it $(docker ps -q --filter ancestor=registry) ls -la /etc/docker/docker-compose.d/

Check for mount namespace differences:

ls -la /proc/$(pgrep dockerd)/root/etc/docker/docker-compose.d/

Solution 1: Verify ACL restrictions

getfacl /etc/docker/docker-compose.d/20-registry.yaml

Solution 2: Temporary bypass for testing

cp /etc/docker/docker-compose.d/20-registry.yaml /tmp/
chmod 644 /tmp/20-registry.yaml
docker-compose -f /tmp/20-registry.yaml up

Solution 3: Check for mount propagation

If using Docker with special storage drivers or snap packages:

findmnt -o TARGET,PROPAGATION /etc/docker

For persistent cases, strace can reveal the actual syscall failure:

strace -f -e trace=file docker-compose -f /etc/docker/docker-compose.d/20-registry.yaml up 2>&1 | grep '20-registry.yaml'

Check kernel audit logs for SELinux/AppArmor denials:

ausearch -m avc -ts recent | grep docker
dmesg | grep -i denied

For production systems, consider these architectural improvements:

# Recommended directory structure
/etc/docker/
├── compose.d/
│   ├── 20-registry.yaml
│   └── ... 
├── config/
└── data/

# Example systemd unit override
[Service]
ReadWritePaths=/etc/docker/compose.d
ReadWritePaths=/etc/docker/config

Remember that Docker snap installations often have stricter confinement rules than native packages.


Recently while performing a bare metal recovery of my Docker server, I encountered a particularly stubborn issue with docker-compose. Despite verifying the physical existence of my compose file, the tool kept insisting it couldn't be found:

docker-compose --verbose -f /etc/docker/docker-compose.d/20-registry.yaml up
compose.config.config.find: Using configuration files: /etc/docker/docker-compose.d/20-registry.yaml
ERROR: compose.cli.main.main: .IOError: [Errno 2] No such file or directory: '/etc/docker/docker-compose.d/20-registry.yaml'

Yet, the file was clearly present with proper permissions:

ls -l /etc/docker/docker-compose.d/20-registry.yaml
-rwxrwxr-x+ 1 root root 842 Jan 24 15:19 /etc/docker/docker-compose.d/20-registry.yaml

After thorough investigation, I discovered several potential causes for this behavior:

  1. Filesystem Namespace Isolation: Docker daemon might be running in a different mount namespace
  2. SELinux/AppArmor Restrictions: Security policies blocking access
  3. Symbolic Link Resolution: Broken links in the path chain
  4. Mount Point Visibility: The /etc/docker directory might not be visible to the container runtime

Here are some diagnostic commands that helped me identify the root cause:

# Check mount namespace
lsns -t mnt

# Verify SELinux context
ls -Z /etc/docker/docker-compose.d/20-registry.yaml

# Check real path resolution
realpath /etc/docker/docker-compose.d/20-registry.yaml

# Test file access as docker user
sudo -u docker cat /etc/docker/docker-compose.d/20-registry.yaml

In my case, the solution involved two steps:

# 1. Temporarily disable SELinux enforcement
setenforce 0

# 2. Copy the file to a different location and try
cp /etc/docker/docker-compose.d/20-registry.yaml /tmp/
docker-compose -f /tmp/20-registry.yaml up

If this works, you've confirmed it's a security policy or mount namespace issue. For a permanent fix:

# For SELinux:
chcon -R -t container_file_t /etc/docker

# For AppArmor:
# Add the following to your docker-default profile
/etc/docker/** r,

If the above doesn't work, consider these alternatives:

# 1. Bind mount the directory when running docker-compose
docker-compose -f /host/path/to/file.yaml up --project-directory=/host/path

# 2. Use docker-compose from within a container
docker run --rm -v /etc/docker:/etc/docker docker/compose:1.29.2 \
  -f /etc/docker/docker-compose.d/20-registry.yaml up

To avoid similar issues in the future:

  • Store compose files in /opt/docker instead of /etc/docker
  • Use relative paths for volumes and other file references
  • Document all required SELinux/AppArmor policies
  • Test recovery procedures regularly