diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c79ac38 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +node_modules +npm-debug.log +.git +.gitignore +.env +.DS_Store +.vscode +.idea +*.log +dist +build +coverage +.next +out +client/node_modules +server/node_modules diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..9e7f037 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,61 @@ +name: Docker Build and Push + +on: + push: + branches: + - main + tags: + - 'v*' + pull_request: + branches: + - main + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..8c37cdc --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,182 @@ +# Docker Setup for SkyWatch + +This guide explains how to build and run SkyWatch using Docker. + +## Prerequisites + +- Docker and Docker Compose installed on your system +- A `.env` file configured in the project root (see README.md for configuration details) + +## Building Locally + +### Using Docker Compose (Recommended) + +The easiest way to build and run SkyWatch with Docker: + +```bash +docker-compose up -d +``` + +This will: +1. Build the Docker image +2. Create a container named `skywatch-monitor` +3. Start the application on port 3001 +4. Mount a persistent volume for data storage + +### Using Docker Directly + +To build the image manually: + +```bash +docker build -t skywatch:latest . +``` + +To run the container: + +```bash +docker run -d \ + --name skywatch \ + -p 3001:3001 \ + --env-file .env \ + -v skywatch-data:/app/data \ + skywatch:latest +``` + +## Pushing to GitHub Container Registry (GHCR) + +### Automatic Deployment (Recommended) + +The project includes a GitHub Actions workflow (`.github/workflows/docker-publish.yml`) that automatically: +- Builds your Docker image when you push to `main` or create a tag +- Pushes it to GitHub Container Registry (GHCR) +- Tags images as: + - `latest` (for main branch) + - Branch name (e.g., `main`) + - Semantic version (if you push a tag like `v1.0.0`) + - Short commit SHA + +**No configuration needed!** The workflow uses GitHub's built-in authentication. + +### Manual Push to GHCR + +If you want to push manually: + +1. Authenticate with GitHub Container Registry: +```bash +echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u USERNAME --password-stdin +# Or use a Personal Access Token (PAT) with `read:packages` and `write:packages` scopes +``` + +2. Build and tag the image: +```bash +docker build -t ghcr.io/YOUR-USERNAME/monitor:latest . +``` + +3. Push to GHCR: +```bash +docker push ghcr.io/YOUR-USERNAME/monitor:latest +``` + +## Viewing Published Images + +Visit: `https://github.com/nmemmert/monitor/pkgs/container/monitor` + +Or pull the image: +```bash +docker pull ghcr.io/nmemmert/monitor:latest +``` + +## Managing Containers + +### View running containers +```bash +docker ps +``` + +### View logs +```bash +docker logs skywatch-monitor +# Follow logs in real-time +docker logs -f skywatch-monitor +``` + +### Stop the container +```bash +docker-compose down +# Or +docker stop skywatch-monitor +``` + +### Remove containers and volumes +```bash +docker-compose down -v +``` + +## Environment Variables + +Make sure your `.env` file is in the project root with required variables: + +```env +PORT=3001 +NODE_ENV=production +# Add other environment variables as needed +``` + +The `.env` file is loaded by Docker Compose from the `env_file` directive. + +## Health Checks + +The Docker container includes a health check that verifies the API is responding: + +```bash +docker inspect skywatch-monitor --format='{{.State.Health.Status}}' +``` + +## Troubleshooting + +### Container exits immediately +Check logs: +```bash +docker logs skywatch-monitor +``` + +### Port already in use +Change the port in `docker-compose.yml`: +```yaml +ports: + - "3002:3001" # Access at localhost:3002 +``` + +### Database issues +Clear the volume and rebuild: +```bash +docker-compose down -v +docker-compose up -d +``` + +### Permission issues +The container runs as non-root user (nodejs). Ensure `.env` file permissions allow reading. + +## Production Deployment + +For production environments, consider: + +1. Using a reverse proxy (nginx, traefik) +2. Setting up SSL/TLS certificates +3. Using environment-specific `.env` files +4. Implementing container orchestration (Kubernetes, Docker Swarm) +5. Setting resource limits in docker-compose.yml: + +```yaml +services: + skywatch: + # ... other config + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M +``` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7c56f41 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,52 @@ +# Build stage for React client +FROM node:20-alpine AS client-builder + +WORKDIR /app/client + +# Copy client package files +COPY client/package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy client source +COPY client/src ./src +COPY client/public ./public + +# Build React app +RUN npm run build + +# Final stage - Node.js server +FROM node:20-alpine + +WORKDIR /app + +# Install dumb-init for proper signal handling +RUN apk add --no-cache dumb-init + +# Copy server package files +COPY package*.json ./ + +# Install production dependencies only +RUN npm ci --only=production + +# Copy server code +COPY server ./server + +# Copy built React client from builder stage +COPY --from=client-builder /app/client/build ./client/build + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nodejs -u 1001 + +USER nodejs + +# Expose port +EXPOSE 3001 + +# Use dumb-init to handle signals properly +ENTRYPOINT ["dumb-init", "--"] + +# Start the server +CMD ["node", "server/index.js"] diff --git a/README.md b/README.md index 104a0a9..340be35 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,40 @@ The script will: - ✅ Set up auto-start on boot - ✅ Guide you through email/webhook setup +### Docker Installation (Recommended) + +The easiest way to get SkyWatch running with Docker: + +#### Prerequisites +- Docker and Docker Compose + +#### Setup + +1. Clone the repository: +```bash +git clone https://github.com/nmemmert/monitor.git +cd monitor +``` + +2. Create and configure your `.env` file: +```bash +cp .env.example .env +# Edit .env with your settings +``` + +3. Start with Docker Compose: +```bash +docker-compose up -d +``` + +The application will be available at `http://localhost:3001` + +See [DOCKER.md](./DOCKER.md) for detailed Docker documentation including: +- Building images locally +- Pushing to Docker registries +- Running with custom ports +- Health checks and monitoring + ### Manual Installation #### Prerequisites @@ -150,26 +184,18 @@ nano .env # Configure your settings npm start ``` -### Option 3: Docker Deployment (Advanced) +### Option 3: Docker Deployment (Recommended) -Create `Dockerfile` in project root: -```dockerfile -FROM node:18 -WORKDIR /app -COPY package*.json ./ -RUN npm install -COPY . . -WORKDIR /app/client -RUN npm install && npm run build -WORKDIR /app -EXPOSE 3001 -CMD ["node", "server/index.js"] -``` +Docker setup is now fully integrated! See [DOCKER.md](./DOCKER.md) for complete documentation. -Then deploy: +Quick start: ```bash -docker build -t resource-monitor . -docker run -d -p 3001:3001 -v ./data:/app/data --name monitor resource-monitor +# Local deployment +docker-compose up -d + +# Using pre-built image from GitHub Container Registry +docker pull ghcr.io/nmemmert/monitor:latest +docker run -d -p 3001:3001 --env-file .env ghcr.io/nmemmert/monitor:latest ``` ### Deployment Workflow (Critical!) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3d62db8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +version: '3.8' + +services: + skywatch: + build: + context: . + dockerfile: Dockerfile + container_name: skywatch-monitor + ports: + - "3001:3001" + environment: + - NODE_ENV=production + - PORT=3001 + env_file: + - .env + volumes: + - skywatch-data:/app/data + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3001/api/groups"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + +volumes: + skywatch-data: + driver: local