AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Flyte Deploy Aws

skill-flyteorg-flyte-agent-plugins-flyte-deploy-aws · by flyteorg

Use when deploying a Flyte v2 (flyte-binary / flyte2) cluster on AWS from scratch — provisions EKS + S3 + RDS PostgreSQL + AWS Load Balancer Controller, then helm-installs the flyte-binary chart behind an ALB, with optional TLS and Okta SSO. Trigger words: "deploy flyte", "flyte v2 on AWS", "flyte EKS".

No reviews yet
0 installs
32 views
0.0% view→install

Install

$ agentstack add skill-flyteorg-flyte-agent-plugins-flyte-deploy-aws

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-flyteorg-flyte-agent-plugins-flyte-deploy-aws)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Flyte Deploy Aws? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Deploying Flyte v2 on AWS (EKS + RDS + S3 + ALB)

Flyte v2 ships as a single unified binary (flyte-binary-v2) plus a separate console image. One HTTP ingress serves the console (/v2), the flyteidl2.* Connect API, and auth-discovery — there is no separate gRPC port. You scale it vertically.

The chart does NOT provision infrastructure. Stand up four things first: EKS cluster, S3 bucket, PostgreSQL (RDS), and (for external access) an ingress controller. This skill does all four with eksctl + aws + helm, then installs the flyte-binary chart (the v2 chart; defaults to flyte-binary-v2 + flyteconsole-v2).

Get the chart first. Install from the published Helm repo — this is what the official docs do, and the released chart pins the Flyte image tag to the chart version (see Image selection in Step 5). Also helm pull --untar a local copy so the TaskAction CRD file is on disk for the Step 5 idempotency check:

helm repo add flyteorg https://flyteorg.github.io/flyte && helm repo update
helm pull flyteorg/flyte-binary --untar   # ./flyte-binary/templates/crds/flyte.org_taskactions.yaml now resolves

(Alternatively clone the repo — git clone https://github.com/flyteorg/flyte — and install from the local ./charts/flyte-binary path for the bleeding-edge chart; its default image tag is a floating :latest, so pair it with pullPolicy: Always — see Image selection.) Official docs: https://www.union.ai/docs/v2/flyte/oss-deployment/aws-deployment/. Validated end-to-end on EKS.

> Replace every placeholder in angle brackets and the example hostnames/IDs with your own.

Prerequisites & decisions

  • CLIs: aws v2, eksctl ≥ 0.227 (older caps out at k8s 1.29 — see gotcha), kubectl, helm, jq.
  • Admin (or EKS+RDS+IAM+S3+EC2) creds. STS/SSO works — export the 3 env vars + region.
  • eksctl writes the kubeconfig context (e.g. @flyte-v2..eksctl.io). Pass

kubectl --context (and helm --kube-context ) per command rather than kubectl config use-context — that way you don't mutate the operator's current context.

  • Decide: region, name prefix, and exposure: ALB+TLS needs a Route53 zone + ACM cert;

ALB HTTP-only needs neither (reached at the auto *.elb.amazonaws.com name) — the simplest default when you own no domain. (This skill provisions RDS PostgreSQL for the DB; an in-cluster Postgres is out of scope here — RDS is assumed by Steps 3–5.)

Persist your variables. This deploy spans many commands and derives values you can't recover later — most critically the random DBPW (Step 3), plus ACCT, BUCKET, RDS_HOST, IRSA_ARN, etc. If your shell state resets between steps (or your AWS session token expires and you re-auth in a fresh shell), these are gone. Keep them in a file you re-source at the start of every step, and append each derived value as you compute it:

export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_SESSION_TOKEN=...
export AWS_DEFAULT_REGION=us-west-2
ENVF=~/flyte-deploy.env                                   # source this at every step
{ echo "export PREFIX=flyte-v2 REGION=us-west-2 CLUSTER=flyte-v2"
  echo "export ACCT=$(aws sts get-caller-identity --query Account --output text)"  # confirm the RIGHT account
} >> $ENVF && source $ENVF
# As you create infra, append its outputs, e.g.:  echo "export DBPW='$DBPW' RDS_HOST=$RDS_HOST" >> $ENVF
# Check for an existing domain/cert (empty => go ALB HTTP-only):
aws route53 list-hosted-zones --query 'HostedZones[].Name' --output text
aws acm list-certificates --region $REGION --query 'CertificateSummaryList[].DomainName' --output text

Step 0 — Reuse an existing cluster?

Before creating anything, list the EKS clusters already in the account/region and ask the user whether to deploy onto one of them or stand up a fresh cluster. Reusing skips Step 1 (~15-20 min + the EKS control-plane + node cost).

aws eks list-clusters --region $REGION --query 'clusters' --output text

Present the list and let the user pick one (or choose "create new"). If they reuse one:

CLUSTER=
aws eks update-kubeconfig --region $REGION --name $CLUSTER --alias $CLUSTER   # writes + selects context
kubectl --context $CLUSTER get nodes                                          # confirm reachable + Ready
# Confirm IRSA is possible (the chart needs an OIDC provider on the cluster):
aws eks describe-cluster --region $REGION --name $CLUSTER \
  --query 'cluster.identity.oidc.issuer' --output text                        # empty => run: eksctl utils associate-iam-oidc-provider --cluster $CLUSTER --approve

Then skip Step 1 and continue from Step 2. S3 (Step 2), RDS (Step 3), and the ALB controller (Step 4) may already exist on a reused cluster — check before recreating (aws s3 ls, aws rds describe-db-instances, kubectl --context $CLUSTER -n kube-system get deploy aws-load-balancer-controller) and reuse what's there. Otherwise proceed normally. Pass --context $CLUSTER / --kube-context $CLUSTER on the later kubectl/helm commands.

Step 0.5 — Confirm deployment parameters (ASK up front, never assume)

Before provisioning or installing anything, gather the deploy parameters by ASKING the user — do NOT silently reuse values you happen to find. A previous deploy leaves identifiers lying around (an old values-eks.yaml with HOST=/certificate-arn/password, a live flyte*-console-oidc k8s Secret, authMetadata.flyteClient.clientId, a memory of the last run). These are suggestions to confirm, not defaults. Silently reusing the prior hostname, OIDC client ID/secret, or cert is the #1 way this skill does the wrong thing.

For each parameter below, discover any prior value, then present it as a choice — e.g. "reuse previous (test.uniondemo.run, loaded from the old values file / the in-cluster Secret), enter a new one, or pick a different existing one" — and let the user decide. Restate the final set back to them before helm install.

| Parameter | Where a prior value hides | Notes | |---|---|---| | Region / name prefix / cluster | Step 0, current kube-context | | | Exposure (HTTP-only / TLS / TLS+SSO) | — | drives which params below apply | | Hostname | HOST= in old values-eks.yaml; existing Route53 record | drives cert, OIDC redirect URI, DNS | | ACM cert ARN | old values certificate-arn; aws acm list-certificates | must match the chosen hostname | | OIDC issuer / client ID / client secret | authMetadata in old values; flyte*-console-oidc Secret; the IdP app | never echo/ask for the secret in chat — have the user create the Secret themselves (see ALB edge SSO) | | OIDC CLI/PKCE client ID | authMetadata.flyteClient.clientId | | | S3 bucket / RDS host+password | Step 2/3 outputs; old values | reuse the live infra's real values |

Only after the user confirms each value do you write values-eks.yaml (Step 5). If reusing a secret/credential, confirm the user still wants that IdP app — switching IdP is just a new Secret + issuer refs (no ALB/DNS churn).

Step 1 — EKS cluster (eksctl)

cluster.yamliam.withOIDC: true is what makes IRSA possible:

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata: { name: flyte-v2, region: us-west-2, version: "1.33" }
iam: { withOIDC: true }
managedNodeGroups:
  - name: ng-default
    instanceType: m5.large
    desiredCapacity: 2
    minSize: 2
    maxSize: 3
    volumeSize: 50
    iam: { withAddonPolicies: { ebs: true } }
addons: [{name: vpc-cni},{name: coredns},{name: kube-proxy},{name: aws-ebs-csi-driver}]
eksctl create cluster -f cluster.yaml     # ~15-20 min; writes kubeconfig + sets context
kubectl get nodes                          # expect Ready

The VPC + private subnets exist within ~2 min (before the control plane finishes), so you can start RDS (step 3) in parallel.

Step 2 — S3 bucket + IRSA role

BUCKET=$PREFIX-data-$ACCT       # account-id suffix => globally unique
aws s3api create-bucket --bucket $BUCKET --region $REGION \
  --create-bucket-configuration LocationConstraint=$REGION
aws s3api put-public-access-block --bucket $BUCKET --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api put-bucket-encryption --bucket $BUCKET --server-side-encryption-configuration \
  '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'

# Scoped S3 policy: ListBucket on the bucket, Get/Put/Delete on its objects.
cat > s3-policy.json > $ENVF   # persist (DBPW is unrecoverable)
aws rds create-db-instance --region $REGION --db-instance-identifier $PREFIX-db \
  --engine postgres --db-instance-class db.t3.micro --allocated-storage 20 --storage-type gp3 \
  --master-username flyte --master-user-password "$DBPW" --db-name flyte \
  --vpc-security-group-ids $RDSSG --db-subnet-group-name $PREFIX-db-subnets \
  --no-publicly-accessible --backup-retention-period 1
# Endpoint (when status=available):
RDS_HOST=$(aws rds describe-db-instances --region $REGION --db-instance-identifier $PREFIX-db \
  --query 'DBInstances[0].Endpoint.Address' --output text)
echo "export RDS_HOST=$RDS_HOST" >> $ENVF

Open 5432 from the nodes — do this once the nodegroup is up (kubectl get nodes Ready), not before: pod egress uses the EKS-managed cluster SG on the nodes (eks-cluster-sg-*), NOT ClusterSharedNodeSecurityGroup (gotcha 2). If you started RDS in parallel with Step 1, the nodes may not exist yet — that's why this is its own step. The DB just needs this one rule:

NODESG=$(aws ec2 describe-instances --region $REGION \
  --filters "Name=tag:eks:cluster-name,Values=$CLUSTER" "Name=instance-state-name,Values=running" \
  --query 'Reservations[0].Instances[0].SecurityGroups[?contains(GroupName,`eks-cluster-sg`)].GroupId' --output text)
[ -n "$NODESG" ] || { echo "no running nodes yet — wait for the nodegroup, then re-run"; }
aws ec2 authorize-security-group-ingress --region $REGION --group-id $RDSSG \
  --protocol tcp --port 5432 --source-group $NODESG   # init container retries until this lands

Step 4 — AWS Load Balancer Controller (for ALB ingress)

# Use the policy matching the controller version the chart installs — currently v3.x.
curl -sL https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v3.4.0/docs/install/iam_policy.json -o alb-iam-policy.json
ALB_POLICY_ARN=$(aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy \
  --policy-document file://alb-iam-policy.json --query Policy.Arn --output text)
eksctl create iamserviceaccount --cluster $CLUSTER --region $REGION \
  --namespace kube-system --name aws-load-balancer-controller \
  --role-name $PREFIX-alb-controller --attach-policy-arn "$ALB_POLICY_ARN" --approve
helm repo add eks https://aws.github.io/eks-charts && helm repo update eks
helm upgrade --install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system \
  --set clusterName=$CLUSTER --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller --set region=$REGION --set vpcId=$VPC
kubectl -n kube-system rollout status deploy/aws-load-balancer-controller

If the controller image is newer than the policy you fetched, you'll see AccessDenied on actions like elasticloadbalancing:DescribeListenerAttributes. Fix WITHOUT reinstalling:

curl -sL .../aws-load-balancer-controller/v/docs/install/iam_policy.json -o p.json
aws iam create-policy-version --policy-arn $ALB_POLICY_ARN --policy-document file://p.json --set-as-default

(Check version: kubectl -n kube-system get deploy aws-load-balancer-controller -o jsonpath='{..image}'.)

Step 5 — helm install flyte-binary

values-eks.yaml (ALB HTTP-only variant). The UPPERCASE tokens (BUCKET, RDS_HOST, DBPW, IRSA_ARN) and region: are placeholders — substitute your real values before installing, e.g. sed -i "s/BUCKET/$BUCKET/g; s/RDS_HOST/$RDS_HOST/; s/DBPW/$DBPW/; s#IRSA_ARN#$IRSA_ARN#; s/us-west-2/$REGION/g" values-eks.yaml (or hand-edit). Note this chart uses metadataContainer (no userDataContainer) and its run output prefix defaults to a nonexistent s3://flyte-data — override storagePrefix to your bucket:

fullnameOverride: flyte
flyte-core-components:
  runs: { storagePrefix: "s3://BUCKET" }   # under `runs`, NOT `runs.server` (else ignored)
# no image override needed: the repo chart pins its image tag to the chart version
# (only the git-main chart floats `:latest` — see Image selection below)
configuration:
  database:
    postgres:
      host: RDS_HOST
      port: 5432
      dbname: flyte
      username: flyte
      password: "DBPW"
      options: "sslmode=require"
  storage:
    metadataContainer: BUCKET
    provider: s3
    providerConfig: { s3: { region: us-west-2, authType: iam } }   # set to your $REGION
  inline: { executor: { defaultK8sServiceAccount: flyte } }   # task pods inherit S3 via IRSA
serviceAccount:
  create: true
  name: flyte
  annotations: { eks.amazonaws.com/role-arn: IRSA_ARN }
ingress:
  create: true
  host: ""                       # empty => rule matches any host => reach by ALB DNS name
  ingressClassName: alb
  httpAnnotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
    alb.ingress.kubernetes.io/healthcheck-path: /healthz      # binary serves /healthz on :8090
    alb.ingress.kubernetes.io/healthcheck-port: "8090"

For TLS: add certificate-arn, listen-ports: '[{"HTTP":80},{"HTTPS":443}]', ssl-redirect: "443", and set ingress.host to the cert hostname + a Route53 record. See the TLS section below — works even when DNS lives in a different AWS account.

helm install flyte flyteorg/flyte-binary -n flyte --create-namespace -f values-eks.yaml --dry-run  # check
helm install flyte flyteorg/flyte-binary -n flyte --create-namespace -f values-eks.yaml
kubectl -n flyte get pods   # flyte stuck Init:0/1 => wait-for-db can't reach RDS (see gotchas)

ALWAYS confirm the TaskAction CRD is present after install — the chart ships it as a plain template, so in a shared cluster it's easily deleted out-of-band, and the binary then loops Failed to watch ... taskactions.flyte.org and every run sticks at "queued" (gotcha 8). Make it idempotent at the end of every deploy:

kubectl --context  get crd taskactions.flyte.org >/dev/null 2>&1 \
  || kubectl --context  apply -f ./flyte-binary/templates/crds/flyte.org_taskactions.yaml   # from `helm pull --untar`
kubectl --context  get crd taskactions.flyte.org -o jsonpath='{.status.conditions[?(@.type=="Established")].status}'  # => True
# Pre-existing CRD blocks helm adopt? patch ownership, then (re)install:
#   kubectl annotate crd taskactions.flyte.org meta.helm.sh/release-name=flyte meta.helm.sh/release-namespace=flyte --overwrite
#   kubectl label    crd taskactions.flyte.org app.kubernetes.io/managed-by=Helm --overwrite

Only rollout restart if you applied the CRD onto an already-running binary that was missing it (the watch won't retry a resource that 404'd at boot). On a normal install the chart creates the CRD before the pod is Ready, so the watch establishes on first boot — don't restart reflexively, it's a wasted second rollout (+ image re-pull on a floating tag).

Image selection. The published repo chart (what the official docs install) pins the Flyte image tag to the chart version — e.g. chart v2.0.27 runs cr.flyte.org/flyteorg/flyte-binary-v2:v2.0.27 — plus console ghcr.io/unionai-oss/flyteconsole-v2:latest, all with the default pullPolicy: IfNotPresent. No image override is needed: the binary and the DB migrations it runs ship as a matched pair, and upgrading is helm repo update && helm upgrade (a new chart brings its new pinned image). Only

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.