fix(cilium): size the endpoint policy map and alert before it fills
Closes #451. Closes #454. Both issues are the same fault: a pod's dedicated cilium_policy_v3_<id> BPF map ran out of space, endpoint regeneration failed with "no space left on device", the CNI ADD call never returned, and the pod sat in sandbox creation. For paperless — replicas: 1 with strategy Recreate — that was a 41-minute outage on 2026-07-30. It is not over. Prometheus (metrics landed via #452) puts cilium_bpf_map_pressure{map_name="cilium_policy_v3_*"} at 0.867 on all three nodes right now, and max_over_time(...[30d]) at 1.03 — the map has been driven past capacity. Loki has the overflow recurring as recently as 2026-08-12 17:46Z, hitting authentik and esphome endpoints. Three changes: - bpf.policyMapMax 16384 (chart default) -> 65536, matching the cluster's existing bpf-lb-map-max. Takes steady-state pressure from ~87% to ~22%. The map is sized at creation, so this only takes effect as agents restart. - The chart range ">=1.19.0" is what let Flux take 1.19.6 -> 1.20.0 unattended 45 minutes before the first outage. Narrowed to ">=1.20.0 <1.21.0" so a CNI minor is a reviewed diff, not a surprise. - A PrometheusRule on cilium_bpf_map_pressure: warning over 80% for 15m, critical at 100%. The metric was already scraped but nothing alerted on it, so the first signal was a downstream replica mismatch. Not addressed: why the busiest endpoint needs ~14k entries. Only 178 CiliumIdentities exist and no CiliumNetworkPolicy declares more than 9 ports, so the entry count is not obviously explained by policy shape. Establishing that needs `cilium-dbg bpf policy get` on an agent. MERGING THIS ROLLS THE CNI. The DaemonSet uses updateStrategy.rollingUpdate.maxUnavailable: 2, so two of three agents restart at once. Co-Authored-By: Claude Bot <claude-bot@renner.uno>
This commit is contained in:
@@ -4,6 +4,7 @@ kind: Kustomization
|
||||
# come from the kube-prometheus-stack chart. Flux applies this Kustomization
|
||||
# only after `monitoring` is Ready (chart installed → CRDs present).
|
||||
resources:
|
||||
- prometheusrule-cilium.yaml
|
||||
- prometheusrule-hetzner-backup.yaml
|
||||
- prometheusrule-loki.yaml
|
||||
- prometheusrule-netbird-availability.yaml
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: PrometheusRule
|
||||
metadata:
|
||||
name: cilium
|
||||
namespace: monitoring
|
||||
labels:
|
||||
# kube-prometheus-stack's Prometheus resource selects on this label;
|
||||
# without it the rule is created but never loaded into Prometheus.
|
||||
release: kube-prometheus-stack
|
||||
spec:
|
||||
groups:
|
||||
- name: cilium.rules
|
||||
rules:
|
||||
- alert: CiliumBPFMapPressureHigh
|
||||
# cilium_bpf_map_pressure is used/capacity for the fullest map of
|
||||
# that name on the agent. A full map is not a slow path — it is a
|
||||
# hard failure: the agent cannot program the datapath, so endpoint
|
||||
# regeneration fails and every new pod on the node hangs in sandbox
|
||||
# creation until something frees space.
|
||||
expr: cilium_bpf_map_pressure > 0.8
|
||||
for: 15m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Cilium BPF map {{ $labels.map_name }} is {{ $value | humanizePercentage }} full on {{ $labels.node }}"
|
||||
description: "The BPF map {{ $labels.map_name }} on node {{ $labels.node }} has been over 80% full for 15 minutes. At 100% the Cilium agent can no longer program the datapath and new pods on this node fail sandbox creation. Raise the corresponding size in kubernetes/infrastructure/cilium/helmrelease.yaml (values.bpf) — the map is sized at creation, so the change needs an agent restart."
|
||||
|
||||
- alert: CiliumBPFMapFull
|
||||
# Pressure reaches (and can exceed) 1.0 when the agent wants more
|
||||
# entries than the map holds. Pods are already failing to start.
|
||||
expr: cilium_bpf_map_pressure >= 1
|
||||
for: 0m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Cilium BPF map {{ $labels.map_name }} is full on {{ $labels.node }}"
|
||||
description: "The BPF map {{ $labels.map_name }} on node {{ $labels.node }} is at or over capacity. Endpoint regeneration is failing with 'no space left on device' and pods scheduled to this node will hang in ContainerCreating. Check `{namespace=\"kube-system\",pod=~\"cilium-.+\"} |= \"no space left on device\"` in Loki for the affected endpoints."
|
||||
@@ -17,7 +17,11 @@ spec:
|
||||
chart:
|
||||
spec:
|
||||
chart: cilium
|
||||
version: ">=1.19.0"
|
||||
# Patch-only range: Flux reconciles every 30m and would otherwise take a
|
||||
# CNI minor or major unattended. Widening this is a deliberate, reviewed
|
||||
# act — a minor bump changes datapath behaviour and rolls 2 of 3 agents
|
||||
# at once.
|
||||
version: ">=1.20.0 <1.21.0"
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cilium
|
||||
@@ -46,6 +50,14 @@ spec:
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
bpf:
|
||||
# Size of each endpoint's own cilium_policy_v3_<id> map, holding one
|
||||
# entry per (identity, direction, protocol, port) the endpoint is
|
||||
# allowed. When it fills, endpoint regeneration fails with "no space
|
||||
# left on device", the CNI ADD call never returns, and the pod is stuck
|
||||
# in sandbox creation — so this must stay comfortably above the busiest
|
||||
# endpoint's entry count, tracked by cilium_bpf_map_pressure.
|
||||
# Takes effect on agent restart; the map is sized at creation.
|
||||
policyMapMax: 65536
|
||||
# Let pods reach the cluster's own LoadBalancer external IPs; Cilium
|
||||
# redirects the socket directly to the backend pod instead of sending
|
||||
# traffic out to the VIP and back (which fails with L2 announcements).
|
||||
|
||||
Reference in New Issue
Block a user