Bind Mount Basics
Bind Mount Basics
A bind mount maps a specific file or directory from the host into a container. Unlike named volumes (managed by Docker), bind mounts reference an exact path on the host.
Basic Syntax
# Mount current directory into container
docker run -it -v $(pwd):/app alpine sh
# Using --mount syntax (recommended)
docker run -it --mount type=bind,source=$(pwd),target=/app alpine sh
# Mount specific file
docker run -v $(pwd)/config.json:/app/config.json:ro myapp
# Mount with specific ownership
docker run -v $(pwd):/app:Z myapp # SELinux relabel
Bind Mount vs Named Volume
| Feature | Bind Mount | Named Volume |
|---|---|---|
| Source | Specific host path | Docker-managed |
| Performance | Depends on OS | Always fast (Linux) |
| Sharing | Easy (same path) | Requires volume create |
| Backup | Copy host directory | Docker volume commands |
| Use case | Development | Data persistence |
Development Workflow
Bind mounts are essential for live development:
# Node.js development
docker run -d \
-v $(pwd):/app \
-w /app \
-p 3000:3000 \
node:20 \
npm run dev
# Python development
docker run -it \
-v $(pwd):/app \
-w /app \
python:3.12 \
python main.py
# Go development
docker run -it \
-v $(pwd):/go/src/app \
-w /go/src/app \
golang:1.21 \
go run main.go
Read-Only Bind Mounts
# Prevent container from modifying host files
docker run -d \
--mount type=bind,source=$(pwd)/config,target=/etc/app,readonly \
myapp
Common Use Cases
- Development: Live code reload without rebuilding
- Configuration: Mount config files into containers
- Logs: Write logs to host filesystem
- Build artifacts: Share build output between containers
Permissions and Ownership
Permissions and Ownership
UID/GID Mapping
Containers run with a UID/GID that may not match the host user. This can cause permission issues:
# Container runs as root (UID 0), host files owned by UID 1000
docker run -v $(pwd)/data:/data alpine ls -la /data
# Files may appear owned by root inside container
# Run container as specific user
docker run -v $(pwd)/data:/data \
--user $(id -u):$(id -g) \
alpine ls -la /data
Fixing Permissions
# Option 1: Run as host user
docker run -v $(pwd):/app \
--user $(id -u):$(id -g) \
node:20 npm install
# Option 2: Change ownership on host
sudo chown -R $(id -u):$(id -g) ./node_modules
# Option 3: Use named volume for node_modules
# (avoids permission issues entirely)
docker run -v $(pwd):/app -v node_modules:/app/node_modules \
node:20 npm install
SELinux Labels
On SELinux systems (RHEL, Fedora), bind mounts may fail with permission denied:
# Use :z to relabel for shared containers
docker run -v $(pwd):/app:z myapp
# Use :Z for private relabel (single container)
docker run -v $(pwd):/app:Z myapp
# Use :O for overlay mount (read-only with copy-up)
docker run -v $(pwd):/app:O myapp
macOS File Performance
Docker Desktop on macOS mounts through a VM layer, causing slow I/O:
# Slow: Every file access goes through VM
v /Users/me/project:/app
# Faster: Use named volume for heavy I/O
v app-nodemodules:/app/node_modules
Optimize for macOS:
- Use named volumes for
node_modulesand build caches - Exclude large directories in Docker Desktop settings
- Consider
:cachedor:delegatedmount consistency options
Docker Compose Bind Mounts
services:
web:
image: node:20
volumes:
- .:/app # Current directory
- ./config:/app/config:ro # Read-only config
- /absolute/path:/data # Absolute path
working_dir: /app
command: npm run dev
nginx:
image: nginx:1.25
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./static:/usr/share/nginx/html:ro
Security Considerations
# DANGEROUS: Mounts Docker socket (full host access)
docker run -v /var/run/docker.sock:/var/run/docker.sock docker
# DANGEROUS: Mounts host root
docker run -v /:/host alpine chroot /host
# SAFE: Mount specific config only
docker run -v $(pwd)/config.json:/app/config.json:ro myapp