From 31dfe42613905159193d41746ee9ca04bb6fc9ef Mon Sep 17 00:00:00 2001 From: Stefan Koelle Date: Sun, 9 Aug 2026 13:09:01 +0200 Subject: [PATCH] docker --- .dockerignore | 43 ++++++++++++ .env.example | 9 +++ .github/workflows/docker-build.yml | 101 +++++++++++++++++++++++++++++ gitignore => .gitignore | 0 Dockerfile | 25 +++++++ appsettings.json | 2 +- docker-compose.yml | 11 ++++ init-db.sh | 41 ++++++++++++ init-db.sql | 20 ++++++ 9 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .github/workflows/docker-build.yml rename gitignore => .gitignore (100%) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100755 init-db.sh create mode 100644 init-db.sql diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d752f28 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,43 @@ +.git +.gitignore +.vs/ +.vscode/ +.idea/ +*.swp +*~ + +bin/ +obj/ +publish/ +dist/ + +client/node_modules/ +client/build/ +client/dist/ + +node_modules/ + +.env +.env.local +.env.production +appsettings.*.json + +*.db +*.sqlite +*.sqlite3 + +.DS_Store +Thumbs.db +Desktop.ini + +logs/ +*.log +coverage/ +.nyc_output/ +tmp/ +temp/ + +README.md +LICENSE +init-db.sql +init-db.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..00129bc --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +# MariaDB Connection (externer Host) +DB_HOST=maria-db-server.domain.local +DB_PORT=3306 +DB_NAME=focusapp +DB_USER=focusapp +DB_PASSWORD=change-password + +# MariaDB Root (fuer init-db.sh) +DB_ROOT_PASSWORD=change-root-password diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000..7e0ae6f --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,101 @@ +name: Docker Build & Push + +on: + push: + branches: [main] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + 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=raw,value=latest + type=sha,prefix= + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + cleanup-old-images: + runs-on: ubuntu-latest + needs: build-and-push + permissions: + packages: write + + steps: + - name: Cleanup old images (keep last 4) + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PACKAGE_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') + + echo "Package: $PACKAGE_NAME" + + # Alle Versions-IDs abrufen, sortiert nach Erstellungsdatum (neueste zuerst) + VERSION_IDS=$(gh api \ + -H "Accept: application/vnd.github+json" \ + "/user/packages/maven/$PACKAGE_NAME/versions" \ + --paginate \ + -q 'sort_by(.created_at) | reverse | .[].id' 2>/dev/null || \ + gh api \ + -H "Accept: application/vnd.github+json" \ + "/user/packages/container/$PACKAGE_NAME/versions" \ + --paginate \ + -q 'sort_by(.created_at) | reverse | .[].id') + + # In Array umwandeln + mapfile -t IDS <<< "$VERSION_IDS" + TOTAL=${#IDS[@]} + + echo "Gefundene Versionen: $TOTAL" + + if [ "$TOTAL" -le 4 ]; then + echo "Nur $TOTAL Versionen vorhanden, kein Cleanup noetig." + exit 0 + fi + + # Alle loeschen bis auf die ersten 4 + for ((i=4; i 4 Versionen behalten." diff --git a/gitignore b/.gitignore similarity index 100% rename from gitignore rename to .gitignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fb8196a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +# Stage 1: React Frontend bauen +FROM node:20-alpine AS frontend +WORKDIR /app/client +COPY client/package.json client/package-lock.json ./ +RUN npm ci +COPY client/ ./ +RUN npm run build + +# Stage 2: .NET Publish +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src +COPY *.csproj *.sln ./ +RUN dotnet restore +COPY . . +COPY --from=frontend /app/client/build ./client/build +RUN dotnet publish -c Release -o /app/publish --no-restore + +# Stage 3: Runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +WORKDIR /app +COPY --from=build /app/publish . +EXPOSE 5000 +ENV ASPNETCORE_URLS=http://0.0.0.0:5000 +ENV ASPNETCORE_ENVIRONMENT=Production +ENTRYPOINT ["dotnet", "FocusApp.dll"] diff --git a/appsettings.json b/appsettings.json index 21fc09d..43ad50c 100644 --- a/appsettings.json +++ b/appsettings.json @@ -9,6 +9,6 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "DefaultConnection": "Server=maria-db-server.domain.local;Port=3306;Database=focusapp;User=focusapp;Password=[change-password]" + "DefaultConnection": "Server=localhost;Port=3306;Database=focusapp;User=focusapp;Password=change-password" } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7ca5947 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +services: + app: + image: ghcr.io/stefan-koelle/focusapp:latest + container_name: focusapp + restart: unless-stopped + ports: + - "5000:5000" + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://0.0.0.0:5000 + - ConnectionStrings__DefaultConnection=Server=${DB_HOST};Port=${DB_PORT};Database=${DB_NAME};User=${DB_USER};Password=${DB_PASSWORD} diff --git a/init-db.sh b/init-db.sh new file mode 100755 index 0000000..e0762a3 --- /dev/null +++ b/init-db.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# FocusApp Datenbank Initialisierung +# Fuehrt init-db.sql gegen den externen MariaDB Server aus + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# .env laden +if [ -f "$SCRIPT_DIR/.env" ]; then + export $(grep -v '^#' "$SCRIPT_DIR/.env" | xargs) +else + echo "Fehler: .env Datei nicht gefunden unter $SCRIPT_DIR/.env" + exit 1 +fi + +# Pruefen ob notwendige Variablen gesetzt sind +if [ -z "$DB_HOST" ] || [ -z "$DB_ROOT_PASSWORD" ]; then + echo "Fehler: DB_HOST und DB_ROOT_PASSWORD muessen in .env gesetzt sein" + exit 1 +fi + +DB_PORT=${DB_PORT:-3306} + +echo "Verbinde zu MariaDB auf $DB_HOST:$DB_PORT..." + +# Pruefen ob mysql/mariadb Client verfuegbar ist +if command -v mariadb &> /dev/null; then + MYSQL_CMD="mariadb" +elif command -v mysql &> /dev/null; then + MYSQL_CMD="mysql" +else + echo "Fehler: weder 'mariadb' noch 'mysql' Client gefunden" + echo "Installieren Sie: sudo apt install mariadb-client" + exit 1 +fi + +# SQL ausfuehren +$MYSQL_CMD -h "$DB_HOST" -P "$DB_PORT" -u root -p"$DB_ROOT_PASSWORD" < "$SCRIPT_DIR/init-db.sql" + +echo "Datenbank focusapp erfolgreich initialisiert!" diff --git a/init-db.sql b/init-db.sql new file mode 100644 index 0000000..e291591 --- /dev/null +++ b/init-db.sql @@ -0,0 +1,20 @@ +-- FocusApp Datenbank initialisieren +-- Fuehren Sie dieses Script mit MariaDB Root-Berechtigung aus + +CREATE DATABASE IF NOT EXISTS focusapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE USER IF NOT EXISTS 'focusapp'@'%' IDENTIFIED BY 'change-password'; +GRANT ALL PRIVILEGES ON focusapp.* TO 'focusapp'@'%'; + +FLUSH PRIVILEGES; + +USE focusapp; + +CREATE TABLE IF NOT EXISTS FocusTasks ( + Id INT AUTO_INCREMENT PRIMARY KEY, + Title VARCHAR(255) NOT NULL, + Description VARCHAR(2000) NULL, + `Order` INT NOT NULL, + CreatedAt DATETIME NOT NULL, + UpdatedAt DATETIME NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;