Skip to content

EKS

EKS is managed Kubernetes. Alchemy targets Auto Mode, where AWS manages the nodes, storage, and load-balancer integration for you: AutoCluster stands up the control plane from a VPC, and higher-level workload helpers apply Kubernetes objects straight from your Stack — the deployments and services live in the same TypeScript program as the cluster, with no YAML manifests and no kubectl apply step.

AutoCluster composes IAM roles and the canonical Cluster resource on top of a Network:

alchemy.run.ts
import * as AWS from "alchemy/AWS";
const network = yield* AWS.EC2.Network("Network", {
cidrBlock: "10.42.0.0/16",
availabilityZones: 2,
nat: "single",
});
const cluster = yield* AWS.EKS.AutoCluster("Cluster", {
network,
});

This creates the cluster and node IAM roles with the Auto Mode managed policies, then provisions the control plane with Auto Mode compute (system and general-purpose node pools), block storage, and load balancing enabled — placed in the network’s private subnets. Budget for the create: an EKS control plane takes ~10 minutes to provision.

AutoCluster provisions with authenticationMode: "API", so cluster access is granted through AccessEntry resources rather than the aws-auth ConfigMap, and Addon installs EKS add-ons (EKS picks the default compatible version when you don’t pin one):

const admin = yield* AWS.EKS.AccessEntry("ClusterAdmin", {
clusterName: cluster.cluster.clusterName,
principalArn: "arn:aws:iam::123456789012:role/YourAdminRole",
accessPolicies: [
{
policyArn:
"arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy",
accessScope: { type: "cluster" },
},
],
});
const metricsServer = yield* AWS.EKS.Addon("MetricsServer", {
clusterName: cluster.cluster.clusterName,
addonName: "metrics-server",
});

The deploying principal is bootstrapped as cluster admin, so these are for everyone (and everything) else that needs in.

Workloads are resources in the same Stack. LoadBalancedWorkload bundles a Deployment with an internet-facing LoadBalancer Service:

import * as Kubernetes from "alchemy/Kubernetes";
const namespace = yield* Kubernetes.Namespace("Demo", {
cluster: cluster.cluster,
name: "demo",
});
const echo = yield* AWS.EKS.LoadBalancedWorkload("EchoServer", {
cluster: cluster.cluster,
namespace,
name: "echo-server",
replicas: 2,
containers: [
{
name: "echo-server",
image: "registry.k8s.io/echoserver:1.10",
ports: [{ containerPort: 8080, name: "http" }],
},
],
ports: [{ name: "http", port: 80, targetPort: 8080 }],
});

There is no kubeconfig step: Alchemy authenticates to the cluster’s API with your AWS credentials (a presigned STS token) and applies objects via server-side apply under the alchemy field manager, so deploys converge the live objects the same way the rest of your Stack converges cloud resources. Underneath the helpers sit plain Kubernetes primitives — Namespace, Deployment, Service, ConfigMap, and Job — plus Workload when you want a Deployment without the public load balancer. The full object model — supported kinds, apply ordering, and the Object escape hatch — lives in the Kubernetes hub (How objects deploy).

Give pods AWS credentials with Pod Identity

Section titled “Give pods AWS credentials with Pod Identity”

PodIdentityWorkload wires an IAM role (trusting pods.eks.amazonaws.com), a Kubernetes ServiceAccount, the PodIdentityAssociation, and the Deployment together in one call:

const worker = yield* AWS.EKS.PodIdentityWorkload("Worker", {
cluster: cluster.cluster,
namespace,
managedPolicyArns: ["arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"],
containers: [
{
name: "worker",
image: "public.ecr.aws/aws-cli/aws-cli:2.17.37",
command: ["/bin/sh", "-lc"],
args: ["aws sts get-caller-identity && sleep infinity"],
},
],
});

Pods running under the service account receive the role’s credentials through EKS Pod Identity — no OIDC provider or IRSA annotation ceremony. Pass roleArn instead of managedPolicyArns / inlinePolicies to use an existing role.