Add Loki Alloy logging baseline

This commit is contained in:
2026-05-16 13:26:49 +02:00
parent 5ada1ad153
commit a5add937f8
17 changed files with 330 additions and 5 deletions
+23
View File
@@ -0,0 +1,23 @@
# Loki / Alloy
Internal logging stack for KalliLab CORE.
## Services
- `loki`: internal log store on `backend_net`, no Traefik route, `auth_enabled: false` because access is limited to internal Docker networking.
- `alloy`: Docker log collector. It mounts `/var/run/docker.sock:ro` as a documented observability exception and forwards Docker container logs to Loki.
## Host sync
Before first deploy, sync the checked-in config files to appdata:
```bash
mkdir -p /mnt/user/appdata/loki/config /mnt/user/appdata/loki/data
mkdir -p /mnt/user/appdata/alloy/config /mnt/user/appdata/alloy/data
cp /mnt/user/services/homelab-infra/ops/loki/config/loki-config.yml /mnt/user/appdata/loki/config/loki-config.yml
cp /mnt/user/services/homelab-infra/ops/loki/config/config.alloy /mnt/user/appdata/alloy/config/config.alloy
```
## Restore posture
Loki data is transient operational telemetry. Docker raw logs remain the first fallback, Loki chunks on disk are a convenience cache, and ntfy critical events provide the external first-crash marker.
+43
View File
@@ -0,0 +1,43 @@
discovery.docker "containers" {
host = "unix:///var/run/docker.sock"
}
discovery.relabel "docker_logs" {
targets = []
rule {
source_labels = ["__meta_docker_container_name"]
regex = "/(.*)"
target_label = "container_name"
}
rule {
source_labels = ["__meta_docker_container_label_com_docker_compose_project"]
target_label = "compose_project"
}
rule {
source_labels = ["__meta_docker_container_label_com_docker_compose_service"]
target_label = "compose_service"
}
}
loki.source.docker "containers" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.containers.targets
labels = { platform = "docker", host = "kallilabcore" }
relabel_rules = discovery.relabel.docker_logs.rules
forward_to = [loki.process.docker.receiver]
}
loki.process "docker" {
forward_to = [loki.write.local.receiver]
stage.docker {}
}
loki.write "local" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
}
+45
View File
@@ -0,0 +1,45 @@
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
instance_addr: 127.0.0.1
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
schema_config:
configs:
- from: 2026-05-16
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
limits_config:
retention_period: 720h
allow_structured_metadata: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
delete_request_store: filesystem
+43
View File
@@ -0,0 +1,43 @@
services:
loki:
image: grafana/loki:3.7.2@sha256:191d4fdfb7264f16989f0a57f320872620a5a7c2ceeec6229212c4190ec49b86
container_name: loki
restart: unless-stopped
command:
- -config.file=/etc/loki/loki-config.yml
volumes:
- /mnt/user/appdata/loki/config:/etc/loki:ro
- /mnt/user/appdata/loki/data:/loki
networks:
- backend_net
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3100/ready"]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
alloy:
image: grafana/alloy:v1.16.1@sha256:51aeb9d829239345070619dad3edd6873186f913c84f45b365b74574fcb38ec0
container_name: alloy
restart: unless-stopped
command:
- run
- /etc/alloy/config.alloy
- --storage.path=/var/lib/alloy/data
volumes:
- /mnt/user/appdata/alloy/config:/etc/alloy:ro
- /mnt/user/appdata/alloy/data:/var/lib/alloy/data
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- backend_net
security_opt:
- no-new-privileges:true
depends_on:
- loki
networks:
backend_net:
external: true