Deploy a Serverless Application using Crossplane on EKS
TUTORIAL
Overview
In this tutorial, we will walk you through deploying the Serverless architecture depicted in the diagram using Crossplane on Amazon EKS. Crossplane is a CNCF open source project that extends the capabilities of Kubernetes to include infrastructure resource management. If you are not familiar with the fundamentals of Crossplane, we recommend first completing the official Crossplane getting started guide.

What You Will Learn
In this guide, you will learn how to:
- Create a Docker image and push it to ECR.
- Set Crossplane underlying Compositions and XRDs, and use Claims.
- Validate results with basic commands using kubectl and the AWS CLI.
Prerequisites
Before starting this guide, you will need:
- An AWS account: if you don't already have one follow
the Setup Your Environment (Steps 1, 2, and 3)
getting started guide for a quick overview. - The latest version of the AWS CLI: Visit our guide to get started installing or updating
the AWS CLI. - Kubectl: Visit Amazon EKS guide to get started installing or updating
kubectl. - EKS cluster and Crossplane: follow this Readme to create with Terraform >= 1.0.0
- EKS cluster >= 1.27
- Crossplane helm chart >= 1.13
- Crossplane official aws-provider configured to access AWS API >= 0.38
- Go: Find the installation instructions here.
- Docker: Find the installation instructions here.
Modules
This tutorial is divided into the following short modules. You must complete each module before moving to the next one.
Build a docker image and push to ECR (5 mins): Build a Docker image of a sample application, create an ECR repository, and upload the image to it.
Deploy the serverless application (15 mins): Using the Kubernetes command line, deploy Crossplane Resource Definitions, Compositions, and Claims in order to create your resources for your serverless application.
Test (5 mins): Send a message to your newly created SQS queue and observe it triggering your Lambda function and publishing the result in your S3 bucket.
Clean Up Resources (5 mins): In this last part of the guide you learn how to clean after you are done.
AWS experience
Advanced
Time to complete
30 minutes
Cost to complete
See AWS Lambda, Amazon EKS pricing to estimate cost for this tutorial
Requires
Services used
AWS Lambda, Amazon EKS
Last updated
February 13, 2024
Module 1: Build a docker image and push to ECR
Introduction
In this module, we will be building a Docker image with a sample application, creating an ECR repository, and uploading the image to it. This container image contains the source code for the Lambda function that is part of the serverless application we will be deploying later on in this tutorial.
What you will learn
- Building a Docker image from a given application
- Creating an ECR repo and uploading an image to it using the AWS CLI
Implementation
Clone the crossplane-on-eks repository to your local machine.
git clone https://github.com/awslabs/crossplane-on-eks.git
Navigate to the function code folder
cd crossplane-on-eks/examples/upbound-aws-provider/composite-resources/serverless-examples/object-processor-app
Set AWS_REGION, ECR_URL, and IMAGE_NAME as environment variables.
export AWS_REGION=<replace-me-with-aws-region> # this should make aws cli pointing to the region without explicitly passing --region
export ECR_URL=$(aws sts get-caller-identity --output json | jq -r ".Account" | tr -d '[:space:]').dkr.ecr.$AWS_REGION.amazonaws.com
export IMAGE_NAME=<replace-me-with-image-name>
Log in to ECR
aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URL
Create ECR repository
aws ecr create-repository --repository-name $IMAGE_NAME
Build the Go binary
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o main main.go
Set the DOCKER_IMAGE env var. This step is necessary to properly escape the ':' for the subsequent docker commands
export DOCKER_IMAGE=$ECR_URL/$IMAGE_NAME\:latest
Build the docker image
docker build -t $DOCKER_IMAGE .
Expected output
[+] Building 0.5s (7/7) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 37B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for public.ecr.aws/lambda/go:1 0.3s
=> [internal] load build context 0.1s
=> => transferring context: 13.18MB 0.1s
=> [1/2] FROM public.ecr.aws/lambda/go:1@sha256:ea8389f1a5e7e9d29c4d65008da143985bef131cf901db63ab57e4124f7f66 0.0s
=> CACHED [2/2] COPY main /var/task 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:0f3ea389fa4f3761f25b2b666a8f49b458e825f1180b9c2181ecadd55fd2cc9a 0.0s
=> => naming to 111122223333.dkr.ecr.us-east-1.amazonaws.com/lambda-test:latest 0.0s
Upload the docker image to ECR
docker push $DOCKER_IMAGE
Expected output
The push refers to repository [111122223333.dkr.ecr.us-east-1.amazonaws.com/lambda-test]
8ce4b9b80622: Pushed
02c5912fad21: Pushed
2d244e0816c6: Pushed
2b58bd9b1feb: Pushed
d79a81893db4: Pushed
2ad9f6dfcb67: Pushed
latest: digest: sha256:86bb30cbf14d9ac538946cdd9565f09b7a4a0b9846e28a73cd27116280c0a58e size: 1579
Conclusion
In this module, we covered how to build a Docker image, create an ECR repo, and upload an image to it. In the next module, we will learn how to deploy the serverless application.
Module 2: Deploy the serverless application
Introduction
In this module, we will be using kubectl to deploy Crossplane Resource Definitions (XRDs), Compositions, and a Claim in order to create and deploy the resources for the serverless application.
What you will learn
- Deploying Crossplane XRDs and Compositions
- Deploying a Claim to create serverless application
Implementation
Deploy XRDs and Compositions
Navigate to the following directory:
cd examples/upbound-aws-provider/composite-resources/serverless-examples/sqs-lambda-s3/
Examine and apply the kustomization.yaml file to create Crossplane XRDs and Compositions using the following command:
kubectl apply -k .
Verify the XRDs
kubectl get xrds
Expected output
NAME ESTABLISHED OFFERED AGE
eventsourcemappings.awsblueprints.io True 5m
iampolicies.awsblueprints.io True 5m
xlambdafunctions.awsblueprints.io True True 5m
xobjectstorages.awsblueprints.io True True 5m
xqueues.awsblueprints.io True True 5m
xserverlessapp.awsblueprints.io True True 5m
Verify the Compositions
kubectl get compositions
Expected output. Note: the output might contain more compositions but these are the ones uses by the claim in the next step
NAME XR-KIND XR-APIVERSION AGE
container.lambda.aws.upbound.awsblueprints.io XLambdaFunction awsblueprints.io/v1alpha1 5m
read-s3.iampolicy.awsblueprints.io IAMPolicy awsblueprints.io/v1alpha1 5m
read-sqs.iampolicy.awsblueprints.io IAMPolicy awsblueprints.io/v1alpha1 5m
s3bucket.awsblueprints.io XObjectStorage awsblueprints.io/v1alpha1 5m
sqs.esm.awsblueprints.io EventSourceMapping awsblueprints.io/v1alpha1 5m
sqs.queue.aws.upbound.awsblueprints.io XQueue awsblueprints.io/v1alpha1 5m
write-s3.iampolicy.awsblueprints.io IAMPolicy awsblueprints.io/v1alpha1 5m
xsqslambdas3.awsblueprints.io XServerlessApp awsblueprints.io/v1alpha1 5m
Update and apply the claim
Set the image name and AWS region in the claim with the ones set in Module 1 where the docker image is uploaded to ECR.
export AWS_REGION=<replace-with-aws-region> # example `us-east-1`
export IMAGE_NAME=<replace-with-image-name> # example `lambda-test`
Change the default value for CLAIM_NAME with any name you choose.
export CLAIM_NAME=<replace-with-claim-name> # example `test-sqs-lambda-s3`
Run the below command to use the template file sqs-lambda-s3-claim-tmpl.yaml in the claim folder to create the claim file with the variables CLAIM_NAME, IMAGE_NAME, and AWS_REGION substituted.
envsubst < "claim/sqs-lambda-s3-claim-tmpl.yaml" > "claim/sqs-lambda-s3-claim.yaml"
Check that the claim populated with values
cat claim/sqs-lambda-s3-claim.yaml
Apply the claim
kubectl apply -f claim/sqs-lambda-s3-claim.yaml
Validate the claim
kubectl get serverlessapps
Expected result (it might take sometime before READY=True)
NAME SYNCED READY CONNECTION-SECRET AGE
test-sqs-lambda-s3 True True 20m
The claim will use the XRDs and Compositions created in the previous section to create the following resources:
Each XR in the diagram contains the underlying resource refs:
kubectl describe xserverlessapp | grep "Resource Refs" -A 18
Expected output:
Resource Refs:
API Version: awsblueprints.io/v1alpha1
Kind: XQueue
Name: test-sqs-lambda-s3-hc2m5-7qwnb
API Version: awsblueprints.io/v1alpha1
Kind: EventSourceMapping
Name: test-sqs-lambda-s3-hc2m5-9q2kf
API Version: awsblueprints.io/v1alpha1
Kind: XLambdaFunction
Name: test-sqs-lambda-s3-hc2m5-processor
API Version: awsblueprints.io/v1alpha1
Kind: XObjectStorage
Name: test-sqs-lambda-s3-hc2m5-mbqcc
API Version: awsblueprints.io/v1alpha1
Kind: IAMPolicy
Name: test-sqs-lambda-s3-hc2m5-jspzj
API Version: awsblueprints.io/v1alpha1
Kind: IAMPolicy
Name: test-sqs-lambda-s3-hc2m5-2qzfl
Conclusion
In this module, we defined and grouped resources using Crossplane’s XRDs and Compositions. We then used a Claim to create those resources in order to deploy a serverless application.
Module 3: Test
Introduction
In this module we will test the serverless application by sending a message to the newly created SQS queue so we can observe it triggering the Lambda function and publishing the result into the S3 bucket.
What you will learn
- Pushing messages to SQS using the AWS CLI.
- Exploring the AWS SQS, Lambda, and S3 consoles.
Implementation
Use the following command to get the SQS URL and store it in $SQS_URL environment variable
SQS_URL=$(aws sqs list-queues --output json | jq -r '.QueueUrls|map(select(contains("test-sqs-lambda-s3"))) | .[0]' | tr -d '[:space:]')
The command will only store the first url that contains test-sqs-lambda-s3 in the name. Validate you have the correct url:
echo $SQS_URL
Send a message to the queue.
aws sqs send-message --queue-url $SQS_URL --message-body abc
Or send 100 messages to the queue.
for i in {1..100}; do aws sqs send-message --queue-url $SQS_URL --message-body abc ; done
Navigate to the AWS console and observe the SQS triggering the Lambda, and publishing the result in the S3 bucket.
Conclusion
In this module, we tested the serverless application by sending messages to the SQS queue to verify that it triggers the Lambda function and publishes the result to the S3 bucket.
Module 4: Clean up resources
Introduction
You have now completed this guide, but you still need to clean up the resources created during this guide.
What you will learn
- How to remove Crossplane resources
- How to destroy EKS cluster if created via this terraform code.
Implementation
Remove Crossplane Resources
Delete the repository
aws ecr delete-repository $IMAGE_NAME
Navigate to the following directory
cd examples/upbound-aws-provider/composite-resources/serverless-examples/sqs-lambda-s3/
Remove the claim
kubectl delete -f claim/sqs-lambda-s3-claim.yaml
Validate the claim was removed
kubectl get serverlessapp
Should return no claims.
Navigate to the AWS Console and check that the SQS, Lambda function, and S3 bucket are deleted.
Once deleted, remove the XRDs and Compositions:
kubectl delete -k .
Remove the EKS cluster
If you created EKS cluster with the instructions from this Readme, use the included destroy.sh script to remove it.
Navigate to the following directory:
cd bootstrap/terraform/
Execute the destroy.sh script
./destroy.sh
Conclusion
Congratulations! You have finished the Deploy a Serverless Application using Crossplane on EKS getting started guide. Continue your journey with AWS by following other examples in the Crossplane on EKS repository.