From 6fdf29f040d40409189b81d3528d8a7cbfa86bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20X=2E=20F=C3=BCrst?= Date: Sun, 28 Jun 2026 16:34:24 +0200 Subject: [PATCH] Docker-Deployment fuer nuccy - Dockerfile (Next.js standalone, Multi-Stage) + .dockerignore - deploy.sh fuer strom-next angepasst (Registry docker.citysensor.de, multiplatform build & push) - docker-compose.prod.yml: Netzwerk 'smarthome' (external), InfluxDB als Host 'influx', alle Env-Defaults gesetzt, INFLUX_TOKEN aus .env - .env.production.example (nur Token/Port), public/ fuer den Image-Build - README: Deploy-Anleitung Lokal verifiziert: Image baut, Container startet und liefert HTTP 200. Co-Authored-By: Claude Opus 4.8 (1M context) --- .dockerignore | 51 +++++++++++++++++++++++++++++++++++ .env.production.example | 8 ++++++ .gitignore | 1 + Dockerfile | 51 +++++++++++++++++++++++++++++++++++ README.md | 40 +++++++++++++++++++++++++++- deploy.sh | 59 +++++++++++++++++++++++++++++++++++++++++ docker-compose.prod.yml | 33 +++++++++++++++++++++++ public/.gitkeep | 0 8 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 .env.production.example create mode 100644 Dockerfile create mode 100755 deploy.sh create mode 100644 docker-compose.prod.yml create mode 100644 public/.gitkeep diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ff89c3e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,51 @@ +# dependencies +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# testing +coverage + +# next.js +.next/ +out/ +build +dist + +# misc +.DS_Store +*.pem + +# debug +*.log + +# local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo + +# git +.git +.gitignore + +# editor +.vscode +.idea + +# docker +Dockerfile +.dockerignore +docker-compose*.yml + +# other +README.md diff --git a/.env.production.example b/.env.production.example new file mode 100644 index 0000000..b0c4a57 --- /dev/null +++ b/.env.production.example @@ -0,0 +1,8 @@ +# Auf nuccy als ".env" neben docker-compose.prod.yml ablegen (NICHT committen). +# Nur Geheimnisse/Abweichungen; der Rest steht in docker-compose.prod.yml. + +# InfluxDB Read-Token (Bucket strom) +INFLUX_TOKEN= + +# Optional: abweichender Host-Port (Default 3000) +# STROM_PORT=3000 diff --git a/.gitignore b/.gitignore index dbb1fee..1111116 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ yarn-error.log* .env* !.env.example !.env.local.example +!.env.production.example # vercel .vercel diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..397b505 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +# Multi-stage build for Next.js application (standalone output) +FROM node:22-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Copy package files +COPY package.json package-lock.json* ./ +RUN npm ci + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Set build date as build argument +ARG BUILD_DATE +ENV NEXT_PUBLIC_BUILD_DATE=${BUILD_DATE} + +# Disable telemetry during build +ENV NEXT_TELEMETRY_DISABLED=1 + +# Build the application +RUN npm run build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy necessary files +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["node", "server.js"] diff --git a/README.md b/README.md index 3caeab4..cee3595 100644 --- a/README.md +++ b/README.md @@ -101,10 +101,48 @@ curl -s -XPOST "http://nuccy:8086/api/v2/query?org=citysensor" \ schema.fieldKeys(bucket: "strom", predicate: (r) => r._measurement == "arbeit")' ``` -## Starten +## Starten (lokal) ```bash npm run dev # http://localhost:3000 npm run build # Produktionsbuild npm start ``` + +## Docker / Deployment auf nuccy + +Die App läuft als Container auf **nuccy** im externen Docker-Netzwerk +**`smarthome`** und erreicht die InfluxDB dort unter dem Host **`influx`** +(`http://influx:8086`). + +### Image bauen & in die Registry pushen (vom Entwicklungsrechner) + +```bash +./deploy.sh # Tag latest +./deploy.sh v1.2.0 # eigener Tag +``` + +Baut multiplattform (amd64/arm64) und pusht nach +`docker.citysensor.de/strom-next:`. + +### Auf nuccy starten + +`docker-compose.prod.yml` neben eine `.env` legen (aus +`.env.production.example`) und das **InfluxDB-Read-Token** dort eintragen: + +```bash +# .env +INFLUX_TOKEN=... +# optional: STROM_PORT=3000 +``` + +Dann: + +```bash +docker compose -f docker-compose.prod.yml pull +docker compose -f docker-compose.prod.yml up -d +``` + +Die App ist anschließend auf nuccy unter Port `3000` (bzw. `STROM_PORT`) +erreichbar. Alle InfluxDB-/Lade-Einstellungen sind in `docker-compose.prod.yml` +gesetzt; nur das Token kommt aus der `.env`. diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..ad7af19 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Deploy Script für strom-next +# Baut das Docker Image und lädt es zu docker.citysensor.de hoch + +set -e + +# Konfiguration +REGISTRY="docker.citysensor.de" +IMAGE_NAME="strom-next" +TAG="${1:-latest}" # Erster Parameter oder "latest" +FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${TAG}" + +# Build-Datum +BUILD_DATE=$(date +%d.%m.%Y) + +echo "==========================================" +echo "strom-next Deploy Script" +echo "==========================================" +echo "Registry: ${REGISTRY}" +echo "Image: ${IMAGE_NAME}" +echo "Tag: ${TAG}" +echo "Build-Datum: ${BUILD_DATE}" +echo "==========================================" +echo "" + +# 1. Login zur Registry (falls noch nicht eingeloggt) +echo ">>> Login zu ${REGISTRY}..." +docker login "${REGISTRY}" +echo "" + +# 2. Multiplatform Builder einrichten (docker-container driver erforderlich) +echo ">>> Richte Multiplatform Builder ein..." +if ! docker buildx inspect multiplatform-builder &>/dev/null; then + docker buildx create --name multiplatform-builder --driver docker-container --bootstrap +fi +docker buildx use multiplatform-builder +echo "" + +# 3. Docker Image bauen und pushen (Multiplatform) +echo ">>> Baue Multiplatform Docker Image und pushe zu Registry..." +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --build-arg BUILD_DATE="${BUILD_DATE}" \ + -t "${FULL_IMAGE}" \ + --push \ + . + +echo ">>> Build und Push erfolgreich!" + +echo "" +echo "==========================================" +echo "✓ Deploy erfolgreich abgeschlossen!" +echo "==========================================" +echo "" +echo "Auf nuccy ausführen (Verzeichnis mit docker-compose.prod.yml + .env):" +echo " docker compose -f docker-compose.prod.yml pull" +echo " docker compose -f docker-compose.prod.yml up -d" +echo "" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..553f729 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,33 @@ +# Docker Compose für nuccy +# Container im externen Docker-Netzwerk 'smarthome', erreicht InfluxDB als 'influx'. +# Geheimnisse (INFLUX_TOKEN) kommen aus einer .env-Datei neben dieser Compose-Datei. +services: + strom-app: + image: docker.citysensor.de/strom-next:latest + container_name: strom-next-app + restart: unless-stopped + ports: + - "${STROM_PORT:-3000}:3000" + environment: + - NODE_ENV=production + # InfluxDB im smarthome-Netz + - INFLUX_URL=http://influx:8086 + - INFLUX_TOKEN=${INFLUX_TOKEN} + - INFLUX_ORG=citysensor + - INFLUX_BUCKET=strom + # Rohdaten (24h) bzw. Rollup (7d/31d/365d) + - INFLUX_MEASUREMENT=vzlogger + - INFLUX_ROLLUP_MEASUREMENT=arbeit_hourly + - INFLUX_FIELD=arbeit + - INFLUX_UNIT_FACTOR=0.001 + # E-Auto-Lade-Erkennung + - INFLUX_POWER_FIELD=leistung + - LADEN_THRESHOLD_KW=11 + - LADEN_MIN_HOURS=2 + - LADEN_MAX_GAP_MIN=10 + networks: + - smarthome + +networks: + smarthome: + external: true diff --git a/public/.gitkeep b/public/.gitkeep new file mode 100644 index 0000000..e69de29