feat(aws/sagemaker): HyperPod — Slurm & EKS clusters, task governance, workload DX - #924
Merged
Merged
Conversation
…eQuota Implements SageMaker HyperPod support: the Cluster resource (Slurm/EKS orchestrated, in-place instance-group updates with computed InstanceGroupsToDelete, VPC change => replace), plus the task-governance ClusterSchedulerConfig and ComputeQuota resources (id-addressed with list-by-name fallback, versioned updates via TargetVersion). Full Slurm cluster lifecycle live-verified (create -> InService -> destroy, ~5 min on 1x ml.t3.medium) behind AWS_TEST_SAGEMAKER_HYPERPOD=1; governance lifecycles gate on AWS_TEST_SAGEMAKER_HYPERPOD_EKS_CLUSTER_ARN. Ungated typed-error probes run in every CI pass. createCluster retries the IAM propagation race on freshly created execution roles. Adds examples/aws-hyperpod: bucket + role + deploy-time Action uploading the lifecycle script + the cluster. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
sam-goodwin
marked this pull request as ready for review
July 22, 2026 19:33
Contributor
|
Install the packages built from this commit: alchemy bun add alchemy@https://pkg.ing/alchemy/429e7ee@alchemy.run/better-auth bun add @alchemy.run/better-auth@https://pkg.ing/@alchemy.run/better-auth/429e7ee@alchemy.run/pr-package bun add @alchemy.run/pr-package@https://pkg.ing/@alchemy.run/pr-package/429e7ee |
…mple - AWS.SageMaker.hyperpodScheduling: typed namespace/Kueue-label/nodeSelector fragments for running EKS workloads on HyperPod nodes (instance-group pinning, healthy-nodes-only, task-governance team + priority class). - Cluster attrs expose orchestratorEksClusterArn; ComputeQuota attrs expose teamName (feeds hyperpod-ns-<team> references with a dependency edge). - examples/aws-hyperpod/eks.run.ts: EKS-orchestrated stack covering all tiers — control plane, HyperPod attach, taskgovernance add-on, scheduler policy + team quota, a governed raw Manifest Job, and an effectful EKS.Job pinned via hyperpodScheduling. - Cluster JSDoc now documents Slurm sbatch-over-SSM access and both EKS workload tiers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e runs A deploy that fails before an Addon's Output-valued clusterName resolves persists a row with the unresolved input stripped; the next plan's read then called describeAddon with clusterName undefined and crashed the plan. Return undefined (nothing observable) instead. Also require an explicit control-plane role in the aws-hyperpod EKS example (EKS.Cluster requires roleArn unless compute is "auto"). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ive deploy - LifeCycleConfig is required for EKS-orchestrated instance groups (the API rejects groups without it, contrary to the docs) — the EKS stack now carries the lifecycle bucket + upload Action like the Slurm stack. - The orchestrating EKS cluster must use API (or API_AND_CONFIG_MAP) authentication mode; EKS's CONFIG_MAP default is rejected by CreateCluster. Pinned accessConfig explicitly. - Documented both constraints in the Cluster JSDoc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… EKS version (supports 1.28-1.35) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… to ~5 min A draining EKS/HyperPod control plane releases its public ENI addresses over several minutes; the previous ~50s window reproducibly failed VPC teardown after EKS cluster deletion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rpodScheduling helper
EKS workloads opt onto HyperPod nodes with a typed prop instead of a
spread helper. Passing the team's ComputeQuota resource derives the
hyperpod-ns-<team> namespace, Kueue queue/priority labels, and the
quota -> workload ordering from the data flow:
yield* AWS.EKS.Job("Train", {
cluster: eks,
main: import.meta.url,
hyperpod: { instanceGroup: "workers", quota, priorityClass: "training" },
});
Effective-namespace changes (including hyperpod-derived) trigger
replacement keyed off a real prior row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ps, K8s client hardening
- hyperpod.instanceGroup accepts the same group object passed to the
cluster's instanceGroups (one source of truth for the name) or a string.
- examples/aws-hyperpod: SageMaker validates the HyperPod dependencies
helm chart before an EKS-orchestrated cluster attaches ("missing one or
more required dependencies") — a FetchHyperPodChart Action clones
aws/sagemaker-hyperpod-cli + vendors subcharts, and AWS.EKS.HelmChart
applies it between the EKS cluster and the HyperPod attach.
- KubernetesApiError now carries method/path/status/body in its message,
and applyObject retries transient failures (5xx/429 + the fresh-cluster
401/403 access-entry propagation window) for ~1 min.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- waitForAddonActive budget 10 -> 20 min: node-bound addons (HyperPod task governance) stay DEGRADED until nodes join and pull images, and the wait can start early when upstream attrs resolve from a plan-time read. AddonNotReady now reports cluster/addon/status in its message. - requestJson retries transport-level failures (ECONNREFUSED etc.) for ~40s — a fresh EKS endpoint can refuse connections briefly after ACTIVE. All requests on this path are idempotent (GET / SSA PATCH / DELETE). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…per-cluster conflict - Content-addressed EKS Job names over 63 chars are rejected by the API (the name lands in the batch.kubernetes.io/job-name label) — truncate the base so the content-address suffix always fits. Found live: any long app+stage+id combination hit it. - AWS allows ONE ClusterSchedulerConfig per HyperPod cluster; distilled now types the conflict (ClusterSchedulerConfigAlreadyExists) and the gated test asserts either the typed conflict (cluster already governed) or the full lifecycle (bare cluster). Verified live: ComputeQuota full lifecycle (create/update/destroy) green against a real EKS HyperPod cluster; ClusterSchedulerConfig create/reconcile green via the example stack and the conflict branch via the test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- /aws/compute/hyperpod: orchestrator choice (Slurm vs EKS), Slurm provisioning + sbatch-over-SSM, EKS orchestration constraints (API auth mode, version window, lifecycle scripts, mandatory dependencies chart), the hyperpod: workload prop, and task governance (one policy per cluster, team quotas). - /aws/compute/eks: "Run on SageMaker HyperPod" section + link. - Choosing-a-runtime EKS section and the AWS hub recipes table point at HyperPod; sidebar entry added. - Merged main (docs from #925) so the edits land on the current text. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- AWS.SageMaker.Cluster attributes expose `instanceGroups` keyed by group name; EKS workloads reference `hyperpod.instanceGroups.workers` so the workload is connected to the fleet through the resource graph instead of a shared object literal. - Resource attribute accessors upgrade pure object-record attributes to ObjectExpr for typed nested Output access (scoped conditional — branded string unions and optionals stay plain Output to avoid the ToOutput string-method explosion). - Docs: /aws/compute/hyperpod page, EKS "Run on SageMaker HyperPod" section now shows the cluster attach before the workload snippet, and all snippets use the Output-connected reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te refs
instanceGroups (and restrictedInstanceGroups) are objects keyed by group
name instead of named arrays. A const-generic constructor overlay carries
the keys through to the cluster's attributes, so
`hyperpod.instanceGroups.workers` is typed per key — a typo'd group name
is a compile error — while the resource identity, provider registration,
and wire mapping (keyed object -> named array) stay unchanged.
const hyperpod = yield* AWS.SageMaker.Cluster("HyperPod", {
instanceGroups: { workers: { InstanceType: "ml.g5.xlarge", ... } },
});
hyperpod.instanceGroups.workers // typed
hyperpod.instanceGroups.workerz // compile error
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds SageMaker HyperPod: the
AWS.SageMaker.Clusterresource (Slurm or EKS orchestrated), task governance (ClusterSchedulerConfig+ComputeQuota), a first-classhyperpodprop onAWS.EKS.Job/Deployment,examples/aws-hyperpodcovering every workload tier, and a dedicated docs page at/aws/compute/hyperpod(with EKS, choosing-a-runtime, and the AWS hub updated to point at it).HyperPod is a persistent fleet; how work lands on it depends on the orchestrator, so the DX is tiered the same way ECS/EKS were in #867:
orchestrator: { Eks })AWS.SageMaker.ClusterAWS.EKS.Cluster+AWS.SageMaker.Clusterssm start-session→sbatchAWS.EKS.Manifest(any K8s object)AWS.EKS.Job/Deploymentwithhyperpod:propsClusterSchedulerConfig+ComputeQuota(Kueue)Provision (both orchestrators)
Instance groups reconcile in place (removing one computes
InstanceGroupsToDelete); VPC change replaces;createClusterretries the IAM propagation race on fresh execution roles like Lambda does.Low level on Slurm — sbatch over SSM
Slurm has no remote submission API; jobs are submitted on the cluster. Every node is an SSM target:
Low level on EKS — any Kubernetes object, pinned by node labels
High level on EKS — effectful Jobs/Deployments with
hyperpod:propsThe #867 surfaces run on HyperPod unchanged. The
hyperpodprop references resources through the graph: instance groups are declared as a keyed object whose keys carry through to the cluster's attributes as types —hyperpod.instanceGroups.workersis typed per key (a typo'd name is a compile error) — and governance comes from the team'sComputeQuotaresource, so the node selector, namespace, Kueue labels, and cluster/quota → workload ordering all derive from the data flow:Task governance
Verified live
AWS_TEST_SAGEMAKER_HYPERPOD=1.eks.run.tsstack deployed green against real AWS — network → EKS 1.34 → HyperPod dependencies chart → HyperPod attach (InService) →amazon-sagemaker-hyperpod-taskgovernanceadd-on → scheduler policy → team quota → the governed raw-manifest Job inhyperpod-ns-research→ the effectfulTrainJobviahyperpod:props.AWS_TEST_SAGEMAKER_HYPERPOD_EKS_CLUSTER_ARN):ComputeQuotacreate → in-place update with version bump → destroy, all green live;ClusterSchedulerConfigcreate/reconcile verified via the stack, and the test asserts the typed one-policy-per-cluster conflict when the cluster is already governed (full lifecycle on a bare cluster). Ungated typed-error probes for all three resources run in every CI pass; full SageMaker suite 18/18.API(CONFIG_MAP rejected), HyperPod trails the newest EKS version (1.28–1.35),LifeCycleConfigis required for EKS-orchestrated groups (docs claim otherwise), the HyperPod dependencies helm chart is mandatory pre-attach (its vendored legacy mpi-operator CRD fails k8s ≥1.34 strict SSA — disabled via values), and AWS allows oneClusterSchedulerConfigper cluster (typed asClusterSchedulerConfigAlreadyExistsvia a distilled patch).batch.kubernetes.io/job-namelabel);EKS.Addonwaits up to 20 min for node-bound addons and reports status inAddonNotReady; the K8s client retries transport failures and fresh-cluster auth propagation;EKS.Addon.readtolerates rows from crashed pre-resolve runs;EC2.InternetGatewaydelete retriesDependencyViolationfor ~5 min (EKS control planes release ENI addresses slowly).🤖 Generated with Claude Code