Compare commits
3
Commits
5598fa5156
...
179ad953cb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
179ad953cb | ||
|
|
9d28d23e45 | ||
|
|
46178d915a |
@@ -14,6 +14,11 @@ Platforma Małopolskiego Hubu Innowacji Społecznych (MVP hackathonu).
|
|||||||
|
|
||||||
- .NET SDK 10+
|
- .NET SDK 10+
|
||||||
- Node.js 22+ (npm)
|
- Node.js 22+ (npm)
|
||||||
|
- PowerShell Core 7+ (`pwsh`) — wymagany do uruchomienia `scripts/*.ps1`.
|
||||||
|
|
||||||
|
Windows nie kojarzy domyślnie plików `.ps1`, dlatego skrypty uruchamiaj przez
|
||||||
|
`pwsh` (np. `pwsh ./scripts/docker-push.ps1`), a nie przez dwuklik / samo
|
||||||
|
`./scripts/docker-push.ps1`. Instalacja: https://aka.ms/powershell
|
||||||
|
|
||||||
## Praca lokalna
|
## Praca lokalna
|
||||||
|
|
||||||
@@ -39,19 +44,46 @@ node scripts/build.mjs # buduje całość (client + copy + backend)
|
|||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
|
Szablon pobiera gotowy obraz z rejestru Gitea (pełna ścieżka), bez lokalnego
|
||||||
|
buildowania:
|
||||||
|
|
||||||
```pwsh
|
```pwsh
|
||||||
cp docker-compose.yaml.example docker-compose.yaml
|
cp docker-compose.yaml.example docker-compose.yaml
|
||||||
docker compose up --build
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
- Aplikacja: http://localhost:8080
|
- Aplikacja: http://localhost:8075
|
||||||
- Dane: `./data` (bind mount, trwałe — SurrealDB embedded RocksDB)
|
- Dane: `./data` (bind mount, trwałe — SurrealDB embedded RocksDB)
|
||||||
- Obraz: `tarninahub:0.0.1`
|
- Obraz: `git.rtynski.pl/rtynski/hy2026:latest`
|
||||||
|
|
||||||
Wolumen hosta można wskazać zmienną `TARNINAHUB_PORT` (domyślnie `8080`).
|
Port hosta można wskazać zmienną `TARNINAHUB_PORT` (domyślnie `8075`), a wersję
|
||||||
Plik `docker-compose.yaml.example` jest szablonem; `docker-compose.yaml` możesz
|
obrazu zmienną `APP_VERSION` (domyślnie `latest`). Plik
|
||||||
|
`docker-compose.yaml.example` jest szablonem; `docker-compose.yaml` możesz
|
||||||
dostosować lokalnie.
|
dostosować lokalnie.
|
||||||
|
|
||||||
|
### Publikacja obrazu do Gitea
|
||||||
|
|
||||||
|
Token dostępu utworzysz w Gitea:
|
||||||
|
|
||||||
|
- https://git.rtynski.pl/user/settings/applications
|
||||||
|
- **Generate New Token** → zakres **`write:package`** (wystarcza do pushu obrazu).
|
||||||
|
|
||||||
|
Wymagany **PowerShell Core 7+** (`pwsh`). Windows nie uruchamia domyślnie
|
||||||
|
plików `.ps1`, więc skrypt wywołaj jawnie przez `pwsh`:
|
||||||
|
|
||||||
|
```pwsh
|
||||||
|
$env:GITEA_USER = "rtynski"; $env:GITEA_TOKEN = "<token>"
|
||||||
|
pwsh ./scripts/docker-push.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Skrypt najpierw sprawdza połączenie z demonem Docker i rejestrem, czyta wersję z
|
||||||
|
`backend/TarninaHub.csproj`. Jeśli dana wersja jest już wypchnięta do rejestru,
|
||||||
|
kończy pracę z czerwonym komunikatem; w przeciwnym razie buduje frontend,
|
||||||
|
kopiuje go do `backend/wwwroot`, buduje backend, buduje obraz Docker i wypycha go
|
||||||
|
do `git.rtynski.pl/rtynski/hy2026` jako `<wersja>` oraz `latest`. Nadpisanie
|
||||||
|
sprawdzenia: `-Force`.
|
||||||
|
|
||||||
## Struktura
|
## Struktura
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ services:
|
|||||||
# RocksDB zapisuje do bind-mountu ./data; root upraszcza uprawnienia (MVP).
|
# RocksDB zapisuje do bind-mountu ./data; root upraszcza uprawnienia (MVP).
|
||||||
user: "0:0"
|
user: "0:0"
|
||||||
ports:
|
ports:
|
||||||
- "${TARNINAHUB_PORT:-8080}:8080"
|
- "${TARNINAHUB_PORT:-8075}:8080"
|
||||||
environment:
|
environment:
|
||||||
ASPNETCORE_ENVIRONMENT: Production
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
ASPNETCORE_URLS: http://+:8080
|
ASPNETCORE_URLS: http://+:8080
|
||||||
|
|||||||
+20
-10
@@ -2,29 +2,29 @@
|
|||||||
#
|
#
|
||||||
# Użycie:
|
# Użycie:
|
||||||
# cp docker-compose.yaml.example docker-compose.yaml
|
# cp docker-compose.yaml.example docker-compose.yaml
|
||||||
# docker compose up --build
|
# docker compose pull
|
||||||
|
# docker compose up -d
|
||||||
#
|
#
|
||||||
# Aplikacja: http://localhost:8080
|
# Obraz pobierany z rejestru Gitea (pełna ścieżka):
|
||||||
|
# git.rtynski.pl/rtynski/hy2026:<wersja>
|
||||||
|
#
|
||||||
|
# Aplikacja: http://localhost:8075
|
||||||
# Dane: ./data (bind mount, trwałe, SurrealDB embedded RocksDB)
|
# Dane: ./data (bind mount, trwałe, SurrealDB embedded RocksDB)
|
||||||
|
|
||||||
name: tarninahub
|
name: tarninahub
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
# Obraz budowany lokalnie z Dockerfile (multi-stage: klient Vue + backend .NET).
|
# Obraz z rejestru Gitea — pobierany przez `docker compose pull`.
|
||||||
image: tarninahub:${APP_VERSION:-0.0.1}
|
# `latest` domyślnie; konkretną wersję ustaw przez APP_VERSION, np. 0.0.1.
|
||||||
build:
|
image: git.rtynski.pl/rtynski/hy2026:${APP_VERSION:-latest}
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
APP_VERSION: ${APP_VERSION:-0.0.1}
|
|
||||||
container_name: tarninahub
|
container_name: tarninahub
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# RocksDB zapisuje do bind-mountu ./data; root upraszcza uprawnienia (MVP).
|
# RocksDB zapisuje do bind-mountu ./data; root upraszcza uprawnienia (MVP).
|
||||||
# W produkcji użyj named volume albo dopasuj właściciela katalogu ./data.
|
# W produkcji użyj named volume albo dopasuj właściciela katalogu ./data.
|
||||||
user: "0:0"
|
user: "0:0"
|
||||||
ports:
|
ports:
|
||||||
- "${TARNINAHUB_PORT:-8080}:8080"
|
- "${TARNINAHUB_PORT:-8075}:8080"
|
||||||
environment:
|
environment:
|
||||||
ASPNETCORE_ENVIRONMENT: Production
|
ASPNETCORE_ENVIRONMENT: Production
|
||||||
ASPNETCORE_URLS: http://+:8080
|
ASPNETCORE_URLS: http://+:8080
|
||||||
@@ -40,9 +40,19 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
# Jedyny volumen aplikacji — trwałe dane (SurrealDB / RocksDB).
|
# Jedyny volumen aplikacji — trwałe dane (SurrealDB / RocksDB).
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
|
# Podłączenie do zewnętrznej sieci (odkomentuj razem z blokiem `networks`).
|
||||||
|
# networks:
|
||||||
|
# - ovh_net
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-fsS", "http://localhost:8080/api/health"]
|
test: ["CMD", "curl", "-fsS", "http://localhost:8080/api/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 20s
|
start_period: 20s
|
||||||
|
|
||||||
|
# Zewnętrzna sieć (opcjonalnie) — odkomentuj, aby podłączyć usługę do
|
||||||
|
# istniejącej sieci hosta. Pamiętaj też odkomentować `networks:` w `app`.
|
||||||
|
# networks:
|
||||||
|
# ovh_net:
|
||||||
|
# external:
|
||||||
|
# name: ovh_net
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Buduje i publikuje obraz aplikacji w rejestrze kontenerów Gitea.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Wersja czytana jest z backend/TarninaHub.csproj (<Version>).
|
||||||
|
Krok 0 sprawdza połączenie z demonem Docker i dostępność rejestru Gitea.
|
||||||
|
Jeżeli obraz w tej wersji jest już wypchnięty do rejestru, skrypt wypisuje
|
||||||
|
czerwony komunikat i kończy pracę. W przeciwnym razie wykonuje po kolei:
|
||||||
|
0. sprawdzenie połączenia (demon Docker + rejestr),
|
||||||
|
1. odczyt wersji z backendu,
|
||||||
|
2. logowanie do rejestru,
|
||||||
|
3. sprawdzenie, czy wersja już istnieje,
|
||||||
|
4. build frontendu, kopiowanie i build backendu,
|
||||||
|
5. build obrazu Docker,
|
||||||
|
6. push obrazu jako <version> oraz :latest.
|
||||||
|
|
||||||
|
Dane logowania pobierane są ze zmiennych środowiskowych GITEA_USER oraz
|
||||||
|
GITEA_TOKEN (preferowany) lub GITEA_PASSWORD; jeśli ich brak, używany jest
|
||||||
|
`docker login` (interaktywnie). Token utworzysz na stronie:
|
||||||
|
https://<adres-gitea>/user/settings/applications (zakres: write:package)
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
pwsh ./scripts/docker-push.ps1
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
$env:GITEA_USER = "rtynski"; $env:GITEA_TOKEN = "xxx"
|
||||||
|
pwsh ./scripts/docker-push.ps1 -Force
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[string]$Registry = "git.rtynski.pl",
|
||||||
|
[string]$Owner = "rtynski",
|
||||||
|
[string]$Repo = "hy2026",
|
||||||
|
[string]$ProjectFile = "backend/TarninaHub.csproj",
|
||||||
|
[string]$SolutionFile = "TarninaHub.slnx",
|
||||||
|
[string]$Username = $env:GITEA_USER,
|
||||||
|
[string]$Token = $env:GITEA_TOKEN,
|
||||||
|
[string]$Password = $env:GITEA_PASSWORD,
|
||||||
|
[switch]$Force
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$root = Split-Path -Parent $PSScriptRoot
|
||||||
|
$image = "$Registry/$Owner/$Repo"
|
||||||
|
|
||||||
|
function Invoke-Step {
|
||||||
|
param([string]$Label, [scriptblock]$Action)
|
||||||
|
Write-Host "`n> $Label" -ForegroundColor Cyan
|
||||||
|
Push-Location $root
|
||||||
|
try { & $Action } finally { Pop-Location }
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "Krok nie powiódł się: $Label" }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-TcpConnection {
|
||||||
|
param([string]$HostName, [int]$Port, [int]$TimeoutMs = 5000)
|
||||||
|
$client = [System.Net.Sockets.TcpClient]::new()
|
||||||
|
try {
|
||||||
|
$task = $client.ConnectAsync($HostName, $Port)
|
||||||
|
return $task.Wait($TimeoutMs) -and $client.Connected
|
||||||
|
} catch {
|
||||||
|
return $false
|
||||||
|
} finally {
|
||||||
|
$client.Dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 0. Sprawdzenie połączenia (demon Docker + dostępność rejestru)
|
||||||
|
Write-Host "Krok 0: sprawdzanie połączenia..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
|
||||||
|
throw "Nie znaleziono 'docker' w PATH."
|
||||||
|
}
|
||||||
|
|
||||||
|
docker info *> $null
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "Brak połączenia z demonem Docker. Uruchom Docker Desktop."
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-TcpConnection -HostName $Registry -Port 443)) {
|
||||||
|
throw "Nie mogę połączyć się z rejestrem ${Registry}:443. Sprawdź sieć/adres."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Połączenie OK (Docker + ${Registry}:443)." -ForegroundColor Green
|
||||||
|
|
||||||
|
# 1. Wersja z backendu
|
||||||
|
$projectPath = Join-Path $root $ProjectFile
|
||||||
|
if (-not (Test-Path -LiteralPath $projectPath)) {
|
||||||
|
throw "Nie znaleziono pliku projektu: $projectPath"
|
||||||
|
}
|
||||||
|
$xml = [xml](Get-Content -LiteralPath $projectPath -Raw)
|
||||||
|
$versionNode = $xml.SelectSingleNode('/Project/PropertyGroup/Version')
|
||||||
|
if (-not $versionNode -or [string]::IsNullOrWhiteSpace($versionNode.InnerText)) {
|
||||||
|
throw "Brak <Version> w $ProjectFile."
|
||||||
|
}
|
||||||
|
$version = $versionNode.InnerText.Trim()
|
||||||
|
$versionTag = "${image}:$version"
|
||||||
|
$latestTag = "${image}:latest"
|
||||||
|
|
||||||
|
Write-Host "Wersja backendu: $version"
|
||||||
|
|
||||||
|
# 2. Logowanie do rejestru (potrzebne do sprawdzenia i push)
|
||||||
|
$secret = if ($Token) { $Token } elseif ($Password) { $Password } else { $null }
|
||||||
|
|
||||||
|
if ($Username -and $secret) {
|
||||||
|
Write-Host "Loguję do $Registry jako $Username..."
|
||||||
|
$secret | docker login $Registry --username $Username --password-stdin
|
||||||
|
} else {
|
||||||
|
Write-Host "Loguję do $Registry (interaktywnie)..."
|
||||||
|
Write-Host "Jeśli nie widzisz promptu, wpisz nazwę użytkownika i naciśnij Enter." -ForegroundColor Yellow
|
||||||
|
docker login $Registry
|
||||||
|
}
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "docker login nie powiodło się." }
|
||||||
|
|
||||||
|
# 3. Sprawdzenie, czy wersja została już wypchnięta
|
||||||
|
docker manifest inspect $versionTag *> $null
|
||||||
|
$alreadyPushed = ($LASTEXITCODE -eq 0)
|
||||||
|
|
||||||
|
if ($alreadyPushed -and -not $Force) {
|
||||||
|
Write-Host "`nObraz $versionTag jest już wypchnięty do rejestru." -ForegroundColor Red
|
||||||
|
Write-Host "Zmien <Version> w $ProjectFile lub użyj -Force." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if ($alreadyPushed) {
|
||||||
|
Write-Host "Obraz $versionTag już istnieje, ale -Force pomija sprawdzenie." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
# 4. Build frontendu, kopiowanie i build backendu
|
||||||
|
Invoke-Step "Build frontendu (Vite)" { npm --prefix client run build }
|
||||||
|
Invoke-Step "Kopiowanie client/dist -> backend/wwwroot" { node scripts/copy-client.mjs }
|
||||||
|
Invoke-Step "Build backendu (.NET)" { dotnet build $SolutionFile --configuration Release }
|
||||||
|
|
||||||
|
# 5. Build obrazu Docker
|
||||||
|
Invoke-Step "Build obrazu Docker ($versionTag)" {
|
||||||
|
docker build --build-arg "APP_VERSION=$version" -f Dockerfile -t $versionTag -t $latestTag .
|
||||||
|
}
|
||||||
|
|
||||||
|
# 6. Push wersji oraz latest
|
||||||
|
Invoke-Step "Push $versionTag" { docker push $versionTag }
|
||||||
|
Invoke-Step "Push $latestTag" { docker push $latestTag }
|
||||||
|
|
||||||
|
Write-Host "`nGotowe: $versionTag oraz $latestTag" -ForegroundColor Green
|
||||||
Reference in New Issue
Block a user