Add policy demo to handle topology spread
This commit is contained in:
parent
7826b9d39a
commit
f359292d05
22
anydatacenter/30-policy-demo/.terraform.lock.hcl
Normal file
22
anydatacenter/30-policy-demo/.terraform.lock.hcl
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# This file is maintained automatically by "terraform init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.terraform.io/hashicorp/kubernetes" {
|
||||||
|
version = "2.34.0"
|
||||||
|
constraints = "~> 2.34"
|
||||||
|
hashes = [
|
||||||
|
"h1:QOiO85qZnkUm7kAtuPkfblchuKPWUqRdNVWE5agpr8k=",
|
||||||
|
"zh:076b451dc8629c49f4260de6d43595e98ac5f1bdbebb01d112659ef94d99451f",
|
||||||
|
"zh:0c29855dbd3c6ba82fce680fa5ac969d4e09e20fecb4ed40166b778bd19895a4",
|
||||||
|
"zh:583b4dfcea4d8392dd7904c00b2ff41bbae78d238e8b72e5ad580370a24a4ecb",
|
||||||
|
"zh:5e20844d8d1af052381d00de4febd4055ad0f3c3c02795c361265b9ef72a1075",
|
||||||
|
"zh:766b7ab7c4727c62b5887c3922e0467c4cc355ba0dc3aabe465ebb86bc1caabb",
|
||||||
|
"zh:776a5000b441d7c8262d17d4a4aa4aa9760ae64de4cb7172961d9e007e0be1e5",
|
||||||
|
"zh:7838f509235116e55adeeecbe6def3da1b66dd3c4ce0de02fc7dc66a60e1d630",
|
||||||
|
"zh:931e5581ec66c145c1d29198bd23fddc8d0c5cbf4cda22e02dba65644c7842f2",
|
||||||
|
"zh:95e728efa2a31a63b879fd093507466e509e3bfc9325eb35ea3dc28fed15c6f7",
|
||||||
|
"zh:972b9e3ca2b6a1057dcf5003fc78cabb0dd8847580bddeb52d885ebd64df38ea",
|
||||||
|
"zh:ef6114217965d55f5bddbd7a316b8f85f15b8a77c075fcbed95813039d522e0a",
|
||||||
|
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||||
|
]
|
||||||
|
}
|
||||||
11
anydatacenter/30-policy-demo/kyvernoPolicies.tf
Normal file
11
anydatacenter/30-policy-demo/kyvernoPolicies.tf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
resource "kubernetes_manifest" "kyverno_policy_topology_spread" {
|
||||||
|
# To ensure the correct namespace is used, we could do a patch on the manifest
|
||||||
|
# For the sake of the demo and to ensure the kyverno tests are running correctly
|
||||||
|
# the namespace is hardcoded in the policy
|
||||||
|
manifest = yamldecode(file("${path.module}/kyvernoPolicies/rossumTopologySpread.yaml"))
|
||||||
|
depends_on = [
|
||||||
|
kubernetes_namespace.rossum,
|
||||||
|
kubernetes_deployment.pre_policy_sleeper,
|
||||||
|
kubernetes_deployment.pre_policy_sleeper_without_topology_spread,
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,116 @@
|
|||||||
|
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"}}'
|
||||||
13
anydatacenter/30-policy-demo/main.tf
Normal file
13
anydatacenter/30-policy-demo/main.tf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
terraform {
|
||||||
|
backend "local" {
|
||||||
|
path = "30-policy-demo.tfstate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "kubectx" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "kubernetes" {
|
||||||
|
config_context = var.kubectx
|
||||||
|
}
|
||||||
55
anydatacenter/30-policy-demo/postPolicy.tf
Normal file
55
anydatacenter/30-policy-demo/postPolicy.tf
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
resource "kubernetes_deployment" "post_policy_sleeper" {
|
||||||
|
metadata {
|
||||||
|
name = "post-policy-sleeper"
|
||||||
|
namespace = kubernetes_namespace.rossum.metadata[0].name
|
||||||
|
labels = {
|
||||||
|
"app.kubernetes.io/name" = "post-policy-sleeper"
|
||||||
|
"app.kubernetes.io/version" = "v5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec {
|
||||||
|
replicas = 3
|
||||||
|
|
||||||
|
selector {
|
||||||
|
match_labels = {
|
||||||
|
"app.kubernetes.io/name" = "post-policy-sleeper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
metadata {
|
||||||
|
labels = {
|
||||||
|
"app.kubernetes.io/name" = "post-policy-sleeper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec {
|
||||||
|
container {
|
||||||
|
name = "sleepy"
|
||||||
|
image = "busybox"
|
||||||
|
command = [
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
"while true; do sleep 60; done"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
security_context {
|
||||||
|
run_as_user = 1000
|
||||||
|
run_as_group = 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
# Injected by kyverno policy on create
|
||||||
|
spec[0].template[0].spec[0].topology_spread_constraint
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute after the kyverno policy is in place
|
||||||
|
depends_on = [kubernetes_manifest.kyverno_policy_topology_spread]
|
||||||
|
}
|
||||||
110
anydatacenter/30-policy-demo/prePolicy.tf
Normal file
110
anydatacenter/30-policy-demo/prePolicy.tf
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# Deployment will be added before the kyverno policy is created
|
||||||
|
resource "kubernetes_deployment" "pre_policy_sleeper" {
|
||||||
|
metadata {
|
||||||
|
name = "pre-policy-sleeper"
|
||||||
|
namespace = kubernetes_namespace.rossum.metadata[0].name
|
||||||
|
labels = {
|
||||||
|
"app.kubernetes.io/name" = "pre-policy-sleeper"
|
||||||
|
"app.kubernetes.io/version" = "v3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec {
|
||||||
|
replicas = 3
|
||||||
|
|
||||||
|
selector {
|
||||||
|
match_labels = {
|
||||||
|
"app.kubernetes.io/name" = "pre-policy-sleeper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
metadata {
|
||||||
|
labels = {
|
||||||
|
"app.kubernetes.io/name" = "pre-policy-sleeper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec {
|
||||||
|
topology_spread_constraint {
|
||||||
|
max_skew = 1
|
||||||
|
topology_key = "topology.kubernetes.io/hostname"
|
||||||
|
when_unsatisfiable = "ScheduleAnyway"
|
||||||
|
label_selector {
|
||||||
|
match_labels = {
|
||||||
|
"app.kubernetes.io/name" = "pre-policy-sleeper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
container {
|
||||||
|
name = "sleepy"
|
||||||
|
image = "busybox"
|
||||||
|
command = [
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
"while true; do sleep 60; done"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
security_context {
|
||||||
|
run_as_user = 1000
|
||||||
|
run_as_group = 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "kubernetes_deployment" "pre_policy_sleeper_without_topology_spread" {
|
||||||
|
metadata {
|
||||||
|
name = "pre-policy-sleeper-without-topology-spread"
|
||||||
|
namespace = kubernetes_namespace.rossum.metadata[0].name
|
||||||
|
labels = {
|
||||||
|
"app.kubernetes.io/name" = "pre-policy-sleeper-without-topology-spread"
|
||||||
|
"app.kubernetes.io/version" = "v2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec {
|
||||||
|
replicas = 3
|
||||||
|
|
||||||
|
selector {
|
||||||
|
match_labels = {
|
||||||
|
"app.kubernetes.io/name" = "pre-policy-sleeper-without-topology-spread"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
metadata {
|
||||||
|
labels = {
|
||||||
|
"app.kubernetes.io/name" = "pre-policy-sleeper-without-topology-spread"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec {
|
||||||
|
container {
|
||||||
|
name = "sleepy"
|
||||||
|
image = "busybox"
|
||||||
|
command = [
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
"while true; do sleep 60; done"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
security_context {
|
||||||
|
run_as_user = 1000
|
||||||
|
run_as_group = 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
# Injected by kyverno policy on update
|
||||||
|
spec[0].template[0].spec[0].topology_spread_constraint
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
5
anydatacenter/30-policy-demo/rossum.tf
Normal file
5
anydatacenter/30-policy-demo/rossum.tf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
resource "kubernetes_namespace" "rossum" {
|
||||||
|
metadata {
|
||||||
|
name = "rossum"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
anydatacenter/30-policy-demo/versions.tf
Normal file
3
anydatacenter/30-policy-demo/versions.tf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module "versions" {
|
||||||
|
source = "../../modules/versions"
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user