fix(server): Read database config directly from environment variables
This commit is contained in:
@@ -16,3 +16,4 @@ captures
|
||||
!*.xcodeproj/project.xcworkspace/
|
||||
!*.xcworkspace/contents.xcworkspacedata
|
||||
**/xcshareddata/WorkspaceSettings.xcsettings
|
||||
/.env
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# ----------- Stage 1: Build Stage -----------
|
||||
FROM gradle:8.13-jdk21 AS build
|
||||
WORKDIR /home/gradle/src
|
||||
COPY build.gradle.kts settings.gradle.kts gradle.properties ./
|
||||
COPY gradle ./gradle
|
||||
COPY shared ./shared
|
||||
COPY server ./server
|
||||
RUN gradle :server:shadowJar --no-configure-on-demand
|
||||
|
||||
# ----------- Stage 2: Runtime Stage -----------
|
||||
FROM openjdk:21-slim-bookworm AS runtime
|
||||
WORKDIR /app
|
||||
COPY --from=build /home/gradle/src/server/build/libs/*.jar ./app.jar
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
|
||||
@@ -0,0 +1,70 @@
|
||||
services:
|
||||
server:
|
||||
build:
|
||||
context: . # Baut mit Dockerfile im Root
|
||||
image: meldestelle/server:latest
|
||||
container_name: meldestelle-server
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- DB_USER=${POSTGRES_USER}
|
||||
- DB_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- DB_NAME=${POSTGRES_DB}
|
||||
- DB_HOST=db
|
||||
- DB_PORT=5432
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- meldestelle-net
|
||||
# PostgreSQL Datenbank (Service-Name 'db')
|
||||
db:
|
||||
image: postgres:16-alpine # Spezifische Version
|
||||
container_name: meldestelle-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# Liest Werte aus .env
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
# PGDATA nicht nötig, Standard verwenden
|
||||
volumes:
|
||||
# Benanntes Volume für Daten auf Standardpfad
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- meldestelle-net # <--- Muss zum Netzwerk-Namen passen
|
||||
healthcheck: # Wichtig für depends_on
|
||||
test: [ "CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}" ] # Doppelte $$ beachten!
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
# ports: # Nur bei Bedarf freigeben, z.B. für lokalen Zugriff
|
||||
# - "127.0.0.1:54321:5432" # Host-Port 54321 → Container-Port 5432
|
||||
|
||||
# Optional: PgAdmin Service
|
||||
# pgadmin:
|
||||
# image: dpage/pgadmin4:latest # Oder spezifische Version
|
||||
# container_name: meldestelle-pgadmin
|
||||
# restart: unless-stopped
|
||||
# environment:
|
||||
# # Werte aus .env lesen (oder Defaults nutzen)
|
||||
# PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-admin@example.com}
|
||||
# PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-DeinSicheresPgAdminPasswort!} # UNBEDINGT IN .env SETZEN!
|
||||
# PGADMIN_CONFIG_SERVER_MODE: 'False'
|
||||
# volumes:
|
||||
# - pgadmin_data:/var/lib/pgadmin # Benanntes Volume
|
||||
# ports:
|
||||
# # Port 5050 auf dem Host (nur localhost) → Port 80 im Container
|
||||
# - "${PGADMIN_PORT:-127.0.0.1:5050}:80"
|
||||
# networks:
|
||||
# - meldestelle-net # <--- Muss zum Netzwerk-Namen passen
|
||||
# depends_on: # PgAdmin braucht die DB
|
||||
# - db
|
||||
|
||||
networks:
|
||||
meldestelle-net:
|
||||
driver: bridge
|
||||
volumes:
|
||||
postgres_data: # <--- Konsistenter Name
|
||||
# pgadmin_data: # <--- Konsistenter Name
|
||||
@@ -9,6 +9,9 @@ ktor-tests = "2.3.13"
|
||||
logback = "1.5.18"
|
||||
junit-jupiter = "5.12.0"
|
||||
junit-jupiter-version = "5.8.1"
|
||||
exposed = "0.52.0"
|
||||
postgresql = "42.7.3"
|
||||
hikari = "5.1.0"
|
||||
|
||||
[libraries]
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
@@ -29,6 +32,12 @@ jupiter-junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", v
|
||||
ktor-server-config-yaml = { module = "io.ktor:ktor-server-config-yaml", version.ref = "ktor" }
|
||||
junit-junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit-jupiter-version" }
|
||||
|
||||
exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
|
||||
exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
|
||||
exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" }
|
||||
postgresql-driver = { module = "org.postgresql:postgresql", version.ref = "postgresql" }
|
||||
hikari-cp = { module = "com.zaxxer:HikariCP", version.ref = "hikari" }
|
||||
|
||||
[plugins]
|
||||
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
|
||||
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
|
||||
@@ -22,4 +22,16 @@ dependencies {
|
||||
testImplementation(libs.jupiter.junit.jupiter)
|
||||
implementation(libs.ktor.server.config.yaml)
|
||||
testImplementation(libs.junit.junit.jupiter)
|
||||
|
||||
// Exposed für Datenbankzugriff (Core, DAO-Pattern, JDBC-Implementierung)
|
||||
implementation(libs.exposed.core)
|
||||
implementation(libs.exposed.dao)
|
||||
implementation(libs.exposed.jdbc)
|
||||
|
||||
// JDBC Treiber für PostgreSQL (nur zur Laufzeit benötigt)
|
||||
runtimeOnly(libs.postgresql.driver)
|
||||
|
||||
// HikariCP für Connection Pooling
|
||||
implementation(libs.hikari.cp)
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package at.mocode
|
||||
|
||||
import at.mocode.plugins.configureDatabase
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.netty.*
|
||||
import io.ktor.server.response.*
|
||||
@@ -10,6 +11,11 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
fun Application.module() {
|
||||
|
||||
// Als Erstes die Datenbank konfigurieren:
|
||||
configureDatabase()
|
||||
|
||||
// Danach deine anderen Konfigurationen (Routing etc.):
|
||||
routing {
|
||||
get("/") {
|
||||
call.respondText("Ktor: ${Greeting().greet()}")
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package at.mocode.plugins
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig
|
||||
import com.zaxxer.hikari.HikariDataSource
|
||||
import io.ktor.server.application.*
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
fun Application.configureDatabase() {
|
||||
val log = LoggerFactory.getLogger("DatabaseInitialization")
|
||||
log.info("Initializing database connection from environment variables...")
|
||||
|
||||
// Lese Konfiguration direkt aus Umgebungsvariablen,
|
||||
// die von Docker Compose (aus .env) gesetzt werden.
|
||||
val dbHost = System.getenv("DB_HOST") ?: "db" // Fallback auf 'db', falls nicht gesetzt
|
||||
val dbPort = System.getenv("DB_PORT") ?: "5432"
|
||||
val dbName = System.getenv("DB_NAME")
|
||||
?: error("Database name (DB_NAME) not set in environment") // Fehler, wenn nicht gesetzt
|
||||
val dbUser = System.getenv("DB_USER")
|
||||
?: error("Database user (DB_USER) not set in environment") // Fehler, wenn nicht gesetzt
|
||||
val dbPassword = System.getenv("DB_PASSWORD")
|
||||
?: error("Database password (DB_PASSWORD) not set in environment") // Fehler, wenn nicht gesetzt
|
||||
val driverClassName = "org.postgresql.Driver" // Ist für Postgres fix
|
||||
// Pool Size auch optional aus Env Var lesen
|
||||
val maxPoolSize = System.getenv("DB_POOL_SIZE")?.toIntOrNull() ?: 10
|
||||
|
||||
// Baue die JDBC URL zusammen
|
||||
val jdbcURL = "jdbc:postgresql://$dbHost:$dbPort/$dbName"
|
||||
|
||||
log.info("Attempting to connect to database at URL: {}", jdbcURL) // Logge die URL (ohne User/Passwort!)
|
||||
|
||||
// Konfiguriere HikariCP mit den Werten aus der Umgebung
|
||||
val hikariConfig = HikariConfig().apply {
|
||||
this.driverClassName = driverClassName
|
||||
this.jdbcUrl = jdbcURL
|
||||
this.username = dbUser
|
||||
this.password = dbPassword
|
||||
this.maximumPoolSize = maxPoolSize
|
||||
// Hier könnten weitere HikariCP-Optimierungen hin
|
||||
try {
|
||||
this.validate() // Prüft die Konfiguration frühzeitig
|
||||
} catch (e: Exception) {
|
||||
log.error("HikariCP configuration validation failed!", e)
|
||||
throw e // Wirft den Fehler weiter, damit die App nicht startet
|
||||
}
|
||||
}
|
||||
|
||||
// Erstelle DataSource und verbinde Exposed
|
||||
try {
|
||||
val dataSource = HikariDataSource(hikariConfig)
|
||||
Database.connect(dataSource)
|
||||
log.info("Database connection pool initialized successfully!")
|
||||
} catch (e: Exception) {
|
||||
log.error("Failed to initialize database connection pool!", e)
|
||||
// Optional: Hier entscheiden, ob die App trotzdem starten soll oder nicht.
|
||||
// Aktuell würde sie bei Fehlern hier abstürzen (was oft gewünscht ist).
|
||||
throw e
|
||||
}
|
||||
|
||||
|
||||
// --- TODO für den NÄCHSTEN Schritt ---
|
||||
// Hier kommt später die Logik zum Erstellen der Tabellen hin,
|
||||
// z.B. innerhalb einer Transaktion:
|
||||
// transaction {
|
||||
// SchemaUtils.create(TurniereTable) // Erstellt die Tabelle, wenn sie nicht existiert
|
||||
// }
|
||||
// ------------------------------------
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
# Grundkonfiguration für Ktor in YAML
|
||||
|
||||
ktor:
|
||||
deployment:
|
||||
# Der Port, auf dem der Server lauschen soll
|
||||
@@ -9,11 +8,7 @@ ktor:
|
||||
# watch:
|
||||
# - classes
|
||||
# - resources
|
||||
|
||||
application:
|
||||
# Hier wird Ktor gesagt, welche Funktion die Konfiguration enthält
|
||||
# PASSE DEN PFAD AN, falls deine Application.kt oder module() anders heißt/liegt!
|
||||
modules:
|
||||
- at.mocode.ApplicationKt.module
|
||||
# Wenn Application.kt direkt unter at.mocode liegt:
|
||||
# - at.mocode.ApplicationKt.module
|
||||
- at.mocode.ApplicationKt.module
|
||||
Reference in New Issue
Block a user