fix:
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
build:
|
||||
maxIssues: 0
|
||||
excludeCorrectable: false
|
||||
|
||||
config:
|
||||
validation: true
|
||||
warningsAsErrors: false
|
||||
|
||||
processors:
|
||||
active: true
|
||||
|
||||
console-reports:
|
||||
active: true
|
||||
exclude:
|
||||
- 'ProjectStatisticsReport'
|
||||
- 'ComplexityReport'
|
||||
- 'NotificationReport'
|
||||
|
||||
comments:
|
||||
active: true
|
||||
AbsentOrWrongFileLicense:
|
||||
active: false
|
||||
|
||||
style:
|
||||
active: true
|
||||
MagicNumber:
|
||||
active: false
|
||||
WildcardImport:
|
||||
active: false
|
||||
MaxLineLength:
|
||||
active: true
|
||||
maxLineLength: 140
|
||||
UnusedImports:
|
||||
active: true
|
||||
|
||||
complexity:
|
||||
active: true
|
||||
LongMethod:
|
||||
active: true
|
||||
threshold: 80
|
||||
TooManyFunctions:
|
||||
active: true
|
||||
thresholdInClasses: 30
|
||||
|
||||
performance:
|
||||
active: true
|
||||
|
||||
potential-bugs:
|
||||
active: true
|
||||
|
||||
exceptions:
|
||||
active: true
|
||||
@@ -0,0 +1,20 @@
|
||||
// Kafka JAAS Configuration for Production
|
||||
// =============================================================================
|
||||
// This file configures SASL authentication for Kafka in production
|
||||
// Change the passwords to strong, randomly generated values
|
||||
// =============================================================================
|
||||
|
||||
KafkaServer {
|
||||
org.apache.kafka.common.security.plain.PlainLoginModule required
|
||||
username="admin"
|
||||
password="CHANGE_ME_STRONG_KAFKA_ADMIN_PASSWORD"
|
||||
user_admin="CHANGE_ME_STRONG_KAFKA_ADMIN_PASSWORD"
|
||||
user_producer="CHANGE_ME_STRONG_KAFKA_PRODUCER_PASSWORD"
|
||||
user_consumer="CHANGE_ME_STRONG_KAFKA_CONSUMER_PASSWORD";
|
||||
};
|
||||
|
||||
Client {
|
||||
org.apache.kafka.common.security.plain.PlainLoginModule required
|
||||
username="admin"
|
||||
password="CHANGE_ME_STRONG_KAFKA_ADMIN_PASSWORD";
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
// Zookeeper JAAS Configuration for Production
|
||||
// =============================================================================
|
||||
// This file configures SASL authentication for Zookeeper in production
|
||||
// Change the passwords to strong, randomly generated values
|
||||
// =============================================================================
|
||||
|
||||
Server {
|
||||
org.apache.zookeeper.server.auth.DigestLoginModule required
|
||||
user_admin="CHANGE_ME_STRONG_ZOOKEEPER_ADMIN_PASSWORD"
|
||||
user_kafka="CHANGE_ME_STRONG_ZOOKEEPER_KAFKA_PASSWORD";
|
||||
};
|
||||
|
||||
Client {
|
||||
org.apache.zookeeper.server.auth.DigestLoginModule required
|
||||
username="kafka"
|
||||
password="CHANGE_ME_STRONG_ZOOKEEPER_KAFKA_PASSWORD";
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
# syntax=docker/dockerfile:1.8
|
||||
# ===================================================================
|
||||
# Production-Ready Keycloak Dockerfile
|
||||
# ===================================================================
|
||||
# Based on: quay.io/keycloak/keycloak:26.4
|
||||
# Features:
|
||||
# - Pre-built optimized image (faster startup)
|
||||
# - Security hardening
|
||||
# - Custom theme support
|
||||
# - Health monitoring
|
||||
# ===================================================================
|
||||
ARG KEYCLOAK_IMAGE_TAG
|
||||
|
||||
FROM quay.io/keycloak/keycloak:${KEYCLOAK_IMAGE_TAG}
|
||||
|
||||
LABEL maintainer="Meldestelle Development Team"
|
||||
LABEL description="Production-ready Keycloak for Meldestelle authentication"
|
||||
LABEL version="${KEYCLOAK_IMAGE_TAG}"
|
||||
|
||||
# Set environment variables for build
|
||||
ENV KC_HEALTH_ENABLED=true
|
||||
ENV KC_METRICS_ENABLED=true
|
||||
ENV KC_DB=postgres
|
||||
|
||||
WORKDIR /opt/keycloak
|
||||
|
||||
# Pre-build Keycloak for faster startup
|
||||
RUN /opt/keycloak/bin/kc.sh build \
|
||||
--db=postgres \
|
||||
--health-enabled=true \
|
||||
--metrics-enabled=true
|
||||
|
||||
# Set user
|
||||
USER 1000
|
||||
|
||||
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
|
||||
@@ -0,0 +1,296 @@
|
||||
{
|
||||
"realm": "meldestelle",
|
||||
"enabled": true,
|
||||
"displayName": "Meldestelle Authentication",
|
||||
"displayNameHtml": "<div class=\"kc-logo-text\"><span>Meldestelle</span></div>",
|
||||
"sslRequired": "external",
|
||||
"registrationAllowed": false,
|
||||
"registrationEmailAsUsername": false,
|
||||
"rememberMe": true,
|
||||
"verifyEmail": false,
|
||||
"loginWithEmailAllowed": true,
|
||||
"duplicateEmailsAllowed": false,
|
||||
"resetPasswordAllowed": true,
|
||||
"editUsernameAllowed": false,
|
||||
"bruteForceProtected": true,
|
||||
"permanentLockout": false,
|
||||
"maxFailureWaitSeconds": 900,
|
||||
"minimumQuickLoginWaitSeconds": 60,
|
||||
"waitIncrementSeconds": 60,
|
||||
"quickLoginCheckMilliSeconds": 1000,
|
||||
"maxDeltaTimeSeconds": 43200,
|
||||
"failureFactor": 5,
|
||||
"defaultSignatureAlgorithm": "RS256",
|
||||
"offlineSessionMaxLifespan": 5184000,
|
||||
"offlineSessionMaxLifespanEnabled": false,
|
||||
"accessTokenLifespan": 300,
|
||||
"accessTokenLifespanForImplicitFlow": 900,
|
||||
"ssoSessionIdleTimeout": 1800,
|
||||
"ssoSessionMaxLifespan": 36000,
|
||||
"refreshTokenMaxReuse": 0,
|
||||
"accessCodeLifespan": 60,
|
||||
"accessCodeLifespanUserAction": 300,
|
||||
"accessCodeLifespanLogin": 1800,
|
||||
"actionTokenGeneratedByAdminLifespan": 43200,
|
||||
"actionTokenGeneratedByUserLifespan": 300,
|
||||
"oauth2DeviceCodeLifespan": 600,
|
||||
"oauth2DevicePollingInterval": 5,
|
||||
"internationalizationEnabled": true,
|
||||
"supportedLocales": ["de", "en"],
|
||||
"defaultLocale": "de",
|
||||
"roles": {
|
||||
"realm": [
|
||||
{
|
||||
"name": "ADMIN",
|
||||
"description": "Administrator role with full system access",
|
||||
"composite": false,
|
||||
"clientRole": false
|
||||
},
|
||||
{
|
||||
"name": "USER",
|
||||
"description": "Standard user role with limited access",
|
||||
"composite": false,
|
||||
"clientRole": false
|
||||
},
|
||||
{
|
||||
"name": "MONITORING",
|
||||
"description": "Monitoring role for system health checks",
|
||||
"composite": false,
|
||||
"clientRole": false
|
||||
},
|
||||
{
|
||||
"name": "GUEST",
|
||||
"description": "Guest role with minimal access",
|
||||
"composite": false,
|
||||
"clientRole": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "api-gateway",
|
||||
"name": "API Gateway Client",
|
||||
"description": "OAuth2 client for the Meldestelle API Gateway",
|
||||
"enabled": true,
|
||||
"alwaysDisplayInConsole": false,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "K5RqonwVOaxPKaXVH4mbthSRbjRh5tOK",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/*",
|
||||
"http://localhost:3000/*",
|
||||
"https://app.meldestelle.at/*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"http://localhost:8081",
|
||||
"http://localhost:3000",
|
||||
"https://app.meldestelle.at"
|
||||
],
|
||||
"protocol": "openid-connect",
|
||||
"bearerOnly": false,
|
||||
"publicClient": false,
|
||||
"standardFlowEnabled": true,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": true,
|
||||
"serviceAccountsEnabled": true,
|
||||
"authorizationServicesEnabled": false,
|
||||
"fullScopeAllowed": true,
|
||||
"frontchannelLogout": true,
|
||||
"attributes": {
|
||||
"access.token.lifespan": "300",
|
||||
"client.secret.creation.time": "0",
|
||||
"oauth2.device.authorization.grant.enabled": "false",
|
||||
"backchannel.logout.session.required": "true",
|
||||
"backchannel.logout.revoke.offline.tokens": "false"
|
||||
},
|
||||
"protocolMappers": [
|
||||
{
|
||||
"name": "realm-roles",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-realm-role-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"multivalued": "true",
|
||||
"userinfo.token.claim": "true",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "realm_access.roles",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "client-roles",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-client-role-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"multivalued": "true",
|
||||
"userinfo.token.claim": "true",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "resource_access.${client_id}.roles",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"userinfo.token.claim": "true",
|
||||
"user.attribute": "username",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "preferred_username",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"userinfo.token.claim": "true",
|
||||
"user.attribute": "email",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "email",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "full-name",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-full-name-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"clientId": "web-app",
|
||||
"name": "Web Application Client",
|
||||
"description": "Public client for web frontend",
|
||||
"enabled": true,
|
||||
"publicClient": true,
|
||||
"standardFlowEnabled": true,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": false,
|
||||
"redirectUris": [
|
||||
"http://localhost:4000/*",
|
||||
"http://localhost:3000/*",
|
||||
"https://app.meldestelle.at/*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"http://localhost:4000",
|
||||
"http://localhost:3000",
|
||||
"https://app.meldestelle.at"
|
||||
],
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"pkce.code.challenge.method": "S256"
|
||||
}
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"username": "admin",
|
||||
"enabled": true,
|
||||
"emailVerified": true,
|
||||
"firstName": "System",
|
||||
"lastName": "Administrator",
|
||||
"email": "admin@meldestelle.local",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "Change_Me_In_Production!",
|
||||
"temporary": true
|
||||
}
|
||||
],
|
||||
"realmRoles": ["ADMIN", "USER"],
|
||||
"clientRoles": {
|
||||
"api-gateway": ["ADMIN"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups": [],
|
||||
"defaultRoles": ["USER", "GUEST"],
|
||||
"requiredCredentials": ["password"],
|
||||
"passwordPolicy": "length(8)",
|
||||
"otpPolicyType": "totp",
|
||||
"otpPolicyAlgorithm": "HmacSHA1",
|
||||
"otpPolicyInitialCounter": 0,
|
||||
"otpPolicyDigits": 6,
|
||||
"otpPolicyLookAheadWindow": 1,
|
||||
"otpPolicyPeriod": 30,
|
||||
"otpSupportedApplications": ["FreeOTP", "Google Authenticator"],
|
||||
"webAuthnPolicyRpEntityName": "meldestelle",
|
||||
"webAuthnPolicySignatureAlgorithms": ["ES256", "RS256"],
|
||||
"smtpServer": {},
|
||||
"eventsEnabled": true,
|
||||
"eventsListeners": ["jboss-logging"],
|
||||
"enabledEventTypes": [
|
||||
"LOGIN",
|
||||
"LOGIN_ERROR",
|
||||
"LOGOUT",
|
||||
"REGISTER",
|
||||
"REGISTER_ERROR",
|
||||
"UPDATE_PASSWORD",
|
||||
"UPDATE_PASSWORD_ERROR"
|
||||
],
|
||||
"adminEventsEnabled": true,
|
||||
"adminEventsDetailsEnabled": true,
|
||||
"identityProviders": [],
|
||||
"identityProviderMappers": [],
|
||||
"components": {
|
||||
"org.keycloak.keys.KeyProvider": [
|
||||
{
|
||||
"name": "rsa-generated",
|
||||
"providerId": "rsa-generated",
|
||||
"subComponents": {},
|
||||
"config": {
|
||||
"priority": ["100"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hmac-generated",
|
||||
"providerId": "hmac-generated",
|
||||
"subComponents": {},
|
||||
"config": {
|
||||
"priority": ["100"],
|
||||
"algorithm": ["HS256"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "aes-generated",
|
||||
"providerId": "aes-generated",
|
||||
"subComponents": {},
|
||||
"config": {
|
||||
"priority": ["100"]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"authenticationFlows": [],
|
||||
"authenticatorConfig": [],
|
||||
"requiredActions": [],
|
||||
"browserFlow": "browser",
|
||||
"registrationFlow": "registration",
|
||||
"directGrantFlow": "direct grant",
|
||||
"resetCredentialsFlow": "reset credentials",
|
||||
"clientAuthenticationFlow": "clients",
|
||||
"dockerAuthenticationFlow": "docker auth",
|
||||
"attributes": {
|
||||
"frontendUrl": "",
|
||||
"acr.loa.map": "{}",
|
||||
"clientOfflineSessionMaxLifespan": "0",
|
||||
"clientSessionIdleTimeout": "0",
|
||||
"clientSessionMaxLifespan": "0",
|
||||
"clientOfflineSessionIdleTimeout": "0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
global:
|
||||
resolve_timeout: 5m
|
||||
# SMTP configuration for email alerts - use environment variables
|
||||
smtp_smarthost: '${SMTP_SMARTHOST:-smtp.example.com:587}'
|
||||
smtp_from: '${SMTP_FROM:-alertmanager@meldestelle.at}'
|
||||
smtp_auth_username: '${SMTP_AUTH_USERNAME:-alertmanager@meldestelle.at}'
|
||||
smtp_auth_password: '${SMTP_AUTH_PASSWORD}'
|
||||
smtp_require_tls: true
|
||||
|
||||
# The root route on which each incoming alert enters.
|
||||
route:
|
||||
# The root route must not have any matchers as it is the entry point for all alerts
|
||||
# The default receiver is the one that handles alerts that don't match any of the specific routes
|
||||
receiver: 'email-notifications'
|
||||
|
||||
# How long to wait before sending a notification again if it has already been sent successfully
|
||||
repeat_interval: 4h
|
||||
|
||||
# How long to initially wait to send a notification for a group of alerts
|
||||
group_wait: 30s
|
||||
|
||||
# How long to wait before sending a notification about new alerts that are added to a group
|
||||
group_interval: 5m
|
||||
|
||||
# A default grouping of alerts
|
||||
group_by: ['alertname', 'cluster', 'service']
|
||||
|
||||
# Child routes for specific alert categories
|
||||
routes:
|
||||
- receiver: 'slack-critical'
|
||||
matchers:
|
||||
- severity="critical"
|
||||
repeat_interval: 1h
|
||||
|
||||
- receiver: 'slack-warnings'
|
||||
matchers:
|
||||
- severity="warning"
|
||||
repeat_interval: 12h
|
||||
|
||||
# Inhibition rules allow to mute a set of alerts given that another alert is firing
|
||||
inhibit_rules:
|
||||
- source_matchers:
|
||||
- severity="critical"
|
||||
target_matchers:
|
||||
- severity="warning"
|
||||
# Apply inhibition if the alertname is the same
|
||||
equal: ['alertname', 'cluster', 'service']
|
||||
|
||||
# Receivers define notification integrations
|
||||
receivers:
|
||||
- name: 'email-notifications'
|
||||
email_configs:
|
||||
- to: 'admin@meldestelle.at'
|
||||
send_resolved: true
|
||||
|
||||
- name: 'slack-critical'
|
||||
slack_configs:
|
||||
- api_url: '${SLACK_WEBHOOK_URL_CRITICAL}'
|
||||
channel: '${SLACK_CHANNEL_CRITICAL:-#alerts-critical}'
|
||||
send_resolved: true
|
||||
title: '{{ .CommonAnnotations.summary }}'
|
||||
text: >-
|
||||
{{ range .Alerts }}
|
||||
*Alert:* {{ .Annotations.summary }}
|
||||
*Description:* {{ .Annotations.description }}
|
||||
*Severity:* {{ .Labels.severity }}
|
||||
*Instance:* {{ .Labels.instance }}
|
||||
{{ end }}
|
||||
|
||||
- name: 'slack-warnings'
|
||||
slack_configs:
|
||||
- api_url: '${SLACK_WEBHOOK_URL_WARNINGS}'
|
||||
channel: '${SLACK_CHANNEL_WARNINGS:-#alerts-warnings}'
|
||||
send_resolved: true
|
||||
title: '{{ .CommonAnnotations.summary }}'
|
||||
text: >-
|
||||
{{ range .Alerts }}
|
||||
*Alert:* {{ .Annotations.summary }}
|
||||
*Description:* {{ .Annotations.description }}
|
||||
*Severity:* {{ .Labels.severity }}
|
||||
*Instance:* {{ .Labels.instance }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
## Default Elasticsearch configuration
|
||||
cluster.name: "meldestelle-elk"
|
||||
network.host: 0.0.0.0
|
||||
|
||||
# Minimum memory requirements
|
||||
discovery.type: single-node
|
||||
|
||||
# X-Pack security disabled for development
|
||||
xpack.security.enabled: false
|
||||
|
||||
# Enable monitoring
|
||||
xpack.monitoring.collection.enabled: true
|
||||
@@ -0,0 +1,51 @@
|
||||
input {
|
||||
# TCP input for logback appender
|
||||
tcp {
|
||||
port => 5000
|
||||
codec => json_lines
|
||||
}
|
||||
|
||||
# File input for server logs
|
||||
file {
|
||||
path => "/var/log/meldestelle/*.log"
|
||||
start_position => "beginning"
|
||||
sincedb_path => "/dev/null"
|
||||
}
|
||||
}
|
||||
|
||||
filter {
|
||||
if [type] == "syslog" {
|
||||
grok {
|
||||
match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
|
||||
add_field => [ "received_at", "%{@timestamp}" ]
|
||||
add_field => [ "received_from", "%{host}" ]
|
||||
}
|
||||
date {
|
||||
match => [ "syslog_timestamp", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ]
|
||||
}
|
||||
}
|
||||
|
||||
# Parse JSON logs
|
||||
if [message] =~ /^\{.*\}$/ {
|
||||
json {
|
||||
source => "message"
|
||||
}
|
||||
}
|
||||
|
||||
# Add application name
|
||||
mutate {
|
||||
add_field => { "application" => "meldestelle" }
|
||||
}
|
||||
}
|
||||
|
||||
output {
|
||||
elasticsearch {
|
||||
hosts => ["elasticsearch:9200"]
|
||||
index => "meldestelle-logs-%{+YYYY.MM.dd}"
|
||||
}
|
||||
|
||||
# For debugging
|
||||
stdout {
|
||||
codec => rubydebug
|
||||
}
|
||||
}
|
||||
+389
@@ -0,0 +1,389 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Meldestelle Application Overview Dashboard - Key metrics and health indicators",
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "reqps"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "rate(http_server_requests_seconds_count{application=\"meldestelle\"}[5m])",
|
||||
"interval": "",
|
||||
"legendFormat": "{{method}} {{uri}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "HTTP Request Rate",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"colorMode": "background",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"values": false,
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": ""
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "8.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "up{application=\"meldestelle\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "{{instance}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Application Status",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "ms"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "histogram_quantile(0.95, rate(http_server_requests_seconds_bucket{application=\"meldestelle\"}[5m])) * 1000",
|
||||
"interval": "",
|
||||
"legendFormat": "95th percentile",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "histogram_quantile(0.50, rate(http_server_requests_seconds_bucket{application=\"meldestelle\"}[5m])) * 1000",
|
||||
"interval": "",
|
||||
"legendFormat": "50th percentile",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "HTTP Response Times",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percent"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "rate(http_server_requests_seconds_count{application=\"meldestelle\",status=~\"[45].*\"}[5m]) / rate(http_server_requests_seconds_count{application=\"meldestelle\"}[5m]) * 100",
|
||||
"interval": "",
|
||||
"legendFormat": "Error Rate",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Error Rate",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "30s",
|
||||
"schemaVersion": 36,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"meldestelle",
|
||||
"application",
|
||||
"overview"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Meldestelle - Application Overview",
|
||||
"uid": "meldestelle-app-overview",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
+599
@@ -0,0 +1,599 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Infrastructure Components Dashboard - Monitoring of PostgreSQL, Redis, Kafka, and other supporting services",
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"colorMode": "background",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "horizontal",
|
||||
"reduceOptions": {
|
||||
"values": false,
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": ""
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "8.5.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "up{job=\"postgres\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "PostgreSQL",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "up{job=\"redis\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "Redis",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "up{job=\"kafka\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "Kafka",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "up{job=\"keycloak\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "Keycloak",
|
||||
"refId": "D"
|
||||
}
|
||||
],
|
||||
"title": "Infrastructure Services Status",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percent"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 4
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
|
||||
"interval": "",
|
||||
"legendFormat": "CPU Usage",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "System CPU Usage",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "bytes"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 4
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes",
|
||||
"interval": "",
|
||||
"legendFormat": "Memory Used",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "node_memory_MemTotal_bytes",
|
||||
"interval": "",
|
||||
"legendFormat": "Memory Total",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "System Memory Usage",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 12
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "pg_stat_database_numbackends{job=\"postgres\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "{{datname}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "PostgreSQL Active Connections",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 12
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "redis_connected_clients{job=\"redis\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "Connected Clients",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Redis Connected Clients",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 12
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "kafka_server_brokertopicmetrics_messagesin_total{job=\"kafka\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "{{topic}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Kafka Messages In",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "30s",
|
||||
"schemaVersion": 36,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"meldestelle",
|
||||
"infrastructure",
|
||||
"postgres",
|
||||
"redis",
|
||||
"kafka"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Meldestelle - Infrastructure Components",
|
||||
"uid": "meldestelle-infrastructure",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
@@ -0,0 +1,659 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": 1,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "bytes"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_memory_used_bytes{area=\"heap\"}",
|
||||
"legendFormat": "Used Heap",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_memory_committed_bytes{area=\"heap\"}",
|
||||
"hide": false,
|
||||
"legendFormat": "Committed Heap",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_memory_max_bytes{area=\"heap\"}",
|
||||
"hide": false,
|
||||
"legendFormat": "Max Heap",
|
||||
"range": true,
|
||||
"refId": "C"
|
||||
}
|
||||
],
|
||||
"title": "JVM Heap Memory",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "bytes"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_memory_used_bytes{area=\"nonheap\"}",
|
||||
"legendFormat": "Used Non-Heap",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_memory_committed_bytes{area=\"nonheap\"}",
|
||||
"hide": false,
|
||||
"legendFormat": "Committed Non-Heap",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_memory_max_bytes{area=\"nonheap\"}",
|
||||
"hide": false,
|
||||
"legendFormat": "Max Non-Heap",
|
||||
"range": true,
|
||||
"refId": "C"
|
||||
}
|
||||
],
|
||||
"title": "JVM Non-Heap Memory",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_threads_live_threads",
|
||||
"legendFormat": "Live Threads",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_threads_daemon_threads",
|
||||
"hide": false,
|
||||
"legendFormat": "Daemon Threads",
|
||||
"range": true,
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "JVM Threads",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "jvm_gc_pause_seconds_sum / jvm_gc_pause_seconds_count",
|
||||
"legendFormat": "GC Pause Time",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "JVM GC Pause Time",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "rate(http_server_requests_seconds_count[1m])",
|
||||
"legendFormat": "{{method}} {{uri}} {{status}}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "HTTP Request Rate",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 16
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "http_server_requests_seconds_sum / http_server_requests_seconds_count",
|
||||
"legendFormat": "{{method}} {{uri}} {{status}}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "HTTP Request Duration",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 38,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Meldestelle JVM Metrics",
|
||||
"uid": "meldestelle-jvm",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: 'Meldestelle Dashboards'
|
||||
orgId: 1
|
||||
folder: 'Meldestelle'
|
||||
type: file
|
||||
disableDeletion: false
|
||||
editable: true
|
||||
options:
|
||||
path: /var/lib/grafana/dashboards
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
access: proxy
|
||||
url: http://prometheus:9090
|
||||
isDefault: true
|
||||
editable: false
|
||||
version: 1
|
||||
@@ -0,0 +1,46 @@
|
||||
# Prometheus configuration for Meldestelle project
|
||||
# Basic configuration to enable service monitoring
|
||||
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
# Alertmanager configuration
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- static_configs:
|
||||
- targets:
|
||||
- "alertmanager:9093"
|
||||
|
||||
rule_files:
|
||||
- "/etc/prometheus/rules/alerts.yaml"
|
||||
|
||||
scrape_configs:
|
||||
# Job 1: Prometheus überwacht sich selbst
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: [ 'localhost:9090' ]
|
||||
|
||||
# Job 2: API Gateway (Spring Boot Actuator)
|
||||
- job_name: 'api-gateway'
|
||||
metrics_path: '/actuator/prometheus'
|
||||
scrape_interval: "30s"
|
||||
static_configs:
|
||||
- targets: [ 'api-gateway:8081' ]
|
||||
|
||||
# Job 3: Postgres (ACHTUNG)
|
||||
# Postgres direkt auf 5432 zu scrapen geht nicht.
|
||||
# Entweder auskommentieren oder 'postgres-exporter' Container hinzufügen.
|
||||
# - job_name: 'postgres-exporter'
|
||||
# static_configs:
|
||||
# - targets: ['postgres-exporter:9187']
|
||||
|
||||
# Add consul for service discovery monitoring
|
||||
- job_name: 'consul'
|
||||
metrics_path: '/v1/agent/metrics'
|
||||
params:
|
||||
format: [ 'prometheus' ]
|
||||
static_configs:
|
||||
- targets: [ 'consul:8500' ]
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
groups:
|
||||
- name: meldestelle_alerts
|
||||
rules:
|
||||
# 1. Memory: Passt soweit, ist okay.
|
||||
- alert: HighMemoryUsage
|
||||
expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100 > 85
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "High memory usage ({{ $value | humanize }}%)"
|
||||
description: "JVM Heap usage is above 85%.\n Instance: {{ $labels.instance }}"
|
||||
|
||||
# 2. CPU: Passt auch.
|
||||
- alert: HighCpuUsage
|
||||
expr: process_cpu_usage * 100 > 85
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "High CPU usage ({{ $value | humanize }}%)"
|
||||
description: "CPU usage is above 85%.\n Instance: {{ $labels.instance }}"
|
||||
|
||||
# 3. Error Rate: FIX - Division durch null abfangen & Rate nutzen
|
||||
- alert: HighErrorRate
|
||||
# Wir prüfen nur, wenn überhaupt Requests > 0 da sind, um DivByZero zu vermeiden
|
||||
expr: |
|
||||
(
|
||||
sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
|
||||
/
|
||||
sum(rate(http_server_requests_seconds_count[5m]))
|
||||
) * 100 > 5
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "High error rate ({{ $value | humanize }}%)"
|
||||
description: "More than 5% of requests resulted in 5xx errors.\n Instance: {{ $labels.instance }}"
|
||||
|
||||
# 4. Service Down: FIX - Job Name Regex
|
||||
- alert: ServiceDown
|
||||
# Prüft alle Jobs, die du in prometheus.yml definiert hast (api-gateway, consul etc.),
|
||||
# 'up == 0' bedeutet: Target ist konfiguriert, aber nicht erreichbar.
|
||||
expr: up == 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Service {{ $labels.job }} is down"
|
||||
description: "Service instance {{ $labels.instance }} of job {{ $labels.job }} is not reachable."
|
||||
|
||||
# 5. Slow Response: FIX - 'rate' benutzen!
|
||||
- alert: SlowResponseTime
|
||||
# Berechnet die durchschnittliche Dauer pro request im 5-Minuten-Fenster
|
||||
expr: rate(http_server_requests_seconds_sum[5m]) / rate(http_server_requests_seconds_count[5m]) > 1
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Slow response time ({{ $value | humanizeDuration }})"
|
||||
description: "Average response time is > 1s for the last 5 minutes.\n Instance: {{ $labels.instance }}\n Path: {{ $labels.uri }}"
|
||||
|
||||
# 6. GC Pause: FIX - 'rate' benutzen!
|
||||
- alert: HighGcPauseTime
|
||||
# Zeigt an, wie viel Zeit PRO SEKUNDE für GC draufgeht (nicht pro GC Event, das ist oft aussagekräftiger)
|
||||
# Oder "Durchschnittliche Dauer pro GC Event im Zeitfenster":
|
||||
expr: rate(jvm_gc_pause_seconds_sum[5m]) / rate(jvm_gc_pause_seconds_count[5m]) > 0.5
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "High GC pause time ({{ $value | humanizeDuration }})"
|
||||
description: "Average GC pause is > 0.5s.\n Instance: {{ $labels.instance }}"
|
||||
@@ -0,0 +1,133 @@
|
||||
# Nginx Production Configuration
|
||||
# =============================================================================
|
||||
# This configuration provides secure reverse proxy with SSL termination,
|
||||
# security headers, and performance optimizations for production
|
||||
# =============================================================================
|
||||
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
# Performance and Security Settings
|
||||
worker_rlimit_nofile 65535;
|
||||
|
||||
events {
|
||||
worker_connections 4096;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
# Basic Settings
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Performance Settings
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
server_tokens off;
|
||||
|
||||
# Buffer Settings
|
||||
client_body_buffer_size 128k;
|
||||
client_max_body_size 10m;
|
||||
client_header_buffer_size 1k;
|
||||
large_client_header_buffers 4 4k;
|
||||
output_buffers 1 32k;
|
||||
postpone_output 1460;
|
||||
|
||||
# Timeout Settings
|
||||
client_body_timeout 12;
|
||||
client_header_timeout 12;
|
||||
send_timeout 10;
|
||||
|
||||
# Gzip Compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 10240;
|
||||
gzip_proxied expired no-cache no-store private must-revalidate auth;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/x-javascript
|
||||
application/xml+rss
|
||||
application/javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/rss+xml
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# Security Headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Rate Limiting
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;
|
||||
limit_req_zone $binary_remote_addr zone=general:10m rate=1000r/m;
|
||||
|
||||
# Logging Format
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'$request_time $upstream_response_time';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_session_tickets off;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# Upstream Definitions
|
||||
upstream keycloak {
|
||||
server keycloak:8443;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream grafana {
|
||||
server grafana:3000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream prometheus {
|
||||
server prometheus:9090;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# HTTP to HTTPS Redirect
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# Health Check Endpoint
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
|
||||
# Include additional server configurations
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
-- ===================================================================
|
||||
-- PostgreSQL Initialization Script for Keycloak
|
||||
-- ===================================================================
|
||||
-- Dieses Skript erstellt ein separates Schema für Keycloak-Daten innerhalb der
|
||||
-- meldestelle-Datenbank und sorgt so für Isolation und bessere Organisation.
|
||||
--
|
||||
-- Ausführung: Wird automatisch von PostgreSQL beim ersten Start ausgeführt
|
||||
-- über den docker-entrypoint-initdb.d-Mechanismus.
|
||||
-- ===================================================================
|
||||
|
||||
-- Erstellt das Keycloak-Schema, falls es noch nicht existiert.
|
||||
CREATE SCHEMA IF NOT EXISTS keycloak;
|
||||
|
||||
-- Da der "POSTGRES_USER" (Superuser) das Skript ausführt,
|
||||
-- gehört ihm das Schema automatisch oder er hat Zugriff.
|
||||
-- Explizite GRANTS auf "pg-user" entfernen, um .env-Unabhängigkeit zu wahren.
|
||||
|
||||
-- Falls du es explizit willst, nutze current_user (der ausführende User):
|
||||
GRANT ALL PRIVILEGES ON SCHEMA keycloak TO current_user;
|
||||
-- Gewährt dem Benutzer „meldestelle“ alle Berechtigungen für das Schema.
|
||||
-- GRANT ALL PRIVILEGES ON SCHEMA keycloak TO "pg-user";
|
||||
|
||||
-- Gewährt die Nutzung des Schemas
|
||||
GRANT USAGE ON SCHEMA keycloak TO "pg-user";
|
||||
|
||||
-- Standardberechtigungen für zukünftige Tabellen im Keycloak-Schema festlegen
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON TABLES TO "pg-user";
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON SEQUENCES TO "pg-user";
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON FUNCTIONS TO "pg-user";
|
||||
|
||||
-- Log successful schema Erstellung
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'Keycloak schema created successfully in database';
|
||||
END $$;
|
||||
@@ -0,0 +1,11 @@
|
||||
-- ===================================================================
|
||||
-- Keycloak Schema Init (No-Op)
|
||||
-- ===================================================================
|
||||
-- DEPRECATED: Schema-initialization erfolgt über die Datei 01-init-keycloak-schema.sql.
|
||||
-- Diese Datei dient lediglich der Sicherstellung der Ausführungsreihenfolge, führt aber keine Aktionen aus.
|
||||
-- ===================================================================
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE '02-init-keycloak-schema.sql is a no-op (handled by 01-init-keycloak-schema.sql)';
|
||||
END $$;
|
||||
@@ -0,0 +1,90 @@
|
||||
# PostgreSQL Configuration File
|
||||
# Optimized for Meldestelle application
|
||||
|
||||
# Connection Settings
|
||||
listen_addresses = '*'
|
||||
max_connections = 100
|
||||
superuser_reserved_connections = 3
|
||||
|
||||
# Memory Settings
|
||||
# These will be overridden by environment variables in docker-compose.yaml
|
||||
shared_buffers = 256MB # min 128kB
|
||||
work_mem = 16MB # min 64kB
|
||||
maintenance_work_mem = 64MB # min 1MB
|
||||
effective_cache_size = 768MB
|
||||
|
||||
# Write-Ahead Log (WAL)
|
||||
wal_level = replica # minimal, replica, or logical
|
||||
max_wal_size = 1GB
|
||||
min_wal_size = 80MB
|
||||
wal_buffers = 16MB # min 32kB, -1 sets based on shared_buffers
|
||||
checkpoint_completion_target = 0.9 # checkpoint target duration, 0.0 - 1.0
|
||||
random_page_cost = 1.1 # For SSD storage
|
||||
|
||||
# Background Writer
|
||||
bgwriter_delay = 200ms
|
||||
bgwriter_lru_maxpages = 100
|
||||
bgwriter_lru_multiplier = 2.0
|
||||
|
||||
# Asynchronous Behavior
|
||||
effective_io_concurrency = 200 # For SSD storage
|
||||
max_worker_processes = 8
|
||||
max_parallel_workers_per_gather = 4
|
||||
max_parallel_workers = 8
|
||||
max_parallel_maintenance_workers = 4
|
||||
|
||||
# Query Planner
|
||||
default_statistics_target = 100
|
||||
constraint_exclusion = partition
|
||||
|
||||
# Logging
|
||||
log_destination = 'stderr'
|
||||
logging_collector = off
|
||||
# log_directory = 'log'
|
||||
# log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
|
||||
log_truncate_on_rotation = off
|
||||
log_rotation_age = 1d
|
||||
log_rotation_size = 100MB
|
||||
log_min_duration_statement = 250ms # Log slow queries (250ms or slower)
|
||||
log_checkpoints = on
|
||||
log_connections = on
|
||||
log_disconnections = on
|
||||
log_lock_waits = on
|
||||
log_temp_files = 0
|
||||
log_autovacuum_min_duration = 250ms
|
||||
log_line_prefix = '%m [%p] %q%u@%d '
|
||||
|
||||
# Autovacuum
|
||||
autovacuum = on
|
||||
autovacuum_max_workers = 3
|
||||
autovacuum_naptime = 1min
|
||||
autovacuum_vacuum_threshold = 50
|
||||
autovacuum_analyze_threshold = 50
|
||||
autovacuum_vacuum_scale_factor = 0.05
|
||||
autovacuum_analyze_scale_factor = 0.025
|
||||
autovacuum_vacuum_cost_delay = 20ms
|
||||
autovacuum_vacuum_cost_limit = 2000
|
||||
|
||||
# Statement Behavior
|
||||
search_path = '"$user", public'
|
||||
row_security = on
|
||||
|
||||
# Client Connection Defaults
|
||||
client_min_messages = notice
|
||||
statement_timeout = 60000 # 60 seconds, prevents long-running queries
|
||||
lock_timeout = 10000 # 10 seconds, prevents lock contention
|
||||
idle_in_transaction_session_timeout = 600000 # 10 minutes, prevents idle transactions
|
||||
|
||||
# Disk
|
||||
temp_file_limit = 1GB # Limits temp file size
|
||||
|
||||
# SSL
|
||||
ssl = off
|
||||
ssl_prefer_server_ciphers = on
|
||||
|
||||
# Performance Monitoring
|
||||
track_activities = on
|
||||
track_counts = on
|
||||
track_io_timing = on
|
||||
track_functions = pl # none, pl, all
|
||||
track_activity_query_size = 2048
|
||||
@@ -0,0 +1,149 @@
|
||||
# Redis Production Configuration
|
||||
# =============================================================================
|
||||
# This configuration file contains production-ready settings for Redis
|
||||
# with security, performance, and reliability optimizations.
|
||||
# =============================================================================
|
||||
|
||||
# Network and Security
|
||||
bind 0.0.0.0
|
||||
protected-mode yes
|
||||
port 6379
|
||||
|
||||
# Authentication (password will be set via command line)
|
||||
# requirepass will be set via --requirepass flag in docker-compose
|
||||
|
||||
# General Settings
|
||||
timeout 300
|
||||
tcp-keepalive 300
|
||||
tcp-backlog 511
|
||||
|
||||
# Memory Management
|
||||
maxmemory 256mb
|
||||
maxmemory-policy allkeys-lru
|
||||
maxmemory-samples 5
|
||||
|
||||
# Persistence Settings
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
stop-writes-on-bgsave-error yes
|
||||
rdbcompression yes
|
||||
rdbchecksum yes
|
||||
dbfilename dump.rdb
|
||||
dir /data
|
||||
|
||||
# Append Only File (AOF)
|
||||
appendonly yes
|
||||
appendfilename "appendonly.aof"
|
||||
appendfsync everysec
|
||||
no-appendfsync-on-rewrite no
|
||||
auto-aof-rewrite-percentage 100
|
||||
auto-aof-rewrite-min-size 64mb
|
||||
aof-load-truncated yes
|
||||
aof-use-rdb-preamble yes
|
||||
|
||||
# Logging
|
||||
loglevel notice
|
||||
logfile ""
|
||||
syslog-enabled no
|
||||
|
||||
# Database Settings
|
||||
databases 16
|
||||
|
||||
# Slow Log
|
||||
slowlog-log-slower-than 10000
|
||||
slowlog-max-len 128
|
||||
|
||||
# Latency Monitoring
|
||||
latency-monitor-threshold 100
|
||||
|
||||
# Client Settings
|
||||
maxclients 10000
|
||||
|
||||
# Security Settings
|
||||
rename-command FLUSHDB ""
|
||||
rename-command FLUSHALL ""
|
||||
# KEYS ist langsam, sperren ist okay (Admin tools funktionieren dann aber evtl. nicht mehr)
|
||||
rename-command KEYS ""
|
||||
rename-command CONFIG "CONFIG_b835c3f8a5d2e7f1"
|
||||
rename-command SHUTDOWN "SHUTDOWN_a9b4c2d1e3f5g6h7"
|
||||
rename-command DEBUG ""
|
||||
|
||||
# EVAL wird für Lua-Skripte benötigt (Locks, Rate Limiting etc.)
|
||||
# rename-command EVAL ""
|
||||
|
||||
# DEL wird benötigt, damit die App Cache-Einträge invalidieren kann!
|
||||
# rename-command DEL "DEL_prod_safe"
|
||||
|
||||
# TLS Configuration (uncomment and configure for TLS)
|
||||
# port 0
|
||||
# tls-port 6380
|
||||
# tls-cert-file /tls/redis.crt
|
||||
# tls-key-file /tls/redis.key
|
||||
# tls-ca-cert-file /tls/ca.crt
|
||||
# tls-dh-params-file /tls/redis.dh
|
||||
# tls-protocols "TLSv1.2 TLSv1.3"
|
||||
# tls-ciphers "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS"
|
||||
# tls-ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
|
||||
# tls-prefer-server-ciphers yes
|
||||
# tls-session-caching no
|
||||
# tls-session-cache-size 5000
|
||||
# tls-session-cache-timeout 60
|
||||
|
||||
# Performance Tuning
|
||||
hash-max-ziplist-entries 512
|
||||
hash-max-ziplist-value 64
|
||||
list-max-ziplist-size -2
|
||||
list-compress-depth 0
|
||||
set-max-intset-entries 512
|
||||
zset-max-ziplist-entries 128
|
||||
zset-max-ziplist-value 64
|
||||
hll-sparse-max-bytes 3000
|
||||
stream-node-max-bytes 4096
|
||||
stream-node-max-entries 100
|
||||
|
||||
# Active Rehashing
|
||||
activerehashing yes
|
||||
|
||||
# Client Output Buffer Limits
|
||||
client-output-buffer-limit normal 0 0 0
|
||||
client-output-buffer-limit replica 256mb 64mb 60
|
||||
client-output-buffer-limit pubsub 32mb 8mb 60
|
||||
|
||||
# Client Query Buffer
|
||||
client-query-buffer-limit 1gb
|
||||
|
||||
# Protocol Buffer
|
||||
proto-max-bulk-len 512mb
|
||||
|
||||
# Replication (for Redis cluster/replica setup)
|
||||
# replica-serve-stale-data yes
|
||||
# replica-read-only yes
|
||||
# repl-diskless-sync no
|
||||
# repl-diskless-sync-delay 5
|
||||
# repl-ping-replica-period 10
|
||||
# repl-timeout 60
|
||||
# repl-disable-tcp-nodelay no
|
||||
# repl-backlog-size 1mb
|
||||
# repl-backlog-ttl 3600
|
||||
|
||||
# Security: Disable potentially dangerous features
|
||||
enable-protected-configs no
|
||||
enable-debug-command no
|
||||
enable-module-command no
|
||||
|
||||
# Notifications (disable for performance)
|
||||
notify-keyspace-events ""
|
||||
|
||||
# Advanced Configuration
|
||||
hz 10
|
||||
dynamic-hz yes
|
||||
aof-rewrite-incremental-fsync yes
|
||||
rdb-save-incremental-fsync yes
|
||||
|
||||
# Jemalloc Configuration
|
||||
jemalloc-bg-thread yes
|
||||
|
||||
# Threading (Redis 6.0+)
|
||||
# io-threads 4
|
||||
# io-threads-do-reads yes
|
||||
@@ -0,0 +1,619 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://meldestelle.at/schemas/docker-versions.json",
|
||||
"title": "Docker Versions TOML Schema",
|
||||
"description": "Schema for docker/versions.toml - centralized Docker version management",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"versions": {
|
||||
"type": "object",
|
||||
"description": "Central version definitions for all Docker components",
|
||||
"properties": {
|
||||
"gradle": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
||||
"description": "Gradle version for build tools",
|
||||
"examples": ["9.0.0", "8.14.0"]
|
||||
},
|
||||
"java": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+$",
|
||||
"description": "Java version (LTS recommended)",
|
||||
"examples": ["21", "17", "11"]
|
||||
},
|
||||
"node": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
||||
"description": "Node.js version for client builds",
|
||||
"examples": ["20.12.0", "18.19.0"]
|
||||
},
|
||||
"nginx": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+-alpine$",
|
||||
"description": "Nginx version with Alpine base",
|
||||
"examples": ["1.25-alpine", "1.24-alpine"]
|
||||
},
|
||||
"alpine": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+$",
|
||||
"description": "Alpine Linux base image version",
|
||||
"examples": ["3.19", "3.18"]
|
||||
},
|
||||
"eclipse-temurin-jdk": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-jdk-alpine$",
|
||||
"description": "Eclipse Temurin JDK image tag",
|
||||
"examples": ["21-jdk-alpine", "17-jdk-alpine"]
|
||||
},
|
||||
"eclipse-temurin-jre": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-jre-alpine$",
|
||||
"description": "Eclipse Temurin JRE image tag",
|
||||
"examples": ["21-jre-alpine", "17-jre-alpine"]
|
||||
},
|
||||
"prometheus": {
|
||||
"type": "string",
|
||||
"pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$",
|
||||
"description": "Prometheus monitoring version",
|
||||
"examples": ["v2.54.1", "v2.47.0"]
|
||||
},
|
||||
"grafana": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
||||
"description": "Grafana visualization version",
|
||||
"examples": ["11.3.0", "10.1.0"]
|
||||
},
|
||||
"keycloak": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
||||
"description": "Keycloak authentication version",
|
||||
"examples": ["26.0.7", "25.0.6"]
|
||||
},
|
||||
"spring-profiles-default": {
|
||||
"type": "string",
|
||||
"enum": ["default", "dev", "test", "prod"],
|
||||
"description": "Default Spring profile for infrastructure services"
|
||||
},
|
||||
"spring-profiles-docker": {
|
||||
"type": "string",
|
||||
"enum": ["docker", "dev", "test", "prod"],
|
||||
"description": "Spring profile for Docker containers"
|
||||
},
|
||||
"spring-profiles-prod": {
|
||||
"type": "string",
|
||||
"enum": ["prod", "production"],
|
||||
"description": "Spring profile for production environment"
|
||||
},
|
||||
"app-version": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
||||
"description": "Application version for all services",
|
||||
"examples": ["1.0.0", "2.1.3"]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"gradle",
|
||||
"java",
|
||||
"node",
|
||||
"nginx",
|
||||
"alpine",
|
||||
"prometheus",
|
||||
"grafana",
|
||||
"keycloak",
|
||||
"app-version"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"service-ports": {
|
||||
"type": "object",
|
||||
"description": "Centralized port definitions for all services",
|
||||
"properties": {
|
||||
"api-gateway": {
|
||||
"type": "integer",
|
||||
"minimum": 8081,
|
||||
"maximum": 8081,
|
||||
"description": "API Gateway port"
|
||||
},
|
||||
"auth-server": {
|
||||
"type": "integer",
|
||||
"minimum": 8087,
|
||||
"maximum": 8087,
|
||||
"description": "Authentication server port"
|
||||
},
|
||||
"monitoring-server": {
|
||||
"type": "integer",
|
||||
"minimum": 8088,
|
||||
"maximum": 8088,
|
||||
"description": "Monitoring server port"
|
||||
},
|
||||
"ping-service": {
|
||||
"type": "integer",
|
||||
"minimum": 8082,
|
||||
"maximum": 8082,
|
||||
"description": "Ping service port"
|
||||
},
|
||||
"members-service": {
|
||||
"type": "integer",
|
||||
"minimum": 8083,
|
||||
"maximum": 8083,
|
||||
"description": "Members service port"
|
||||
},
|
||||
"horses-service": {
|
||||
"type": "integer",
|
||||
"minimum": 8084,
|
||||
"maximum": 8084,
|
||||
"description": "Horses service port"
|
||||
},
|
||||
"events-service": {
|
||||
"type": "integer",
|
||||
"minimum": 8085,
|
||||
"maximum": 8085,
|
||||
"description": "Events service port"
|
||||
},
|
||||
"masterdata-service": {
|
||||
"type": "integer",
|
||||
"minimum": 8086,
|
||||
"maximum": 8086,
|
||||
"description": "Masterdata service port"
|
||||
},
|
||||
"postgres": {
|
||||
"type": "integer",
|
||||
"minimum": 5432,
|
||||
"maximum": 5432,
|
||||
"description": "PostgreSQL database port"
|
||||
},
|
||||
"redis": {
|
||||
"type": "integer",
|
||||
"minimum": 6379,
|
||||
"maximum": 6379,
|
||||
"description": "Redis cache port"
|
||||
},
|
||||
"keycloak": {
|
||||
"type": "integer",
|
||||
"minimum": 8180,
|
||||
"maximum": 8180,
|
||||
"description": "Keycloak authentication port"
|
||||
},
|
||||
"consul": {
|
||||
"type": "integer",
|
||||
"minimum": 8500,
|
||||
"maximum": 8500,
|
||||
"description": "Consul service discovery port"
|
||||
},
|
||||
"zookeeper": {
|
||||
"type": "integer",
|
||||
"minimum": 2181,
|
||||
"maximum": 2181,
|
||||
"description": "Zookeeper coordination port"
|
||||
},
|
||||
"kafka": {
|
||||
"type": "integer",
|
||||
"minimum": 9092,
|
||||
"maximum": 9092,
|
||||
"description": "Kafka messaging port"
|
||||
},
|
||||
"prometheus": {
|
||||
"type": "integer",
|
||||
"minimum": 9090,
|
||||
"maximum": 9090,
|
||||
"description": "Prometheus monitoring port"
|
||||
},
|
||||
"grafana": {
|
||||
"type": "integer",
|
||||
"minimum": 3000,
|
||||
"maximum": 3000,
|
||||
"description": "Grafana visualization port"
|
||||
},
|
||||
"web-app": {
|
||||
"type": "integer",
|
||||
"minimum": 4000,
|
||||
"maximum": 4000,
|
||||
"description": "Web application port"
|
||||
},
|
||||
"desktop-app-vnc": {
|
||||
"type": "integer",
|
||||
"minimum": 5901,
|
||||
"maximum": 5901,
|
||||
"description": "Desktop app VNC port"
|
||||
},
|
||||
"desktop-app-novnc": {
|
||||
"type": "integer",
|
||||
"minimum": 6080,
|
||||
"maximum": 6080,
|
||||
"description": "Desktop app noVNC web port"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"api-gateway",
|
||||
"auth-server",
|
||||
"monitoring-server",
|
||||
"ping-service",
|
||||
"postgres",
|
||||
"redis",
|
||||
"keycloak",
|
||||
"prometheus",
|
||||
"grafana",
|
||||
"web-app"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"port-ranges": {
|
||||
"type": "object",
|
||||
"description": "Port range definitions for service categories",
|
||||
"properties": {
|
||||
"infrastructure": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "Port range for infrastructure services",
|
||||
"examples": ["8081-8088"]
|
||||
},
|
||||
"services": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "Port range for application services",
|
||||
"examples": ["8082-8099"]
|
||||
},
|
||||
"monitoring": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "Port range for monitoring services",
|
||||
"examples": ["9090-9099"]
|
||||
},
|
||||
"clients": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "Port range for client applications",
|
||||
"examples": ["4000-4099"]
|
||||
},
|
||||
"vnc": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "Port range for VNC connections",
|
||||
"examples": ["5901-5999"]
|
||||
},
|
||||
"debug": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "Port range for debug connections",
|
||||
"examples": ["5005-5009"]
|
||||
},
|
||||
"system-reserved": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "System reserved port range",
|
||||
"examples": ["0-1023"]
|
||||
},
|
||||
"ephemeral": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+-[0-9]+$",
|
||||
"description": "Ephemeral port range",
|
||||
"examples": ["32768-65535"]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"infrastructure",
|
||||
"services",
|
||||
"monitoring",
|
||||
"clients",
|
||||
"debug"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"build-args": {
|
||||
"type": "object",
|
||||
"description": "Build argument categories for different service types",
|
||||
"properties": {
|
||||
"global": {
|
||||
"type": "array",
|
||||
"description": "Global build arguments used by all services",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"GRADLE_VERSION",
|
||||
"JAVA_VERSION",
|
||||
"BUILD_DATE",
|
||||
"VERSION"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"spring-services": {
|
||||
"type": "array",
|
||||
"description": "Spring Boot service-specific build arguments",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"SPRING_PROFILES_ACTIVE",
|
||||
"SERVICE_PATH",
|
||||
"SERVICE_NAME",
|
||||
"SERVICE_PORT"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"web-clients": {
|
||||
"type": "array",
|
||||
"description": "Web client-specific build arguments",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"NODE_VERSION",
|
||||
"NGINX_VERSION",
|
||||
"CLIENT_PATH",
|
||||
"CLIENT_MODULE",
|
||||
"CLIENT_NAME"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
"required": ["global"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"categories": {
|
||||
"type": "object",
|
||||
"description": "Service category configurations",
|
||||
"properties": {
|
||||
"services": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default-spring-profile": {
|
||||
"type": "string",
|
||||
"enum": ["docker", "dev", "test", "prod"]
|
||||
},
|
||||
"default-port-start": {
|
||||
"type": "integer",
|
||||
"minimum": 8082,
|
||||
"maximum": 8099
|
||||
},
|
||||
"services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ping-service",
|
||||
"members-service",
|
||||
"horses-service",
|
||||
"events-service",
|
||||
"masterdata-service"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
"required": ["services"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"infrastructure": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default-spring-profile": {
|
||||
"type": "string",
|
||||
"enum": ["default", "dev", "test", "prod"]
|
||||
},
|
||||
"services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"gateway",
|
||||
"auth-server",
|
||||
"monitoring-server"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
"required": ["services"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"clients": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default-node-version": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"default-nginx-version": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+\\.[0-9]+-alpine$"
|
||||
},
|
||||
"clients": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"web-app",
|
||||
"desktop-app"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
"required": ["clients"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["services", "infrastructure", "clients"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"environment-mapping": {
|
||||
"type": "object",
|
||||
"description": "Maps internal version names to environment variable names",
|
||||
"properties": {
|
||||
"gradle-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_GRADLE_VERSION"]
|
||||
},
|
||||
"java-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_JAVA_VERSION"]
|
||||
},
|
||||
"node-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_NODE_VERSION"]
|
||||
},
|
||||
"nginx-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_NGINX_VERSION"]
|
||||
},
|
||||
"prometheus-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_PROMETHEUS_VERSION"]
|
||||
},
|
||||
"grafana-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_GRAFANA_VERSION"]
|
||||
},
|
||||
"keycloak-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_KEYCLOAK_VERSION"]
|
||||
},
|
||||
"spring-profiles-default": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_SPRING_PROFILES_DEFAULT"]
|
||||
},
|
||||
"spring-profiles-docker": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_SPRING_PROFILES_DOCKER"]
|
||||
},
|
||||
"app-version": {
|
||||
"type": "string",
|
||||
"enum": ["DOCKER_APP_VERSION"]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"gradle-version",
|
||||
"java-version",
|
||||
"node-version",
|
||||
"nginx-version",
|
||||
"prometheus-version",
|
||||
"grafana-version",
|
||||
"keycloak-version",
|
||||
"app-version"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"environments": {
|
||||
"type": "object",
|
||||
"description": "Environment-specific configurations",
|
||||
"properties": {
|
||||
"development": {
|
||||
"$ref": "#/definitions/environment-config"
|
||||
},
|
||||
"production": {
|
||||
"$ref": "#/definitions/environment-config"
|
||||
},
|
||||
"testing": {
|
||||
"$ref": "#/definitions/environment-config"
|
||||
}
|
||||
},
|
||||
"required": ["development", "production", "testing"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"versions",
|
||||
"service-ports",
|
||||
"port-ranges",
|
||||
"build-args",
|
||||
"categories",
|
||||
"environment-mapping",
|
||||
"environments"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"definitions": {
|
||||
"environment-config": {
|
||||
"type": "object",
|
||||
"description": "Environment-specific configuration settings",
|
||||
"properties": {
|
||||
"spring-profiles": {
|
||||
"type": "string",
|
||||
"enum": ["dev", "test", "prod", "docker"],
|
||||
"description": "Default Spring profiles for this environment"
|
||||
},
|
||||
"debug-enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether debug mode is enabled"
|
||||
},
|
||||
"log-level": {
|
||||
"type": "string",
|
||||
"enum": ["TRACE", "DEBUG", "INFO", "WARN", "ERROR"],
|
||||
"description": "Default log level for services"
|
||||
},
|
||||
"health-check-interval": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+s$",
|
||||
"description": "Health check interval (e.g., '30s')"
|
||||
},
|
||||
"health-check-timeout": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+s$",
|
||||
"description": "Health check timeout (e.g., '5s')"
|
||||
},
|
||||
"health-check-retries": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 10,
|
||||
"description": "Number of health check retries"
|
||||
},
|
||||
"health-check-start-period": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+s$",
|
||||
"description": "Health check start period (e.g., '40s')"
|
||||
},
|
||||
"resource-limits": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enforce resource limits"
|
||||
},
|
||||
"jvm-debug-port": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"minimum": 5005,
|
||||
"maximum": 5009
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"enum": [false]
|
||||
}
|
||||
],
|
||||
"description": "JVM debug port (5005-5009) or false to disable"
|
||||
},
|
||||
"hot-reload": {
|
||||
"type": "boolean",
|
||||
"description": "Whether hot reload is enabled for development"
|
||||
},
|
||||
"security-headers": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to add security headers (production)"
|
||||
},
|
||||
"tls-enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether TLS/SSL is enabled (production)"
|
||||
},
|
||||
"ephemeral-storage": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use ephemeral storage (testing)"
|
||||
},
|
||||
"test-containers": {
|
||||
"type": "boolean",
|
||||
"description": "Whether test containers are used (testing)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"spring-profiles",
|
||||
"debug-enabled",
|
||||
"log-level",
|
||||
"health-check-interval",
|
||||
"health-check-timeout",
|
||||
"health-check-retries",
|
||||
"health-check-start-period",
|
||||
"resource-limits",
|
||||
"jvm-debug-port",
|
||||
"hot-reload"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
# SSL/TLS Zertifikat-Setup für die Produktionsumgebung
|
||||
|
||||
Dieses Verzeichnis enthält SSL/TLS-Zertifikate und Schlüssel zur Absicherung der Meldestelle-Anwendung in der Produktionsumgebung.
|
||||
|
||||
## Verzeichnisstruktur
|
||||
|
||||
```
|
||||
config/ssl/
|
||||
├── postgres/ # PostgreSQL SSL-Zertifikate
|
||||
├── redis/ # Redis TLS-Zertifikate
|
||||
├── keycloak/ # Keycloak HTTPS-Zertifikate
|
||||
├── prometheus/ # Prometheus HTTPS-Zertifikate
|
||||
├── grafana/ # Grafana HTTPS-Zertifikate
|
||||
├── nginx/ # Nginx SSL-Zertifikate
|
||||
└── README.md # Diese Datei
|
||||
```
|
||||
|
||||
## Zertifikat-Anforderungen
|
||||
|
||||
### 1. PostgreSQL SSL-Zertifikate
|
||||
|
||||
Platzieren Sie die folgenden Dateien in `config/ssl/postgres/`:
|
||||
|
||||
- `server.crt` - Server-Zertifikat
|
||||
- `server.key` - Privater Server-Schlüssel
|
||||
- `ca.crt` - Certificate Authority-Zertifikat
|
||||
|
||||
### 2. Redis TLS-Zertifikate
|
||||
|
||||
Platzieren Sie die folgenden Dateien in `config/ssl/redis/`:
|
||||
|
||||
- `redis.crt` - Redis Server-Zertifikat
|
||||
- `redis.key` - Privater Redis Server-Schlüssel
|
||||
- `ca.crt` - Certificate Authority-Zertifikat
|
||||
- `redis.dh` - Diffie-Hellman Parameter
|
||||
|
||||
### 3. Keycloak HTTPS-Zertifikate
|
||||
|
||||
Platzieren Sie die folgenden Dateien in `config/ssl/keycloak/`:
|
||||
|
||||
- `server.crt.pem` - Server-Zertifikat im PEM-Format
|
||||
- `server.key.pem` - Privater Server-Schlüssel im PEM-Format
|
||||
|
||||
### 4. Prometheus HTTPS-Zertifikate
|
||||
|
||||
Platzieren Sie die folgenden Dateien in `config/ssl/prometheus/`:
|
||||
|
||||
- `prometheus.crt` - Prometheus Server-Zertifikat
|
||||
- `prometheus.key` - Privater Prometheus Server-Schlüssel
|
||||
- `web.yml` - Prometheus Web-Konfigurationsdatei
|
||||
|
||||
### 5. Grafana HTTPS-Zertifikate
|
||||
|
||||
Platzieren Sie die folgenden Dateien in `config/ssl/grafana/`:
|
||||
|
||||
- `server.crt` - Grafana Server-Zertifikat
|
||||
- `server.key` - Privater Grafana Server-Schlüssel
|
||||
|
||||
### 6. Nginx SSL-Zertifikate
|
||||
|
||||
Platzieren Sie die folgenden Dateien in `config/ssl/nginx/`:
|
||||
|
||||
- `server.crt` - Haupt-SSL-Zertifikat
|
||||
- `server.key` - Privater Haupt-SSL-Schlüssel
|
||||
- `dhparam.pem` - Diffie-Hellman Parameter
|
||||
|
||||
## Generierung selbstsignierter Zertifikate (Entwicklung/Test)
|
||||
|
||||
⚠️ **Warnung**: Verwenden Sie selbstsignierte Zertifikate nur für Entwicklung und Tests. Nutzen Sie ordnungsgemäß von einer CA signierte Zertifikate in der Produktion.
|
||||
|
||||
### CA-Zertifikat generieren
|
||||
|
||||
```bash
|
||||
# CA privaten Schlüssel erstellen
|
||||
openssl genrsa -out ca.key 4096
|
||||
|
||||
# CA-Zertifikat erstellen
|
||||
openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
|
||||
-subj "/C=AT/ST=Vienna/L=Vienna/O=Meldestelle/OU=IT/CN=Meldestelle-CA"
|
||||
```
|
||||
|
||||
### Server-Zertifikate generieren
|
||||
|
||||
```bash
|
||||
# Für jeden Service privaten Schlüssel und Certificate Signing Request generieren
|
||||
openssl genrsa -out server.key 2048
|
||||
openssl req -new -key server.key -out server.csr \
|
||||
-subj "/C=AT/ST=Vienna/L=Vienna/O=Meldestelle/OU=IT/CN=ihre-domain.com"
|
||||
|
||||
# Zertifikat mit CA signieren
|
||||
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key \
|
||||
-CAcreateserial -out server.crt
|
||||
|
||||
# Aufräumen
|
||||
rm server.csr
|
||||
```
|
||||
|
||||
### Diffie-Hellman Parameter generieren
|
||||
|
||||
```bash
|
||||
openssl dhparam -out dhparam.pem 2048
|
||||
```
|
||||
|
||||
## Produktions-Zertifikat Setup
|
||||
|
||||
### Option 1: Let's Encrypt (Empfohlen)
|
||||
|
||||
Verwenden Sie Certbot, um kostenlose SSL-Zertifikate zu erhalten:
|
||||
|
||||
```bash
|
||||
# Certbot installieren
|
||||
sudo apt-get install certbot
|
||||
|
||||
# Zertifikate erhalten
|
||||
sudo certbot certonly --standalone -d ihre-domain.com -d www.ihre-domain.com
|
||||
|
||||
# Zertifikate in entsprechende Verzeichnisse kopieren
|
||||
sudo cp /etc/letsencrypt/live/ihre-domain.com/fullchain.pem config/ssl/nginx/server.crt
|
||||
sudo cp /etc/letsencrypt/live/ihre-domain.com/privkey.pem config/ssl/nginx/server.key
|
||||
```
|
||||
|
||||
### Option 2: Kommerzielle CA
|
||||
|
||||
1. Certificate Signing Requests (CSRs) generieren
|
||||
2. CSRs an Ihre Certificate Authority übermitteln
|
||||
3. Signierte Zertifikate herunterladen
|
||||
4. Zertifikate in entsprechende Verzeichnisse platzieren
|
||||
|
||||
### Option 3: Interne CA
|
||||
|
||||
Bei Verwendung einer internen Certificate Authority:
|
||||
|
||||
1. CSRs für jeden Service generieren
|
||||
2. Zertifikate mit Ihrer internen CA signieren
|
||||
3. CA-Zertifikat an alle Clients verteilen
|
||||
|
||||
## Dateiberechtigungen
|
||||
|
||||
Stellen Sie ordnungsgemäße Dateiberechtigungen für die Sicherheit sicher:
|
||||
|
||||
```bash
|
||||
# Restriktive Berechtigungen für private Schlüssel setzen
|
||||
chmod 600 config/ssl/*/server.key
|
||||
chmod 600 config/ssl/*/redis.key
|
||||
chmod 600 config/ssl/*/prometheus.key
|
||||
|
||||
# Lesbare Berechtigungen für Zertifikate setzen
|
||||
chmod 644 config/ssl/*/server.crt
|
||||
chmod 644 config/ssl/*/ca.crt
|
||||
|
||||
# Verzeichnisberechtigungen setzen
|
||||
chmod 755 config/ssl/*/
|
||||
```
|
||||
|
||||
## Docker Volume Mounts
|
||||
|
||||
Die Zertifikate werden als schreibgeschützte Volumes in die Docker-Container eingebunden:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./config/ssl/nginx:/etc/ssl/nginx:ro
|
||||
- ./config/ssl/keycloak:/opt/keycloak/conf:ro
|
||||
# ... weitere Mounts
|
||||
```
|
||||
|
||||
## Zertifikat-Erneuerung
|
||||
|
||||
### Automatisierte Erneuerung (Let's Encrypt)
|
||||
|
||||
Richten Sie einen Cron-Job für automatische Erneuerung ein:
|
||||
|
||||
```bash
|
||||
# Zu Crontab hinzufügen
|
||||
0 12 * * * /usr/bin/certbot renew --quiet --post-hook "docker-compose -f docker-compose.prod.yml restart nginx"
|
||||
```
|
||||
|
||||
### Manuelle Erneuerung
|
||||
|
||||
1. Neue Zertifikate generieren
|
||||
2. Alte Zertifikate in SSL-Verzeichnissen ersetzen
|
||||
3. Betroffene Services neu starten:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.prod.yml restart nginx keycloak grafana prometheus
|
||||
```
|
||||
|
||||
## Sicherheits-Best-Practices
|
||||
|
||||
1. **Starke Verschlüsselung verwenden**: Mindestens 2048-Bit RSA-Schlüssel oder 256-Bit ECDSA-Schlüssel verwenden
|
||||
2. **Regelmäßige Rotation**: Zertifikate regelmäßig rotieren (jährlich oder halbjährlich)
|
||||
3. **Sichere Speicherung**: Private Schlüssel sicher speichern und Zugriff beschränken
|
||||
4. **Ablauf überwachen**: Überwachung für Zertifikat-Ablauf einrichten
|
||||
5. **HSTS verwenden**: HTTP Strict Transport Security aktivieren
|
||||
6. **Perfect Forward Secrecy**: ECDHE-Cipher-Suites verwenden
|
||||
7. **Certificate Transparency**: CT-Logs auf unbefugte Zertifikate überwachen
|
||||
|
||||
## Fehlerbehebung
|
||||
|
||||
### Häufige Probleme
|
||||
|
||||
1. **Berechtigung verweigert**
|
||||
|
||||
```bash
|
||||
# Dateiberechtigungen korrigieren
|
||||
sudo chown -R $USER:$USER config/ssl/
|
||||
chmod -R 755 config/ssl/
|
||||
chmod 600 config/ssl/*/server.key
|
||||
```
|
||||
|
||||
2. **Zertifikat-Verifizierung fehlgeschlagen**
|
||||
|
||||
```bash
|
||||
# Zertifikat verifizieren
|
||||
openssl x509 -in config/ssl/nginx/server.crt -text -noout
|
||||
|
||||
# Zertifikatskette prüfen
|
||||
openssl verify -CAfile config/ssl/nginx/ca.crt config/ssl/nginx/server.crt
|
||||
```
|
||||
|
||||
3. **TLS-Handshake-Fehler**
|
||||
- Gültigkeitsdaten des Zertifikats prüfen
|
||||
- Verifizieren, dass Zertifikat zum Hostnamen passt
|
||||
- Ordnungsgemäße Cipher-Suite-Konfiguration sicherstellen
|
||||
|
||||
### SSL-Konfiguration testen
|
||||
|
||||
```bash
|
||||
# SSL-Zertifikat testen
|
||||
openssl s_client -connect ihre-domain.com:443 -servername ihre-domain.com
|
||||
|
||||
# Mit spezifischem Protokoll testen
|
||||
openssl s_client -connect ihre-domain.com:443 -tls1_2
|
||||
|
||||
# Zertifikat-Ablauf prüfen
|
||||
openssl x509 -in config/ssl/nginx/server.crt -noout -dates
|
||||
|
||||
# Zertifikat-Details anzeigen
|
||||
openssl x509 -in config/ssl/nginx/server.crt -text -noout
|
||||
```
|
||||
|
||||
## Monitoring und Wartung
|
||||
|
||||
### Zertifikat-Überwachung
|
||||
|
||||
Implementieren Sie Überwachung für:
|
||||
|
||||
- Zertifikat-Ablaufdaten
|
||||
- Zertifikat-Gültigkeit
|
||||
- SSL/TLS-Handshake-Erfolg
|
||||
- Cipher-Suite-Verwendung
|
||||
|
||||
### Wartungsaufgaben
|
||||
|
||||
- Regelmäßige Überprüfung der Zertifikat-Gültigkeit
|
||||
- Aktualisierung der Cipher-Suites
|
||||
- Überwachung der Sicherheitsupdates
|
||||
- Backup der Zertifikate und privaten Schlüssel
|
||||
|
||||
## Weitere Ressourcen
|
||||
|
||||
- [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/)
|
||||
- [SSL Labs Server Test](https://www.ssllabs.com/ssltest/)
|
||||
- [Let's Encrypt Dokumentation](https://letsencrypt.org/docs/)
|
||||
- [OpenSSL Dokumentation](https://www.openssl.org/docs/)
|
||||
|
||||
---
|
||||
|
||||
**Letzte Aktualisierung**: 25. Juli 2025
|
||||
|
||||
Für weitere Informationen zur Produktionsumgebung siehe [README-PRODUCTION.md](../../Tagebuch/README-PRODUCTION.md).
|
||||
@@ -0,0 +1,141 @@
|
||||
# ===================================================================
|
||||
# Multi-stage Dockerfile Template for Kotlin Multiplatform Web Client
|
||||
# Features: Kotlin/JS compilation, Nginx serving, development support, centralized version management
|
||||
# Version: 3.0.0 - Central Version Management Implementation
|
||||
# ===================================================================
|
||||
# IMPORTANT: Build arguments are now managed centrally via docker/versions.toml
|
||||
# Use: docker-compose build or scripts/docker-build.sh for automated version injection
|
||||
|
||||
# === CENTRALIZED BUILD ARGUMENTS ===
|
||||
# Values sourced from docker/versions.toml and docker/build-args/
|
||||
# Global arguments (docker/build-args/global.env)
|
||||
ARG GRADLE_VERSION
|
||||
ARG JAVA_VERSION
|
||||
ARG BUILD_DATE
|
||||
ARG VERSION
|
||||
|
||||
# Client-specific arguments (docker/build-args/clients.env)
|
||||
ARG NODE_VERSION
|
||||
ARG NGINX_VERSION
|
||||
|
||||
# Client-specific build arguments (can be overridden at build time)
|
||||
ARG CLIENT_PATH=client/web-app
|
||||
ARG CLIENT_MODULE=client:web-app
|
||||
ARG CLIENT_NAME=web-app
|
||||
|
||||
# ===================================================================
|
||||
# Build Stage - Kotlin/JS Compilation
|
||||
# ===================================================================
|
||||
FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION}-alpine AS kotlin-builder
|
||||
|
||||
# Re-declare build arguments for kotlin-builder stage
|
||||
ARG CLIENT_PATH=client/web-app
|
||||
ARG CLIENT_MODULE=client:web-app
|
||||
ARG CLIENT_NAME=web-app
|
||||
ARG NODE_VERSION
|
||||
|
||||
LABEL stage=kotlin-builder
|
||||
LABEL maintainer="Meldestelle Development Team"
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Install specific Node.js version for Kotlin/JS compatibility
|
||||
RUN apk add --no-cache wget ca-certificates && \
|
||||
wget -q -O - https://unofficial-builds.nodejs.org/download/release/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64-musl.tar.xz | \
|
||||
tar -xJ -C /usr/local --strip-components=1 && \
|
||||
apk del wget ca-certificates && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
npm config set cache /tmp/.npm-cache && \
|
||||
npm config set progress false && \
|
||||
npm config set audit false
|
||||
|
||||
# Gradle optimizations for Kotlin Multiplatform builds
|
||||
ENV GRADLE_OPTS="-Dorg.gradle.caching=true \
|
||||
-Dorg.gradle.daemon=false \
|
||||
-Dorg.gradle.parallel=true \
|
||||
-Dorg.gradle.configureondemand=true \
|
||||
-Dorg.gradle.jvmargs=-Xmx3g \
|
||||
-Dkotlin.compiler.execution.strategy=in-process"
|
||||
|
||||
# Kotlin/JS and Node.js environment variables
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096" \
|
||||
NPM_CONFIG_CACHE="/tmp/.npm-cache" \
|
||||
KOTLIN_JS_GENERATE_EXTERNALS=false
|
||||
|
||||
# Copy build configuration files first for optimal caching
|
||||
COPY gradlew gradlew.bat gradle.properties settings.gradle.kts ./
|
||||
COPY gradle/ gradle/
|
||||
COPY build.gradle.kts ./
|
||||
|
||||
# Copy platform and core dependencies
|
||||
COPY platform/ platform/
|
||||
COPY core/ core/
|
||||
|
||||
# Copy client modules in dependency order
|
||||
COPY client/common-ui/ client/common-ui/
|
||||
COPY ${CLIENT_PATH}/ ${CLIENT_PATH}/
|
||||
|
||||
# Clear npm cache and verify Node.js installation
|
||||
RUN npm cache clean --force && \
|
||||
node --version && npm --version
|
||||
|
||||
# Download dependencies in a separate layer
|
||||
RUN ./gradlew :${CLIENT_MODULE}:dependencies --no-daemon --info --stacktrace
|
||||
|
||||
# Build web application with production optimizations and better error handling
|
||||
RUN ./gradlew :${CLIENT_MODULE}:jsBrowserProductionWebpack --no-daemon --info --stacktrace --debug
|
||||
|
||||
# Verify build output
|
||||
RUN ls -la /workspace/${CLIENT_PATH}/build/dist/ || (echo "Build failed - no dist directory found" && exit 1)
|
||||
|
||||
# ===================================================================
|
||||
# Production Stage - Nginx serving
|
||||
# ===================================================================
|
||||
FROM nginx:${NGINX_VERSION} AS runtime
|
||||
|
||||
# Re-declare build arguments for runtime stage
|
||||
ARG CLIENT_PATH=client/web-app
|
||||
ARG CLIENT_MODULE=client:web-app
|
||||
ARG CLIENT_NAME=web-app
|
||||
|
||||
# Metadata
|
||||
LABEL service="${CLIENT_NAME}" \
|
||||
version="1.0.0" \
|
||||
description="Kotlin Multiplatform Web Client for Meldestelle" \
|
||||
maintainer="Meldestelle Development Team"
|
||||
|
||||
# Security and system setup
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add --no-cache curl jq && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# Remove default nginx content and logs
|
||||
RUN rm -rf /usr/share/nginx/html/* && \
|
||||
rm -f /var/log/nginx/*.log
|
||||
|
||||
# Copy built web application from builder stage
|
||||
COPY --from=kotlin-builder /workspace/${CLIENT_PATH}/build/dist/ /usr/share/nginx/html/
|
||||
|
||||
# Copy nginx configuration
|
||||
COPY ${CLIENT_PATH}/nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# Set proper permissions for nginx
|
||||
RUN chown -R nginx:nginx /usr/share/nginx/html /var/cache/nginx /var/run /var/log/nginx && \
|
||||
chmod -R 755 /usr/share/nginx/html
|
||||
|
||||
# Switch to nginx user for security
|
||||
USER nginx
|
||||
|
||||
# Health check specifically for the web application
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD curl -f http://localhost/health || exit 1
|
||||
|
||||
# Expose HTTP port
|
||||
EXPOSE 80
|
||||
|
||||
# Start nginx with proper signal handling for graceful shutdowns
|
||||
STOPSIGNAL SIGQUIT
|
||||
|
||||
# Run nginx in foreground with error handling
|
||||
CMD ["sh", "-c", "nginx -t && exec nginx -g 'daemon off;'"]
|
||||
@@ -0,0 +1,147 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
# ===================================================================
|
||||
# Multi-stage Dockerfile Template for Spring Boot Services
|
||||
# Features: Security hardening, monitoring support, optimal caching, centralized version management
|
||||
# Version: 3.0.0 - Central Version Management Implementation
|
||||
# ===================================================================
|
||||
# IMPORTANT: Build arguments are now managed centrally via docker/versions.toml
|
||||
# Use: docker-compose build or scripts/docker-build.sh for automated version injection
|
||||
|
||||
# === CENTRALIZED BUILD ARGUMENTS ===
|
||||
# Values sourced from docker/versions.toml and docker/build-args/
|
||||
# Global arguments (docker/build-args/global.env)
|
||||
ARG GRADLE_VERSION
|
||||
ARG JAVA_VERSION
|
||||
ARG BUILD_DATE
|
||||
ARG VERSION
|
||||
|
||||
# Service-specific arguments (docker/build-args/services.env or infrastructure.env)
|
||||
# Note: No runtime profiles/ports as build ARGs
|
||||
ARG SERVICE_PATH=.
|
||||
ARG SERVICE_NAME=spring-boot-service
|
||||
|
||||
# ===================================================================
|
||||
# Build Stage
|
||||
# ===================================================================
|
||||
FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION}-alpine AS builder
|
||||
|
||||
# Re-declare build arguments for this stage
|
||||
ARG SERVICE_PATH=.
|
||||
ARG SERVICE_NAME=spring-boot-service
|
||||
|
||||
LABEL stage=builder
|
||||
LABEL maintainer="Meldestelle Development Team"
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Gradle optimizations
|
||||
ENV GRADLE_OPTS="-Dorg.gradle.caching=true \
|
||||
-Dorg.gradle.daemon=false \
|
||||
-Dorg.gradle.parallel=true \
|
||||
-Dorg.gradle.configureondemand=true \
|
||||
-Xmx2g"
|
||||
|
||||
# Copy build files in optimal order for caching
|
||||
COPY gradlew gradlew.bat gradle.properties settings.gradle.kts ./
|
||||
COPY gradle/ gradle/
|
||||
COPY platform/ platform/
|
||||
COPY build.gradle.kts ./
|
||||
|
||||
# Create standalone project structure when using template generically
|
||||
RUN if [ "${SERVICE_PATH}" = "." ]; then \
|
||||
echo "Creating isolated standalone Spring Boot application..."; \
|
||||
mkdir -p /tmp/standalone-app/src/main/kotlin/com/example /tmp/standalone-app/src/main/resources; \
|
||||
cd /tmp/standalone-app; \
|
||||
echo 'plugins { id("org.springframework.boot") version "3.2.0"; id("io.spring.dependency-management") version "1.1.4"; kotlin("jvm") version "2.2.0"; kotlin("plugin.spring") version "2.2.0" }' > build.gradle.kts; \
|
||||
echo 'group = "com.example"; version = "1.0.0"; java { sourceCompatibility = JavaVersion.VERSION_21 }' >> build.gradle.kts; \
|
||||
echo 'repositories { mavenCentral() }' >> build.gradle.kts; \
|
||||
echo 'dependencies { implementation("org.springframework.boot:spring-boot-starter-web"); testImplementation("org.springframework.boot:spring-boot-starter-test") }' >> build.gradle.kts; \
|
||||
echo 'package com.example; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.runApplication; @SpringBootApplication class Application; fun main(args: Array<String>) { runApplication<Application>(*args) }' > src/main/kotlin/com/example/Application.kt; \
|
||||
echo 'rootProject.name = "standalone-app"' > settings.gradle.kts; \
|
||||
cp /workspace/gradlew /workspace/gradlew.bat .; \
|
||||
cp -r /workspace/gradle .; \
|
||||
echo "Building standalone application..."; \
|
||||
./gradlew bootJar --no-daemon --info; \
|
||||
cp build/libs/*.jar /workspace/app.jar; \
|
||||
else \
|
||||
echo "Building specific service: ${SERVICE_NAME}"; \
|
||||
./gradlew :${SERVICE_NAME}:dependencies --no-daemon --info; \
|
||||
./gradlew :${SERVICE_NAME}:bootJar --no-daemon --info; \
|
||||
cp ${SERVICE_PATH}/build/libs/*.jar /workspace/app.jar; \
|
||||
fi
|
||||
|
||||
# ===================================================================
|
||||
# Runtime Stage
|
||||
# ===================================================================
|
||||
FROM eclipse-temurin:${JAVA_VERSION}-jre-alpine AS runtime
|
||||
|
||||
# Metadata
|
||||
LABEL service="${SERVICE_NAME}" \
|
||||
version="1.0.0" \
|
||||
maintainer="Meldestelle Development Team" \
|
||||
java.version="${JAVA_VERSION}"
|
||||
|
||||
# Build arguments
|
||||
ARG APP_USER=appuser
|
||||
ARG APP_GROUP=appgroup
|
||||
ARG APP_UID=1001
|
||||
ARG APP_GID=1001
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# System setup
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add --no-cache curl jq tzdata && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# Non-root user creation
|
||||
RUN addgroup -g ${APP_GID} -S ${APP_GROUP} && \
|
||||
adduser -u ${APP_UID} -S ${APP_USER} -G ${APP_GROUP} -h /app -s /bin/sh
|
||||
|
||||
# Directory setup
|
||||
RUN mkdir -p /app/logs /app/tmp && \
|
||||
chown -R ${APP_USER}:${APP_GROUP} /app
|
||||
|
||||
# Re-declare build arguments for runtime stage
|
||||
ARG SERVICE_PATH=.
|
||||
ARG SERVICE_NAME=spring-boot-service
|
||||
|
||||
# Copy JAR (different locations for standalone vs service-specific builds)
|
||||
COPY --from=builder --chown=${APP_USER}:${APP_GROUP} \
|
||||
/workspace/app.jar app.jar
|
||||
|
||||
USER ${APP_USER}
|
||||
|
||||
# Expose ports (runtime port configured via environment)
|
||||
EXPOSE 8080 5005
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=15s --timeout=3s --start-period=40s --retries=3 \
|
||||
CMD curl -fsS --max-time 2 http://localhost:${SERVER_PORT:-8080}/actuator/health/readiness || exit 1
|
||||
|
||||
# JVM configuration
|
||||
ENV JAVA_OPTS="-XX:MaxRAMPercentage=80.0 \
|
||||
-XX:+UseG1GC \
|
||||
-XX:+UseStringDeduplication \
|
||||
-XX:+UseContainerSupport \
|
||||
-Djava.security.egd=file:/dev/./urandom \
|
||||
-Djava.awt.headless=true \
|
||||
-Dfile.encoding=UTF-8 \
|
||||
-Duser.timezone=UTC \
|
||||
-Dmanagement.endpoints.web.exposure.include=health,info,metrics,prometheus"
|
||||
|
||||
# Spring Boot configuration
|
||||
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS
|
||||
ENV LOGGING_LEVEL_ROOT=INFO
|
||||
ENV SERVER_PORT=8080
|
||||
|
||||
# Startup command with debug support
|
||||
ENTRYPOINT ["sh", "-c", "\
|
||||
if [ \"${DEBUG:-false}\" = \"true\" ]; then \
|
||||
echo 'Starting ${SERVICE_NAME} in DEBUG mode on port 5005...'; \
|
||||
exec java $JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar; \
|
||||
else \
|
||||
exec java $JAVA_OPTS -jar app.jar; \
|
||||
fi"]
|
||||
Reference in New Issue
Block a user