1957 lines
35 KiB
Markdown
1957 lines
35 KiB
Markdown
# Docker and Container Issues
|
|
|
|
This guide covers Docker-specific problems in Changemaker Lite V2.
|
|
|
|
## Overview
|
|
|
|
### Docker Troubleshooting Approach
|
|
|
|
1. **Check status** - Are containers running?
|
|
2. **Read logs** - What do container logs show?
|
|
3. **Inspect configuration** - Is docker-compose.yml correct?
|
|
4. **Test connectivity** - Can containers communicate?
|
|
5. **Resource check** - Enough CPU/memory/disk?
|
|
|
|
### Essential Docker Commands
|
|
|
|
```bash
|
|
# View running containers
|
|
docker compose ps
|
|
|
|
# View all containers (including stopped)
|
|
docker compose ps -a
|
|
|
|
# View logs
|
|
docker compose logs [service-name]
|
|
|
|
# Follow logs in real-time
|
|
docker compose logs -f [service-name]
|
|
|
|
# Execute command in container
|
|
docker compose exec [service-name] [command]
|
|
|
|
# Restart service
|
|
docker compose restart [service-name]
|
|
|
|
# Stop all services
|
|
docker compose down
|
|
|
|
# Start services
|
|
docker compose up -d
|
|
|
|
# Rebuild and start
|
|
docker compose up -d --build [service-name]
|
|
```
|
|
|
|
---
|
|
|
|
## Container Won't Start
|
|
|
|
### Port Already in Use
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
```
|
|
Error response from daemon: driver failed programming external connectivity
|
|
on endpoint changemaker-lite-admin-1: Bind for 0.0.0.0:3000 failed:
|
|
port is already allocated
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
ERROR: for api Cannot start service api: Ports are not available:
|
|
exposing port TCP 0.0.0.0:4000 -> 0.0.0.0:0: listen tcp 0.0.0.0:4000:
|
|
bind: address already in use
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Another container using port** - Different Docker project
|
|
2. **Host process using port** - npm dev server running
|
|
3. **Previous container not stopped** - Old container still running
|
|
4. **Port conflict in docker-compose.yml** - Two services same port
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Find what's using the port**
|
|
|
|
```bash
|
|
# Linux/Mac
|
|
sudo lsof -i :4000
|
|
|
|
# Or with netstat
|
|
netstat -tuln | grep :4000
|
|
|
|
# Windows
|
|
netstat -ano | findstr :4000
|
|
```
|
|
|
|
Output shows:
|
|
```
|
|
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
|
|
node 12345 user 23u IPv4 123456 0t0 TCP *:4000 (LISTEN)
|
|
```
|
|
|
|
**Solution 2: Stop conflicting process**
|
|
|
|
```bash
|
|
# Kill process by PID
|
|
kill 12345
|
|
|
|
# Or kill all node processes (careful!)
|
|
killall node
|
|
|
|
# Or stop other Docker containers
|
|
docker ps # List all running containers
|
|
docker stop container-name-or-id
|
|
```
|
|
|
|
**Solution 3: Change port in docker-compose.yml**
|
|
|
|
```yaml
|
|
# In docker-compose.yml
|
|
api:
|
|
ports:
|
|
- "4002:4000" # Changed from 4000:4000
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
# Restart with new port
|
|
docker compose up -d api
|
|
|
|
# Update .env to use new port
|
|
VITE_API_URL=http://localhost:4002
|
|
```
|
|
|
|
**Solution 4: Stop all and restart**
|
|
|
|
```bash
|
|
# Stop all Changemaker Lite containers
|
|
docker compose down
|
|
|
|
# Verify nothing running
|
|
docker compose ps
|
|
|
|
# Start fresh
|
|
docker compose up -d
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Use unique ports** - Avoid common ports (3000, 4000, 8000, 8080)
|
|
- **Stop properly** - Always use `docker compose down`
|
|
- **Check before start** - Run `docker compose ps` first
|
|
- **Document ports** - Keep port reference updated
|
|
|
|
---
|
|
|
|
### Volume Mount Errors
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
```
|
|
Error response from daemon: invalid mount config for type "bind":
|
|
bind source path does not exist: /home/user/changemaker.lite/uploads
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
Error: EACCES: permission denied, open '/media/local/inbox/video.mp4'
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Path doesn't exist** - Directory not created
|
|
2. **Permission denied** - Container can't access directory
|
|
3. **Wrong path** - Typo in docker-compose.yml
|
|
4. **SELinux blocking** - Linux security policy
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Create missing directories**
|
|
|
|
```bash
|
|
# Create all required directories
|
|
mkdir -p uploads
|
|
mkdir -p media/local/inbox
|
|
mkdir -p media/local/library
|
|
mkdir -p data
|
|
mkdir -p configs/prometheus
|
|
mkdir -p configs/grafana
|
|
|
|
# Verify they exist
|
|
ls -la
|
|
```
|
|
|
|
**Solution 2: Fix permissions**
|
|
|
|
```bash
|
|
# Make directories writable
|
|
chmod -R 777 uploads
|
|
chmod -R 777 media/local/inbox
|
|
|
|
# Or set ownership to container user
|
|
# Check container user ID
|
|
docker compose exec api id
|
|
# uid=1000(node) gid=1000(node)
|
|
|
|
# Set ownership
|
|
sudo chown -R 1000:1000 uploads
|
|
sudo chown -R 1000:1000 media
|
|
```
|
|
|
|
**Solution 3: Check volume configuration**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
volumes:
|
|
# Correct format:
|
|
- ./uploads:/app/uploads:rw # Read-write
|
|
- ./media:/media:ro # Read-only
|
|
|
|
# Wrong formats:
|
|
# - uploads:/app/uploads # Named volume, not bind mount
|
|
# - /uploads:/app/uploads # Absolute path on host
|
|
```
|
|
|
|
**Solution 4: Disable SELinux (last resort)**
|
|
|
|
```bash
|
|
# Check if SELinux is the issue
|
|
getenforce
|
|
# If "Enforcing":
|
|
|
|
# Option 1: Add :z flag to volume
|
|
# In docker-compose.yml:
|
|
- ./uploads:/app/uploads:z
|
|
|
|
# Option 2: Temporarily disable (not recommended)
|
|
sudo setenforce 0
|
|
```
|
|
|
|
**Solution 5: Verify mount inside container**
|
|
|
|
```bash
|
|
# Check if mount exists
|
|
docker compose exec api ls -la /app/uploads
|
|
|
|
# Check permissions
|
|
docker compose exec api ls -ld /app/uploads
|
|
|
|
# Try creating file
|
|
docker compose exec api touch /app/uploads/test.txt
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Create directories first** - Before `docker compose up`
|
|
- **Set permissions early** - In setup script
|
|
- **Use relative paths** - Start with `./` in docker-compose.yml
|
|
- **Document requirements** - List all required directories
|
|
|
|
---
|
|
|
|
### Missing Environment Variables
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
Container logs show:
|
|
|
|
```
|
|
Error: DATABASE_URL is required
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
ZodError: [
|
|
{
|
|
"code": "invalid_type",
|
|
"expected": "string",
|
|
"received": "undefined",
|
|
"path": ["SMTP_HOST"],
|
|
"message": "Required"
|
|
}
|
|
]
|
|
```
|
|
|
|
Or container exits immediately:
|
|
|
|
```
|
|
changemaker-lite-api-1 exited with code 1
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **.env not found** - Missing .env file
|
|
2. **Variable not set** - Missing required variable
|
|
3. **Wrong .env location** - .env not in project root
|
|
4. **Syntax error** - Malformed .env file
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Check .env exists**
|
|
|
|
```bash
|
|
# Verify .env file
|
|
ls -la .env
|
|
|
|
# If missing, copy from example
|
|
cp .env.example .env
|
|
```
|
|
|
|
**Solution 2: Find missing variables**
|
|
|
|
```bash
|
|
# View container logs to see which variable
|
|
docker compose logs api | grep -i "required\|undefined"
|
|
|
|
# Example output:
|
|
# Error: SMTP_HOST is required
|
|
```
|
|
|
|
**Solution 3: Add missing variables**
|
|
|
|
```bash
|
|
# Edit .env
|
|
nano .env
|
|
|
|
# Add missing variable
|
|
SMTP_HOST=smtp.gmail.com
|
|
|
|
# Save and restart
|
|
docker compose restart api
|
|
```
|
|
|
|
**Solution 4: Validate .env format**
|
|
|
|
```bash
|
|
# Check for common issues:
|
|
# - No spaces around =
|
|
# - Quotes for values with spaces
|
|
# - No trailing commas
|
|
# - No comments on same line as value
|
|
|
|
# Good:
|
|
DATABASE_URL="postgresql://user:pass@host:5432/db"
|
|
CORS_ORIGINS=http://localhost:3000,http://localhost:4000
|
|
|
|
# Bad:
|
|
DATABASE_URL = "postgresql://..." # Space around =
|
|
CORS_ORIGINS=http://localhost:3000, http://localhost:4000 # Space after comma
|
|
SMTP_HOST=smtp.gmail.com # Gmail # Comment on same line
|
|
```
|
|
|
|
**Solution 5: Check which variables are loaded**
|
|
|
|
```bash
|
|
# View environment inside container
|
|
docker compose exec api env | grep -E "DATABASE_URL|SMTP_HOST|JWT_"
|
|
|
|
# Should show actual values (not undefined)
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Use .env.example** - Keep template updated
|
|
- **Validation on startup** - Zod validates env in `config/env.ts`
|
|
- **Documentation** - Document all required variables
|
|
- **Setup script** - Validate .env before starting
|
|
|
|
---
|
|
|
|
### Health Check Failures
|
|
|
|
**Severity:** 🟠 High
|
|
|
|
#### Symptoms
|
|
|
|
```bash
|
|
docker compose ps
|
|
```
|
|
|
|
Shows:
|
|
|
|
```
|
|
NAME STATUS
|
|
api Up 30 seconds (unhealthy)
|
|
v2-postgres Up 1 minute (healthy)
|
|
```
|
|
|
|
Or logs show:
|
|
|
|
```
|
|
Health check failed
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Service not ready** - Still starting up
|
|
2. **Health check endpoint failing** - /health returns error
|
|
3. **Timeout too short** - Service needs more time
|
|
4. **Dependencies not ready** - Database not connected
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Check health check configuration**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:4000/api/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
```
|
|
|
|
**Solution 2: Test health endpoint manually**
|
|
|
|
```bash
|
|
# From inside container
|
|
docker compose exec api wget -O- http://localhost:4000/api/health
|
|
|
|
# Should return:
|
|
# {"status":"healthy","timestamp":"2026-02-13T..."}
|
|
|
|
# From host
|
|
curl http://localhost:4000/api/health
|
|
```
|
|
|
|
**Solution 3: View health check logs**
|
|
|
|
```bash
|
|
# Detailed health check output
|
|
docker inspect changemaker-lite-api-1 --format='{{json .State.Health}}' | jq
|
|
|
|
# Shows:
|
|
# {
|
|
# "Status": "unhealthy",
|
|
# "FailingStreak": 3,
|
|
# "Log": [
|
|
# {
|
|
# "Start": "2026-02-13T...",
|
|
# "End": "2026-02-13T...",
|
|
# "ExitCode": 1,
|
|
# "Output": "Error: Connection refused"
|
|
# }
|
|
# ]
|
|
# }
|
|
```
|
|
|
|
**Solution 4: Increase timeout/interval**
|
|
|
|
```yaml
|
|
api:
|
|
healthcheck:
|
|
interval: 60s # Check less frequently
|
|
timeout: 30s # Allow more time
|
|
start_period: 90s # Wait longer before first check
|
|
```
|
|
|
|
**Solution 5: Check service logs**
|
|
|
|
```bash
|
|
# Real issue is usually in service logs
|
|
docker compose logs api | tail -50
|
|
|
|
# Common issues:
|
|
# - Database connection failed
|
|
# - Missing environment variable
|
|
# - Port already in use
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Reasonable timeouts** - Allow enough time for startup
|
|
- **Accurate health checks** - Check actual readiness
|
|
- **Monitor health** - Alert on unhealthy containers
|
|
- **Dependencies** - Use `depends_on` with `condition: service_healthy`
|
|
|
|
---
|
|
|
|
## Container Crashes
|
|
|
|
### Out of Memory
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
Container logs show:
|
|
|
|
```
|
|
<--- Last few GCs --->
|
|
[1:0x5588e4f8e000] 65432 ms: Mark-sweep 2048.0 (2048.4) -> 2047.9 (2048.4) MB, 1845.2 / 0.0 ms (average mu = 0.123, current mu = 0.001) allocation failure scavenge might not succeed
|
|
|
|
<--- JS stacktrace --->
|
|
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
Killed
|
|
```
|
|
|
|
Or `docker compose ps` shows:
|
|
|
|
```
|
|
api Exit 137
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Memory leak** - Application leaking memory
|
|
2. **Large dataset** - Processing too much data
|
|
3. **Too many connections** - Database connection pool too large
|
|
4. **Container limit** - Memory limit too low
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Check memory usage**
|
|
|
|
```bash
|
|
# View container memory usage
|
|
docker stats
|
|
|
|
# Shows:
|
|
# CONTAINER CPU % MEM USAGE / LIMIT MEM %
|
|
# api 15.5% 1.2GiB / 2GiB 60%
|
|
```
|
|
|
|
**Solution 2: Increase Node.js heap size**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
environment:
|
|
- NODE_OPTIONS=--max-old-space-size=4096 # 4GB heap
|
|
```
|
|
|
|
Or in `api/package.json`:
|
|
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"start": "node --max-old-space-size=4096 dist/server.js"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Solution 3: Increase container memory limit**
|
|
|
|
```yaml
|
|
api:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 4G # Increase from 2G
|
|
reservations:
|
|
memory: 2G
|
|
```
|
|
|
|
**Solution 4: Find memory leak**
|
|
|
|
```bash
|
|
# Enable heap snapshots
|
|
docker compose exec api node --inspect dist/server.js
|
|
|
|
# Or use clinic.js
|
|
npm install -g clinic
|
|
clinic doctor -- node dist/server.js
|
|
```
|
|
|
|
**Solution 5: Reduce memory usage**
|
|
|
|
```typescript
|
|
// Reduce database connection pool
|
|
// In prisma/schema.prisma
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
// Add connection limit
|
|
}
|
|
|
|
// In DATABASE_URL:
|
|
DATABASE_URL="postgresql://...?connection_limit=5"
|
|
|
|
// Process data in batches
|
|
const users = await prisma.user.findMany({
|
|
take: 100, // Limit batch size
|
|
skip: offset
|
|
});
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Monitor memory** - Alert on high usage
|
|
- **Generous limits** - Set limits higher than expected usage
|
|
- **Memory profiling** - Regular memory audits
|
|
- **Optimize queries** - Reduce data fetched
|
|
|
|
---
|
|
|
|
### Application Errors
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
Container exits immediately:
|
|
|
|
```
|
|
api-1 exited with code 1
|
|
```
|
|
|
|
Logs show:
|
|
|
|
```
|
|
Error: Cannot find module 'express'
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
SyntaxError: Unexpected token 'export'
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Missing dependencies** - npm install not run
|
|
2. **Build not run** - TypeScript not compiled
|
|
3. **Syntax error** - Code has errors
|
|
4. **Wrong Node version** - Incompatible Node.js version
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Rebuild container**
|
|
|
|
```bash
|
|
# Rebuild with no cache
|
|
docker compose build --no-cache api
|
|
|
|
# Start
|
|
docker compose up -d api
|
|
|
|
# View logs
|
|
docker compose logs -f api
|
|
```
|
|
|
|
**Solution 2: Check dependencies**
|
|
|
|
```bash
|
|
# Verify package.json and package-lock.json exist
|
|
docker compose exec api ls -la package*.json
|
|
|
|
# Verify node_modules exists
|
|
docker compose exec api ls -la node_modules | head
|
|
|
|
# If missing, install
|
|
docker compose exec api npm install
|
|
```
|
|
|
|
**Solution 3: Verify build**
|
|
|
|
```bash
|
|
# Check if TypeScript compiled
|
|
docker compose exec api ls -la dist/
|
|
|
|
# If missing, build
|
|
docker compose exec api npm run build
|
|
|
|
# Or rebuild container
|
|
docker compose up -d --build api
|
|
```
|
|
|
|
**Solution 4: Check Node version**
|
|
|
|
```bash
|
|
# Check version in container
|
|
docker compose exec api node --version
|
|
|
|
# Should match Dockerfile
|
|
cat api/Dockerfile | grep "FROM node:"
|
|
|
|
# Example:
|
|
# FROM node:20-alpine
|
|
```
|
|
|
|
**Solution 5: Test locally**
|
|
|
|
```bash
|
|
# Test build locally
|
|
cd api
|
|
npm install
|
|
npm run build
|
|
npm start
|
|
|
|
# If works locally but not in Docker, check:
|
|
# - Dockerfile COPY commands
|
|
# - .dockerignore file
|
|
# - Volume mounts
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Multi-stage builds** - Separate build and runtime
|
|
- **Lock files** - Commit package-lock.json
|
|
- **CI/CD** - Automated build testing
|
|
- **Version pinning** - Pin Node.js version
|
|
|
|
---
|
|
|
|
### Database Connection Failures
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
API logs show:
|
|
|
|
```
|
|
Error: Can't reach database server at `v2-postgres:5432`
|
|
Error: connect ECONNREFUSED 172.18.0.2:5432
|
|
```
|
|
|
|
Container restarts repeatedly.
|
|
|
|
#### Common Causes
|
|
|
|
1. **Database not ready** - API started before database
|
|
2. **Wrong host** - Incorrect database hostname
|
|
3. **Network issue** - Containers on different networks
|
|
4. **Database crashed** - PostgreSQL container down
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Check database status**
|
|
|
|
```bash
|
|
# Is database running?
|
|
docker compose ps v2-postgres
|
|
|
|
# Should show "Up" status
|
|
# If not:
|
|
docker compose up -d v2-postgres
|
|
|
|
# Check logs
|
|
docker compose logs v2-postgres | tail -50
|
|
```
|
|
|
|
**Solution 2: Verify DATABASE_URL**
|
|
|
|
```bash
|
|
# Check .env
|
|
cat .env | grep DATABASE_URL
|
|
|
|
# From API container, should use container name:
|
|
DATABASE_URL="postgresql://changemaker:password@v2-postgres:5432/changemaker_v2"
|
|
|
|
# From host, use localhost:
|
|
DATABASE_URL="postgresql://changemaker:password@localhost:5433/changemaker_v2"
|
|
```
|
|
|
|
**Solution 3: Test database connection**
|
|
|
|
```bash
|
|
# From API container
|
|
docker compose exec api sh -c 'psql $DATABASE_URL -c "SELECT NOW();"'
|
|
|
|
# Should return current timestamp
|
|
# If fails, database connection is broken
|
|
```
|
|
|
|
**Solution 4: Check Docker network**
|
|
|
|
```bash
|
|
# List networks
|
|
docker network ls
|
|
|
|
# Inspect changemaker-lite network
|
|
docker network inspect changemaker-lite
|
|
|
|
# All containers should be on same network
|
|
```
|
|
|
|
**Solution 5: Use depends_on with health check**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
depends_on:
|
|
v2-postgres:
|
|
condition: service_healthy
|
|
# ...
|
|
|
|
v2-postgres:
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U changemaker"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Health checks** - Wait for database to be ready
|
|
- **Retry logic** - Retry connection on startup
|
|
- **Connection pooling** - Handle connection failures gracefully
|
|
- **Monitoring** - Alert on connection failures
|
|
|
|
---
|
|
|
|
## Networking Issues
|
|
|
|
### Containers Can't Communicate
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
```
|
|
Error: getaddrinfo ENOTFOUND v2-postgres
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
Error: connect EHOSTUNREACH 172.18.0.2:5432
|
|
```
|
|
|
|
Containers can't ping each other.
|
|
|
|
#### Common Causes
|
|
|
|
1. **Different networks** - Containers on separate Docker networks
|
|
2. **Wrong hostname** - Using IP instead of container name
|
|
3. **Firewall** - Host firewall blocking
|
|
4. **DNS issue** - Docker DNS not working
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Verify same network**
|
|
|
|
```bash
|
|
# Check container networks
|
|
docker inspect changemaker-lite-api-1 | grep NetworkMode
|
|
docker inspect changemaker-lite-v2-postgres-1 | grep NetworkMode
|
|
|
|
# Should both show "changemaker-lite"
|
|
```
|
|
|
|
**Solution 2: Use container names**
|
|
|
|
```yaml
|
|
# Correct - use service names
|
|
api:
|
|
environment:
|
|
- DATABASE_URL=postgresql://user:pass@v2-postgres:5432/db
|
|
|
|
# Wrong - using IPs
|
|
api:
|
|
environment:
|
|
- DATABASE_URL=postgresql://user:pass@172.18.0.2:5432/db
|
|
```
|
|
|
|
**Solution 3: Test connectivity**
|
|
|
|
```bash
|
|
# Ping from one container to another
|
|
docker compose exec api ping v2-postgres
|
|
|
|
# DNS lookup
|
|
docker compose exec api nslookup v2-postgres
|
|
|
|
# Telnet to port
|
|
docker compose exec api telnet v2-postgres 5432
|
|
```
|
|
|
|
**Solution 4: Recreate network**
|
|
|
|
```bash
|
|
# Stop all containers
|
|
docker compose down
|
|
|
|
# Remove network
|
|
docker network rm changemaker-lite
|
|
|
|
# Start fresh (network auto-created)
|
|
docker compose up -d
|
|
```
|
|
|
|
**Solution 5: Check firewall**
|
|
|
|
```bash
|
|
# Temporarily disable firewall (Linux)
|
|
sudo ufw disable
|
|
|
|
# Test if containers can communicate
|
|
# If yes, firewall is blocking
|
|
|
|
# Re-enable and add rules
|
|
sudo ufw enable
|
|
sudo ufw allow from 172.18.0.0/16 to any
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Use service names** - Never hardcode IPs
|
|
- **Single network** - All services on same network
|
|
- **Docker DNS** - Rely on Docker's built-in DNS
|
|
- **Health checks** - Verify connectivity on startup
|
|
|
|
---
|
|
|
|
### Port Not Accessible from Host
|
|
|
|
**Severity:** 🟠 High
|
|
|
|
#### Symptoms
|
|
|
|
From host:
|
|
|
|
```bash
|
|
curl http://localhost:4000/api/health
|
|
# curl: (7) Failed to connect to localhost port 4000: Connection refused
|
|
```
|
|
|
|
But from inside container:
|
|
|
|
```bash
|
|
docker compose exec api curl http://localhost:4000/api/health
|
|
# {"status":"healthy"}
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Port not published** - Missing `ports:` in docker-compose.yml
|
|
2. **Bound to 127.0.0.1** - Only listening on localhost inside container
|
|
3. **Firewall blocking** - Host firewall blocking port
|
|
4. **Wrong port** - Trying different port than published
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Check port publishing**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
ports:
|
|
- "4000:4000" # host:container
|
|
```
|
|
|
|
Verify:
|
|
|
|
```bash
|
|
docker compose ps api
|
|
|
|
# Should show:
|
|
# PORTS: 0.0.0.0:4000->4000/tcp
|
|
```
|
|
|
|
**Solution 2: Bind to 0.0.0.0**
|
|
|
|
In `api/src/server.ts`:
|
|
|
|
```typescript
|
|
// Wrong - only localhost
|
|
app.listen(4000, '127.0.0.1');
|
|
|
|
// Right - all interfaces
|
|
app.listen(4000, '0.0.0.0');
|
|
|
|
// Or just
|
|
app.listen(4000); // Defaults to 0.0.0.0
|
|
```
|
|
|
|
**Solution 3: Check firewall**
|
|
|
|
```bash
|
|
# Check if port allowed (Linux)
|
|
sudo ufw status
|
|
|
|
# Allow port
|
|
sudo ufw allow 4000/tcp
|
|
|
|
# Or disable temporarily for testing
|
|
sudo ufw disable
|
|
```
|
|
|
|
**Solution 4: Verify correct port**
|
|
|
|
```bash
|
|
# Check what ports are actually listening
|
|
docker compose exec api netstat -tuln
|
|
|
|
# Should show:
|
|
# tcp6 0 0 :::4000 :::* LISTEN
|
|
```
|
|
|
|
**Solution 5: Restart with port forwarding**
|
|
|
|
```bash
|
|
# Stop container
|
|
docker compose stop api
|
|
|
|
# Remove container
|
|
docker compose rm -f api
|
|
|
|
# Start fresh
|
|
docker compose up -d api
|
|
|
|
# Verify port
|
|
curl http://localhost:4000/api/health
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Always publish ports** - In docker-compose.yml
|
|
- **Bind to 0.0.0.0** - Not 127.0.0.1
|
|
- **Test from host** - Verify accessibility
|
|
- **Document ports** - Keep port reference updated
|
|
|
|
---
|
|
|
|
### DNS Resolution Failures
|
|
|
|
**Severity:** 🟠 High
|
|
|
|
#### Symptoms
|
|
|
|
```
|
|
Error: getaddrinfo ENOTFOUND smtp.gmail.com
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
Error: getaddrinfo EAI_AGAIN api.represent.org
|
|
```
|
|
|
|
Container can't resolve external hostnames.
|
|
|
|
#### Common Causes
|
|
|
|
1. **Docker DNS issue** - Docker DNS not working
|
|
2. **No internet** - Container has no internet access
|
|
3. **Firewall blocking DNS** - Port 53 blocked
|
|
4. **Wrong DNS servers** - Using invalid DNS servers
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Test DNS resolution**
|
|
|
|
```bash
|
|
# From inside container
|
|
docker compose exec api nslookup google.com
|
|
|
|
# Should return IP address
|
|
# If not, DNS is broken
|
|
```
|
|
|
|
**Solution 2: Check Docker DNS**
|
|
|
|
```bash
|
|
# View container DNS config
|
|
docker compose exec api cat /etc/resolv.conf
|
|
|
|
# Should show:
|
|
# nameserver 127.0.0.11 # Docker's embedded DNS
|
|
```
|
|
|
|
**Solution 3: Use custom DNS servers**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
dns:
|
|
- 8.8.8.8 # Google DNS
|
|
- 8.8.4.4
|
|
```
|
|
|
|
Or in `/etc/docker/daemon.json`:
|
|
|
|
```json
|
|
{
|
|
"dns": ["8.8.8.8", "8.8.4.4"]
|
|
}
|
|
```
|
|
|
|
Then restart Docker:
|
|
|
|
```bash
|
|
sudo systemctl restart docker
|
|
```
|
|
|
|
**Solution 4: Check internet connectivity**
|
|
|
|
```bash
|
|
# Ping external host
|
|
docker compose exec api ping -c 3 8.8.8.8
|
|
|
|
# If fails, no internet access
|
|
# Check host internet connection
|
|
ping -c 3 8.8.8.8
|
|
```
|
|
|
|
**Solution 5: Restart Docker daemon**
|
|
|
|
```bash
|
|
# Sometimes Docker DNS gets stuck
|
|
sudo systemctl restart docker
|
|
|
|
# Then restart containers
|
|
docker compose down
|
|
docker compose up -d
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Reliable DNS** - Use public DNS servers as backup
|
|
- **Monitor connectivity** - Alert on DNS failures
|
|
- **Health checks** - Include external connectivity checks
|
|
- **Retry logic** - Handle transient DNS failures
|
|
|
|
---
|
|
|
|
## Volume Issues
|
|
|
|
### Permission Denied
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
```
|
|
Error: EACCES: permission denied, open '/app/uploads/image.jpg'
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
Error: EACCES: permission denied, mkdir '/media/local/inbox'
|
|
```
|
|
|
|
File operations fail inside container.
|
|
|
|
#### Common Causes
|
|
|
|
1. **Wrong ownership** - Host directory owned by different user
|
|
2. **Wrong permissions** - Directory not writable
|
|
3. **SELinux** - Linux security policy blocking
|
|
4. **Read-only mount** - Volume mounted as read-only
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Check ownership**
|
|
|
|
```bash
|
|
# On host
|
|
ls -la uploads/
|
|
|
|
# Shows:
|
|
# drwxr-xr-x 2 root root 4096 Feb 13 10:00 uploads
|
|
|
|
# Check container user
|
|
docker compose exec api id
|
|
# uid=1000(node) gid=1000(node)
|
|
|
|
# Fix ownership
|
|
sudo chown -R 1000:1000 uploads/
|
|
```
|
|
|
|
**Solution 2: Fix permissions**
|
|
|
|
```bash
|
|
# Make writable
|
|
chmod -R 755 uploads/
|
|
|
|
# Or more permissive (dev only)
|
|
chmod -R 777 uploads/
|
|
```
|
|
|
|
**Solution 3: Check mount mode**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
volumes:
|
|
- ./uploads:/app/uploads:rw # Read-write
|
|
# Not:
|
|
# - ./uploads:/app/uploads:ro # Read-only
|
|
```
|
|
|
|
**Solution 4: SELinux labels**
|
|
|
|
```bash
|
|
# Add :z flag to volume
|
|
# In docker-compose.yml:
|
|
- ./uploads:/app/uploads:z
|
|
|
|
# Or relabel directory
|
|
sudo chcon -Rt svirt_sandbox_file_t uploads/
|
|
```
|
|
|
|
**Solution 5: Run as root (not recommended)**
|
|
|
|
```yaml
|
|
# In docker-compose.yml (last resort)
|
|
api:
|
|
user: "0:0" # Run as root
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Set permissions early** - In setup script
|
|
- **Match UIDs** - Container user matches host user
|
|
- **SELinux-aware** - Use :z flag on volumes
|
|
- **Document requirements** - List permission requirements
|
|
|
|
---
|
|
|
|
### Volume Not Mounted
|
|
|
|
**Severity:** 🟠 High
|
|
|
|
#### Symptoms
|
|
|
|
Container can't see files that exist on host.
|
|
|
|
```bash
|
|
# On host
|
|
ls uploads/
|
|
# image.jpg video.mp4
|
|
|
|
# In container
|
|
docker compose exec api ls /app/uploads/
|
|
# (empty)
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Wrong path** - Volume path incorrect
|
|
2. **Typo** - Syntax error in docker-compose.yml
|
|
3. **Not mounted** - Volume mount missing
|
|
4. **Cached old config** - Using old container
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Verify volume configuration**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
api:
|
|
volumes:
|
|
- ./uploads:/app/uploads # host:container
|
|
```
|
|
|
|
**Solution 2: Check mounts in running container**
|
|
|
|
```bash
|
|
# Inspect container mounts
|
|
docker inspect changemaker-lite-api-1 | grep -A 10 Mounts
|
|
|
|
# Should show:
|
|
# "Mounts": [
|
|
# {
|
|
# "Type": "bind",
|
|
# "Source": "/home/user/changemaker.lite/uploads",
|
|
# "Destination": "/app/uploads",
|
|
# "Mode": "",
|
|
# "RW": true,
|
|
# "Propagation": "rprivate"
|
|
# }
|
|
# ]
|
|
```
|
|
|
|
**Solution 3: Recreate container**
|
|
|
|
```bash
|
|
# Stop and remove container
|
|
docker compose down api
|
|
|
|
# Start fresh
|
|
docker compose up -d api
|
|
|
|
# Verify mount
|
|
docker compose exec api ls /app/uploads/
|
|
```
|
|
|
|
**Solution 4: Use absolute path**
|
|
|
|
```yaml
|
|
# Sometimes relative paths don't work
|
|
api:
|
|
volumes:
|
|
- /home/user/changemaker.lite/uploads:/app/uploads
|
|
```
|
|
|
|
**Solution 5: Check Docker Compose version**
|
|
|
|
```bash
|
|
# Check version
|
|
docker compose version
|
|
|
|
# Should be v2+
|
|
# If v1, syntax might differ
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Test mounts** - Verify after container start
|
|
- **Use relative paths** - Start with `./`
|
|
- **Documentation** - Document all volume mounts
|
|
- **Health checks** - Verify critical files exist
|
|
|
|
---
|
|
|
|
### Data Persistence Problems
|
|
|
|
**Severity:** 🔴 Critical
|
|
|
|
#### Symptoms
|
|
|
|
Data disappears after `docker compose down`:
|
|
|
|
- Database data lost
|
|
- Uploaded files missing
|
|
- Configuration reset
|
|
|
|
#### Common Causes
|
|
|
|
1. **Using containers, not volumes** - Data stored in container filesystem
|
|
2. **Anonymous volumes** - Volume not named or bound
|
|
3. **Deleting volumes** - `docker compose down -v` removes volumes
|
|
4. **Wrong volume type** - tmpfs instead of volume
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Use named volumes**
|
|
|
|
In `docker-compose.yml`:
|
|
|
|
```yaml
|
|
v2-postgres:
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data # Named volume
|
|
|
|
volumes:
|
|
postgres-data: # Declare named volume
|
|
```
|
|
|
|
**Solution 2: Use bind mounts**
|
|
|
|
```yaml
|
|
v2-postgres:
|
|
volumes:
|
|
- ./data/postgres:/var/lib/postgresql/data # Bind to host directory
|
|
```
|
|
|
|
**Solution 3: Don't use -v flag**
|
|
|
|
```bash
|
|
# Wrong - deletes volumes
|
|
docker compose down -v
|
|
|
|
# Right - keeps volumes
|
|
docker compose down
|
|
```
|
|
|
|
**Solution 4: Check volume exists**
|
|
|
|
```bash
|
|
# List volumes
|
|
docker volume ls
|
|
|
|
# Should show:
|
|
# changemaker-lite_postgres-data
|
|
|
|
# Inspect volume
|
|
docker volume inspect changemaker-lite_postgres-data
|
|
```
|
|
|
|
**Solution 5: Backup before down**
|
|
|
|
```bash
|
|
# Backup database before stopping
|
|
docker compose exec v2-postgres pg_dump -U changemaker changemaker_v2 > backup.sql
|
|
|
|
# Then safe to:
|
|
docker compose down -v
|
|
|
|
# Restore after up:
|
|
docker compose up -d v2-postgres
|
|
docker compose exec -T v2-postgres psql -U changemaker changemaker_v2 < backup.sql
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Named volumes** - For all persistent data
|
|
- **Regular backups** - Automated backup script
|
|
- **Never use -v** - Unless intentionally resetting
|
|
- **Documentation** - Document what data persists where
|
|
|
|
---
|
|
|
|
## Performance Issues
|
|
|
|
### Slow Container Startup
|
|
|
|
**Severity:** 🟡 Medium
|
|
|
|
#### Symptoms
|
|
|
|
Container takes minutes to start:
|
|
|
|
```bash
|
|
docker compose up -d api
|
|
# Creating api ... (2 minutes)
|
|
# Creating api ... done
|
|
```
|
|
|
|
#### Common Causes
|
|
|
|
1. **Large image** - Downloading/extracting large image
|
|
2. **Many dependencies** - npm install taking long
|
|
3. **Health check delay** - Waiting for health checks
|
|
4. **Slow disk** - I/O bottleneck
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Use pre-built image**
|
|
|
|
```yaml
|
|
# Instead of building locally
|
|
api:
|
|
build: ./api
|
|
|
|
# Use pre-built image from registry
|
|
api:
|
|
image: ghcr.io/yourorg/changemaker-api:latest
|
|
```
|
|
|
|
**Solution 2: Layer caching**
|
|
|
|
```dockerfile
|
|
# In Dockerfile, copy package files first
|
|
COPY package*.json ./
|
|
RUN npm ci
|
|
|
|
# Then copy code (changes more frequently)
|
|
COPY . .
|
|
RUN npm run build
|
|
```
|
|
|
|
**Solution 3: Multi-stage builds**
|
|
|
|
```dockerfile
|
|
# Build stage
|
|
FROM node:20-alpine AS builder
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm ci
|
|
COPY . .
|
|
RUN npm run build
|
|
|
|
# Runtime stage (smaller)
|
|
FROM node:20-alpine
|
|
WORKDIR /app
|
|
COPY --from=builder /app/dist ./dist
|
|
COPY --from=builder /app/node_modules ./node_modules
|
|
COPY package*.json ./
|
|
CMD ["node", "dist/server.js"]
|
|
```
|
|
|
|
**Solution 4: Increase Docker resources**
|
|
|
|
In Docker Desktop settings:
|
|
|
|
- CPU: 4+ cores
|
|
- Memory: 8GB+
|
|
- Disk: Fast SSD
|
|
|
|
**Solution 5: Parallel builds**
|
|
|
|
```bash
|
|
# Build all services in parallel
|
|
docker compose build --parallel
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Optimize Dockerfile** - Layer caching, multi-stage
|
|
- **Small base images** - Alpine instead of full images
|
|
- **Registry caching** - Pull from registry instead of building
|
|
- **Resource allocation** - Adequate CPU/memory for Docker
|
|
|
|
---
|
|
|
|
### High CPU Usage
|
|
|
|
**Severity:** 🟠 High
|
|
|
|
#### Symptoms
|
|
|
|
```bash
|
|
docker stats
|
|
# CONTAINER CPU %
|
|
# api 95%
|
|
```
|
|
|
|
Container consuming excessive CPU.
|
|
|
|
#### Common Causes
|
|
|
|
1. **Infinite loop** - Bug causing tight loop
|
|
2. **Heavy computation** - Processing large dataset
|
|
3. **Too many workers** - Worker threads maxed out
|
|
4. **Memory thrashing** - Swapping due to low memory
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Identify process**
|
|
|
|
```bash
|
|
# Top inside container
|
|
docker compose exec api top
|
|
|
|
# Shows process using CPU
|
|
```
|
|
|
|
**Solution 2: Check for loops**
|
|
|
|
```bash
|
|
# View logs for repeated messages
|
|
docker compose logs api | tail -100
|
|
|
|
# Restart if stuck
|
|
docker compose restart api
|
|
```
|
|
|
|
**Solution 3: Limit worker threads**
|
|
|
|
```javascript
|
|
// In BullMQ worker
|
|
new Worker('queueName', processor, {
|
|
concurrency: 2, // Reduce from 10
|
|
limiter: {
|
|
max: 10,
|
|
duration: 1000 // Max 10 jobs per second
|
|
}
|
|
});
|
|
```
|
|
|
|
**Solution 4: Set CPU limits**
|
|
|
|
```yaml
|
|
api:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: '2.0' # Max 2 CPUs
|
|
```
|
|
|
|
**Solution 5: Profile application**
|
|
|
|
```bash
|
|
# Use Node.js profiler
|
|
docker compose exec api node --prof dist/server.js
|
|
|
|
# Or clinic.js
|
|
npm install -g clinic
|
|
clinic doctor -- node dist/server.js
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Monitor CPU** - Alert on high usage
|
|
- **Rate limiting** - Limit request rate
|
|
- **Queue management** - Control worker concurrency
|
|
- **Performance testing** - Load test regularly
|
|
|
|
---
|
|
|
|
### High Memory Usage
|
|
|
|
**Severity:** 🟠 High
|
|
|
|
#### Symptoms
|
|
|
|
```bash
|
|
docker stats
|
|
# CONTAINER MEM USAGE / LIMIT
|
|
# api 3.8GiB / 4GiB
|
|
```
|
|
|
|
Memory usage keeps increasing.
|
|
|
|
#### Common Causes
|
|
|
|
1. **Memory leak** - Not releasing memory
|
|
2. **Large cache** - Caching too much data
|
|
3. **Database connections** - Too many open connections
|
|
4. **Large response bodies** - Sending huge payloads
|
|
|
|
#### Solutions
|
|
|
|
**Solution 1: Identify memory usage**
|
|
|
|
```bash
|
|
# Memory breakdown inside container
|
|
docker compose exec api sh -c 'cat /proc/meminfo'
|
|
|
|
# Node.js heap stats
|
|
docker compose exec api node -e "console.log(process.memoryUsage())"
|
|
```
|
|
|
|
**Solution 2: Restart to free memory**
|
|
|
|
```bash
|
|
# Temporary fix
|
|
docker compose restart api
|
|
|
|
# Memory should drop
|
|
docker stats api
|
|
```
|
|
|
|
**Solution 3: Reduce cache size**
|
|
|
|
```typescript
|
|
// In Redis cache
|
|
redis.set(key, value, 'EX', 3600); // Expire after 1 hour
|
|
|
|
// Limit cache size
|
|
const cache = new LRU({
|
|
max: 1000, // Max 1000 entries
|
|
maxAge: 3600000 // 1 hour
|
|
});
|
|
```
|
|
|
|
**Solution 4: Set memory limit**
|
|
|
|
```yaml
|
|
api:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 2G # Hard limit
|
|
reservations:
|
|
memory: 1G # Reserved amount
|
|
```
|
|
|
|
**Solution 5: Find memory leak**
|
|
|
|
```bash
|
|
# Take heap snapshot
|
|
docker compose exec api node --expose-gc --inspect dist/server.js
|
|
|
|
# Use Chrome DevTools to analyze
|
|
# chrome://inspect
|
|
```
|
|
|
|
#### Prevention
|
|
|
|
- **Monitor memory** - Alert on high usage
|
|
- **Memory limits** - Prevent runaway processes
|
|
- **Regular restarts** - Restart daily if leaking
|
|
- **Memory profiling** - Profile in staging
|
|
|
|
---
|
|
|
|
## Useful Commands
|
|
|
|
### Viewing Logs
|
|
|
|
```bash
|
|
# Last 100 lines
|
|
docker compose logs api --tail=100
|
|
|
|
# Follow logs (real-time)
|
|
docker compose logs -f api
|
|
|
|
# All services
|
|
docker compose logs
|
|
|
|
# Since timestamp
|
|
docker compose logs --since="2026-02-13T10:00:00"
|
|
|
|
# Filter by keyword
|
|
docker compose logs api | grep -i error
|
|
|
|
# Save to file
|
|
docker compose logs api > api-logs.txt
|
|
```
|
|
|
|
### Executing Commands
|
|
|
|
```bash
|
|
# Run command in running container
|
|
docker compose exec api npm run migrate
|
|
|
|
# Interactive shell
|
|
docker compose exec api sh
|
|
|
|
# Run as different user
|
|
docker compose exec -u root api sh
|
|
|
|
# Run in new container (one-off)
|
|
docker compose run --rm api npm test
|
|
```
|
|
|
|
### Inspecting Containers
|
|
|
|
```bash
|
|
# View container details
|
|
docker inspect changemaker-lite-api-1
|
|
|
|
# View specific field
|
|
docker inspect changemaker-lite-api-1 --format='{{.State.Status}}'
|
|
|
|
# View environment variables
|
|
docker inspect changemaker-lite-api-1 --format='{{range .Config.Env}}{{println .}}{{end}}'
|
|
|
|
# View mounts
|
|
docker inspect changemaker-lite-api-1 --format='{{json .Mounts}}' | jq
|
|
```
|
|
|
|
### Container Management
|
|
|
|
```bash
|
|
# Start all services
|
|
docker compose up -d
|
|
|
|
# Start specific service
|
|
docker compose up -d api
|
|
|
|
# Stop all services
|
|
docker compose stop
|
|
|
|
# Stop specific service
|
|
docker compose stop api
|
|
|
|
# Restart service
|
|
docker compose restart api
|
|
|
|
# Remove stopped containers
|
|
docker compose rm
|
|
|
|
# Stop and remove
|
|
docker compose down
|
|
```
|
|
|
|
### Rebuilding
|
|
|
|
```bash
|
|
# Rebuild single service
|
|
docker compose build api
|
|
|
|
# Rebuild without cache
|
|
docker compose build --no-cache api
|
|
|
|
# Build all services
|
|
docker compose build
|
|
|
|
# Build and start
|
|
docker compose up -d --build
|
|
|
|
# Force recreate containers
|
|
docker compose up -d --force-recreate
|
|
```
|
|
|
|
---
|
|
|
|
## Log Analysis
|
|
|
|
### Reading Container Logs
|
|
|
|
Logs follow this pattern:
|
|
|
|
```
|
|
[timestamp] [level] [message]
|
|
2026-02-13T10:30:00.000Z INFO Server started on port 4000
|
|
```
|
|
|
|
### Common Log Patterns
|
|
|
|
**Successful startup:**
|
|
|
|
```
|
|
INFO Connecting to database...
|
|
INFO Database connected
|
|
INFO Registered route: GET /api/health
|
|
INFO Registered route: POST /api/auth/login
|
|
INFO Server started on port 4000
|
|
```
|
|
|
|
**Database connection error:**
|
|
|
|
```
|
|
INFO Connecting to database...
|
|
ERROR Can't reach database server at `v2-postgres:5432`
|
|
ERROR Retrying in 5 seconds...
|
|
```
|
|
|
|
**Missing environment variable:**
|
|
|
|
```
|
|
ERROR Environment validation failed:
|
|
ERROR SMTP_HOST is required
|
|
ERROR JWT_ACCESS_SECRET is required
|
|
```
|
|
|
|
**Health check failure:**
|
|
|
|
```
|
|
WARN Health check failed: Database not connected
|
|
```
|
|
|
|
### Filtering Logs
|
|
|
|
```bash
|
|
# Only errors
|
|
docker compose logs api | grep ERROR
|
|
|
|
# Only warnings and errors
|
|
docker compose logs api | grep -E "ERROR|WARN"
|
|
|
|
# Exclude health checks
|
|
docker compose logs api | grep -v "GET /api/health"
|
|
|
|
# Find specific request
|
|
docker compose logs api | grep "POST /api/users"
|
|
|
|
# Find by request ID
|
|
docker compose logs api | grep "req-abc123"
|
|
```
|
|
|
|
---
|
|
|
|
## Cleanup Commands
|
|
|
|
### Remove Stopped Containers
|
|
|
|
```bash
|
|
# Remove all stopped containers
|
|
docker compose down
|
|
|
|
# Remove specific service containers
|
|
docker compose rm api
|
|
|
|
# Force remove running containers
|
|
docker compose rm -f api
|
|
```
|
|
|
|
### Remove Images
|
|
|
|
```bash
|
|
# Remove all images for project
|
|
docker compose down --rmi all
|
|
|
|
# Remove only project-built images (not postgres, redis, etc.)
|
|
docker compose down --rmi local
|
|
|
|
# Remove specific image
|
|
docker rmi changemaker-lite-api
|
|
|
|
# Remove dangling images
|
|
docker image prune
|
|
```
|
|
|
|
### Remove Volumes
|
|
|
|
```bash
|
|
# ⚠️ WARNING: Deletes all data!
|
|
docker compose down -v
|
|
|
|
# Remove specific volume
|
|
docker volume rm changemaker-lite_postgres-data
|
|
|
|
# Remove unused volumes
|
|
docker volume prune
|
|
```
|
|
|
|
### Remove Networks
|
|
|
|
```bash
|
|
# Remove project network (containers must be stopped first)
|
|
docker network rm changemaker-lite
|
|
|
|
# Remove unused networks
|
|
docker network prune
|
|
```
|
|
|
|
### Full Cleanup
|
|
|
|
```bash
|
|
# ⚠️ DANGER: Removes everything!
|
|
docker compose down -v --rmi all
|
|
docker system prune -a --volumes
|
|
|
|
# This deletes:
|
|
# - All containers
|
|
# - All volumes (data lost!)
|
|
# - All images
|
|
# - All networks
|
|
# - All build cache
|
|
```
|
|
|
|
### Safe Cleanup
|
|
|
|
```bash
|
|
# Safe cleanup (keeps volumes)
|
|
docker compose down
|
|
docker image prune -a
|
|
docker network prune
|
|
|
|
# This keeps:
|
|
# - Volumes (data safe)
|
|
# - .env file
|
|
# - Application code
|
|
```
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
### Docker Documentation
|
|
- [Docker Issues](docker-issues.md) - This guide
|
|
- [Installation Guide](../user/installation.md) - Initial setup
|
|
- [Architecture Overview](../technical/architecture.md) - System design
|
|
|
|
### Other Troubleshooting
|
|
- [Common Errors](common-errors.md) - General errors
|
|
- [Database Issues](database-issues.md) - PostgreSQL problems
|
|
- [Monitoring Issues](monitoring-issues.md) - Observability problems
|
|
|
|
### Docker Resources
|
|
- [Docker Compose Reference](https://docs.docker.com/compose/)
|
|
- [Dockerfile Best Practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
|
|
- [Docker Networking](https://docs.docker.com/network/)
|
|
|
|
---
|
|
|
|
**Last Updated:** February 2026
|
|
**Version:** V2.0
|
|
**Status:** Complete
|