gitea: grow data volume 40Gi -> 60Gi via Flux-owned PVC, add low-space alert (REN-583) #1116

Merged
Ghost merged 1 commits from atlas/ren-583-gitea-volume-60gi into master 2026-10-03 21:26:21 +00:00
8 changed files with 138 additions and 9 deletions
+2
View File
@@ -6,6 +6,8 @@ kind: Kustomization
# and verified. See MIGRATION-gitea-woodpecker.md.
resources:
- statefulset.yaml
# The live size of the data volume; see the file (REN-583).
- pvc.yaml
- service.yaml
- ingressroute-ssh.yaml
- ingress.yaml
+34
View File
@@ -0,0 +1,34 @@
# The live data volume of gitea-0, owned here so its size is set in git
# (REN-583). The StatefulSet controller created this claim from the
# volumeClaimTemplates in statefulset.yaml, but that template is immutable on
# an existing StatefulSet, so changing the size there cannot be applied. A
# PVC's resources.requests.storage CAN grow in place (ceph-block has
# allowVolumeExpansion: true; ceph-csi grows the RBD image and the filesystem
# online, no pod restart). Flux applies this over the existing claim with
# server-side apply and the resize follows.
#
# - Name, namespace, accessModes, storageClassName and volumeMode must match
# the live claim exactly: they are immutable, a mismatch fails the whole
# gitea Kustomization (no change to the live claim).
# - Grow only. A smaller value is rejected by the API server.
# - prune: disabled, so removing this file from git never deletes the claim
# and its data. To hand ownership back, delete the file; the claim stays.
#
# Size history: 20Gi -> 40Gi 2026-07-22 (#336, live resize by hand);
# 40Gi -> 60Gi 2026-10-03 (REN-583, after the volume filled again on REN-580).
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-gitea-0
namespace: gitea
labels:
app.kubernetes.io/name: gitea
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ceph-block
volumeMode: Filesystem
resources:
requests:
storage: 60Gi
+5 -9
View File
@@ -147,14 +147,10 @@ spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ceph-block
resources:
# Expanded 20Gi -> 40Gi on 2026-07-22 (ceph-block online resize) to
# clear a 100%-full outage (#336). The live PVC was resized directly.
# NOTE: volumeClaimTemplates is immutable on an existing StatefulSet,
# so bumping this value cannot be `kubectl apply`-ed in place — Flux
# will reject the whole object. Landing this size change requires a
# one-time `kubectl delete statefulset gitea -n gitea --cascade=orphan`
# (pod + PVC keep running) so Flux re-creates the STS from this
# template and re-adopts them. After the cleanup_packages GC reclaims
# the ~10G of orphaned blobs, real usage is ~9G, so 40Gi is headroom.
# This template only applies when the claim does not exist yet. The
# live size of data-gitea-0 is set in pvc.yaml (REN-583), not here:
# volumeClaimTemplates is immutable on an existing StatefulSet, so a
# change to this value cannot be applied and Flux would reject the
# whole object. Leave it at 40Gi.
requests:
storage: 40Gi
@@ -77,4 +77,7 @@ resources:
# customResourceState block in apps/monitoring/helmrelease-prometheus.yaml —
# these two files must land and be reverted together.
- prometheusrule-flux.yaml
# Gitea's data volume. It filled twice (#336, REN-580) and the chart's
# KubePersistentVolumeFillingUp warned 33 minutes before the second (REN-583).
- prometheusrule-gitea.yaml
- probes-blackbox.yaml
@@ -0,0 +1,42 @@
# Gitea's data volume (data-gitea-0) running low (REN-583).
#
# It filled twice: 2026-07-22 (#336) and 2026-10-03 (REN-580), both times
# because the package registry grew faster than cleanup_packages reclaimed it.
# A full volume fails image pushes (HTTP 500) and Gitea's own SQLite writes.
#
# The chart's KubePersistentVolumeFillingUp did not give usable lead time on
# REN-580: its warning needs under 15% free AND a 4-day linear projection to
# zero AND one hour of both, so it fired at 20:26Z; the volume was full at
# 20:59Z. Growth here comes in steps (a run of image builds added 8 GiB in a
# few hours that day), which a linear projection lags.
#
# So this is a plain floor: under 25% free (15 GiB at 60Gi) for 15m. That is
# about two of the 8 GiB steps seen on REN-580, and time for someone to run the
# package cleanup or grow pvc.yaml in apps/gitea.
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: gitea
namespace: monitoring
labels:
release: kube-prometheus-stack
spec:
groups:
- name: gitea.rules
rules:
- alert: GiteaDataVolumeLow
expr: >-
kubelet_volume_stats_available_bytes{namespace="gitea",persistentvolumeclaim="data-gitea-0"}
/ kubelet_volume_stats_capacity_bytes{namespace="gitea",persistentvolumeclaim="data-gitea-0"}
< 0.25
for: 15m
labels:
severity: warning
annotations:
summary: "Gitea data volume has {{ $value | humanizePercentage }} free"
description: >-
data-gitea-0 is under 25% free. When it fills, image pushes fail
with HTTP 500 and Gitea cannot write its database. Run the
cleanup_packages cron in Gitea's site admin and delete old
package versions, or grow the claim in apps/gitea/pvc.yaml
(ceph-block resizes online).
@@ -31,6 +31,7 @@ retired the depth rule in favour of one persistence rule (`> 5` for `20m`).
| `home-assistant_test.yaml` | Hand-written suite for `prometheusrule-home-assistant.yaml` (REN-245). |
| `ceph_test.yaml` | Hand-written suite for the `CephPoolLostRedundancyBlind` canary in `prometheusrule-ceph.yaml` (REN-93). |
| `disk-wear_test.yaml` | Hand-written suite for the EPHEMERAL exclusion in `prometheusrule-disk-wear.yaml` (REN-419). |
| `gitea_test.yaml` | Hand-written suite for `GiteaDataVolumeLow` in `prometheusrule-gitea.yaml` (REN-583). |
| `mutations.txt` | Negative controls. Each must make the suite fail. |
## Adding a suite
@@ -0,0 +1,46 @@
# Suite for prometheusrule-gitea.yaml (REN-583). Capacity 60 GiB; free space
# in GiB. 15 GiB free is exactly 25% and must stay silent.
rule_files:
- ../prometheusrule-gitea.yaml
evaluation_interval: 1m
tests:
# 20 GiB free, then 14 GiB free from minute 10 on: pending at 10m, fires
# at 25m (15m later), not before.
- interval: 1m
input_series:
- series: 'kubelet_volume_stats_capacity_bytes{namespace="gitea",persistentvolumeclaim="data-gitea-0"}'
values: '64424509440+0x40'
- series: 'kubelet_volume_stats_available_bytes{namespace="gitea",persistentvolumeclaim="data-gitea-0"}'
values: '21474836480+0x9 15032385536+0x30'
alert_rule_test:
- eval_time: 24m
alertname: GiteaDataVolumeLow
exp_alerts: []
- eval_time: 25m
alertname: GiteaDataVolumeLow
exp_alerts:
- exp_labels:
severity: warning
namespace: gitea
persistentvolumeclaim: data-gitea-0
exp_annotations:
summary: "Gitea data volume has 23.33% free"
description: "data-gitea-0 is under 25% free. When it fills, image pushes fail with HTTP 500 and Gitea cannot write its database. Run the cleanup_packages cron in Gitea's site admin and delete old package versions, or grow the claim in apps/gitea/pvc.yaml (ceph-block resizes online)."
# Exactly 25% free stays silent; another claim at 1% free is not this alert.
- interval: 1m
input_series:
- series: 'kubelet_volume_stats_capacity_bytes{namespace="gitea",persistentvolumeclaim="data-gitea-0"}'
values: '64424509440+0x40'
- series: 'kubelet_volume_stats_available_bytes{namespace="gitea",persistentvolumeclaim="data-gitea-0"}'
values: '16106127360+0x40'
- series: 'kubelet_volume_stats_capacity_bytes{namespace="other",persistentvolumeclaim="data-other-0"}'
values: '64424509440+0x40'
- series: 'kubelet_volume_stats_available_bytes{namespace="other",persistentvolumeclaim="data-other-0"}'
values: '644245094+0x40'
alert_rule_test:
- eval_time: 40m
alertname: GiteaDataVolumeLow
exp_alerts: []
@@ -167,3 +167,8 @@ disk-wear-critical-device-only|kubernetes/apps/monitoring-rules/prometheusrule-d
# exclusion matches nothing.
# Detected by: cases A and B.
disk-wear-ephemeral-keeps-partition|kubernetes/apps/monitoring-rules/prometheusrule-disk-wear.yaml|s/n\[0-9\]+(p\[0-9\]+)?"/n[0-9]+"/
# prometheusrule-gitea.yaml (REN-583). Detected by the 24m/25m pair and the
# exactly-25% case in gitea_test.yaml.
gitea-for-10m|kubernetes/apps/monitoring-rules/prometheusrule-gitea.yaml|/alert: GiteaDataVolumeLow/,/for:/s/for: 15m/for: 10m/
gitea-floor-le|kubernetes/apps/monitoring-rules/prometheusrule-gitea.yaml|s/^\([[:space:]]*\)< 0\.25$/\1<= 0.25/