# Phase 6, Plan 1: Docker Containerization & Deployment Automation --- **plan**: 06-deployment-scale/01-docker-deployment **feature**: Docker containerization, automated deployment, environment automation **status**: Ready for execution **estimated_tasks**: 6 **total_lines**: ~450 (Dockerfile updates ~200, deploy.sh ~180, compose enhancements ~70) --- ## Overview This plan hardens the existing Docker setup and creates a single-command deployment script. The system already has Dockerfiles and docker-compose.yml; this plan: 1. **Enhances Dockerfiles** — Add health checks, optimize layers, improve logging 2. **Creates deploy.sh** — Automated deployment with validation, initialization, health checks 3. **Environment automation** — Template generation, pre-flight validation 4. **Docker Compose improvements** — Health checks, volume management, dependency ordering 5. **Documentation** — Quick start guide for operators **Success**: `./deploy.sh` deploys full stack on fresh Ubuntu 22.04+ in <5 minutes with zero manual steps. --- ## Tasks ### Task 1: Enhance Backend Dockerfile **File**: `backend/Dockerfile` **Status**: Ready **Description**: Add health checks, optimize build layers, improve production readiness **Changes**: - Add `HEALTHCHECK` instruction (GET /health endpoint) - Optimize RUN commands (reduce layers) - Add metadata labels (version, maintainer, build-date) - Ensure logs go to stdout for Docker log capture - Pin Python version to 3.12 **Acceptance Criteria**: - [ ] Dockerfile builds without warnings - [ ] Health check responds correctly - [ ] Image size <500MB - [ ] Container logs visible in `docker logs` - [ ] All tests still pass **Testing**: ```bash docker build -t inventory-backend:test backend/ docker run --rm -p 8000:8000 inventory-backend:test curl http://localhost:8000/health # Should return 200 ``` --- ### Task 2: Enhance Frontend Dockerfile **File**: `frontend/Dockerfile` **Status**: Ready **Description**: Add health checks, optimize Next.js production build, logging **Changes**: - Add `HEALTHCHECK` instruction (curl to /health or equivalent) - Multi-stage build (builder + runtime) to reduce image size - Ensure Next.js logs to stdout - Optimize node_modules caching layer - Pin Node.js version to LTS **Acceptance Criteria**: - [ ] Dockerfile builds without warnings - [ ] Health check responds correctly - [ ] Image size <300MB - [ ] Next.js startup logs appear in `docker logs` **Testing**: ```bash docker build -t inventory-frontend:test frontend/ docker run --rm -p 3000:3000 inventory-frontend:test curl http://localhost:3000/_next/health # Or custom endpoint ``` --- ### Task 3: Update docker-compose.yml **File**: `docker-compose.yml` **Status**: Ready **Description**: Add health checks, improve service dependencies, enhance resilience **Changes**: - Add `healthcheck` to all three services (backend, frontend, proxy) - Update `depends_on` to use health checks (wait_for: service_healthy) - Add resource limits (memory, CPU) - Improve volume definitions (use named volumes for persistence) - Add restart policies (restart: unless-stopped already present; verify) - Document all environment variables inline **Acceptance Criteria**: - [ ] docker-compose up starts all services in order - [ ] Health checks report healthy status - [ ] Services restart on failure - [ ] Logs from all services visible via `docker-compose logs` **Testing**: ```bash docker-compose up -d docker-compose ps # Should show all healthy docker-compose logs -f docker-compose down ``` --- ### Task 4: Create deploy.sh (Automated Deployment) **File**: `deploy.sh` (new, executable) **Status**: Ready **Description**: Single-command deployment with initialization, validation, health checks **Content** (~180 lines): ```bash #!/bin/bash set -euo pipefail # Phase 6, Plan 1, Task 4: Automated Deployment Script # Usage: ./deploy.sh [production|staging|development] [--rebuild] DEPLOYMENT_ENV="${1:-production}" REBUILD="${2:---no-rebuild}" # Color output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } # 1. Pre-flight checks log_info "Running pre-flight checks..." command -v docker &> /dev/null || log_error "Docker not installed" command -v docker-compose &> /dev/null || log_error "Docker Compose not installed" [[ -f "docker-compose.yml" ]] || log_error "docker-compose.yml not found" [[ -f "inventory.env" ]] || log_error "inventory.env not found; copy from template" # 2. Validate environment file log_info "Validating inventory.env..." source inventory.env [[ -z "${BACKEND_PORT:-}" ]] && log_warn "BACKEND_PORT not set; using default 8000" [[ -z "${FRONTEND_PORT:-}" ]] && log_warn "FRONTEND_PORT not set; using default 3000" # 3. Check port availability log_info "Checking port availability..." for port in ${BACKEND_PORT:-8000} ${FRONTEND_PORT:-3000} ${BACKEND_SSL_PORT:-8918} ${FRONTEND_SSL_PORT:-8919}; do netstat -tuln 2>/dev/null | grep -q ":$port " && log_error "Port $port already in use" done # 4. Build or pull images log_info "Building Docker images (${REBUILD})..." if [[ "$REBUILD" == "--rebuild" ]]; then docker-compose build --no-cache else docker-compose build fi # 5. Create data directories log_info "Creating data directories..." mkdir -p data logs config [[ -d "data/caddy_data" ]] || mkdir -p data/caddy_data [[ -d "data/caddy_config" ]] || mkdir -p data/caddy_config # 6. Initialize database (if not exists) if [[ ! -f "data/inventory.db" ]]; then log_info "Initializing database..." # This will be handled by backend startup; just log the action log_info "Database will be initialized on first backend startup" fi # 7. Start services log_info "Starting services..." docker-compose up -d # 8. Wait for health checks log_info "Waiting for services to be healthy..." max_attempts=30 attempt=0 while [[ $attempt -lt $max_attempts ]]; do healthy=$(docker-compose ps | grep -c "healthy" || echo "0") if [[ $healthy -eq 3 ]]; then log_info "All services healthy!" break fi attempt=$((attempt + 1)) sleep 2 done if [[ $attempt -eq $max_attempts ]]; then log_warn "Services did not become healthy within 60 seconds" docker-compose logs exit 1 fi # 9. Verify connectivity log_info "Verifying connectivity..." if curl -sf "http://localhost:${BACKEND_PORT:-8000}/health" &> /dev/null; then log_info "Backend healthy: http://localhost:${BACKEND_PORT:-8000}" else log_error "Backend health check failed" fi # 10. Display summary log_info "Deployment successful!" echo "" echo "Access points:" echo " Frontend: http://localhost:${FRONTEND_PORT:-3000}" echo " Backend API: http://localhost:${BACKEND_PORT:-8000}" echo " Secure (HTTPS): https://localhost:${FRONTEND_SSL_PORT:-8919}" echo "" echo "View logs: docker-compose logs -f" echo "Stop services: docker-compose down" ``` **Acceptance Criteria**: - [ ] Script exits with error on missing Docker/Compose - [ ] Pre-flight checks validate all prerequisites - [ ] Images build successfully - [ ] Services start and health checks pass - [ ] Displays access URLs at end - [ ] Exit code 0 on success, non-zero on failure **Testing**: ```bash chmod +x deploy.sh ./deploy.sh production # Verify all services running and accessible ./deploy.sh staging --rebuild # Clean up docker-compose down ``` --- ### Task 5: Create Environment Template & Validation **Files**: - `inventory.env.template` (new) - `.env.validation.sh` (new, 80 lines) **Status**: Ready **Description**: Provide environment template and validation script to prevent misconfiguration **inventory.env.template**: ```env # TFM aInventory Deployment Configuration # Copy to inventory.env and customize for your deployment # Service Ports BACKEND_PORT=8000 FRONTEND_PORT=3000 BACKEND_SSL_PORT=8918 FRONTEND_SSL_PORT=8919 # Security JWT_SECRET_KEY=change_me_in_production_use_openssl_rand_hex_32 # AI Configuration (Optional, uses defaults if not set) AI_PROVIDER=gemini GEMINI_API_KEY= CLAUDE_API_KEY= # LDAP Configuration (Optional, uses local auth if not set) LDAP_SERVER= LDAP_PORT=389 LDAP_BASE_DN= LDAP_USE_SSL=false # Database DATA_DIR=/app/data DB_PATH=/app/data/inventory.db # Logging LOGS_DIR=/app/logs LOG_LEVEL=INFO # Network (CORS) ALLOWED_ORIGINS=http://localhost:3000,https://localhost:8919 EXTRA_ALLOWED_ORIGINS= # Deployment metadata DEPLOYMENT_NAME=production DEPLOYMENT_REGION=default ``` **.env.validation.sh**: ```bash #!/bin/bash # Validate inventory.env before deployment set -euo pipefail log_error() { echo "[ERROR] $1" >&2; exit 1; } log_warn() { echo "[WARN] $1" >&2; } [[ -f "inventory.env" ]] || log_error "inventory.env not found" source inventory.env # Validate required variables [[ -z "${BACKEND_PORT:-}" ]] && log_error "BACKEND_PORT not set" [[ -z "${FRONTEND_PORT:-}" ]] && log_error "FRONTEND_PORT not set" [[ "$BACKEND_PORT" =~ ^[0-9]+$ ]] || log_error "BACKEND_PORT must be numeric" [[ "$FRONTEND_PORT" =~ ^[0-9]+$ ]] || log_error "FRONTEND_PORT must be numeric" # Warn on defaults if [[ "${JWT_SECRET_KEY:-}" == "change_me_in_production_use_openssl_rand_hex_32" ]]; then log_warn "JWT_SECRET_KEY is using default value; regenerate for production" fi echo "[OK] inventory.env validation passed" ``` **Acceptance Criteria**: - [ ] Template covers all deployment scenarios (dev/staging/prod) - [ ] Validation script checks all critical variables - [ ] Clear comments explaining each setting - [ ] Example values provided (not actual secrets) --- ### Task 6: Create Quick Start Guide & Troubleshooting **File**: `docs/DEPLOYMENT_QUICKSTART.md` (new, ~150 lines) **Status**: Ready **Description**: Operator-friendly deployment guide, no domain knowledge required **Content**: ```markdown # Deployment Quick Start Guide ## Prerequisites - Ubuntu 22.04 LTS or similar Linux distro - Docker 24.0+ - Docker Compose 2.0+ - 2GB RAM, 10GB free disk ## Installation (5 minutes) ### 1. Prepare Environment \`\`\`bash git clone tfm-inventory cd tfm-inventory cp inventory.env.template inventory.env # Edit inventory.env with your deployment settings \`\`\` ### 2. Generate Secure Secret \`\`\`bash openssl rand -hex 32 > /tmp/jwt_secret # Copy output into inventory.env JWT_SECRET_KEY \`\`\` ### 3. Deploy \`\`\`bash chmod +x deploy.sh ./deploy.sh production \`\`\` ### 4. Verify Access - Frontend: http://localhost:3000 - Backend: http://localhost:8000 - API Docs: http://localhost:8000/docs ## Scaling (Adding Users) System tested and stable with 5 concurrent users. For more: 1. Increase BACKEND_PORT pool (run multiple instances behind load balancer) 2. Monitor logs for errors: `docker-compose logs -f backend` 3. Check database locks: `docker-compose exec backend python -c "import sqlite3; db=sqlite3.connect('/app/data/inventory.db'); print(db.execute('PRAGMA database_list').fetchall())"` ## Troubleshooting | Issue | Solution | |-------|----------| | Port already in use | Change BACKEND_PORT/FRONTEND_PORT in inventory.env | | Health check failing | Wait 30s, then: `docker-compose logs` to check service logs | | Database locked | Restart backend: `docker-compose restart backend` | | HTTPS certificate warning | First-time is normal; trust the certificate in browser | ## Backup & Restore \`\`\`bash # Automatic daily backups (see BACKUP_RUNBOOK.md) ./backup.sh daily ./restore.sh data/backups/inventory-2026-04-22.tar.gz \`\`\` ## Support - Logs: `docker-compose logs -f` - Health status: `docker-compose ps` - Stop all: `docker-compose down` - Full reset: `docker-compose down -v` (⚠️ deletes data) ``` **Acceptance Criteria**: - [ ] Guide is readable by non-technical ops teams - [ ] All 5 steps complete in <5 minutes - [ ] Troubleshooting covers common issues - [ ] Links to related docs (backup, scaling, health monitoring) --- ## Dependencies **Upstream**: - Phase 5 complete (all features implemented, tests passing) - Existing Dockerfiles and docker-compose.yml **Cross-Plan**: - Plan 2 (Scale Testing) uses `deploy.sh` from this plan - Plan 3 (Backup/Restore) integrates with deployment structure **Blocked By**: None --- ## Testing Strategy ### Unit Testing (Standalone) ```bash # Each component can be tested independently docker build -t inventory-backend:test backend/ docker build -t inventory-frontend:test frontend/ docker run --rm inventory-backend:test pytest backend/tests/ # Verify tests still pass ``` ### Integration Testing ```bash # Deploy stack ./deploy.sh production --rebuild # Verify all services healthy docker-compose ps | grep healthy # Run smoke tests curl http://localhost:8000/health curl http://localhost:3000/ # Verify data persistence # (detailed in Plan 3) ``` ### Deployment Validation ```bash # On fresh VM with only Docker installed git clone cd tfm-inventory ./deploy.sh production # Should complete without errors ``` --- ## Success Metrics - [ ] `./deploy.sh` completes in <5 minutes - [ ] Zero manual intervention required - [ ] All services report healthy - [ ] Backend API responds at /health - [ ] Frontend loads in browser - [ ] Logs accessible via docker-compose logs - [ ] Environment validation prevents misconfiguration --- ## Notes - Existing docker-compose.yml already has 3 services; we enhance, not replace - Health checks will help automation tools (Kubernetes, Docker Swarm) manage restarts - Pre-flight checks prevent common pitfalls (port conflicts, missing files) - Logging to stdout ensures compatibility with container log aggregation --- **Effort Estimate**: 16 hours (2 days) **Dependencies**: None (Phase 5 complete assumed) **Risk**: Low (mostly additive enhancements to existing Dockerfiles) --- Last updated: 2026-04-22 (Planning Phase)