mirror of
https://github.com/vhaudiquet/homeprod.git
synced 2026-10-15 19:56:15 +00:00
The longhorn instance-manager and engine-image pods carry longhorn.io/component labels, not app, so the exclusions never matched. Kyverno stripped their cpu requests at admission, longhorn-manager saw a spec mismatch and deleted the pod in a loop, and after any node reboot all longhorn volumes stayed detached with every workload stuck in ContainerCreating. Match the real labels instead.
122 lines
5.2 KiB
YAML
122 lines
5.2 KiB
YAML
---
|
|
# ============================================================================
|
|
# CPU-REQUEST RELIEF — TOGGLEABLE CLUSTER POLICY
|
|
# ============================================================================
|
|
# Emergency relief for CPU-saturated scenarios
|
|
#
|
|
# When ENABLED, this Kyverno ClusterPolicy removes the `resources.requests.cpu`
|
|
# field from every Pod created/updated in the cluster (except Kyverno's own pods,
|
|
# critical kube-system control-plane pods, and the Longhorn instance-manager /
|
|
# engine-image / longhorn-manager, which must keep guarantees so admission and
|
|
# the storage layer keep working). With no CPU request, pods schedule onto
|
|
# whatever capacity is free and burst freely.
|
|
#
|
|
# === TOGGLE ===
|
|
# The policy is ACTIVE by default (failurePolicy: Ignore = mutate, never block).
|
|
#
|
|
# DISABLE relief (restore the per-app CPU requests on next Flux reconcile):
|
|
# kubectl patch clusterpolicy.kyverno.io strip-cpu-requests --type=merge \
|
|
# -p '{"spec":{"failurePolicy":"Never"}}'
|
|
# # failurePolicy: Never tells Kyverno to skip the rule without mutating, so the
|
|
# # original CPU requests from each HelmRelease are restored on next reconcile.
|
|
#
|
|
# RE-ENABLE relief (strip requests again):
|
|
# kubectl patch clusterpolicy.kyverno.io strip-cpu-requests --type=merge \
|
|
# -p '{"spec":{"failurePolicy":"Ignore"}}'
|
|
# ============================================================================
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: strip-cpu-requests
|
|
annotations:
|
|
policies.kyverno.io/title: Strip CPU Requests (Emergency Relief)
|
|
policies.kyverno.io/category: Other
|
|
policies.kyverno.io/severity: low
|
|
policies.kyverno.io/subject: Pod
|
|
policies.kyverno.io/description: >-
|
|
Removes resources.requests.cpu AND resources.limits.cpu from pods so they
|
|
can be scheduled on an overloaded single-node cluster. Limits must be
|
|
stripped too: the LimitRanger admission plugin defaults requests.cpu =
|
|
limits.cpu whenever a limit exists without a request, so stripping only
|
|
the request is a no-op. Toggle via spec.failurePolicy:
|
|
Ignore = active (strip), Never = inactive (restore).
|
|
spec:
|
|
# Never block a pod if Kyverno admission is itself under pressure.
|
|
failurePolicy: Ignore
|
|
# background: true so the backgroundController also mutates ALREADY-EXISTING
|
|
# pods (not just new/updated ones at admission). This makes the relief take
|
|
# effect immediately on flip-on, without waiting for a pod restart.
|
|
background: true
|
|
rules:
|
|
- name: remove-cpu-request-from-containers
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
# Keep guarantees for things that must keep running so admission and the
|
|
# storage layer keep working even while everything else is bursting.
|
|
exclude:
|
|
any:
|
|
- resources:
|
|
namespaces:
|
|
- kyverno
|
|
- resources:
|
|
namespaces:
|
|
- kube-system
|
|
names:
|
|
# Control-plane static pods (apiserver, scheduler, controller-manager)
|
|
- kube-apiserver-*
|
|
- kube-scheduler-*
|
|
- kube-controller-manager-*
|
|
- resources:
|
|
namespaces:
|
|
- longhorn-system
|
|
selector:
|
|
matchLabels:
|
|
app: longhorn-manager
|
|
- resources:
|
|
namespaces:
|
|
- longhorn-system
|
|
selector:
|
|
matchLabels:
|
|
longhorn.io/component: instance-manager
|
|
- resources:
|
|
namespaces:
|
|
- longhorn-system
|
|
selector:
|
|
matchLabels:
|
|
longhorn.io/component: engine-image
|
|
mutate:
|
|
# `request.object` is available in BOTH admission and background modes:
|
|
# the backgroundController synthesizes an admission-like request for
|
|
# existing resources, so the same foreach works for both.
|
|
# NOTE 1: inside `foreach`, patchStrategicMerge must be an INLINE YAML
|
|
# mapping — a `|` block scalar is parsed as a string and fails with
|
|
# "wrong node kind: expected MappingNode but got ScalarNode".
|
|
# NOTE 2: limits.cpu MUST be stripped together with requests.cpu.
|
|
# The LimitRanger admission plugin defaults requests.cpu = limits.cpu
|
|
# whenever a container has a limit but no request, so stripping only
|
|
# the request is a no-op for any container that declares a limit.
|
|
foreach:
|
|
- list: "request.object.spec.containers"
|
|
patchStrategicMerge:
|
|
spec:
|
|
containers:
|
|
- name: "{{ element.name }}"
|
|
resources:
|
|
requests:
|
|
cpu: null
|
|
limits:
|
|
cpu: null
|
|
- list: "request.object.spec.initContainers || `[]`"
|
|
patchStrategicMerge:
|
|
spec:
|
|
initContainers:
|
|
- name: "{{ element.name }}"
|
|
resources:
|
|
requests:
|
|
cpu: null
|
|
limits:
|
|
cpu: null
|