inital
This commit is contained in:
501
DOCKER_SETUP.md
Normal file
501
DOCKER_SETUP.md
Normal file
@@ -0,0 +1,501 @@
|
||||
# Docker Setup Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the production-ready Docker setup for the Feuerwehr Dashboard application, including multi-stage builds, security best practices, and deployment instructions.
|
||||
|
||||
## Architecture
|
||||
|
||||
The application consists of three Docker containers:
|
||||
|
||||
1. **PostgreSQL Database** - postgres:16-alpine
|
||||
2. **Backend API** - Node.js application (TypeScript compiled to JavaScript)
|
||||
3. **Frontend** - React SPA served by Nginx
|
||||
|
||||
All containers are connected via a Docker bridge network and orchestrated using Docker Compose.
|
||||
|
||||
## Files Structure
|
||||
|
||||
```
|
||||
feuerwehr_dashboard/
|
||||
├── docker-compose.yml # Production orchestration
|
||||
├── docker-compose.dev.yml # Development orchestration
|
||||
├── docker-test.sh # Docker build testing script
|
||||
├── backend/
|
||||
│ ├── Dockerfile # Multi-stage backend build
|
||||
│ └── .dockerignore # Backend Docker ignore rules
|
||||
└── frontend/
|
||||
├── Dockerfile # Multi-stage frontend build
|
||||
├── nginx.conf # Nginx configuration for SPA
|
||||
└── .dockerignore # Frontend Docker ignore rules
|
||||
```
|
||||
|
||||
## Backend Dockerfile
|
||||
|
||||
**Location:** `/backend/Dockerfile`
|
||||
|
||||
### Features
|
||||
|
||||
- **Multi-stage build** - Separate build and production stages
|
||||
- **Build stage:**
|
||||
- Based on node:20-alpine
|
||||
- Installs all dependencies (including devDependencies)
|
||||
- Compiles TypeScript to JavaScript
|
||||
- Prunes devDependencies after build
|
||||
- **Production stage:**
|
||||
- Based on node:20-alpine
|
||||
- Installs wget for health checks
|
||||
- Creates non-root user (nodejs:1001)
|
||||
- Copies only production node_modules
|
||||
- Copies compiled JavaScript
|
||||
- Copies database migrations to dist/
|
||||
- Runs as non-root user
|
||||
- Exposes port 3000
|
||||
- Includes health check
|
||||
|
||||
### Build Command
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
docker build -t feuerwehr-backend:latest .
|
||||
```
|
||||
|
||||
### Image Size
|
||||
|
||||
Expected final image size: ~150-200 MB (alpine-based)
|
||||
|
||||
### Security Features
|
||||
|
||||
- Non-root user execution
|
||||
- Minimal base image (Alpine Linux)
|
||||
- Only production dependencies included
|
||||
- No source code in final image
|
||||
|
||||
## Frontend Dockerfile
|
||||
|
||||
**Location:** `/frontend/Dockerfile`
|
||||
|
||||
### Features
|
||||
|
||||
- **Multi-stage build** - Build stage with Node.js + production stage with Nginx
|
||||
- **Build stage:**
|
||||
- Based on node:20-alpine
|
||||
- Installs dependencies
|
||||
- Runs Vite build
|
||||
- Accepts build arguments for environment variables
|
||||
- **Production stage:**
|
||||
- Based on nginx:alpine
|
||||
- Installs wget for health checks
|
||||
- Copies custom nginx.conf
|
||||
- Copies built static assets
|
||||
- Configures non-root nginx user
|
||||
- Exposes port 80
|
||||
- Includes health check
|
||||
|
||||
### Build Command
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
docker build \
|
||||
--build-arg VITE_API_URL=http://localhost:3000 \
|
||||
--build-arg VITE_APP_NAME="Feuerwehr Dashboard" \
|
||||
--build-arg VITE_APP_VERSION="1.0.0" \
|
||||
-t feuerwehr-frontend:latest .
|
||||
```
|
||||
|
||||
### Build Arguments
|
||||
|
||||
- `VITE_API_URL` - Backend API URL (default: http://localhost:3000)
|
||||
- `VITE_APP_NAME` - Application name (default: "Feuerwehr Dashboard")
|
||||
- `VITE_APP_VERSION` - Application version (default: "1.0.0")
|
||||
|
||||
### Image Size
|
||||
|
||||
Expected final image size: ~50-80 MB (alpine + static assets)
|
||||
|
||||
### Security Features
|
||||
|
||||
- Non-root nginx execution
|
||||
- Minimal base image (Alpine Linux)
|
||||
- Security headers configured
|
||||
- No source code in final image
|
||||
|
||||
## Nginx Configuration
|
||||
|
||||
**Location:** `/frontend/nginx.conf`
|
||||
|
||||
### Features
|
||||
|
||||
1. **SPA Routing**
|
||||
- All routes fall back to index.html
|
||||
- Proper handling of client-side routing
|
||||
|
||||
2. **Performance**
|
||||
- Gzip compression enabled
|
||||
- Static asset caching (1 year)
|
||||
- No caching for index.html
|
||||
|
||||
3. **Security Headers**
|
||||
- X-Frame-Options: SAMEORIGIN
|
||||
- X-Content-Type-Options: nosniff
|
||||
- X-XSS-Protection: 1; mode=block
|
||||
- Referrer-Policy: strict-origin-when-cross-origin
|
||||
|
||||
4. **Health Check**
|
||||
- Endpoint: /health
|
||||
- Returns 200 with "healthy" text
|
||||
|
||||
5. **Error Handling**
|
||||
- 404 errors redirect to index.html
|
||||
- Custom 50x error page
|
||||
|
||||
## Docker Compose
|
||||
|
||||
**Location:** `/docker-compose.yml`
|
||||
|
||||
### Services
|
||||
|
||||
#### PostgreSQL
|
||||
|
||||
```yaml
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
ports: 5432:5432
|
||||
volumes: postgres_data_prod
|
||||
health_check: pg_isready
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
#### Backend
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
build: ./backend
|
||||
ports: 3000:3000
|
||||
depends_on: postgres (healthy)
|
||||
health_check: wget localhost:3000/health
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
#### Frontend
|
||||
|
||||
```yaml
|
||||
frontend:
|
||||
build: ./frontend
|
||||
build_args: VITE_API_URL
|
||||
ports: 80:80
|
||||
depends_on: backend (healthy)
|
||||
health_check: wget localhost:80/health
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Create a `.env` file based on `.env.example`:
|
||||
|
||||
**Required:**
|
||||
- `POSTGRES_PASSWORD` - Database password
|
||||
- `JWT_SECRET` - JWT signing secret
|
||||
|
||||
**Optional:**
|
||||
- `POSTGRES_DB` - Database name (default: feuerwehr_prod)
|
||||
- `POSTGRES_USER` - Database user (default: prod_user)
|
||||
- `POSTGRES_PORT` - Database port (default: 5432)
|
||||
- `BACKEND_PORT` - Backend port (default: 3000)
|
||||
- `FRONTEND_PORT` - Frontend port (default: 80)
|
||||
- `CORS_ORIGIN` - CORS origin (default: http://localhost:80)
|
||||
- `VITE_API_URL` - Frontend API URL (default: http://localhost:3000)
|
||||
|
||||
### Networks
|
||||
|
||||
- `feuerwehr_network` - Bridge network connecting all services
|
||||
|
||||
### Volumes
|
||||
|
||||
- `postgres_data_prod` - Persistent PostgreSQL data
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Test Docker Builds
|
||||
|
||||
Run the test script to verify Docker builds work:
|
||||
|
||||
```bash
|
||||
./docker-test.sh
|
||||
```
|
||||
|
||||
This script will:
|
||||
- Check Docker availability
|
||||
- Build backend image
|
||||
- Build frontend image
|
||||
- Report success/failure
|
||||
- Optionally cleanup test images
|
||||
|
||||
### 2. Configure Environment
|
||||
|
||||
Copy and configure environment file:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env and set required variables
|
||||
```
|
||||
|
||||
### 3. Build and Start Services
|
||||
|
||||
```bash
|
||||
# Build and start all services
|
||||
docker-compose up -d
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Check service status
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### 4. Access Application
|
||||
|
||||
- **Frontend:** http://localhost:80
|
||||
- **Backend API:** http://localhost:3000
|
||||
- **Database:** localhost:5432
|
||||
|
||||
### 5. Stop Services
|
||||
|
||||
```bash
|
||||
# Stop all services
|
||||
docker-compose down
|
||||
|
||||
# Stop and remove volumes
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
## Health Checks
|
||||
|
||||
All services include health checks:
|
||||
|
||||
### PostgreSQL
|
||||
- **Command:** `pg_isready -U $USER -d $DB`
|
||||
- **Interval:** 10s
|
||||
- **Retries:** 5
|
||||
|
||||
### Backend
|
||||
- **Command:** `wget localhost:3000/health`
|
||||
- **Interval:** 30s
|
||||
- **Retries:** 3
|
||||
- **Start Period:** 40s
|
||||
|
||||
### Frontend
|
||||
- **Command:** `wget localhost:80/health`
|
||||
- **Interval:** 30s
|
||||
- **Retries:** 3
|
||||
- **Start Period:** 30s
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Backend Build Fails
|
||||
|
||||
1. Check TypeScript compilation:
|
||||
```bash
|
||||
cd backend
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
2. Verify all source files exist
|
||||
3. Check tsconfig.json configuration
|
||||
|
||||
### Frontend Build Fails
|
||||
|
||||
1. Check Vite build:
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
2. Verify all dependencies are installed
|
||||
3. Check build arguments are correct
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
1. Check logs:
|
||||
```bash
|
||||
docker-compose logs [service-name]
|
||||
```
|
||||
|
||||
2. Verify environment variables in .env
|
||||
3. Check health check status:
|
||||
```bash
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
1. Verify DATABASE_URL format:
|
||||
```
|
||||
postgresql://user:password@postgres:5432/database
|
||||
```
|
||||
|
||||
2. Check postgres service is healthy:
|
||||
```bash
|
||||
docker-compose ps postgres
|
||||
```
|
||||
|
||||
3. Verify network connectivity:
|
||||
```bash
|
||||
docker-compose exec backend ping postgres
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Production Checklist
|
||||
|
||||
- [ ] Set strong POSTGRES_PASSWORD
|
||||
- [ ] Set strong JWT_SECRET (min 32 characters)
|
||||
- [ ] Use HTTPS in production
|
||||
- [ ] Configure proper CORS_ORIGIN
|
||||
- [ ] Enable firewall rules
|
||||
- [ ] Regular security updates
|
||||
- [ ] Monitor container logs
|
||||
- [ ] Backup database regularly
|
||||
|
||||
### Image Security
|
||||
|
||||
- Alpine Linux base (minimal attack surface)
|
||||
- Non-root user execution
|
||||
- No unnecessary packages
|
||||
- Security headers enabled
|
||||
- Health checks configured
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Update Dependencies
|
||||
|
||||
```bash
|
||||
# Rebuild images with latest dependencies
|
||||
docker-compose build --no-cache
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Backup Database
|
||||
|
||||
```bash
|
||||
# Create backup
|
||||
docker-compose exec postgres pg_dump -U $USER $DB > backup.sql
|
||||
|
||||
# Restore backup
|
||||
docker-compose exec -T postgres psql -U $USER $DB < backup.sql
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# All services
|
||||
docker-compose logs -f
|
||||
|
||||
# Specific service
|
||||
docker-compose logs -f backend
|
||||
|
||||
# Last 100 lines
|
||||
docker-compose logs --tail=100 backend
|
||||
```
|
||||
|
||||
### Restart Services
|
||||
|
||||
```bash
|
||||
# Restart all
|
||||
docker-compose restart
|
||||
|
||||
# Restart specific service
|
||||
docker-compose restart backend
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Build Cache
|
||||
|
||||
Docker uses layer caching. To optimize:
|
||||
|
||||
1. Copy package files first
|
||||
2. Install dependencies
|
||||
3. Copy source code last
|
||||
|
||||
This ensures dependency installation is cached.
|
||||
|
||||
### Image Size
|
||||
|
||||
Current image sizes:
|
||||
- Backend: ~150-200 MB
|
||||
- Frontend: ~50-80 MB
|
||||
- Total: ~200-280 MB
|
||||
|
||||
### Resource Limits
|
||||
|
||||
Add resource limits in docker-compose.yml:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 512M
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Container Stats
|
||||
|
||||
```bash
|
||||
docker stats
|
||||
```
|
||||
|
||||
### Health Status
|
||||
|
||||
```bash
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### Resource Usage
|
||||
|
||||
```bash
|
||||
docker system df
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### Using Docker Compose
|
||||
|
||||
```bash
|
||||
# On production server
|
||||
git clone <repository>
|
||||
cd feuerwehr_dashboard
|
||||
cp .env.example .env
|
||||
# Configure .env with production values
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Using Container Registry
|
||||
|
||||
```bash
|
||||
# Build and tag images
|
||||
docker build -t registry.example.com/feuerwehr-backend:v1.0.0 backend/
|
||||
docker build -t registry.example.com/feuerwehr-frontend:v1.0.0 frontend/
|
||||
|
||||
# Push to registry
|
||||
docker push registry.example.com/feuerwehr-backend:v1.0.0
|
||||
docker push registry.example.com/feuerwehr-frontend:v1.0.0
|
||||
|
||||
# Pull and run on production
|
||||
docker pull registry.example.com/feuerwehr-backend:v1.0.0
|
||||
docker pull registry.example.com/feuerwehr-frontend:v1.0.0
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Docker Documentation](https://docs.docker.com/)
|
||||
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
||||
- [Nginx Documentation](https://nginx.org/en/docs/)
|
||||
- [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices)
|
||||
Reference in New Issue
Block a user