Amazon EKS Deployment Example
Section titled “Amazon EKS Deployment Example”Introduction
Section titled “Introduction”This is an example that demonstrates how to deploy a Python application to Amazon EKS.
The example deploys a weather forecaster application that runs as a containerized service in Amazon EKS with an Application Load Balancer. The application is built with FastAPI and provides two weather endpoints:
/weather- A standard endpoint that returns weather information based on the provided prompt/weather-streaming- A streaming endpoint that delivers weather information in real-time as it’s being generated
Prerequisites
Section titled “Prerequisites”- AWS CLI installed and configured
- eksctl (v0.208.x or later) installed
- Helm (v3 or later) installed
- kubectl installed
- Either:
- Amazon Bedrock Anthropic Claude 4 model enabled in your AWS environment
Project Structure
Section titled “Project Structure”chart/- Contains the Helm chartvalues.yaml- Helm chart default values
docker/- Contains the Dockerfile and application code for the container:Dockerfile- Docker image definitionapp/- Application coderequirements.txt- Python dependencies for the container & local development
Create EKS Auto Mode cluster
Section titled “Create EKS Auto Mode cluster”Set environment variables
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)export AWS_REGION=us-east-1export CLUSTER_NAME=eks-strands-agents-demoCreate EKS Auto Mode cluster
eksctl create cluster --name $CLUSTER_NAME --enable-auto-modeConfigure kubeconfig context
aws eks update-kubeconfig --name $CLUSTER_NAMEBuilding and Pushing Docker Image to ECR
Section titled “Building and Pushing Docker Image to ECR”Follow these steps to build the Docker image and push it to Amazon ECR:
- Authenticate to Amazon ECR:
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com- Create the ECR repository if it doesn’t exist:
aws ecr create-repository --repository-name strands-agents-weather --region ${AWS_REGION}- Build the Docker image:
docker build --platform linux/amd64 -t strands-agents-weather:latest docker/- Tag the image for ECR:
docker tag strands-agents-weather:latest ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/strands-agents-weather:latest- Push the image to ECR:
docker push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/strands-agents-weather:latestConfigure EKS Pod Identity to access Amazon Bedrock
Section titled “Configure EKS Pod Identity to access Amazon Bedrock”Create an IAM policy to allow InvokeModel & InvokeModelWithResponseStream to all Amazon Bedrock models
cat > bedrock-policy.json << EOF{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream" ], "Resource": "*" } ]}EOF
aws iam create-policy \ --policy-name strands-agents-weather-bedrock-policy \ --policy-document file://bedrock-policy.jsonrm -f bedrock-policy.jsonCreate an EKS Pod Identity association
eksctl create podidentityassociation --cluster $CLUSTER_NAME \ --namespace default \ --service-account-name strands-agents-weather \ --permission-policy-arns arn:aws:iam::$AWS_ACCOUNT_ID:policy/strands-agents-weather-bedrock-policy \ --role-name eks-strands-agents-weatherDeploy strands-agents-weather application
Section titled “Deploy strands-agents-weather application”Deploy the helm chart with the image from ECR
helm install strands-agents-weather ./chart \ --set image.repository=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/strands-agents-weather --set image.tag=latestWait for Deployment to be available (Pods Running)
kubectl wait --for=condition=available deployments strands-agents-weather --allTest the Agent
Section titled “Test the Agent”Using kubernetes port-forward
kubectl --namespace default port-forward service/strands-agents-weather 8080:80 &Call the weather service
curl -X POST \ http://localhost:8080/weather \ -H 'Content-Type: application/json' \ -d '{"prompt": "What is the weather in Seattle?"}'Call the weather streaming endpoint
curl -X POST \ http://localhost:8080/weather-streaming \ -H 'Content-Type: application/json' \ -d '{"prompt": "What is the weather in New York in Celsius?"}'Expose Agent through Application Load Balancer
Section titled “Expose Agent through Application Load Balancer”Create an IngressClass to configure an Application Load Balancer
cat <<EOF | kubectl apply -f -apiVersion: eks.amazonaws.com/v1kind: IngressClassParamsmetadata: name: albspec: scheme: internet-facingEOFcat <<EOF | kubectl apply -f -apiVersion: networking.k8s.io/v1kind: IngressClassmetadata: name: alb annotations: ingressclass.kubernetes.io/is-default-class: "true"spec: controller: eks.amazonaws.com/alb parameters: apiGroup: eks.amazonaws.com kind: IngressClassParams name: albEOFUpdate helm deployment to create Ingress using the IngressClass created
helm upgrade strands-agents-weather ./chart \ --set image.repository=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/strands-agents-weather --set image.tag=latest \ --set ingress.enabled=true \ --set ingress.className=albGet the ALB URL
export ALB_URL=$(kubectl get ingress strands-agents-weather -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')echo "The shared ALB is available at: http://$ALB_URL"Wait for ALB to be active
aws elbv2 wait load-balancer-available --load-balancer-arns $(aws elbv2 describe-load-balancers --query 'LoadBalancers[?DNSName==`'"$ALB_URL"'`].LoadBalancerArn' --output text)Call the weather service Application Load Balancer endpoint
curl -X POST \ http://$ALB_URL/weather \ -H 'Content-Type: application/json' \ -d '{"prompt": "What is the weather in Portland?"}'Configure High Availability and Resiliency
Section titled “Configure High Availability and Resiliency”- Increase replicas to 3
- Topology Spread Constraints: Spread workload across multi-az
- Pod Disruption Budgets: Tolerate minAvailable of 1
helm upgrade strands-agents-weather ./chart -f - <<EOFimage: repository: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/strands-agents-weather tag: latest
ingress: enabled: true className: alb
replicaCount: 3
topologySpreadConstraints: - maxSkew: 1 minDomains: 3 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app.kubernetes.io/name: strands-agents-weather - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app.kubernetes.io/instance: strands-agents-weather
podDisruptionBudget: enabled: true minAvailable: 1EOFCleanup
Section titled “Cleanup”Uninstall helm chart
helm uninstall strands-agents-weatherDelete EKS Auto Mode cluster
eksctl delete cluster --name $CLUSTER_NAME --waitDelete IAM policy
aws iam delete-policy --policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/strands-agents-weather-bedrock-policy