1/**
2 * An EKS-orchestrated SageMaker HyperPod cluster with every DX tier:
3 *
4 * - `src/eks-infra.ts` — network → EKS control plane → HyperPod cluster →
5 * task governance (the amazon-sagemaker-hyperpod-taskgovernance add-on,
6 * an `AWS.SageMaker.ClusterSchedulerConfig` policy, and a team
7 * `AWS.SageMaker.ComputeQuota`),
8 * - LOW LEVEL: a raw batch/v1 Job applied via `Kubernetes.Manifest`, pinned
9 * to HyperPod nodes with the well-known node labels and submitted
10 * through task governance with the Kueue labels (below),
11 * - HIGH LEVEL: `src/TrainJob.ts`, an effectful `Kubernetes.Job` bundled from
12 * TypeScript and pinned + governed through HyperPod resource attributes
13 * (`quota.namespace`, `quota.queueName`, the group's `nodeSelector`).
14 *
15 * Deploy with `bun alchemy deploy --config ./eks.run.ts`. The EKS control plane
16 * takes ~10-15 minutes and the HyperPod cluster another ~10-20.
17 */
18import * as Alchemy from "alchemy";
19import * as AWS from "alchemy/AWS";
20import * as Kubernetes from "alchemy/Kubernetes";
21import * as Effect from "effect/Effect";
22import * as Layer from "effect/Layer";
23import { HyperPodEksInfra } from "./src/eks-infra.ts";
24import TrainJob from "./src/TrainJob.ts";
25
26export default Alchemy.Stack(
27 "AwsHyperPodEksExample",
28 {
29 providers: Layer.mergeAll(AWS.providers(), Kubernetes.providers()),
30 state: Alchemy.localState(),
31 },
32 Effect.gen(function* () {
33 const { eks, hyperpod, scheduler, researchQuota } = yield* HyperPodEksInfra;
34
35 // ── LOW LEVEL: any Kubernetes object, applied as data. This one is
36 // governed: it runs in the research team's namespace (created by the
37 // ComputeQuota) and carries the Kueue queue + priority labels, so
38 // HyperPod task governance arbitrates it against the team's quota.
39 const governedJob = yield* Kubernetes.Manifest("GovernedJob", {
40 cluster: eks,
41 manifest: {
42 apiVersion: "batch/v1",
43 kind: "Job",
44 metadata: {
45 name: "governed-hello",
46 namespace: researchQuota.namespace,
47 labels: {
48 [AWS.SageMaker.KUEUE_QUEUE_NAME_LABEL]: researchQuota.queueName,
49 [AWS.SageMaker.KUEUE_PRIORITY_CLASS_LABEL]: "training-priority",
50 },
51 },
52 spec: {
53 backoffLimit: 1,
54 template: {
55 spec: {
56 nodeSelector: hyperpod.instanceGroups.workers.nodeSelector,
57 containers: [
58 {
59 name: "hello",
60 image: "public.ecr.aws/docker/library/busybox:stable",
61 command: ["sh", "-c", "echo hello from HyperPod"],
62 },
63 ],
64 restartPolicy: "Never",
65 },
66 },
67 },
68 },
69 });
70
71 // ── HIGH LEVEL: the effectful Job (bundled TypeScript, pinned +
72 // governed through the same attributes). See src/TrainJob.ts.
73 const trainJob = yield* TrainJob;
74
75 return {
76 eksClusterName: eks.clusterName,
77 hyperpodClusterArn: hyperpod.clusterArn,
78 hyperpodStatus: hyperpod.clusterStatus,
79 schedulerPolicyId: scheduler.clusterSchedulerConfigId,
80 researchTeam: researchQuota.teamName,
81 governedJobName: governedJob.name,
82 trainJobName: trainJob.jobName,
83 };
84 }),
85);