Karpenter AWS Provider

repository·main·Indexed 27 days ago

https://github.com/aws/karpenter-provider-aws

An open-source Kubernetes node provisioning project that automates scaling based on workload requirements to optimize performance and cost. It manages the node lifecycle by evaluating pod scheduling constraints and provisioning nodes that satisfy those requirements. The project includes OCI Helm charts for installation, support for AWS Launch Templates, and tools such as allocatable-diff, kompat, and kubereplay.

Tokens
144.1K
Snippets
230
Records
652
Agent score
92%

What's inside karpenter-provider-aws

  1. Overview of Karpenter node provisioning

    main

    Karpenter is an open-source node provisioning project for Kubernetes designed to improve cluster efficiency and cost. It automates the node lifecycle by:

    1. Watching for unschedulable pods marked by the Kubernetes scheduler.
    2. Evaluating pod scheduling constraints (including resource requests, nodeSelector, affinities, tolerations, and topology spread constraints).
    3. Provisioning nodes that satisfy the specific requirements of those pods.
    4. Removing nodes when they are no longer needed to optimize costs.
  2. Understand the Machine CRD Object Store solution for Node ownership

    main

    One proposed solution for managing node ownership and in-flight capacity is to use a Machine CRD as a representation of a scheduling decision. In this model, Karpenter creates a Machine CR instead of a Node object or launching instances directly during the provisioning loop.

    Key behaviors of the Machine CRD model:

    • Provisioning Flow: Karpenter creates a Machine CR $\rightarrow$ a separate controller launches capacity based on requirements $\rightarrow$ the controller resolves values from the CreateFleet response into the Machine's status.
    • Mapping: Once the instance launches and the kubelet joins the cluster, Machines are mapped to Nodes by matching the Node's spec.providerID with the Machine's status.providerID.
    • Termination: The Node termination finalizer (karpenter.sh/termination) is migrated to the Machine to orchestrate cordoning, draining, and deletion. For compatibility, the Node finalizer remains but checks for the presence of a Machine and triggers Machine deletion if found.
    • Capacity Tracking: In-flight capacity is represented by the Machine's .metadata.labels and .status.allocatable until the actual Node registers and initializes its own .status.allocatable.
    • Synchronization: Machine labels, taints, and annotations are mirrored onto the Node via a reconciliation mechanism after the Node joins the cluster.
    • Liveness: Liveness checks are performed on Nodes; if a Node does not register or become ready within a certain TTL, the backing Machine is deleted.
  3. Understand Karpenter Metric Implementation Details

    main

    When working with or extending Karpenter metrics, keep the following architectural design choices in mind:

    • Cluster State vs. Polling: Capacity metrics are not populated by continuously polling the Kubernetes API. Instead, they are based on Karpenter's internal cluster state representation. This reduces computation and network load.
    • Histogram vs. Summary:
      • Histograms are used for fixed-range buckets and are easier to implement but poor for unbounded data.
      • Summaries are used for tracking running quantiles (e.g., p99 latency) and work better for unbounded data, though they cannot be aggregated across different label values.
    • API Monitoring: Measuring API calls directly is difficult. Implementation strategies include using custom HTTP clients (e.g., via the AWS SDK) or implementing a proxy through which Karpenter makes API calls.
  4. Understand Karpenter security actors and capabilities

    main

    Karpenter's security model is defined by three primary actors with distinct responsibilities and permission levels:

    • Cluster Operator: Responsible for installing and configuring Karpenter. They have full control over NodePools and EC2NodeClasses, and manage the cloud identities (IAM) and permissions for both Karpenter and the resulting Nodes.
    • Cluster Developer: Users who create pods via Deployments, ReplicaSets, StatefulSets, or Jobs. They should not have permissions to modify the Karpenter deployment, pods, or service accounts.
    • Karpenter Controller: The application running in the cluster. It has Kubernetes API permissions to manage nodes and evict pods, and AWS IAM permissions to create and manage EC2 instances with specific IAM roles.
  5. Understand Karpenter Node Creation and Ownership Issues

    main

    Karpenter's current model of creating Node objects immediately after launching VM instances leads to several operational challenges. Understanding these issues is critical for troubleshooting provisioning behavior:

    Synchronization and Performance

    Karpenter must create the Node object to capture in-flight details (node name, allocatable resources, capacity) for its scheduler. This creates a dependency on the cloud provider API or the kubelet's registration speed, which can slow down provisioning. If resolution fails, Karpenter may lack capacity knowledge, leading to over-provisioning.

    Race Conditions and Instance Orphaning

    • Node Creation Conflicts: If a kubelet registers a node before Karpenter attempts to create it (e.g., during large scale-ups), Karpenter receives a conflict error. If this conflict occurs with a stale Node object (e.g., from a previously deleted instance with the same name), Karpenter may assume the new instance is already registered. This results in the Node provider ID mapping to the old instance, causing the termination finalizer to fail and leaving the new EC2 instance orphaned.
    • Provisioner Deletion: Karpenter uses Kubernetes ownerReference to link nodes to their Provisioners. If a Provisioner is deleted during a provisioning loop after the VM has launched but before the ownerReference is reconciled, the resulting nodes and VM instances will be orphaned.

    Capacity Reporting Errors

    Because Karpenter creates nodes without initial capacity details, Kubernetes 1.23+ control planes may report NotReady or unhealthy events due to insufficient image filesystem capacity. These errors typically resolve once the kubelet begins reporting ephemeral-storage.

    Labeling and Kubelet Conflicts

    When Karpenter (or any third party) registers a node, the kubelet only updates a fixed set of labels. This prevents users from applying dynamic labels via KubeletConfig or userData in AWS, as the kubelet's updates may be ignored or overwritten.

  6. Understand Karpenter Node Ownership and the Machine CRD

    main

    Karpenter is migrating its node ownership model to use a Machine CRD to represent scheduling decisions. This CRD acts as the primary record for in-flight nodes before they register as Kubernetes Nodes.

    Key Characteristics of the Machine CRD Model:

    • Scheduling State Persistence: The Machine CRD stores scheduling decisions, including labels, annotations, and taints (including startupTaints). This state is reconciled onto the Kubernetes Node once the Node registers.
    • Observability: Users gain visibility into in-flight nodes and scheduling decisions by inspecting the Machine resources on the cluster, rather than waiting for the Node to appear in the API server.
    • Decoupled Startup Scripts: Because scheduling state is managed via the Machine CRD, users can customize cloudprovider startup scripts (e.g., AWS userData) without interfering with Karpenter's ability to reconcile labels, annotations, and taints.
    • Performance Impact: The impact on kube-apiserver QPS and etcd storage is expected to be negligible. The model performs approximately 2 write operations per created node, which is comparable to or less than the current Node-based reconciliation flow.
  7. Understand Karpenter preference handling

    main

    Karpenter treats pod preferences (node affinity, pod affinity, pod anti-affinity, and pod topology) as requirements when determining if a pod can schedule on a node or be shifted to a new node.

    When constructing requirements, Karpenter initially treats preferred affinities as required. If these cannot be met, Karpenter relaxes the preferences one-at-a-time in ascending order of weight (lowest weight relaxed first) and retries.

    Warning: Karpenter does not interpret preferred affinities as required when constructing topology requirements. If a preference is strictly necessary, you must use required affinities.

  8. Understand the In-Memory Node Store solution for Node ownership

    main

    An alternative solution for managing node ownership is to use an In-Memory Node Store that relies on the cloud provider's instance data rather than the Kubernetes API server for in-flight capacity.

    Key behaviors of the In-Memory Store model:

    • Capacity Tracking: In-flight capacity is tracked exclusively in Karpenter's in-memory state. The node is modeled as an "in-flight node" until the instance registers the real Node object on the API server.
    • State Recovery: To handle restarts, the ListMachines() method is added to the CloudProvider interface to re-populate Karpenter-owned instances onto the API server (similar to the Kubernetes List/Watch mechanism).
    • Node Management: Karpenter continues to operate directly on the Node object, including applying labels, annotations, status conditions, and finalizers.
    • Metadata Management: Because userData does not support annotations, scheduling decisions (labels, taints, and annotations) must be stored in cloud provider tags.
      • Note: This approach is limited by cloud provider constraints on the number of allowed tags.
    • Liveness & GC: Includes liveness checks to delete backing instances for nodes that fail to register within a TTL, and garbage collection for in-flight nodes that no longer have backing instances.
  9. Understand Karpenter interaction with Kubernetes features

    main

    Karpenter interacts with core Kubernetes components as follows:

    • Kubernetes Scheduler: Karpenter monitors for pods that the Kubernetes scheduler has marked as unschedulable and attempts to provision nodes to satisfy those requirements.
    • Kubernetes Cluster Autoscaler: Karpenter can operate alongside the standard Cluster Autoscaler.
  10. Understand Karpenter interaction with AWS node groups

    main

    Karpenter's NodePools are designed to coexist with static capacity management solutions such as EKS Managed Node Groups and EC2 Auto Scaling Groups. Users can adopt several management models:

    • Full Karpenter management: Manage all capacity using NodePools.
    • Mixed model: Use both dynamic (NodePool-managed) and static (Managed Node Groups/ASGs) capacity.
    • Fully static approach: Rely entirely on existing static capacity management.

    Most users are expected to use a mixed approach initially, transitioning to full NodePool management over time.

  11. Understand NodeClaims in Karpenter

    main

    NodeClaims are immutable, cluster-scoped resources used by Karpenter to manage the lifecycle of Kubernetes Nodes with the underlying cloud provider. They serve as requests for capacity and map one-to-one with a cloud provider instance and a Kubernetes Node.

    Key characteristics of NodeClaims:

    • Ownership: Each NodeClaim is owned by a single NodePool and references a single NodeClass.
    • Naming: Names are auto-generated by Karpenter using the NodePool name as a prefix.
    • Lifecycle: Karpenter creates and deletes NodeClaims in response to Pod demands (provisioning) or disruption needs. The lifecycle involves three main stages: launch (asking the cloud provider to create the instance), registration (linking the created node to the NodeClaim), and initialization (waiting for the node and its resources to be ready).
    • Properties: Labels, annotations, and taints are propagated from the NodePool template. Karpenter also applies a termination finalizer to ensure proper cleanup.