soroban-abacus-flashcards/infra/terraform/gatus.tf

254 lines
5.9 KiB
HCL

# Gatus - Self-hosted Status Page
#
# Lightweight status page that monitors endpoints and displays uptime.
# Accessible at status.abaci.one
resource "kubernetes_config_map" "gatus_config" {
metadata {
name = "gatus-config"
namespace = kubernetes_namespace.abaci.metadata[0].name
}
data = {
"config.yaml" = <<-EOT
storage:
type: sqlite
path: /data/gatus.db
ui:
title: Abaci.one Status
description: Service health and uptime monitoring
header: Abaci.one
logo: ""
endpoints:
# ============ Website ============
- name: "Homepage"
group: Website
url: "https://abaci.one/"
interval: 60s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 2000"
# ============ Arcade ============
- name: "Games Hub — /games"
group: Arcade
url: "https://abaci.one/games"
interval: 120s
conditions:
- "[STATUS] == 200"
# ============ Worksheets ============
- name: "Worksheet Builder — /create/worksheets"
group: Worksheets
url: "https://abaci.one/create/worksheets"
interval: 120s
conditions:
- "[STATUS] == 200"
- name: "Flashcard Generator — /create/flashcards"
group: Worksheets
url: "https://abaci.one/create/flashcards"
interval: 120s
conditions:
- "[STATUS] == 200"
# ============ Flowcharts ============
- name: "Flowchart Viewer — /flowchart"
group: Flowcharts
url: "https://abaci.one/flowchart"
interval: 120s
conditions:
- "[STATUS] == 200"
# ============ Core API ============
- name: "Health Check — /api/health"
group: Core API
url: "https://abaci.one/api/health"
interval: 30s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 500"
- "[BODY].status == healthy"
# ============ Infrastructure ============
- name: "SQLite Database"
group: Infrastructure
url: "https://abaci.one/api/health"
interval: 30s
conditions:
- "[STATUS] == 200"
- "[BODY].checks.database.status == ok"
- name: "Redis Cache"
group: Infrastructure
url: "tcp://redis.abaci.svc.cluster.local:6379"
interval: 30s
conditions:
- "[CONNECTED] == true"
# ============ E2E Tests ============
- name: "Browser Smoke Tests"
group: E2E Tests
url: "https://abaci.one/api/smoke-test-status"
interval: 60s
conditions:
- "[STATUS] == 200"
- "[BODY].status == passed"
EOT
}
}
# Note: Using emptyDir for simplicity. Gatus rebuilds history on restart.
# If persistent history is needed, use a PVC but terraform may timeout
# waiting for local-path provisioner (which only binds when pod mounts).
resource "kubernetes_deployment" "gatus" {
metadata {
name = "gatus"
namespace = kubernetes_namespace.abaci.metadata[0].name
labels = {
app = "gatus"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "gatus"
}
}
template {
metadata {
labels = {
app = "gatus"
}
}
spec {
container {
name = "gatus"
image = "twinproduction/gatus:v5.11.0"
port {
container_port = 8080
}
volume_mount {
name = "config"
mount_path = "/config"
read_only = true
}
volume_mount {
name = "data"
mount_path = "/data"
}
resources {
requests = {
memory = "64Mi"
cpu = "50m"
}
limits = {
memory = "128Mi"
cpu = "200m"
}
}
liveness_probe {
http_get {
path = "/health"
port = 8080
}
initial_delay_seconds = 10
period_seconds = 30
}
readiness_probe {
http_get {
path = "/health"
port = 8080
}
initial_delay_seconds = 5
period_seconds = 10
}
}
volume {
name = "config"
config_map {
name = kubernetes_config_map.gatus_config.metadata[0].name
}
}
volume {
name = "data"
empty_dir {}
}
}
}
}
}
resource "kubernetes_service" "gatus" {
metadata {
name = "gatus"
namespace = kubernetes_namespace.abaci.metadata[0].name
}
spec {
selector = {
app = "gatus"
}
port {
port = 80
target_port = 8080
}
type = "ClusterIP"
}
}
# Ingress for status.abaci.one (HTTP only for now, SSL can be added later)
# Note: ACME HTTP-01 challenge has issues with Traefik ingress routing.
# Consider DNS-01 challenge or using the main domain's wildcard cert.
resource "kubernetes_ingress_v1" "gatus" {
metadata {
name = "gatus"
namespace = kubernetes_namespace.abaci.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.entrypoints" = "web,websecure"
}
}
spec {
ingress_class_name = "traefik"
rule {
host = "status.${var.app_domain}"
http {
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = kubernetes_service.gatus.metadata[0].name
port {
number = 80
}
}
}
}
}
}
}
}