diff --git a/docker/README.md b/docker/README.md index d55aa2b..5a45e7b 100644 --- a/docker/README.md +++ b/docker/README.md @@ -37,6 +37,42 @@ Version tags are also available (e.g. `1.2.3`) for both of these images. ``` 6. Access the application at `http://localhost:3000` +## Updating + +To update PatchMon to the latest version: + +```bash +docker compose up -d --pull +``` + +This command will: +- Pull the latest images from the registry +- Recreate containers with updated images +- Maintain your data and configuration + +### Version-Specific Updates + +If you're using specific version tags instead of `latest` in your compose file: + +1. Update the image tags in your `docker-compose.yml`. For example: + ```yaml + services: + backend: + image: ghcr.io/9technologygroup/patchmon-backend:1.2.7 # Update version here + ... + frontend: + image: ghcr.io/9technologygroup/patchmon-frontend:1.2.7 # Update version here + ... + ``` + +2. Then run the update command: + ```bash + docker compose up -d --pull + ``` + +> [!TIP] +> Check the [releases page](https://github.com/9technologygroup/patchmon.net/releases) for version-specific changes and migration notes. + ## Configuration ### Environment Variables @@ -99,41 +135,55 @@ For development with live reload and source code mounting: 2. Start development environment: ```bash - # Attached, live log output, services stopped on Ctrl+C docker compose -f docker/docker-compose.dev.yml up - - # Detached - docker compose -f docker/docker-compose.dev.yml up -d ``` + _See [Development Commands](#development-commands) for more options._ + +3. Access the application: + - Frontend: `http://localhost:3000` + - Backend API: `http://localhost:3001` + - Database: `localhost:5432` ## Development Docker Compose The development compose file (`docker/docker-compose.dev.yml`): -- Builds images locally from source -- Enables development workflow -- Supports live reload and debugging +- Builds images locally from source using development targets +- Enables hot reload with Docker Compose watch functionality +- Exposes database and backend ports for testing and development +- Mounts source code directly into containers for live development +- Supports debugging with enhanced logging ## Building Images Locally -``` -docker build -t patchmon-backend:dev -f docker/backend.Dockerfile . -docker build -t patchmon-frontend:dev -f docker/frontend.Dockerfile . -``` - -## Running in Docker Compose - -For development or custom builds: +Both Dockerfiles use multi-stage builds with separate development and production targets: ```bash -# Build backend image -docker build -f docker/backend.Dockerfile -t patchmon-backend:dev . +# Build development images +docker build -f docker/backend.Dockerfile --target development -t patchmon-backend:dev . +docker build -f docker/frontend.Dockerfile --target development -t patchmon-frontend:dev . -# Build frontend image -docker build -f docker/frontend.Dockerfile -t patchmon-frontend:dev . +# Build production images (default target) +docker build -f docker/backend.Dockerfile -t patchmon-backend:latest . +docker build -f docker/frontend.Dockerfile -t patchmon-frontend:latest . ``` ## Development Commands +### Hot Reload Development +```bash +# Attached, live log output, services stopped on Ctrl+C +docker compose -f docker/docker-compose.dev.yml up + +# Attached with Docker Compose watch for hot reload +docker compose -f docker/docker-compose.dev.yml up --watch + +# Detached +docker compose -f docker/docker-compose.dev.yml up -d + +# Quiet, no log output, with Docker Compose watch for hot reload +docker compose -f docker/docker-compose.dev.yml watch +``` + ### Rebuild Services ```bash # Rebuild specific service @@ -143,9 +193,43 @@ docker compose -f docker/docker-compose.dev.yml up -d --build backend docker compose -f docker/docker-compose.dev.yml up -d --build ``` +### Development Ports +The development setup exposes additional ports for debugging: +- **Database**: `5432` - Direct PostgreSQL access +- **Backend**: `3001` - API server with development features +- **Frontend**: `3000` - React development server with hot reload + ## Development Workflow -1. **Code Changes**: Edit source files -2. **Rebuild**: `docker compose -f docker/docker-compose.dev.yml up -d --build` -3. **Test**: Access application and verify changes -4. **Debug**: Check logs with `docker compose logs -f` +1. **Initial Setup**: Clone repository and start development environment + ```bash + git clone https://github.com/9technologygroup/patchmon.net.git + cd patchmon.net + docker compose -f docker/docker-compose.dev.yml up -d --build + ``` + +2. **Hot Reload Development**: Use Docker Compose watch for automatic reload + ```bash + docker compose -f docker/docker-compose.dev.yml up --watch --build + ``` + +3. **Code Changes**: + - **Frontend/Backend Source**: Files are synced automatically with watch mode + - **Package.json Changes**: Triggers automatic service rebuild + - **Prisma Schema Changes**: Backend service restarts automatically + +4. **Database Access**: Connect database client directly to `localhost:5432` + +5. **Debug**: If started with `docker compose [...] up -d` or `docker compose [...] watch`, check logs manually: + ```bash + docker compose -f docker/docker-compose.dev.yml logs -f + ``` + Otherwise logs are shown automatically in attached modes (`up`, `up --watch`). + +### Features in Development Mode + +- **Hot Reload**: Automatic code synchronization and service restarts +- **Enhanced Logging**: Detailed logs for debugging +- **Direct Access**: Exposed ports for database and API debugging +- **Health Checks**: Built-in health monitoring for services +- **Volume Persistence**: Development data persists between restarts diff --git a/docker/backend.Dockerfile b/docker/backend.Dockerfile index e40b0da..fc28021 100644 --- a/docker/backend.Dockerfile +++ b/docker/backend.Dockerfile @@ -1,22 +1,8 @@ -FROM node:lts-alpine AS builder +# Development target +FROM node:lts-alpine AS development -RUN apk add --no-cache openssl - -WORKDIR /app - -COPY --chown=node:node package*.json /app/ -COPY --chown=node:node backend/ /app/backend/ - -WORKDIR /app/backend - -RUN npm ci --ignore-scripts &&\ - npx prisma generate &&\ - npm prune --omit=dev &&\ - npm cache clean --force - -FROM node:lts-alpine - -ENV NODE_ENV=production \ +ENV NODE_ENV=development \ + NPM_CONFIG_UPDATE_NOTIFIER=false \ ENABLE_LOGGING=true \ LOG_LEVEL=info \ PM_LOG_TO_CONSOLE=true \ @@ -28,8 +14,61 @@ USER node WORKDIR /app -COPY --from=builder /app/backend /app/backend -COPY --from=builder /app/node_modules /app/node_modules +COPY --chown=node:node package*.json ./ +COPY --chown=node:node backend/ ./backend/ +COPY --chown=node:node agents ./agents_backup +COPY --chown=node:node agents ./agents +COPY --chmod=755 docker/backend.docker-entrypoint.sh ./entrypoint.sh + +WORKDIR /app/backend + +RUN npm ci --ignore-scripts && npx prisma generate + +EXPOSE 3001 + +VOLUME [ "/app/agents" ] + +HEALTHCHECK --interval=10s --timeout=5s --start-period=30s --retries=5 \ + CMD curl -f http://localhost:3001/health || exit 1 + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["/app/entrypoint.sh"] + +# Builder stage for production +FROM node:lts-alpine AS builder + +RUN apk add --no-cache openssl + +WORKDIR /app + +COPY --chown=node:node package*.json ./ +COPY --chown=node:node backend/ ./backend/ + +WORKDIR /app/backend + +RUN npm ci --ignore-scripts &&\ + npx prisma generate &&\ + npm prune --omit=dev &&\ + npm cache clean --force + +# Production stage +FROM node:lts-alpine + +ENV NODE_ENV=production \ + NPM_CONFIG_UPDATE_NOTIFIER=false \ + ENABLE_LOGGING=true \ + LOG_LEVEL=info \ + PM_LOG_TO_CONSOLE=true \ + PORT=3001 + +RUN apk add --no-cache openssl tini curl + +USER node + +WORKDIR /app + +COPY --from=builder /app/backend ./backend +COPY --from=builder /app/node_modules ./node_modules COPY --chown=node:node agents ./agents_backup COPY --chown=node:node agents ./agents COPY --chmod=755 docker/backend.docker-entrypoint.sh ./entrypoint.sh diff --git a/docker/backend.docker-entrypoint.sh b/docker/backend.docker-entrypoint.sh index 9eaf629..25772fd 100755 --- a/docker/backend.docker-entrypoint.sh +++ b/docker/backend.docker-entrypoint.sh @@ -20,10 +20,14 @@ else log "Agents directory already contains files, skipping copy" fi -log "Starting PatchMon Backend..." +log "Starting PatchMon Backend (${NODE_ENV:-production})..." log "Running database migrations..." npx prisma migrate deploy log "Starting application..." -exec npm start +if [ "${NODE_ENV}" = "development" ]; then + exec npm run dev +else + exec npm start +fi diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 0fd1691..bf401ef 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -6,6 +6,8 @@ services: POSTGRES_DB: patchmon_db POSTGRES_USER: patchmon_user POSTGRES_PASSWORD: INSECURE_REPLACE_ME_PLEASE_INSECURE + ports: + - "5432:5432" volumes: - ./compose_dev_data/db:/var/lib/postgresql/data healthcheck: @@ -18,8 +20,10 @@ services: build: context: .. dockerfile: docker/backend.Dockerfile + target: development restart: unless-stopped environment: + NODE_ENV: development LOG_LEVEL: info DATABASE_URL: postgresql://patchmon_user:INSECURE_REPLACE_ME_PLEASE_INSECURE@database:5432/patchmon_db PM_DB_CONN_MAX_ATTEMPTS: 30 @@ -30,16 +34,31 @@ services: CORS_ORIGIN: http://localhost:3000 RATE_LIMIT_WINDOW_MS: 900000 RATE_LIMIT_MAX: 100 + ports: + - "3001:3001" volumes: - ./compose_dev_data/agents:/app/agents depends_on: database: condition: service_healthy + develop: + watch: + - action: sync + path: ../backend/src + target: /app/backend/src + ignore: + - node_modules/ + - action: sync + path: ../backend/prisma + target: /app/backend/prisma + - action: rebuild + path: ../backend/package.json frontend: build: context: .. dockerfile: docker/frontend.Dockerfile + target: development restart: unless-stopped environment: BACKEND_HOST: backend @@ -49,3 +68,12 @@ services: depends_on: backend: condition: service_healthy + develop: + watch: + - action: sync + path: ../frontend/src + target: /app/frontend/src + ignore: + - node_modules/ + - action: rebuild + path: ../frontend/package.json diff --git a/docker/frontend.Dockerfile b/docker/frontend.Dockerfile index 02d8a87..fd02ec0 100644 --- a/docker/frontend.Dockerfile +++ b/docker/frontend.Dockerfile @@ -1,3 +1,20 @@ +# Development target +FROM node:lts-alpine AS development + +WORKDIR /app + +COPY package*.json ./ +COPY frontend/ ./frontend/ + +RUN npm ci --ignore-scripts + +WORKDIR /app/frontend + +EXPOSE 3000 + +CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "3000"] + +# Builder stage for production FROM node:lts-alpine AS builder WORKDIR /app @@ -11,6 +28,7 @@ COPY frontend/ ./frontend/ RUN npm run build:frontend +# Production stage FROM nginxinc/nginx-unprivileged:alpine ENV BACKEND_HOST=backend \