Run Workflow
Manage container lifecycle, debug running containers, and orchestrate multi-container applications with Docker Compose.
Quick Start
Common run patterns:
# Start a container
docker run -d --name myapp -p 8080:80 myapp:latest
# Start with logs following
docker run -d --name myapp myapp:latest && docker logs -f myapp
# Start and enter shell
docker run -it --name myapp myapp:latest /bin/bash
# Start all services from compose file
docker-compose up -d
# Check running containers
docker ps
# View container logs
docker logs myapp
# Open shell in running container
docker exec -it myapp /bin/bash
Runtime detection:
All commands show both Docker and Podman variants. Use DetectRuntime.sh to determine which is available.
Container Lifecycle
Starting Containers
Basic run:
docker run -d --name myapp -p 8080:80 myapp:latest
podman run -d --name myapp -p 8080:80 myapp:latest
With environment variables:
docker run -d --name myapp -e DATABASE_URL=postgres://db/myapp -e DEBUG=true myapp:latest
podman run -d --name myapp -e DATABASE_URL=postgres://db/myapp myapp:latest
With volume mount:
docker run -d --name myapp -v /host/path:/container/path myapp:latest
podman run -d --name myapp -v /host/path:/container/path myapp:latest
Interactive mode:
docker run -it --name myapp myapp:latest /bin/bash
podman run -it --name myapp myapp:latest /bin/bash
With resource limits:
# Memory limit
docker run -d --name myapp --memory 512m myapp:latest
# CPU limit
docker run -d --name myapp --cpus 1.5 myapp:latest
# Combined limits
docker run -d --name myapp --memory 512m --cpus 1.0 myapp:latest
Restart Policies
Always restart:
docker run -d --restart always --name myapp myapp:latest
Restart on failure:
docker run -d --restart on-failure:5 --name myapp myapp:latest
No restart:
docker run -d --restart no --name myapp myapp:latest
Unless stopped:
docker run -d --restart unless-stopped --name myapp myapp:latest
Listing Containers
Show running containers:
docker ps
podman ps
Show all containers (including stopped):
docker ps -a
podman ps -a
Format output:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
podman ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
Stopping and Restarting
Stop container gracefully:
docker stop myapp
podman stop myapp
Stop with custom timeout:
docker stop -t 30 myapp
podman stop -t 30 myapp
Restart container:
docker restart myapp
podman restart myapp
Kill container forcefully:
docker kill myapp
podman kill myapp
Removing Containers
Remove stopped container:
docker rm myapp
podman rm myapp
Force remove running container:
docker rm -f myapp
podman rm -f myapp
Remove all stopped containers:
docker container prune
podman container prune
Remove with confirmation:
docker container prune -f
Inspecting Containers
Show detailed information:
docker inspect myapp
podman inspect myapp
Get specific field:
# Container status
docker inspect -f '{{.State.Status}}' myapp
# IP address
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
# Exit code
docker inspect -f '{{.State.ExitCode}}' myapp
# Environment variables
docker inspect -f '{{.Config.Env}}' myapp
# Mounts
docker inspect -f '{{.Mounts}}' myapp
# Ports
docker inspect -f '{{.NetworkSettings.Ports}}' myapp
Show resource usage:
docker stats myapp
podman stats myapp
Debugging Containers
Viewing Logs
Show container logs:
docker logs myapp
podman logs myapp
Follow logs (real-time):
docker logs -f myapp
podman logs -f myapp
Show last N lines:
docker logs --tail 100 myapp
podman logs --tail 100 myapp
Show logs with timestamps:
docker logs -t myapp
podman logs -t myapp
Show logs since specific time:
docker logs --since 2024-01-01T10:00:00 myapp
docker logs --since 1h myapp
podman logs --since 1h myapp
Search logs:
docker logs myapp 2>&1 | grep ERROR
docker logs myapp 2>&1 | grep -i "connection failed"
podman logs myapp 2>&1 | grep ERROR
Executing Commands
Open shell in running container:
docker exec -it myapp /bin/bash
docker exec -it myapp /bin/sh # if bash not available
podman exec -it myapp /bin/bash
Run specific command:
docker exec myapp ls -la /app
docker exec myapp ps aux
docker exec myapp cat /etc/os-release
podman exec myapp env
Run as specific user:
docker exec -u www-data -it myapp bash
docker exec -u 0 -it myapp bash # run as root
podman exec -u 1000 -it myapp bash
Set environment variables:
docker exec -e DEBUG=true myapp python script.py
podman exec -e DEBUG=true myapp python script.py
Monitoring Resources
Real-time stats:
docker stats myapp
podman stats myapp
All containers stats:
docker stats
podman stats
Stats without streaming:
docker stats --no-stream
podman stats --no-stream
Format output:
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
List processes in container:
docker top myapp
docker top myapp aux
podman top myapp
Checking Container Health
If healthcheck configured:
docker inspect -f '{{.State.Health.Status}}' myapp
docker inspect -f '{{json .State.Health}}' myapp | jq
Network Debugging
Check container IP:
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
List networks:
docker network ls
podman network ls
Inspect network:
docker network inspect bridge
podman network inspect podman
Test connectivity from container:
docker exec myapp ping google.com
docker exec myapp curl http://api.example.com
docker exec myapp nc -zv database 5432
Check DNS resolution:
docker exec myapp nslookup database
docker exec myapp cat /etc/resolv.conf
Port mapping:
docker port myapp
podman port myapp
Test from host to container:
# Get container IP
IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp)
ping $IP
curl http://$IP:8080
Filesystem Debugging
Copy files from container:
docker cp myapp:/path/to/file ./local/path
podman cp myapp:/path/to/file ./local/path
Copy files to container:
docker cp ./local/file myapp:/path/to/destination
podman cp ./local/file myapp:/path/to/destination
Check disk usage:
docker exec myapp df -h
docker exec myapp du -sh /var/log
View file contents:
docker exec myapp cat /etc/config.yml
docker exec myapp tail -f /var/log/app.log
Container Events
Watch events:
docker events
podman events
Filter events for specific container:
docker events --filter container=myapp
podman events --filter container=myapp
Filter by event type:
docker events --filter event=start
docker events --filter event=die
Troubleshooting Crashes
Check exit code:
docker inspect -f '{{.State.ExitCode}}' myapp
Common exit codes:
- 0: Success
- 1: Application error
- 126: Command cannot be invoked
- 127: Command not found
- 137: SIGKILL (killed by system, often OOM)
- 139: SIGSEGV (segmentation fault)
- 143: SIGTERM (graceful termination)
Check if OOM killed:
docker inspect -f '{{.State.OOMKilled}}' myapp
dmesg | grep -i oom
Run interactively to debug:
docker run -it --entrypoint /bin/bash myapp:latest
Advanced Debugging
Attach to container (see STDOUT/STDERR):
docker attach myapp
# Detach: Ctrl+P, Ctrl+Q
Export container filesystem:
docker export myapp > container.tar
tar -xf container.tar
Commit container state:
docker commit myapp debug_snapshot:latest
Trace system calls:
docker exec myapp strace -p 1
Docker Compose
Compose File Structure
Basic compose.yml:
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:80"
environment:
- DATABASE_URL=postgres://db/myapp
depends_on:
- db
networks:
- app-network
volumes:
- ./app:/app
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
secrets:
- db_password
networks:
app-network:
driver: bridge
volumes:
db-data:
secrets:
db_password:
file: ./secrets/db_password.txt
Starting Services
Start all services:
docker-compose up -d
docker compose up -d
podman-compose up -d
Start specific service:
docker-compose up -d web
docker compose up -d web
podman-compose up -d web
Start with build:
docker-compose up -d --build
docker compose up -d --build
podman-compose up -d --build
Start with specific file:
docker-compose -f docker-compose.prod.yml up -d
docker compose -f docker-compose.prod.yml up -d
podman-compose -f docker-compose.prod.yml up -d
Use multiple compose files:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
Stopping Services
Stop all services:
docker-compose down
docker compose down
podman-compose down
Stop and remove volumes:
docker-compose down -v
docker compose down -v
podman-compose down -v
Stop specific service:
docker-compose stop web
docker compose stop web
podman-compose stop web
Viewing Status and Logs
List running services:
docker-compose ps
docker compose ps
podman-compose ps
View logs:
docker-compose logs
docker compose logs
podman-compose logs
Follow logs:
docker-compose logs -f
docker compose logs -f
podman-compose logs -f
Logs for specific service:
docker-compose logs -f web
docker compose logs web
podman-compose logs web
Last N lines:
docker-compose logs --tail 50 web
Building Services
Build all services:
docker-compose build
docker compose build
podman-compose build
Build specific service:
docker-compose build web
docker compose build web
podman-compose build web
Build with no cache:
docker-compose build --no-cache
docker compose build --no-cache
podman-compose build --no-cache
Scaling Services
Scale service to multiple instances:
docker-compose up -d --scale web=3
docker compose up -d --scale web=3
podman-compose up -d --scale web=3
Executing Commands
Run command in service:
docker-compose exec web bash
docker compose exec web bash
podman-compose exec web bash
Run one-off command:
docker-compose run web python manage.py migrate
docker compose run web python manage.py migrate
podman-compose run web python manage.py migrate
Run without starting dependencies:
docker-compose run --no-deps web python script.py
Environment Variables
Using .env file:
# .env
DATABASE_URL=postgres://localhost/myapp
SECRET_KEY=mysecret
DEBUG=false
In compose file:
services:
web:
env_file:
- .env
# Or specific variables
environment:
- DATABASE_URL=${DATABASE_URL}
- DEBUG=${DEBUG:-false}
Important notes:
- .env file must be in same directory as compose file
- Use
KEY=valueformat (no quotes needed) - Variables can have defaults:
${VAR:-default}
Networking in Compose
Services communicate by service name:
services:
web:
environment:
- DATABASE_URL=postgres://db:5432/myapp # 'db' is service name
db:
image: postgres:16-alpine
Custom networks:
services:
web:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
driver: bridge
Volumes in Compose
Named volumes:
services:
db:
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Bind mounts:
services:
web:
volumes:
- ./app:/app
- ./config:/etc/app:ro # read-only
Volume management:
# List volumes
docker volume ls
# Inspect volume
docker volume inspect projectname_db-data
# Remove unused volumes
docker volume prune
Profiles
Define profiles:
services:
web:
# Always runs
debug:
profiles: ["debug"]
# Only runs with --profile debug
test:
profiles: ["testing"]
Use profiles:
docker-compose --profile debug up -d
docker compose --profile debug up -d
podman-compose --profile debug up -d
Override Files
docker-compose.override.yml automatically loaded:
# Automatically uses docker-compose.yml + docker-compose.override.yml
docker-compose up -d
Explicit override:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
Resource Limits
services:
web:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
Podman-Specific Features
Rootless Containers
Run rootless (default in Podman):
podman run -d --name myapp myapp:latest
Check if rootless:
podman info --format '{{.Host.Security.Rootless}}'
Troubleshoot rootless:
# Check subuid/subgid
cat /etc/subuid
cat /etc/subgid
# Migrate storage if needed
podman system migrate
Systemd Integration
Generate systemd unit file:
podman generate systemd --name myapp > ~/.config/systemd/user/myapp.service
# Enable and start service
systemctl --user enable --now myapp.service
Generate from compose:
# Start services with podman-compose
podman-compose up -d
# Get pod name
podman pod ps
# Generate systemd unit
podman generate systemd --name mypod_pod --files
# Move to systemd directory
mv *.service ~/.config/systemd/user/
# Enable
systemctl --user enable --now mypod_pod.service
Pods (Kubernetes-like)
Create pod:
podman pod create --name mypod -p 8080:80
Add container to pod:
podman run -d --pod mypod --name myapp myapp:latest
List pods:
podman pod ps
Inspect pod:
podman pod inspect mypod
Stop entire pod:
podman pod stop mypod
Pod logs:
podman pod logs mypod
Generate Kubernetes YAML:
podman generate kube mypod > pod.yaml
Best Practices
Container Naming
- Use descriptive names that indicate purpose
- Follow consistent naming convention (e.g.,
project-service-env) - Avoid generic names like “app” or “container”
Resource Management
- Always set memory limits for production:
--memory 512m - Set CPU limits to prevent resource hogging:
--cpus 1.5 - Use health checks:
--health-cmd "curl -f http://localhost/health" - Monitor resource usage with
docker stats
Security
- Run as non-root when possible (Podman rootless by default)
- Use read-only filesystem when applicable:
--read-only - Drop unnecessary capabilities:
--cap-drop ALL - Use security profiles:
--security-opt - Don’t expose unnecessary ports
- Use secrets for sensitive data (compose)
Networking
- Use service names for inter-container communication
- Limit exposed ports to necessary ones only
- Use custom networks to isolate services
- Avoid
network_mode: hostin production
Volumes and Persistence
- Use named volumes for data persistence
- Back up volumes regularly
- Use read-only mounts when data shouldn’t change
- Clean up unused volumes:
docker volume prune
Compose Files
- Use specific image tags (not
latest) - Define health checks for all services
- Specify restart policies
- Use
.envfiles for environment-specific config - Define resource limits
- Document dependencies with
depends_on - Use secrets for sensitive data
Development vs Production
- Use override files for environment differences
- Keep production configs minimal and secure
- Use profiles for optional services
- Separate build and runtime concerns
Troubleshooting
Container Exits Immediately
Diagnosis:
# Check exit code
docker inspect -f '{{.State.ExitCode}}' myapp
# Check logs
docker logs myapp
# Run interactively
docker run -it --entrypoint /bin/bash myapp:latest
Common causes:
- Application error (check logs)
- Missing command in Dockerfile
- Configuration issue
- OOM kill (exit code 137)
Port Already in Use
Diagnosis:
# Check what's using port
lsof -i :8080
ss -tlnp | grep 8080
# Check container port mappings
docker port myapp
Solutions:
- Use different host port:
-p 8081:80 - Stop conflicting service
- Remove old container:
docker rm -f old-container
Permission Denied
Docker:
# Add user to docker group
sudo usermod -aG docker $USER
# Then logout and login again
Podman:
# Check if rootless
podman info --format '{{.Host.Security.Rootless}}'
# Check subuid/subgid
cat /etc/subuid
cat /etc/subgid
Container filesystem:
# Check file permissions
docker exec myapp ls -la /app
# Run as root to fix
docker exec -u 0 -it myapp bash
Cannot Connect to Container
Diagnosis:
# Check if container is running
docker ps
# Check port mapping
docker port myapp
# Get container IP
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
# Test from host
curl http://localhost:8080
Check network:
docker network inspect bridge
docker exec myapp ip addr
docker exec myapp netstat -tlnp
Memory/CPU Issues
Check resources:
docker stats myapp
docker stats --no-stream
Check if OOM killed:
docker inspect -f '{{.State.OOMKilled}}' myapp
dmesg | grep -i oom
Set appropriate limits:
docker run -d --memory="1g" --cpus="2.0" --name myapp myapp:latest
Volume/Mount Issues
Check mounts:
docker inspect -f '{{json .Mounts}}' myapp | jq
Verify volume:
docker volume ls
docker volume inspect volume_name
Check permissions:
docker exec myapp ls -la /mounted/path
Common causes:
- Wrong path (bind mount)
- Permission issues (SELinux, user permissions)
- Volume not created
- Path doesn’t exist in container
Compose Issues
Compose file not found:
# Specify file explicitly
docker-compose -f /path/to/docker-compose.yml up -d
Services can’t communicate:
- Ensure services are on same network
- Use service names as hostnames (not IPs)
- Check network configuration in compose file
Environment variables not loading:
- Verify .env file is in same directory as compose file
- Check variable syntax:
KEY=value(no quotes) - Don’t use
.envfor secrets in production
Version not supported:
- Use version 3.8 or omit version for modern compose
- Check compose tool version:
docker-compose --version
Network Connectivity
DNS not resolving:
docker exec myapp cat /etc/resolv.conf
docker exec myapp nslookup google.com
Can’t reach other containers:
docker exec myapp ping other-container
docker network inspect bridge
Can’t reach outside:
docker exec myapp ping 8.8.8.8
docker exec myapp curl https://google.com
Quick Reference
Container lifecycle:
docker run -d --name myapp myapp:latest # Start
docker ps # List running
docker stop myapp # Stop
docker restart myapp # Restart
docker rm myapp # Remove
Debugging:
docker logs -f myapp # Follow logs
docker exec -it myapp bash # Get shell
docker inspect myapp # Full details
docker stats myapp # Resource usage
docker top myapp # Processes
docker port myapp # Port mappings
Compose:
docker-compose up -d # Start all
docker-compose ps # List services
docker-compose logs -f # Follow logs
docker-compose exec web bash # Exec in service
docker-compose down # Stop all