Karpenter Blueprint: Deploy an AWS Trainium or AWS Inferentia workload¶
This blueprint describes the components to get started with using AWS Trainium or AWS Inferentia with Amazon EKS, from AMIs to device plugins. Karpenter streamlines managing accelerated instance node lifecycle management. When you specify accelerated instance types in your Karpenter NodePool, Karpenter automatically selects the appropriate Amazon EKS AMI. Karpenter's provisioning also enables efficient use of Spot Instances across a diverse range of instance types - you can specify multiple accelerator options in your NodePool configuration. This flexibility allows you to balance performance and cost-effectiveness while running accelerator workloads in your Amazon EKS cluster.
When using AL2023 and Bottlerocket you need to deploy a Neuron Kubernetes device plugin to advertise neuron devices from the host, you also need the neuron driver (aws-neuronx-dkms). For AL2023 there is a Neuron EKS Accelerated AMI which is packaged with the Neuron driver. Bottlerocket also has the neuron driver packaged though it is part of the standard EKS Bottlerocket AMI.
Requirements¶
- A Kubernetes cluster with Karpenter installed. You can use the blueprint we've used to test this pattern at the
clusterfolder in the root of this repository.
Deploy Neuron Helm Chart for Kubernetes¶
The neuron helm chart simplifies installation of the Kubernetes device plugin for Neuron, Neuron Scheduler and Neuron Node Problem Detector. The Neuron Scheduler Extension is disabled by default. The Neuron scheduler extension is required for scheduling pods that require more than one Neuron core or device resource. For a graphical depiction of how the Neuron scheduler extension works, see Neuron Scheduler Extension Flow Diagram. The Neuron scheduler extension finds sets of directly connected devices with minimal communication latency when scheduling containers.
If you require the neuron scheduler, this can be deployed on a general purpose or system NodePool with general purpose compute. You can override the scheduler name as part of the helm chart install scheduler.customScheduler.fullnameOverride property. To use the neuron scheduler you must specify the schedulerName in your Pod specification.
For configuring the Neuron Node Problem Detector see the following AWS Neuron documentation.
To install the neuron helm chart run the following:
helm install neuron-helm-chart \
oci://public.ecr.aws/neuron/neuron-helm-chart \
--set "scheduler.enabled=true" \
--set "scheduler.customScheduler.fullnameOverride=neuron-scheduler" \
--set "npd.enabled=false" \
--namespace kube-system
By default, the neuron device plugin and scheduler are deployed in kube-system.
The neuron device plugin advertises both neuron cores aws.amazon.com/neuroncore and neuron devices aws.amazon.com/neuron to the kubelet. When scheduling a workload on aws.amazon.com/neuron all cores associated with that neuron device will be allocated to the Pod.
Confirm installation:
helm ls
Now that you have the device set-up, let’s enable Karpenter to launch AWS Trainium / Inferentia Amazon EC2 Instances.
Create a NodeClass and NodePool with AWS Trainium / Inferentia Amazon EC2 Instances (AL2023)¶
The following NodeClass, specify the Security Group and Subnet selector, along with AMI. We are using AL2023 here, and when launching an accelerated instance Karpenter will pick the respective EKS optimized AMI.
Before applying the neuron-nodeclass.yaml replace KARPENTER_NODE_IAM_ROLE_NAME and CLUSTER_NAME in the file with your specific cluster details. If you're using the Terraform template provided in this repo, run the following commands to get the EKS cluster name and the IAM Role name for the Karpenter nodes:
export CLUSTER_NAME=$(terraform -chdir="../../cluster/terraform" output -raw cluster_name)
export KARPENTER_NODE_IAM_ROLE_NAME=$(terraform -chdir="../../cluster/terraform" output -raw node_instance_role_name)
NOTE: If you're not using Terraform, you need to get those values manually.
CLUSTER_NAMEis the name of your EKS cluster (not the ARN). Karpenter auto-generates the instance profile in yourEC2NodeClassgiven the role that you specify in spec.role with the placeholderKARPENTER_NODE_IAM_ROLE_NAME, which is a way to pass a single IAM role to the EC2 instance launched by the KarpenterNodePool. Typically, the instance profile name is the same as the IAM role(not the ARN).
The EC2NodeClass we’ll deploy looks like this, execute the following command to create the EC2NodeClass file:
cat << EOF > neuron-nodeclass.yaml
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: neuron
spec:
amiSelectorTerms:
- alias: al2023@latest
role: "$KARPENTER_NODE_IAM_ROLE_NAME"
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
deleteOnTermination: true
iops: 10000
throughput: 125
volumeSize: 100Gi
volumeType: gp3
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: $CLUSTER_NAME
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: $CLUSTER_NAME
EOF
kubectl apply -f neuron-nodeclass.yaml
If you want to tune node properties it is suggested to create a new EC2NodeClass. For example, you may want to tune node properties such as ephemeral storage size, block device mappings, capacity reservations selector.
Create a dedicated NodePool, states provision instances from inf and trn category, and only allow workloads that tolerate the aws.amazon.com/neuron taint to be scheduled. Apply the following NodePool.
cat << EOF > neuron-nodepool.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: neuron
spec:
limits:
cpu: 100
memory: 100Gi
aws.amazon.com/neuron: 5
template:
metadata:
labels:
intent: neuron
spec:
nodeClassRef:
group: karpenter.k8s.aws
name: neuron
kind: EC2NodeClass
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand", "spot"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["inf", "trn"]
expireAfter: 720h
taints:
- key: aws.amazon.com/neuron
effect: NoSchedule
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 5m
EOF
kubectl apply -f neuron-nodepool.yaml
We’ve added the aws.amazon.com/neuron taint in the NodePool to prevent workloads that do not tolerate this taint being scheduled on nodes managed by this NodePool (they might not take advantage of it).
Now let’s deploy a test workload.
Deploy a test workload to test neuron drivers are loaded¶
The following Pod manifest launches a pod and calls the Neuron CLI to check if the accelerator is detected and the driver versions printed to standard output, use kubectl logs pod/neuron-ls to observe. Create workload.yaml from the following Pod specification:
cat << EOF > workload.yaml
apiVersion: v1
kind: Pod
metadata:
name: neuron-ls
spec:
nodeSelector:
intent: neuron
karpenter.k8s.aws/instance-accelerator-name: inferentia
restartPolicy: OnFailure
schedulerName: neuron-scheduler
containers:
- name: neuron-ls
image: public.ecr.aws/neuron/pytorch-inference-vllm-neuronx:0.13.0-neuronx-py312-sdk2.27.1-ubuntu24.04
args:
- "neuron-ls"
resources:
requests:
memory: "30Gi"
cpu: "3500m"
limits:
memory: "30Gi"
aws.amazon.com/neuron: 2
tolerations:
- key: aws.amazon.com/neuron
effect: NoSchedule
operator: Exists
EOF
Besides the other constraints to match the workload with the NodePool constraints, we set a node selector karpenter.k8s.aws/instance-accelerator-name to specify the accelerator. We also set the schedulerName to neuron-scheduler.
To deploy the workload execute the following:
$> kubectl apply -f workload.yaml
pod/neuron-ls created
After sometime to list nodes, neuron devices and cores run the following:
$> kubectl get nodes "-o=custom-columns=NAME:.metadata.name,NeuronDevices:.status.allocatable.aws\.amazon\.com/neuron,NeuronCores:.status.allocatable.aws\.amazon\.com/neuroncore"
NAME NeuronDevices NeuronCores
ip-xx-x-x-xxx.ec2.internal 4 16
You can check the pods status by executing:
$> kubectl get pods
NAME READY STATUS RESTARTS AGE
neuron-ls 1/1 Running 0 4m36s
You can view the pods neuron-smi logs by executing:
$> kubectl logs pod/neuron-ls
instance-type: inf1.6xlarge
instance-id: <redacted>
+--------+--------+----------+--------+-----------+--------------+----------+------+
| NEURON | NEURON | NEURON | NEURON | CONNECTED | PCI | CPU | NUMA |
| DEVICE | CORES | CORE IDS | MEMORY | DEVICES | BDF | AFFINITY | NODE |
+--------+--------+----------+--------+-----------+--------------+----------+------+
| 0 | 4 | 0-3 | 8 GB | 1 | 0000:00:1c.0 | 0-23 | -1 |
| 1 | 4 | 4-7 | 8 GB | 2, 0 | 0000:00:1d.0 | 0-23 | -1 |
+--------+--------+----------+--------+-----------+--------------+----------+------+
EKS Auto Mode
**Prerequisite:** an EKS cluster with Auto Mode enabled, and an EKS Access Entry granting `AmazonEKSAutoNodePolicy` to the node IAM role used by Auto Mode. > If you're using the Terraform template under [`cluster/automode/`](https://github.com/aws-samples/karpenter-blueprints/tree/main/cluster/automode) in this repo, the cluster, node IAM role, and Access Entry are all created for you — you can skip the manual access entry steps below. Trainium / Inferentia support is simpler on Auto Mode: the managed Bottlerocket AMIs include the AWS Neuron drivers, **and Auto Mode also includes the Neuron Kubernetes device plugin automatically** ([docs](https://docs.aws.amazon.com/eks/latest/userguide/auto-accelerated.html)). You do **not** need to install the `neuron-helm-chart` — skip that entire step. To deploy on Auto Mode, replace `<sed -i "s/<<CLUSTER_NAME>>/$CLUSTER_NAME/g" neuron-nodeclass-automode.yaml
kubectl apply -f neuron-nodeclass-automode.yaml
kubectl apply -f neuron-nodepool-automode.yaml
nodeSelector:
intent: neuron
eks.amazonaws.com/instance-accelerator-name: inferentia
aws eks create-access-entry \
--cluster-name $CLUSTER_NAME \
--principal-arn <node-role-arn> \
--type EC2
aws eks associate-access-policy \
--cluster-name $CLUSTER_NAME \
--principal-arn <node-role-arn> \
--policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSAutoNodePolicy \
--access-scope type=cluster
Clean-up¶
To clean-up execute the following commands:
kubectl delete -f workload.yaml
kubectl delete -f neuron-nodepool.yaml
kubectl delete -f neuron-nodeclass.yaml
helm delete -n kube-system neuron-helm-chart