Murat ÖZDEMİR 03a3c5fb70 feat(monitoring): add BE microservice health monitoring with dedup and readable crash alerts
Adds two-layer BE-* microservice monitoring: an aggregate Stack Services replica check across the iklimco and monitoring Swarm stacks (checks/swarm_services.py), and per-service actuator/DNS health checks driven by a new microservice_monitors section in monitors.yml (checks/actuator.py). BE-* services are excluded from the Stack Services aggregate so a single service incident produces exactly one Slack alert instead of two.

Fixes found during QA of the initial implementation: RabbitMQ host derivation generated nonexistent numbered DNS names instead of using the real single-service topology, RabbitMQ and Patroni cluster checks did not push down status on node/member shortfall, and the etcd cluster check still used a hardcoded node list and quorum threshold instead of deriving them from CLUSTER_SIZE_ETCD.

Also hardens Docker event crash alerting: excludes ephemeral Gitea Actions runner containers from crash notifications, skips alerts for containers Swarm intentionally stopped (rolling update/scale-down, detected via task DesiredState) instead of alerting on every deploy, and adds human-readable exit code descriptions to the Slack message.

Uptime Kuma monitor names are now prefixed with "iklim [env]" since test and prod share one Kuma instance and unprefixed names collided. setup_uptime_kuma.py gained an ensure_push_monitor helper and a microservice push-monitor creation pass. Removed state.py and the unused restart_threshold config field (dead code, no longer referenced anywhere).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 17:31:11 +03:00

11 KiB
Raw Blame History

iklim.co Health Agent

Docker Swarm cluster içinde çalışan, push modeli üzerinden Uptime Kuma'ya sağlık durumu ileten ve Docker olaylarını Slack'e doğrudan bildiren hafif bir Python servisidir. Gelen bağlantı gerekmez — tüm trafik dışa yönelik HTTPS'tir.


Mimari

Agent, Swarm manager node üzerinde tek replica olarak çalışır ve şu kaynaklara erişir:

  • /var/run/docker.sock (salt okunur) — Swarm servislerini, node'ları ve event stream'ini dinler
  • iklimco-net overlay ağı — tüm iç servislere DNS adıyla erişir
  • StorageBox bind mount (salt okunur) — sertifika dosyaları ve yapılandırma varlığını kontrol eder
  • config/generated/uk_tokens.ymlsetup_uptime_kuma.py tarafından üretilir, agent bu dosyayı okur

Her check bağımsız çalışır ve kendi Uptime Kuma monitörüne push yapar. Bir check'in başarısız olması diğerlerini etkilemez.

Slack bildirimleri iki kanaldan gelir:

  • [Uptime Kuma] — Uptime Kuma'nın kendi HTTP/DNS/Ping monitörleri tarafından üretilir
  • [Health Agent] — health-agent'ın push check'lerinden; Uptime Kuma'nın group monitor mekanizması üzerinden iletilir
  • [Health Agent / Events] — Docker events stream'den gelen anlık restart/OOM bildirimleri; doğrudan Slack webhook'una gönderilir, Uptime Kuma'dan geçmez

Dizin Yapısı

Environment_Monitoring/health-agent/
├── config/
│   ├── monitors.yml              # tüm monitor/group/tag/status-page tanımları; node IP'leri buraya yazılır
│   └── generated/
│       └── uk_tokens.yml         # setup_uptime_kuma.py tarafından üretilir; health-agent okur
├── src/
│   └── health_agent/
│       ├── main.py               # giriş noktası; scheduler loop
│       ├── config.py             # .env + uk_tokens.yml yükler; ortam ayarlarını expose eder
│       ├── uptime_kuma.py        # push(token, status, msg, ping_ms) yardımcısı
│       ├── slack.py              # notify(webhook, source, priority, title, detail, uk_group_url) — kaynak etiketli + UK grup linki
│       ├── checks/
│       │   ├── swarm.py          # Docker API: node listesi (sadece Swarm node kontrolü)
│       │   ├── swarm_services.py # Docker API: iklimco stack servislerinin replica kontrolü
│       │   ├── actuator.py       # Mikroservisler için HTTP actuator health (IP/replica bazlı) check
│       │   ├── http.py           # genel HTTP check + uygulama bazlı parser'lar (Patroni, Vault, RabbitMQ...)
│       │   ├── tcp.py            # TCP port erişilebilirliği
│       │   ├── tls.py            # TLS sertifika son kullanma tarihi (dosyadan veya handshake'den)
│       │   ├── redis_sentinel.py # Redis Sentinel — redis-py ile quorum ve master kontrolü
│       │   ├── mongodb.py        # MongoDB rs.status() — pymongo ile PRIMARY ve lag kontrolü
│       │   └── filesystem.py     # StorageBox mount varlığı ve SSL cert sync durumu
│       └── events/
│           └── docker_events.py  # arka plan thread'i; Docker /events stream'ini dinler, restart/OOM bildirir
├── scripts/
│   └── setup_uptime_kuma.py     # monitors.yml'i okur, UK'da oluşturur, uk_tokens.yml'e yazar
├── Dockerfile
├── pyproject.toml
├── .env.example                  # health-agent runtime değişkenleri (credentials, ENV, CLUSTER_SIZE_*)
└── .env.setup.example            # setup script değişkenleri (UK_URL, UK_USER, UK_PASS, Slack webhook'ları)

Yapılandırma

config/monitors.yml — Tüm monitor, group, tag ve status page tanımları bu dosyadadır. Yeni bir monitor eklemek için kod değişikliği gerekmez; monitors.yml'e yeni bir blok eklenir ve setup_uptime_kuma.py çalıştırılır.

Mikroservis Ekleme: microservice_monitors bölümü, BE servislerinin Uptime Kuma'ya (actuator ve swarm replica bazında) eklenmesini otomatikleştirir. Yeni bir BE servisi eklendiğinde kod değişikliği gerekmez; sadece bu bölüme servis tanımı ve opsiyonel replicas.<env> beklentisi yazılıp setup script çalıştırılır. replicas.<env>, ortam bazlı beklenen replica sayısıdır; Docker "desired" değerinden bağımsız çalışır (yanlış scale-down veya deploy edilmeme durumlarını alarm olarak yakalar). Servisin replica değerini kalıcı olarak değiştiriyorsanız, monitors.yml dosyasını da güncelleyip imajı rebuild etmelisiniz (çünkü bu dosya imaja gömülüdür).

.env — Runtime değişkenler:

Variable Description
UK_PUSH_URL_BASE Uptime Kuma push base URL (e.g. https://status.iklim.co/api/push)
ENV prod or test
CLUSTER_SIZE_ETCD etcd node count (prod: 3, test: 1)
CLUSTER_SIZE_PATRONI Patroni node count
CLUSTER_SIZE_MONGODB MongoDB node count
CLUSTER_SIZE_RABBITMQ Expected RabbitMQ cluster member count (RabbitMQ runs as a single Swarm service — this only sets the expected total, not per-node hostnames)
CLUSTER_SIZE_VAULT Vault node count
REDIS_MODE sentinel or standalone
EXTERNAL_DOMAIN Base domain — iklim.co in both environments
EXTERNAL_SUBDOMAIN_SUFFIX Subdomain suffix — empty for prod, -test for test → api-test.iklim.co
SLACK_WEBHOOK_IKLIM_{ENV}_OPS Direct Slack webhook for container crash/OOM events — e.g. SLACK_WEBHOOK_IKLIM_PROD_OPS
ETCD_HOSTS etcd node list (comma-separated host:port) — e.g. etcd-01:2379,etcd-02:2379; falls back to etcd-01..0N derived from CLUSTER_SIZE_ETCD
PATRONI_HOSTS Patroni node list (comma-separated host:port) — e.g. patroni-01:8008,patroni-02:8008
VAULT_HOSTS Vault node subdomain list (comma-separated) — e.g. vault-1,vault-2,vault-3
RABBITMQ_HOSTS Optional RabbitMQ endpoint override (comma-separated host:port); defaults to the single rabbitmq Swarm service — normally leave unset
RABBITMQ_USER / RABBITMQ_PASS RabbitMQ management credentials
MONGO_URI MongoDB connection URI
REDIS_PASSWORD Redis / Sentinel password
REDIS_MASTER_NAME Redis Sentinel master name
REDIS_SENTINEL_HOSTS Sentinel host list (comma-separated host:port)
STORAGEBOX_PATH StorageBox mount path for filesystem check
APISIX_ADMIN_KEY APISIX admin API key for health check

Altyapı Beklentileri (CLUSTER_SIZE_*): Altyapı check'leri, *_HOSTS listesi .env içinde tanımlıysa onu kullanır, tanımsız/boş ise CLUSTER_SIZE_* sayısına göre (ör. etcd-01, etcd-02...) beklenen host listesini otomatik türetir. Bu sayede cluster node sayısını artırıp azaltmak kod veya imaj rebuild gerektirmez.

Monitör Adlandırma Konvansiyonu: Test ve prod aynı Uptime Kuma'yı paylaştığı için monitörler UK arayüzünde iklim [<env>] <Ad> formatıyla oluşturulur. Ancak uk_tokens.yml dosyası ve kod içi push() fonksiyonu, prefix'siz ham ad (ör. "Stack Services") ile çalışmaya devam eder.

Check periyotları monitors.yml'de her monitor için tanımlanır; .env'e eklenmez.

Push token'ları config/generated/uk_tokens.yml'den otomatik okunur — bu dosya setup_uptime_kuma.py tarafından üretilir ve .env'e elle kopyalanmaz.


Yeni Check Ekleme

  1. src/health_agent/checks/ altına yeni bir dosya ekle veya uygun mevcut dosyaya yeni bir fonksiyon ekle.
  2. Fonksiyon (ok: bool, msg: str, ping_ms: int) tuple'ı döndürmeli.
  3. config/monitors.yml'e yeni monitor bloğu ekle (isim, grup, öncelik, bildirim kanalı, check periyodu).
  4. setup_uptime_kuma.py'yi çalıştır — yeni monitor UK'da oluşturulur ve token uk_tokens.yml'e yazılır.
  5. main.py'de check fonksiyonunu token ve yapılandırmayla kaydet.

İlk Kurulum (Uptime Kuma)

Health-agent deploy edilmeden önce kurulum script'i çalıştırılır. Script, monitors.yml'i okuyarak tüm monitor, tag, group ve status page'leri Uptime Kuma'da oluşturur; push token'larını config/generated/uk_tokens.yml'e yazar.

Script uptime-kuma-api-v2 kütüphanesini kullanır; Socket.IO üzerinden username/password ile bağlanır.

cd Environment_Monitoring/health-agent

# Python 3.12 venv oluştur ve aktive et
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# runtime ve setup değişkenlerini doldur
cp .env.example .env        # ENV, EXTERNAL_DOMAIN vb.
cp .env.setup.example .env.setup  # UK_URL, UK_USER, UK_PASS, Slack webhook'ları

# önce dry-run ile ne yapılacağını gör
python scripts/setup_uptime_kuma.py --dry-run

# tüm kaynakları oluştur
python scripts/setup_uptime_kuma.py

# sadece belirli bir monitörü işle (monitor adıyla)
python scripts/setup_uptime_kuma.py --only SWARM-CLUSTER

Script idempotent çalışır — CI/CD pipeline'ında her deploy'da güvenle tetiklenebilir.


Notification Flood Önleme

Uptime Kuma group monitor mekanizması kullanılır: Slack bildirimi child monitor'lere değil, yalnızca group monitor'e bağlanır. Bir grup içinde birden fazla monitor aynı anda çökse dahi tek bildirim üretilir.

Planlı bakım/deploy sırasında etkilenecek group için Uptime Kuma'da Maintenance penceresi açılır (API üzerinden otomatik yapılabilir). Bu süre zarfında alarm üretilmez.


Yerel Geliştirme

cd Environment_Monitoring/health-agent

# Python 3.12 venv oluştur ve aktive et
python3.12 -m venv .venv
source .venv/bin/activate

# bağımlılıkları kur
pip install -e ".[dev]"

# .env dosyasını hazırla
cp .env.example .env

# check'leri bir kez çalıştır, Uptime Kuma'ya push etme
python -m health_agent.main --once --dry-run

# check'leri bir kez çalıştır, Uptime Kuma'ya gerçekten push et
python -m health_agent.main --once

# tam scheduler'ı başlat
python -m health_agent.main

--once: her check'i bir kez çalıştırıp çıkar. --dry-run: Uptime Kuma push'larını atlar, sadece loglar. İkisi birlikte credential ve bağlantı doğrulaması için kullanılır.


Deployment

Monitoring stack ve health-agent ayrı Gitea workflow'larıyla deploy edilir:

  • .gitea/workflows/deploy-monitoring-prod.yml — prod ortamı
  • .gitea/workflows/deploy-monitoring-test.yml — test ortamı

Her iki workflow da şu sırayı izler: (1) setup_uptime_kuma.py çalıştır → uk_tokens.yml üret, (2) monitoring stack'i deploy et, (3) health-agent stack'ini deploy et.

Manuel deploy için:

# önce setup_uptime_kuma.py çalıştır
python scripts/setup_uptime_kuma.py

# tek stack: portainer + loki + promtail + health-agent
docker stack deploy \
  --with-registry-auth \
  -c docker-stack-monitoring.yml \
  monitoring

Health-agent iklimco-net overlay ağına bağlı olmalı ve Docker socket'a salt okunur erişimi olmalıdır.


Log Formatı

Agent JSON formatında log üretir. Grafana Explore (Loki datasource, {service="monitoring_health-agent"}) veya docker service logs monitoring_health-agent ile izlenebilir. Her log girdisi şu alanları içerir:

  • check — monitor adı
  • statusup veya down
  • msg — Uptime Kuma'ya iletilen mesaj
  • ping_ms — check süresi
  • sourcehealth-agent veya health-agent/events
  • error — yalnızca hata durumunda; exception detayı