Skip to main content

One post tagged with "Container Deployment"

View all tags

Docker Container Can't See Host Files? Anonymous Volume Overrides Bind Mount

· 3 min read

Encountered this issue while deploying a WordPress site for a client. Here's the root cause and solution.

TL;DR

The VOLUME declaration in an image's Dockerfile creates anonymous volumes with higher mount priority than docker-compose.yml bind mounts. Solution: Stop container → Delete anonymous volume → Restart.

Problem

After CI deployment, new static files or PHP code don't exist inside the container:

  • assets/images/logo.png exists on host, missing in container → Logo doesn't display
  • inc/setup.php has new filter code, container has old version → Filter doesn't work
  • Files updated after git pull, container still has old content

Root Cause

WordPress official image's Dockerfile includes:

VOLUME /var/www/html

Even if your docker-compose.yml configures bind mount:

volumes:
- ./wordpress/wp-content:/var/www/html/wp-content

Docker still creates an anonymous volume for the VOLUME declared path. Anonymous volumes have higher mount priority than bind mounts, causing:

  1. /var/www/html is taken over by anonymous volume
  2. Your bind mount targets /var/www/html/wp-content
  3. But the anonymous volume already "occupies" the parent directory, bind mount gets overridden

Verify with docker inspect:

docker inspect prod_wordpress --format '{{range .Mounts}}{{.Type}}: {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'

Output similar to:

volume: /var/lib/docker/volumes/wp-prod_wp_html/_data -> /var/www/html  # Anonymous volume!
bind: /var/www/wp-prod/wordpress/wp-content -> /var/www/html/wp-content

Solution

# 1. Stop containers
cd /var/www/wp-prod && docker compose down

# 2. Delete anonymous volume
docker volume rm wp-prod_wp_html

# 3. Restart
docker compose up -d

Verification

docker inspect prod_wordpress --format '{{range .Mounts}}{{.Type}}: {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'

Should only show bind mount, no anonymous volume:

bind: /var/www/wp-prod/wordpress/wp-content -> /var/www/html/wp-content

Prevention

When using bind mount deployment, check if the image declares VOLUME. If declared:

  1. Before first start, confirm no residual anonymous volumes exist
  2. Or modify docker-compose.yml to make bind mount path match VOLUME path (mount to same level)

After fixing, git pull updates are automatically read by the container—no docker cp or container restart needed.

Important

  • Backup data before deleting anonymous volumes or ensure it can be restored via git pull
  • Test in staging environment before production operations
  • If container has critical data, backup with docker cp first