Azure / karpenter-provider-azure

AKS Karpenter Provider
Apache License 2.0
358 stars 53 forks source link

`karpenter.azure.com/zone` requirement causes continuous drift #205

Open tallaxes opened 5 months ago

tallaxes commented 5 months ago

Version

Karpenter Version: https://github.com/Azure/karpenter-provider-azure/commit/99d1bb0730b3462e40267ec28024368c90801b26 (current main)

Kubernetes Version: v1.27.9

Expected Behavior

One should be able to specify requirements with karpenter.azure.com/zone constraint, for example to only provision nodes in a specific zone, without adverse effects.

Actual Behavior

Specifying any kind of karpenter.azure.com/zone constraint in a NodePool current triggers continuous drift.

Here is what I am thinking is going on. Right now, we cannot (and do not) record this requirement/constraint as a label on NodeClaim. This is because Karpenter will try applying all of these as labels to Node object - and topology.kubernetes.io/zone is a protected label in AKS. (It will be applied to a new Node correctly, but by a different component). So for now, as a workaround, we use an alternative label karpenter.azure.com/zone. I suspect that it is this discrepancy that causes Karpenter to detect Requirements Drift: Based of NodePool, the NodeClaim is expected to have the zone label, and it does not => out of spec, to be replaced. I also suspect that, while we do have E2E tests in this area, they likely only test that the node gets provisioned, and don't notice the subsequent drift.

Steps to Reproduce the Problem

Use NodePool with any kind of karpenter.azure.com/zone requirement.

Resource Specs and Logs

Continuous drift observed.

Workaround

Specify zone-based constraints (including topologySpreadConstraint, if needed) via workload, rather than NodePool.

Community Note

SalvoRusso8 commented 2 months ago

Hi @tallaxes, I'm trying the workaround to spread pods between different zones, but still Karpenter fails to create the nodeClaim. I didn't add the zone requirement in the NodePool.

I'm trying to schedule this deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 2
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      terminationGracePeriodSeconds: 0
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: "topology.kubernetes.io/zone"
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app: inflate
      containers:
        - name: inflate
          image: mcr.microsoft.com/oss/kubernetes/pause:3.6
          resources:
            requests:
              cpu: 1

but I receive this error in the Karpenter logs

{"level":"ERROR","time":"2024-06-05T16:28:58.144Z","logger":"controller.provisioner","message":"creating node claim, NodeClaim.karpenter.sh \"general-purpose-kfwpp\" is invalid: spec.requirements[2].key: Invalid value: \"string\": label domain \"kubernetes.io\" is restricted; creating node claim, NodeClaim.karpenter.sh \"general-purpose-h8j2d\" is invalid: spec.requirements[5].key: Invalid value: \"string\": label domain \"kubernetes.io\" is restricted","commit":"bbaa9b7"}

Using for example topologyKey: "kubernetes.io/hostname" Karpenter does schedule 2 new nodes and one pod for each node, but both the nodes are in the same zone.

Can you give me more info about your workaround? Thank you