wp-mirror: Promtail CT600 + Hausmeister Loki-Sync-Check
Mirror-Sync-Logs nach Loki (host=wp-mirror), check_wp_mirror_sync in monitor.
This commit is contained in:
parent
a6b3c450f8
commit
db341807c7
4 changed files with 154 additions and 5 deletions
91
arakava-news/scripts/install-promtail-ct600.sh
Executable file
91
arakava-news/scripts/install-promtail-ct600.sh
Executable file
|
|
@ -0,0 +1,91 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Promtail auf CT600 wp-mirror (pve-mu-3) — wie CT101, Loki via Tailscale
|
||||||
|
set -euo pipefail
|
||||||
|
apt-get update && apt-get install -y wget unzip curl systemd-journal-remote 2>/dev/null || apt-get install -y wget unzip curl
|
||||||
|
cd /tmp
|
||||||
|
wget -q https://github.com/grafana/loki/releases/download/v3.0.0/promtail-linux-amd64.zip
|
||||||
|
unzip -o promtail-linux-amd64.zip
|
||||||
|
chmod +x promtail-linux-amd64
|
||||||
|
mv promtail-linux-amd64 /usr/local/bin/promtail
|
||||||
|
cat > /etc/promtail-config.yml << 'EOF'
|
||||||
|
server:
|
||||||
|
http_listen_port: 9080
|
||||||
|
grpc_listen_port: 0
|
||||||
|
|
||||||
|
positions:
|
||||||
|
filename: /tmp/positions.yaml
|
||||||
|
|
||||||
|
clients:
|
||||||
|
- url: http://100.109.206.43:3100/loki/api/v1/push
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: journal
|
||||||
|
journal:
|
||||||
|
max_age: 12h
|
||||||
|
labels:
|
||||||
|
job: systemd
|
||||||
|
host: wp-mirror
|
||||||
|
relabel_configs:
|
||||||
|
- source_labels: [__journal__systemd_unit]
|
||||||
|
target_label: unit
|
||||||
|
|
||||||
|
- job_name: system
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- localhost
|
||||||
|
labels:
|
||||||
|
job: varlogs
|
||||||
|
host: wp-mirror
|
||||||
|
__path__: /var/log/*log
|
||||||
|
|
||||||
|
- job_name: docker
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- localhost
|
||||||
|
labels:
|
||||||
|
job: dockerlogs
|
||||||
|
host: wp-mirror
|
||||||
|
__path__: /var/lib/docker/containers/*/*.log
|
||||||
|
pipeline_stages:
|
||||||
|
- json:
|
||||||
|
expressions:
|
||||||
|
output: log
|
||||||
|
stream: stream
|
||||||
|
attrs:
|
||||||
|
- json:
|
||||||
|
expressions:
|
||||||
|
tag:
|
||||||
|
source: attrs
|
||||||
|
- regex:
|
||||||
|
expression: (?P<container_name>(?:[^|]*[^|]))
|
||||||
|
source: tag
|
||||||
|
- timestamp:
|
||||||
|
format: RFC3339Nano
|
||||||
|
source: time
|
||||||
|
- labels:
|
||||||
|
tag:
|
||||||
|
stream:
|
||||||
|
container_name:
|
||||||
|
- output:
|
||||||
|
source: output
|
||||||
|
EOF
|
||||||
|
cat > /etc/systemd/system/promtail.service << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Promtail Log Agent
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
ExecStart=/usr/local/bin/promtail -config.file=/etc/promtail-config.yml
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable promtail
|
||||||
|
systemctl restart promtail
|
||||||
|
systemctl is-active promtail
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Pull WordPress CT101 (pve-hetzner) → CT600 wp-mirror (pve-mu-3)
|
# Pull WordPress CT101 (pve-hetzner) → CT600 wp-mirror (pve-mu-3)
|
||||||
# CT101 impact: read-only mysqldump (--single-transaction) + read-only tar. No restarts.
|
# CT101 impact: read-only mysqldump (--single-transaction) + read-only tar. No restarts.
|
||||||
|
# Logs: Host /var/log/wp-mirror-sync.log + CT600 /var/log/wp-mirror-sync.log → Loki (Promtail)
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
HETZNER_HOST="${HETZNER_HOST:-root@100.88.230.59}"
|
HETZNER_HOST="${HETZNER_HOST:-root@100.88.230.59}"
|
||||||
|
|
@ -8,6 +9,7 @@ HETZNER_CT="${HETZNER_CT:-101}"
|
||||||
MIRROR_CT="${MIRROR_CT:-600}"
|
MIRROR_CT="${MIRROR_CT:-600}"
|
||||||
STAGING="${STAGING:-/opt/wp-mirror-sync/staging}"
|
STAGING="${STAGING:-/opt/wp-mirror-sync/staging}"
|
||||||
LOG="${LOG:-/var/log/wp-mirror-sync.log}"
|
LOG="${LOG:-/var/log/wp-mirror-sync.log}"
|
||||||
|
LOG_CT="/var/log/wp-mirror-sync.log"
|
||||||
LOCK_FILE="/var/run/wp-mirror-sync.lock"
|
LOCK_FILE="/var/run/wp-mirror-sync.lock"
|
||||||
FAILOVER_FLAG="/opt/wp-mirror-sync/FAILOVER_ACTIVE"
|
FAILOVER_FLAG="/opt/wp-mirror-sync/FAILOVER_ACTIVE"
|
||||||
MIRROR_SITEURL="http://192.168.178.142"
|
MIRROR_SITEURL="http://192.168.178.142"
|
||||||
|
|
@ -15,9 +17,29 @@ MYSQL_USER="wordpress"
|
||||||
MYSQL_PASS="astral66"
|
MYSQL_PASS="astral66"
|
||||||
MYSQL_DB="wordpress"
|
MYSQL_DB="wordpress"
|
||||||
WP_VOL="/var/lib/docker/volumes/wordpress_wp_data/_data"
|
WP_VOL="/var/lib/docker/volumes/wordpress_wp_data/_data"
|
||||||
|
MIRROR_RUNNING=0
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"
|
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||||
|
echo "$msg" | tee -a "$LOG"
|
||||||
|
if [[ "$MIRROR_RUNNING" == "1" ]]; then
|
||||||
|
echo "$msg" | pct exec "$MIRROR_CT" -- tee -a "$LOG_CT" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_mirror_ct() {
|
||||||
|
if [[ "$(pct status "$MIRROR_CT" 2>/dev/null | awk '{print $2}')" != "running" ]]; then
|
||||||
|
pct start "$MIRROR_CT"
|
||||||
|
fi
|
||||||
|
for _ in $(seq 1 30); do
|
||||||
|
if pct exec "$MIRROR_CT" -- test -d /var/log 2>/dev/null; then
|
||||||
|
MIRROR_RUNNING=1
|
||||||
|
pct exec "$MIRROR_CT" -- touch "$LOG_CT" 2>/dev/null || true
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
ct101_http_ok() {
|
ct101_http_ok() {
|
||||||
|
|
@ -62,6 +84,12 @@ if ! ct101_http_ok; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log "Starting CT600 (Promtail/Loki)..."
|
||||||
|
if ! ensure_mirror_ct; then
|
||||||
|
log "ABORT: CT600 did not become ready"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
log "START sync CT101 → CT600"
|
log "START sync CT101 → CT600"
|
||||||
|
|
||||||
DB_FILE="${STAGING}/wordpress.sql.gz"
|
DB_FILE="${STAGING}/wordpress.sql.gz"
|
||||||
|
|
@ -82,10 +110,6 @@ log "File sync via tar (read-only, ~5–8 min)..."
|
||||||
tar_sync_files
|
tar_sync_files
|
||||||
log "Files staged: $(du -sh "${STAGING}/wpfiles" | awk '{print $1}')"
|
log "Files staged: $(du -sh "${STAGING}/wpfiles" | awk '{print $1}')"
|
||||||
|
|
||||||
log "Starting CT600 for import..."
|
|
||||||
if [[ "$(pct status "$MIRROR_CT" | awk '{print $2}')" != "running" ]]; then
|
|
||||||
pct start "$MIRROR_CT"
|
|
||||||
fi
|
|
||||||
for _ in $(seq 1 45); do
|
for _ in $(seq 1 45); do
|
||||||
if pct exec "$MIRROR_CT" -- docker info >/dev/null 2>&1; then
|
if pct exec "$MIRROR_CT" -- docker info >/dev/null 2>&1; then
|
||||||
break
|
break
|
||||||
|
|
@ -122,4 +146,5 @@ fi
|
||||||
|
|
||||||
log "Stopping CT600 (standby)..."
|
log "Stopping CT600 (standby)..."
|
||||||
pct stop "$MIRROR_CT"
|
pct stop "$MIRROR_CT"
|
||||||
|
MIRROR_RUNNING=0
|
||||||
log "DONE"
|
log "DONE"
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,34 @@ def check_error_rate(minutes: int = 30) -> list[dict]:
|
||||||
return alerts
|
return alerts
|
||||||
|
|
||||||
|
|
||||||
|
def check_wp_mirror_sync(hours: float = 26) -> list[str]:
|
||||||
|
"""Prüft CT600 wp-mirror Sync-Logs in Loki (host=wp-mirror)."""
|
||||||
|
alerts = []
|
||||||
|
aborts = query_logs(
|
||||||
|
'{host="wp-mirror"} |~ "ABORT|WARN: CT101"',
|
||||||
|
hours=hours,
|
||||||
|
limit=10,
|
||||||
|
)
|
||||||
|
for e in aborts:
|
||||||
|
if "error" in e:
|
||||||
|
continue
|
||||||
|
line = e.get("line", "").strip()
|
||||||
|
if line:
|
||||||
|
alerts.append(f"⚠️ wp-mirror Sync: {line[:160]}")
|
||||||
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
now = datetime.now(ZoneInfo("Europe/Berlin"))
|
||||||
|
except Exception:
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
if now.hour >= 6:
|
||||||
|
done = query_logs('{host="wp-mirror"} |= "DONE"', hours=hours, limit=5)
|
||||||
|
if not [e for e in done if "error" not in e]:
|
||||||
|
alerts.append("⚠️ wp-mirror: kein erfolgreicher Sync (DONE) in den letzten 26h")
|
||||||
|
return alerts
|
||||||
|
|
||||||
|
|
||||||
def format_logs(entries: list[dict], max_lines: int = 30) -> str:
|
def format_logs(entries: list[dict], max_lines: int = 30) -> str:
|
||||||
"""Format log entries for human/LLM consumption."""
|
"""Format log entries for human/LLM consumption."""
|
||||||
if not entries:
|
if not entries:
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ ALERT_COOLDOWN_SECONDS = {
|
||||||
"error_rate": 1800,
|
"error_rate": 1800,
|
||||||
"hermes": 7200,
|
"hermes": 7200,
|
||||||
"backup": 21600,
|
"backup": 21600,
|
||||||
|
"mirror_sync": 21600,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -86,6 +87,7 @@ SILENCE_IGNORED_HOSTS = {
|
||||||
"ct-600-webcam", # kein rsyslog, Stream läuft aber
|
"ct-600-webcam", # kein rsyslog, Stream läuft aber
|
||||||
"ct-103-Intercity-Taxi", # absichtlich gestoppt
|
"ct-103-Intercity-Taxi", # absichtlich gestoppt
|
||||||
"ct-101-freshrss", # auf pve-ka-3, lokale Loki (nicht zentral)
|
"ct-101-freshrss", # auf pve-ka-3, lokale Loki (nicht zentral)
|
||||||
|
"wp-mirror", # CT600 Reserve — gestoppt, Logs nur während Sync
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -174,6 +176,7 @@ def check_all(state: dict | None = None) -> list[str]:
|
||||||
suppressed_names = config.get_suppressed_container_names(cfg)
|
suppressed_names = config.get_suppressed_container_names(cfg)
|
||||||
alerts = []
|
alerts = []
|
||||||
alerts.extend(check_hermes())
|
alerts.extend(check_hermes())
|
||||||
|
alerts.extend(loki_client.check_wp_mirror_sync())
|
||||||
|
|
||||||
containers = proxmox_client.get_all_containers(
|
containers = proxmox_client.get_all_containers(
|
||||||
_get_passwords(cfg), _get_tokens(cfg)
|
_get_passwords(cfg), _get_tokens(cfg)
|
||||||
|
|
@ -451,6 +454,8 @@ def _alert_category(alert_text: str) -> str:
|
||||||
return "backup"
|
return "backup"
|
||||||
if "Memory läuft ab" in alert_text:
|
if "Memory läuft ab" in alert_text:
|
||||||
return "memory_expiry"
|
return "memory_expiry"
|
||||||
|
if "wp-mirror" in alert_text:
|
||||||
|
return "mirror_sync"
|
||||||
return "default"
|
return "default"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue