Infrastructure Workflow
Manage Docker/Podman networking, storage (volumes), and container registries.
Quick Start
Common infrastructure operations for container deployment:
# Network operations
docker network create myapp-net
docker network connect myapp-net container_name
# Volume operations
docker volume create myapp-data
docker run -v myapp-data:/data myapp
# Registry operations
docker login ghcr.io
docker tag myapp:latest ghcr.io/username/myapp:latest
docker push ghcr.io/username/myapp:latest
Quick commands reference:
# List infrastructure
docker network ls
docker volume ls
docker images
# Inspect infrastructure
docker network inspect myapp-net
docker volume inspect myapp-data
# Clean up
docker network prune
docker volume prune
Detect runtime before operations:
# Run DetectRuntime.sh to determine Docker/Podman
# All commands shown support both runtimes
Network Management
Create and manage container networks for connectivity and isolation.
Creating Networks
Bridge network (default, most common):
docker network create mynetwork
podman network create mynetwork
With subnet and gateway:
docker network create \
--subnet=172.20.0.0/16 \
--gateway=172.20.0.1 \
mynetwork
podman network create \
--subnet=172.20.0.0/16 \
--gateway=172.20.0.1 \
mynetwork
With IP range restriction:
docker network create \
--subnet=172.20.0.0/16 \
--ip-range=172.20.240.0/20 \
--gateway=172.20.0.1 \
mynetwork
With driver options:
docker network create \
--driver bridge \
--opt "com.docker.network.bridge.name=br-myapp" \
--opt "com.docker.network.bridge.enable_ip_masquerade=true" \
mynetwork
Network Drivers
Bridge (Default):
- Best for: Single-host deployments, isolated container groups, development
- Characteristics: Software bridge, NAT for external access, DNS between containers
- Isolation: Isolated from host network
Host:
docker run --network host myapp
podman run --network host myapp
- Best for: Maximum performance, direct port binding, legacy apps
- Characteristics: No isolation, uses host network stack, no port mapping needed
- Trade-off: Higher performance, lower security
Overlay (Docker Swarm):
docker network create --driver overlay myoverlay
# With encryption
docker network create --driver overlay --opt encrypted myoverlay
- Best for: Multi-host deployments, Docker Swarm, microservices across hosts
- Characteristics: Spans multiple Docker hosts, requires swarm mode
- Features: Optional encrypted traffic
Macvlan:
docker network create \
--driver macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
mymacvlan
- Best for: Legacy applications, direct Layer 2 access, containers needing MAC address
- Characteristics: Containers get own MAC, appear as physical devices
None (No networking):
docker run --network none myapp
podman run --network none myapp
- Best for: Maximum isolation, custom networking, security-critical containers
- Characteristics: No network interface, complete isolation
Connecting and Disconnecting
Connect running container:
docker network connect mynetwork container_name
podman network connect mynetwork container_name
Connect with specific IP:
docker network connect --ip 172.20.0.100 mynetwork container_name
podman network connect --ip 172.20.0.100 mynetwork container_name
Connect with alias:
docker network connect --alias db mynetwork container_name
podman network connect --alias db mynetwork container_name
Disconnect container:
docker network disconnect mynetwork container_name
podman network disconnect mynetwork container_name
Start container on network:
docker run --network mynetwork --name web nginx
podman run --network mynetwork --name web nginx
# With custom IP
docker run --network mynetwork --ip 172.20.0.100 --name web nginx
# With network alias
docker run --network mynetwork --network-alias webapp --name web nginx
Network Inspection
View network details:
docker network inspect mynetwork
podman network inspect mynetwork
Get specific fields:
# List connected containers
docker network inspect -f '{{range .Containers}}{{.Name}} {{end}}' mynetwork
# Get subnet
docker network inspect -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}' mynetwork
# Get gateway
docker network inspect -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}' mynetwork
JSON output with jq:
docker network inspect mynetwork | jq '.[0].IPAM.Config'
podman network inspect mynetwork | jq '.[0].subnets'
List all containers on network:
docker network inspect mynetwork -f '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
DNS Resolution
Automatic DNS (user-defined networks):
# Create network
docker network create myapp
# Start containers
docker run -d --network myapp --name web nginx
docker run -d --network myapp --name db postgres
# Containers can resolve each other by name
docker exec web ping db
docker exec web curl http://db:5432
Custom DNS
Set DNS servers:
docker run --dns 8.8.8.8 --dns 8.8.4.4 myapp
podman run --dns 8.8.8.8 myapp
Set DNS search domain:
docker run --dns-search example.com myapp
podman run --dns-search example.com myapp
Add multiple aliases:
docker network connect --alias db --alias database mynetwork container_name
Network Isolation
Networks provide isolation between container groups:
# Frontend network
docker network create frontend
# Backend network (internal only)
docker network create --internal backend
# Web server on both networks
docker run -d --network frontend --name web nginx
docker network connect backend web
# Database only on backend (isolated from external)
docker run -d --network backend --name db postgres
Port Mapping Strategies
Basic port mapping:
docker run -p 8080:80 nginx # host:container
podman run -p 8080:80 nginx
Bind to specific interface:
docker run -p 127.0.0.1:8080:80 nginx
podman run -p 127.0.0.1:8080:80 nginx
Map port range:
docker run -p 8080-8090:8080-8090 myapp
podman run -p 8080-8090:8080-8090 myapp
UDP ports:
docker run -p 53:53/udp dns-server
podman run -p 53:53/udp dns-server
Publish all exposed ports:
docker run -P nginx # Maps to random host ports
podman run -P nginx
Check port mappings:
docker port container_name
podman port container_name
Managing Networks
List networks:
docker network ls
podman network ls
# Filter by driver
docker network ls --filter driver=bridge
# Filter by name
docker network ls --filter name=myapp
Remove network:
docker network rm mynetwork
podman network rm mynetwork
Remove all unused networks:
docker network prune
podman network prune
Podman-Specific Networking
CNI plugins (Podman uses CNI):
# CNI config location
/etc/cni/net.d/
# List available plugins
ls /usr/libexec/cni/
Rootless networking:
# Rootless uses slirp4netns by default
podman network inspect podman
# Create rootless network
podman network create mynetwork
Pod networking (containers in pod share network):
# Create pod
podman pod create --name mypod -p 8080:80
# Add containers (share network via localhost)
podman run -d --pod mypod --name web nginx
podman run -d --pod mypod --name app myapp
Volume Management
Create and manage persistent storage for container data.
Volume Types
Named Volumes (Recommended):
- Managed by Docker/Podman
- Easy to backup and migrate
- Work across platforms
- Best for most use cases
Bind Mounts:
- Direct host path mapping
- Useful for development
- Direct file access from host
- Platform-specific paths
tmpfs Mounts (Linux only):
- Stored in host memory
- Not persisted to disk
- Fast but temporary
- Good for sensitive data
Creating Volumes
Simple named volume:
docker volume create myvolume
podman volume create myvolume
With driver options (NFS example):
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.1,rw \
--opt device=:/path/to/dir \
nfs-volume
With labels:
docker volume create \
--label project=myapp \
--label environment=production \
myvolume
podman volume create \
--label project=myapp \
myvolume
Volume Drivers
Local driver (default):
docker volume create --driver local myvolume
Local with bind mount options:
docker volume create \
--driver local \
--opt type=none \
--opt device=/path/to/host/dir \
--opt o=bind \
myvolume
NFS driver:
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw,nfsvers=4 \
--opt device=:/exported/path \
nfs-volume
Bind Mounts vs Volumes
Named volume (preferred):
docker run -v myvolume:/data myapp
docker run --mount source=myvolume,target=/data myapp
podman run -v myvolume:/data myapp
Bind mount:
docker run -v /host/path:/container/path myapp
docker run --mount type=bind,source=/host/path,target=/container/path myapp
podman run -v /host/path:/container/path myapp
When to use volumes:
- Database data
- Application state
- Uploaded files
- Configuration that persists
When to use bind mounts:
- Development (live code reload)
- Configuration files from host
- Log file access
- Sharing files with host
Mounting Volumes in Containers
Mount named volume:
docker run -v myvolume:/data myapp
podman run -v myvolume:/data myapp
Mount read-only:
docker run -v myvolume:/data:ro myapp
docker run --mount source=myvolume,target=/data,readonly myapp
podman run -v myvolume:/data:ro myapp
Mount with volume options:
docker run --mount type=volume,source=myvolume,target=/data,volume-opt=o=size=100m myapp
Bind mount with propagation:
# Shared propagation
docker run -v /host/path:/container/path:shared myapp
# Private propagation (default)
docker run -v /host/path:/container/path:private myapp
# Slave propagation
docker run -v /host/path:/container/path:slave myapp
tmpfs mount:
docker run --tmpfs /app/cache myapp
docker run --mount type=tmpfs,target=/app/cache myapp
podman run --tmpfs /app/cache myapp
tmpfs with size limit:
docker run --tmpfs /app/cache:size=100m myapp
docker run --mount type=tmpfs,target=/app/cache,tmpfs-size=100m myapp
When to use tmpfs:
- Temporary files
- Cache
- Sensitive data (not persisted)
- Session storage
Volume Inspection
View volume details:
docker volume inspect myvolume
podman volume inspect myvolume
Get specific fields:
# Get mountpoint
docker volume inspect -f '{{.Mountpoint}}' myvolume
podman volume inspect -f '{{.Mountpoint}}' myvolume
# Get driver
docker volume inspect -f '{{.Driver}}' myvolume
# Get labels
docker volume inspect -f '{{.Labels}}' myvolume
JSON output with jq:
docker volume inspect myvolume | jq '.[0].Mountpoint'
podman volume inspect myvolume | jq '.[] | .Mountpoint'
Find containers using volume:
docker ps -a --filter volume=myvolume
podman ps -a --filter volume=myvolume
List volumes used by container:
docker inspect -f '{{range .Mounts}}{{.Name}} {{.Destination}}{{"\n"}}{{end}}' container_name
podman inspect -f '{{range .Mounts}}{{.Name}} {{.Destination}}{{"\n"}}{{end}}' container_name
Backup and Restore
Backup volume to tar archive:
docker run --rm \
-v myvolume:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/myvolume-backup.tar.gz -C /data .
podman run --rm \
-v myvolume:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/myvolume-backup.tar.gz -C /data .
Backup with timestamp:
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
docker run --rm \
-v myvolume:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/myvolume-${TIMESTAMP}.tar.gz -C /data .
Restore from tar archive:
# Create volume if needed
docker volume create myvolume
# Restore data
docker run --rm \
-v myvolume:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/myvolume-backup.tar.gz -C /data
podman run --rm \
-v myvolume:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/myvolume-backup.tar.gz -C /data
Copy between volumes:
docker run --rm \
-v source-volume:/source:ro \
-v dest-volume:/dest \
alpine \
cp -av /source/. /dest/
Export volume to host:
docker run --rm \
-v myvolume:/data \
-v $(pwd)/export:/export \
alpine \
cp -av /data/. /export/
Volume Plugins
Third-party drivers available:
- REX-Ray (cloud storage)
- Convoy
- Flocker
- GlusterFS
- NetApp
tmpfs Mounts
In-memory storage for temporary data:
docker run --tmpfs /app/cache myapp
# With size and mode options
docker run --tmpfs /app/cache:rw,size=100m,mode=1777 myapp
Managing Volumes
List volumes:
docker volume ls
podman volume ls
# Filter by name
docker volume ls --filter name=myapp
# Filter by driver
docker volume ls --filter driver=local
# Show dangling volumes
docker volume ls --filter dangling=true
Access volume data directly:
# Find volume location (Docker requires root)
docker volume inspect -f '{{.Mountpoint}}' myvolume
# Usually: /var/lib/docker/volumes/myvolume/_data
# Podman (rootless)
podman volume inspect -f '{{.Mountpoint}}' myvolume
# Usually: ~/.local/share/containers/storage/volumes/myvolume/_data
Browse volume with helper container:
docker run -it --rm \
-v myvolume:/data \
alpine \
sh
Remove volume:
docker volume rm myvolume
podman volume rm myvolume
Remove all unused volumes:
docker volume prune
podman volume prune
# Filter and remove
docker volume prune --filter "label=project=old"
Podman-Specific Volumes
Rootless volume location:
~/.local/share/containers/storage/volumes/
Import/Export (Podman):
# Export volume
podman volume export myvolume > myvolume.tar
# Import volume
podman volume import myvolume < myvolume.tar
Registry Management
Push, pull, and manage container images across registries.
Registry Types
- Docker Hub (docker.io)
- GitHub Container Registry (ghcr.io)
- GitLab Container Registry (registry.gitlab.com)
- Private/self-hosted registries
- Cloud provider registries (AWS ECR, Google GCR, Azure ACR)
Authentication
Docker Hub:
docker login
docker login -u username -p password
podman login docker.io
podman login -u username -p password docker.io
GitHub Container Registry:
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
echo $GITHUB_TOKEN | podman login ghcr.io -u USERNAME --password-stdin
# Interactive
docker login ghcr.io
podman login ghcr.io
GitLab Container Registry:
docker login registry.gitlab.com -u USERNAME -p $CI_JOB_TOKEN
podman login registry.gitlab.com -u USERNAME -p $CI_JOB_TOKEN
Private registry:
docker login myregistry.example.com
podman login myregistry.example.com
AWS ECR:
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
aws ecr get-login-password --region us-east-1 | \
podman login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
Google Container Registry:
gcloud auth configure-docker
# Or manually
cat keyfile.json | docker login -u _json_key --password-stdin gcr.io
Azure Container Registry:
az acr login --name myregistry
# Or with service principal
docker login myregistry.azurecr.io -u $SP_ID -p $SP_PASSWORD
Logout:
docker logout
docker logout ghcr.io
podman logout docker.io
podman logout ghcr.io
Pushing Images
Tag for registry:
docker tag myapp:latest myregistry/myapp:latest
docker tag myapp:latest myregistry/myapp:v1.0.0
podman tag myapp:latest myregistry/myapp:latest
Tag for Docker Hub:
docker tag myapp:latest username/myapp:latest
podman tag myapp:latest docker.io/username/myapp:latest
Tag for GHCR:
docker tag myapp:latest ghcr.io/username/myapp:latest
podman tag myapp:latest ghcr.io/username/myapp:latest
Push image:
docker push myregistry/myapp:latest
podman push myregistry/myapp:latest
Push all tags:
docker push --all-tags myregistry/myapp
podman push --all-tags myregistry/myapp
Pulling Images
Pull latest tag:
docker pull myregistry/myapp:latest
podman pull myregistry/myapp:latest
Pull specific tag:
docker pull myregistry/myapp:v1.0.0
podman pull myregistry/myapp:v1.0.0
Pull by digest:
docker pull myregistry/myapp@sha256:abc123...
podman pull myregistry/myapp@sha256:abc123...
Pull all tags:
docker pull --all-tags myregistry/myapp
podman pull --all-tags myregistry/myapp
Pull for specific platform:
docker pull --platform linux/arm64 myregistry/myapp:latest
podman pull --arch arm64 myregistry/myapp:latest
Tagging Strategies
Semantic versioning:
docker tag myapp:latest ghcr.io/username/myapp:v1.2.3
docker tag myapp:latest ghcr.io/username/myapp:v1.2
docker tag myapp:latest ghcr.io/username/myapp:v1
docker tag myapp:latest ghcr.io/username/myapp:latest
Git commit SHA:
docker tag myapp:latest ghcr.io/username/myapp:abc123
Build date:
docker tag myapp:latest ghcr.io/username/myapp:2024-01-15
Naming convention:
registry.example.com/project/app:version
ghcr.io/username/myapp:v1.0.0
docker.io/library/nginx:1.25-alpine
Private Registries
Run local registry:
docker run -d -p 5000:5000 --name registry registry:2
# With persistence
docker run -d -p 5000:5000 \
--name registry \
-v registry-data:/var/lib/registry \
registry:2
# With authentication
docker run -d -p 5000:5000 \
--name registry \
-v registry-data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
registry:2
Use local registry:
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest
Configure insecure registry (Docker):
# /etc/docker/daemon.json
{
"insecure-registries": ["myregistry.local:5000"]
}
Configure insecure registry (Podman):
podman login --tls-verify=false myregistry.example.com
Harbor/GitLab/GitHub Registries
Harbor (enterprise registry):
# Login
docker login harbor.example.com
# Push to project
docker tag myapp:latest harbor.example.com/myproject/myapp:latest
docker push harbor.example.com/myproject/myapp:latest
GitLab Container Registry:
# Login
docker login registry.gitlab.com
# Push to project
docker tag myapp:latest registry.gitlab.com/username/project/myapp:latest
docker push registry.gitlab.com/username/project/myapp:latest
GitHub Container Registry:
# Login with token
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Push to user/org
docker tag myapp:latest ghcr.io/username/myapp:latest
docker push ghcr.io/username/myapp:latest
Multi-Registry Workflows
Copy between registries using skopeo:
# Copy from Docker Hub to GHCR
skopeo copy \
docker://docker.io/username/myapp:latest \
docker://ghcr.io/username/myapp:latest
# Copy with authentication
skopeo copy \
--src-creds username:password \
--dest-creds username:token \
docker://registry1.com/myapp:latest \
docker://registry2.com/myapp:latest
Copy all tags with skopeo:
skopeo sync \
--src docker --dest docker \
username/myapp \
ghcr.io/username/
Copy using Docker/Podman:
docker pull registry1.com/myapp:latest
docker tag registry1.com/myapp:latest registry2.com/myapp:latest
docker push registry2.com/myapp:latest
Search images:
docker search nginx
docker search --filter "is-official=true" nginx
docker search --filter "stars=100" nginx
podman search nginx
podman search --filter=stars=100 nginx
List tags:
# Using skopeo
skopeo list-tags docker://docker.io/nginx
skopeo list-tags docker://ghcr.io/username/myapp
# Using podman
podman search --list-tags docker.io/nginx
Inspect remote images without pulling:
# With skopeo
skopeo inspect docker://myregistry/myapp:latest
skopeo inspect docker://ghcr.io/username/myapp:latest
# Show specific field
skopeo inspect docker://myapp:latest | jq '.Layers'
# Inspect manifest
docker manifest inspect myregistry/myapp:latest
podman manifest inspect myregistry/myapp:latest
# Raw manifest
skopeo inspect --raw docker://myregistry/myapp:latest
Registry Mirrors
Configure Docker daemon mirrors:
# /etc/docker/daemon.json
{
"registry-mirrors": ["https://mirror.example.com"],
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5
}
Configure Podman mirrors:
# /etc/containers/registries.conf
[registries.search]
registries = ['docker.io', 'ghcr.io']
[registries.insecure]
registries = ['myregistry.local:5000']
[[registry]]
location = "docker.io"
[[registry.mirror]]
location = "mirror.example.com"
Credential Management
Docker credentials stored in:
~/.docker/config.json
Use credential helper:
# Configure in ~/.docker/config.json
{
"credsStore": "secretservice"
}
# For Linux: docker-credential-secretservice
# For macOS: docker-credential-osxkeychain
# For Windows: docker-credential-wincred
Podman credentials stored in:
# Rootless
$XDG_RUNTIME_DIR/containers/auth.json
# Rootful
/run/containers/0/auth.json
View stored credentials:
cat ${XDG_RUNTIME_DIR}/containers/auth.json | jq
Best Practices
Network Best Practices
Security:
- Use user-defined networks, not default bridge
- Isolate sensitive services on separate networks
- Use internal networks for backend services
- Limit external exposure with firewall rules
Organization:
- Name networks descriptively:
frontend,backend,data - One network per application tier
- Document network topology
- Use labels for organization and filtering
Performance:
- Use host networking for high-throughput apps (with caution)
- Keep containers on same network for inter-container communication
- Use overlay networks sparingly (has overhead)
Volume Best Practices
Storage selection:
- Use named volumes for production data persistence
- Use bind mounts for development and configuration
- Use tmpfs for temporary, sensitive, or frequently accessed data
Naming:
- Use descriptive names:
postgres-data,app-uploads - Include app name:
myapp-database,myapp-cache - Use labels for organization
- Maintain consistent naming convention
Security:
- Use read-only mounts when possible
- Limit bind mount scope to minimum necessary
- Don’t mount sensitive host directories
- Set appropriate permissions
- Consider using secrets for sensitive data
Performance:
- Named volumes are faster than bind mounts on macOS/Windows
- Use tmpfs for frequently accessed temporary data
- Place volumes on fast storage
- Consider volume drivers for distributed storage
Data management:
- Regular backups of important volumes
- Test restore procedures
- Monitor volume usage and clean up unused volumes
- Document volume dependencies
Registry Best Practices
Tagging strategy:
- Use semantic versioning:
v1.2.3 - Tag with git commit SHA:
abc123 - Tag with build date:
2024-01-15 - Always tag
latestfor current production - Tag stable releases:
stable
Security:
- Use credential helpers, not plain text passwords
- Rotate access tokens regularly
- Use least privilege access
- Scan images before pushing
- Sign images with Docker Content Trust or Cosign
Optimization:
- Use multi-stage builds to reduce image size
- Push during off-peak hours for large images
- Use registry mirrors for faster pulls
- Enable layer compression
Multi-registry:
- Mirror critical images across registries
- Use skopeo for efficient registry operations
- Document registry dependencies
- Test failover scenarios
Troubleshooting
Network Issues
Containers can’t communicate:
- Check: Ensure containers are on the same network
- Check: Verify DNS resolution with
docker exec container ping other_container - Check: Inspect network connections with
docker network inspect - Check: Firewall rules:
sudo iptables -L DOCKER
Port already in use:
- Check:
lsof -i :8080 - Solution: Use different host port
- Solution: Stop conflicting service
Can’t remove network:
- Cause: Containers still connected
- Solution: Disconnect or remove containers first
- Solution:
docker network disconnect -f mynetwork container_name
Check container network:
# Get container IP
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name
podman inspect -f '{{.NetworkSettings.IPAddress}}' container_name
# Test connectivity from container
docker exec web ping db
docker exec web nc -zv db 5432
docker exec web nslookup db
docker exec web ip route
Check bridge and firewall:
# List bridges
ip link show type bridge
# Show bridge details
bridge link show
# Check iptables rules
sudo iptables -L DOCKER
sudo iptables -L DOCKER-USER
sudo iptables -t nat -L DOCKER
Volume Issues
Permission denied in container:
- Cause: User ID mismatch between host and container
- Solution: Run container as specific user
docker run --user $(id -u):$(id -g) -v myvolume:/data myapp - Solution: Fix permissions in container
docker run --rm -v myvolume:/data alpine chown -R 1000:1000 /data
Volume data disappeared:
- Cause: Used anonymous volume or accidentally removed volume
- Solution: Always use named volumes for persistent data
- Prevention: Regular backups
Cannot remove volume:
- Cause: Container still using it
- Check:
docker ps -a --filter volume=myvolume - Solution: Remove container first or use
docker volume rm -f
Bind mount not updating (macOS/Windows):
- Cause: File sync delay in Docker Desktop
- Solution: Use named volumes or configure file sharing
Volume full:
- Check size:
docker run --rm -v myvolume:/data alpine du -sh /data - Solution: Remove unnecessary files or increase volume size
Registry Issues
Authentication failed:
- Check: Verify credentials
- Check: Ensure token hasn’t expired
- Check: Verify proper permissions on registry
- Solution: Re-login with fresh credentials
Push denied:
- Check: Repository permissions
- Check: Namespace/organization access
- Solution: Create repository first (some registries require this)
Image not found:
- Check: Image name and tag spelling
- Check: Registry URL is correct
- Check: Image was pushed successfully
TLS certificate error:
- Solution (dev only): Add registry to insecure registries
- Solution (production): Install proper CA certificates
- Temporary: Use
--tls-verify=falsefor testing only
Rate limit exceeded (Docker Hub):
- Solution: Login to increase limit (200 pulls/6 hours free)
- Solution: Use registry mirror
- Solution: Upgrade to paid plan
Infrastructure Integration Examples
Multi-Tier Application
# Create networks
docker network create frontend
docker network create backend
# Create volumes
docker volume create db-data
docker volume create app-uploads
# Start database with volume
docker run -d \
--name postgres \
--network backend \
-v db-data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:15
# Start application server
docker run -d \
--name app \
--network backend \
--network frontend \
-v app-uploads:/uploads \
myapp:latest
# Start web server
docker run -d \
--name nginx \
--network frontend \
-p 80:80 \
nginx:latest
# Database is isolated on backend network
# Web server only accesses app via frontend network
Development with Live Reload
# Create network
docker network create dev-network
# Create volume for dependencies
docker volume create node-modules
# Start with bind mount for code
docker run -d \
--name dev-server \
--network dev-network \
-v $(pwd)/src:/app/src \
-v node-modules:/app/node_modules \
-p 3000:3000 \
node:18 npm run dev
Registry Workflow with Infrastructure
# Build application
docker build -t myapp:latest .
# Create production volume
docker volume create prod-data
# Test locally with network
docker network create test-net
docker run -d --name test --network test-net -v prod-data:/data myapp:latest
# Tag for registry
docker tag myapp:latest ghcr.io/username/myapp:v1.0.0
docker tag myapp:latest ghcr.io/username/myapp:latest
# Login and push
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
docker push ghcr.io/username/myapp:v1.0.0
docker push ghcr.io/username/myapp:latest
# Deploy on production server
docker pull ghcr.io/username/myapp:latest
docker network create prod-net
docker volume create prod-data
docker run -d \
--name prod \
--network prod-net \
-v prod-data:/data \
-p 80:8080 \
ghcr.io/username/myapp:latest
Backup Infrastructure Before Update
# Backup volume
docker run --rm \
-v app-data:/data \
-v $(pwd)/backups:/backup \
alpine \
tar czf /backup/app-data-$(date +%Y%m%d).tar.gz -C /data .
# Export network configuration
docker network inspect prod-net > network-config.json
# Tag current production image
docker tag myapp:latest myapp:backup-$(date +%Y%m%d)
# Push backup to registry
docker tag myapp:backup-$(date +%Y%m%d) ghcr.io/username/myapp:backup-$(date +%Y%m%d)
docker push ghcr.io/username/myapp:backup-$(date +%Y%m%d)