V1.1.0 Responsive
Footer angepasst Lauffähigkeit auf Server verbessert deploy.sh mit for loop
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -5,6 +7,7 @@ WORKDIR /app
|
|||||||
# System-Abhängigkeiten installieren
|
# System-Abhängigkeiten installieren
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
gcc \
|
gcc \
|
||||||
|
curl \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Python-Abhängigkeiten installieren
|
# Python-Abhängigkeiten installieren
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
FROM python:3.13-slim
|
FROM python:3.13-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
89
deploy.sh
Executable file
89
deploy.sh
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Deploy Script für laufschrift
|
||||||
|
# Baut das Docker Image und lädt es zu docker.citysensor.de hoch
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
|
||||||
|
# Konfiguration
|
||||||
|
REGISTRY="docker.citysensor.de"
|
||||||
|
PROJEKT="wetterstation"
|
||||||
|
IMAGE_NAME=("${PROJEKT}-frontend" "${PROJEKT}-collector" "${PROJEKT}-api")
|
||||||
|
TAG="${TAG:-$(date +%Y%m%d%H%M)}" # default Datum
|
||||||
|
|
||||||
|
# Build-Datum
|
||||||
|
BUILD_DATE=$(date +%d.%m.%Y)
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo " Deploy Script"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Registry: ${REGISTRY}"
|
||||||
|
echo "Images: ${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 ""
|
||||||
|
|
||||||
|
for image in "${IMAGE_NAME[@]}"; do
|
||||||
|
# Entferne Projekt-Präfix für Verzeichnisnamen
|
||||||
|
IMAGE_DIR="${image#${PROJEKT}-}"
|
||||||
|
FULL_IMAGE="${REGISTRY}/${image}:${TAG}"
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo ">>> Baue ${image}..."
|
||||||
|
echo ">>> Image: ${FULL_IMAGE}"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
# Build-Args vorbereiten (für Frontend Version und Build-Date)
|
||||||
|
BUILD_ARGS="--build-arg BUILD_DATE=${BUILD_DATE}"
|
||||||
|
if [ "${IMAGE_DIR}" = "frontend" ]; then
|
||||||
|
VERSION=$(grep '"version"' "${IMAGE_DIR}/package.json" | head -1 | sed 's/.*"version": "\(.*\)".*/\1/')
|
||||||
|
BUILD_ARGS="${BUILD_ARGS} --build-arg VERSION=${VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Docker Image bauen und pushen (Multiplatform)
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
${BUILD_ARGS} \
|
||||||
|
-t "${FULL_IMAGE}" \
|
||||||
|
--push \
|
||||||
|
"./${IMAGE_DIR}"
|
||||||
|
|
||||||
|
# 4. Tagge auch als :latest
|
||||||
|
echo ">>> Tagge ${image} als :latest..."
|
||||||
|
docker buildx imagetools create \
|
||||||
|
-t "${REGISTRY}/${image}:latest" \
|
||||||
|
"${FULL_IMAGE}"
|
||||||
|
|
||||||
|
echo "✓ ${image} erfolgreich gebaut und gepusht!"
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ">>> Alle Builds erfolgreich!"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "✓ Deploy erfolgreich abgeschlossen!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Registry: ${REGISTRY}"
|
||||||
|
echo "Projekt: ${PROJEKT}"
|
||||||
|
echo "Tag: ${TAG}"
|
||||||
|
echo ""
|
||||||
|
echo "Auf dem Server ausführen:"
|
||||||
|
echo " docker compose -f docker-compose.prod.yml pull"
|
||||||
|
echo " docker compose -f docker-compose.prod.yml up -d"
|
||||||
|
echo ""
|
||||||
@@ -56,6 +56,12 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
- proxy
|
- proxy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.docker.network=dockge_default"
|
- "traefik.docker.network=dockge_default"
|
||||||
@@ -72,7 +78,8 @@ services:
|
|||||||
container_name: wetterstation_frontend_prod
|
container_name: wetterstation_frontend_prod
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- api
|
api:
|
||||||
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
- proxy
|
- proxy
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
# Build stage
|
# Build stage
|
||||||
FROM node:20-alpine AS builder
|
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
|
||||||
|
|
||||||
|
# Build arguments
|
||||||
|
ARG BUILD_DATE=unknown
|
||||||
|
ARG VERSION=unknown
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -12,14 +18,18 @@ RUN npm ci
|
|||||||
# Copy source code
|
# Copy source code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build app
|
# Build app with build info
|
||||||
|
ENV VITE_BUILD_DATE=${BUILD_DATE}
|
||||||
|
ENV VITE_VERSION=${VERSION}
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Production stage
|
# Production stage
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
WORKDIR /usr/share/nginx/html
|
||||||
|
|
||||||
# Copy built app from builder
|
# Copy built app from builder
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist .
|
||||||
|
|
||||||
# Copy nginx configuration
|
# Copy nginx configuration
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ server {
|
|||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
|
# Docker DNS resolver für dynamische Service-Auflösung
|
||||||
|
resolver 127.0.0.11 valid=30s;
|
||||||
|
resolver_timeout 5s;
|
||||||
|
|
||||||
# Gzip compression
|
# Gzip compression
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_vary on;
|
gzip_vary on;
|
||||||
@@ -12,7 +16,8 @@ server {
|
|||||||
|
|
||||||
# API proxy (wird im Docker-Compose-Netzwerk aufgelöst)
|
# API proxy (wird im Docker-Compose-Netzwerk aufgelöst)
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://api:8000/;
|
set $upstream_api api:8000;
|
||||||
|
proxy_pass http://$upstream_api/;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection 'upgrade';
|
proxy_set_header Connection 'upgrade';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "wetterstation-frontend",
|
"name": "wetterstation-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.dashboard {
|
.dashboard {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 795px;
|
max-width: 1900px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,3 +65,83 @@
|
|||||||
color: #666;
|
color: #666;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-footer {
|
||||||
|
/* margin-top: 2rem;
|
||||||
|
*/ padding-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-divider {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
margin: 0 0 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-credits {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-sponsor {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-sponsor a {
|
||||||
|
color: #0066cc;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-sponsor a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-short {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-full {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design für schmale Bildschirme (Smartphones) */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.charts-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-values {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard {
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-short {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-full {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import HighchartsReact from 'highcharts-react-official'
|
|||||||
import { format } from 'date-fns'
|
import { format } from 'date-fns'
|
||||||
import { de } from 'date-fns/locale'
|
import { de } from 'date-fns/locale'
|
||||||
import './WeatherDashboard.css'
|
import './WeatherDashboard.css'
|
||||||
|
// Build-Informationen (werden beim Build eingef\u00fcgt)
|
||||||
|
const buildDate = __BUILD_DATE__
|
||||||
|
const version = __VERSION__
|
||||||
// Deutsche Lokalisierung für Highcharts
|
// Deutsche Lokalisierung für Highcharts
|
||||||
Highcharts.setOptions({
|
Highcharts.setOptions({
|
||||||
lang: {
|
lang: {
|
||||||
@@ -426,6 +428,30 @@ const WeatherDashboard = ({ data }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="dashboard-footer">
|
||||||
|
<div className="version-line">
|
||||||
|
<div><a href="mailto:rxf@gmx.de">
|
||||||
|
mailto:rxf@gmx.de
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="version-full">Version</span>
|
||||||
|
<span className="version-short">V</span>
|
||||||
|
{' '}{version} – {buildDate}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div className="footer-credits">
|
||||||
|
<div className="footer-left">Daten-Erfassung mit einer Davis VantagePro.</div>
|
||||||
|
<div className="footer-right">Grafiken erzeugt mit HighCharts</div>
|
||||||
|
</div>
|
||||||
|
<div className="footer-sponsor">
|
||||||
|
Die Wetterstation wurde vom Zeitungsverlag Waiblingen <a href="https://www.zvw.de" target="_blank" rel="noopener noreferrer">www.zvw.de</a> gestiftet.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import react from '@vitejs/plugin-react'
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
base: './',
|
base: './', define: {
|
||||||
server: {
|
__BUILD_DATE__: JSON.stringify(process.env.VITE_BUILD_DATE || 'dev'),
|
||||||
|
__VERSION__: JSON.stringify(process.env.VITE_VERSION || '0.0.0')
|
||||||
|
}, server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: 3000,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
|
|||||||
@@ -1,24 +1,38 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Script zum Bauen und Pushen der Docker Images zur Registry
|
# Script zum Bauen und Pushen der Docker Images zur Registry (Multi-Plattform)
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
REGISTRY="docker.citysensor.de"
|
REGISTRY="docker.citysensor.de"
|
||||||
PROJECT="wetterstation"
|
PROJECT="wetterstation"
|
||||||
|
PLATFORMS="linux/amd64,linux/arm64"
|
||||||
|
|
||||||
echo "🔨 Building Docker images..."
|
echo "🔧 Setting up buildx builder..."
|
||||||
docker compose build collector
|
# Erstelle oder verwende existierenden Builder
|
||||||
docker compose build api
|
docker buildx create --name multiplatform --use 2>/dev/null || docker buildx use multiplatform
|
||||||
docker compose build frontend
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "📤 Pushing images to ${REGISTRY}..."
|
echo "🔨 Building and pushing Docker images for ${PLATFORMS}..."
|
||||||
docker compose push collector
|
|
||||||
docker compose push api
|
# Baue und pushe alle Images mit buildx
|
||||||
docker compose push frontend
|
docker buildx build --platform ${PLATFORMS} \
|
||||||
|
-t ${REGISTRY}/${PROJECT}/collector:latest \
|
||||||
|
--push \
|
||||||
|
./collector
|
||||||
|
|
||||||
|
docker buildx build --platform ${PLATFORMS} \
|
||||||
|
-t ${REGISTRY}/${PROJECT}/api:latest \
|
||||||
|
--push \
|
||||||
|
./api
|
||||||
|
|
||||||
|
docker buildx build --platform ${PLATFORMS} \
|
||||||
|
-t ${REGISTRY}/${PROJECT}/frontend:latest \
|
||||||
|
--push \
|
||||||
|
./frontend
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "✅ Done! Images successfully pushed to ${REGISTRY}"
|
echo "✅ Done! Multi-platform images successfully pushed to ${REGISTRY}"
|
||||||
|
echo " Platforms: ${PLATFORMS}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To pull and run on another machine:"
|
echo "To pull and run on another machine:"
|
||||||
echo " docker compose pull"
|
echo " docker compose pull"
|
||||||
|
|||||||
Reference in New Issue
Block a user