rossum/anydatacenter/30-policy-demo/kyvernoPolicies/rossumTopologySpread.yaml

117 lines
4.6 KiB
YAML

apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: enforce-topology-spread
namespace: rossum
annotations:
policies.kyverno.io/title: Spread pods based on zone topology
policies.kyverno.io/subject: Pod
spec:
# Depending on the desired outcome for the applications, there could be multiple solutions
# to the problem, naturally, the most complex and difficult was chosen in order to:
# 1. Preserve existing topology spread if defined
# 2. Inject topology spread if not defined
# 3. Override any settings of topology spread based on zones
#
# see https://github.com/kyverno/kyverno/issues/10655 for details why it cannot
# be achieved using the merge patch
rules:
# Check if existing zone topology spread is defined and overwrite it
- name: enforce-zone-topology-spread-configuration
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
selector:
matchLabels:
# Additional validation policies would be needed to ensure the label is present on every resource
app.kubernetes.io/name: "*"
operations:
- CREATE
- UPDATE
mutate:
foreach:
- list: "request.object.spec.template.spec.topologySpreadConstraints || []"
# Use precondition to mutate
preconditions:
any:
- key: "{{ element.topologyKey }}"
operator: Equals
value: topology.kubernetes.io/zone
patchesJson6902: |-
- path: /spec/template/spec/topologySpreadConstraints/{{elementIndex}}
op: replace
value:
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: '{{request.object.spec.selector.matchLabels."app.kubernetes.io/name"}}'
# Check if the zone topology spread is not defined and inject it
- name: inject-zone-topology-spread
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
selector:
matchLabels:
# Additional validation policies would be needed to ensure the label is present on every resource
app.kubernetes.io/name: "*"
operations:
- CREATE
- UPDATE
mutate:
foreach:
- list: "request.object.spec.template.spec.topologySpreadConstraints || []"
# Use precondition to mutate
preconditions:
any:
- key: "{{ request.object.spec.template.spec.topologySpreadConstraints[].topologyKey }}"
operator: AllNotIn
value:
- topology.kubernetes.io/zone
patchesJson6902: |-
- path: /spec/template/spec/topologySpreadConstraints/0
op: add
value:
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: '{{request.object.spec.selector.matchLabels."app.kubernetes.io/name"}}'
# Create topology spread if it does not exist
- name: create-topology-spread
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
selector:
matchLabels:
# Additional validation policies would be needed to ensure the label is present on every resource
app.kubernetes.io/name: "*"
operations:
- CREATE
- UPDATE
mutate:
patchStrategicMerge:
spec:
template:
spec:
# Ensure the zone topology spread is present if undefined
+(topologySpreadConstraints):
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
# Depending on the workload and requirements, ScheduleAnyway or DoNotSchedule might be chosen
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: '{{request.object.spec.selector.matchLabels."app.kubernetes.io/name"}}'