Component | Version |
---|---|
JDK | 21 |
Spring Cloud | 2023.0.0 |
Spring Boot | 3.2.1 |
$ sdk use java 21.0.1-graal
$ ./mvnw -ntp clean verify -U
- Run the following commands
$ docker-compose up
- Make a call
The service responds
$ curl --location --request POST 'http://localhost:4566/restapis/<restApiId>/compose/_user_request_/somePathId' \ --header 'Content-Type: application/json' \ --data-raw '{ "body": "{ \"name\": \"CoffeeBeans\" }" }'
[ { "name": "CoffeeBeans", "saved": true } ]
- Run the following commands
The service starts in less than 100 ms
$ export SPRING_PROFILES_ACTIVE=local $ ./mvnw -ntp clean -Pnative -DskipTests native:compile package -pl spring-native-aws-lambda-function $ ./spring-native-aws-lambda-function/target/spring-native-aws-lambda-function
2022-12-07 02:56:51.706 INFO 42417 --- [ main] c.c.s.Application : Starting Application using Java 17.0.4 2022-12-07 02:56:51.706 INFO 42417 --- [ main] c.c.s.Application : No active profile set, falling back to 1 default profile: "default" 2022-12-07 02:56:51.723 INFO 42417 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-12-07 02:56:51.724 INFO 42417 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-12-07 02:56:51.724 INFO 42417 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.68] 2022-12-07 02:56:51.733 INFO 42417 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-12-07 02:56:51.733 INFO 42417 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 27 ms 2022-12-07 02:56:51.761 INFO 42417 --- [ main] o.s.c.f.web.mvc.FunctionHandlerMapping : FunctionCatalog: org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry@7efd575 2022-12-07 02:56:51.763 INFO 42417 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-12-07 02:56:51.763 INFO 42417 --- [ main] c.c.s.Application : Started Application in 0.084 seconds (JVM running for 0.087)
- Make a call
The service responds
$ curl --location --request POST 'http://localhost:8080' \ --header 'Content-Type: application/json' \ --data-raw '{ "body": "{ \"name\": \"CoffeeBeans\" }" }'
[ { "name": "CoffeeBeans", "saved": true } ]
- Create an Identity providers in AWS for github actions.
- Create a new
CoffeebeansCoreGithubActions
Iam role with the following inline IAM policy
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-lookup-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-file-publishing-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-image-publishing-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-cfn-exec-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-deploy-role-{aws-account-number}-{aws-region}"
],
"Effect": "Allow"
}
]
}
and the following trust relationship
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::{aws-account-number}:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:{github-account-or-org}/spring-native-aws-lambda:*"
}
}
}
]
}
- Create a new
CDKBootstrapForCoffeebeansCore
IAM role for CDK bootstrap with the following IAM managed policyCoffeebeansCoreCdkBootstrapAccess
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECRPermissions",
"Effect": "Allow",
"Action": [
"ecr:CreateRepository",
"ecr:DeleteRepository",
"ecr:SetRepositoryPolicy",
"ecr:DescribeRepositories"
],
"Resource": "arn:aws:ecr:{aws-region}:{aws-account-number}:repository/cdk-{qualifier}-container-assets-{aws-account-number}-{aws-region}"
},
{
"Sid": "IAMPermissions",
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:CreateRole",
"iam:DeleteRole",
"iam:AttachRolePolicy",
"iam:PutRolePolicy",
"iam:DetachRolePolicy",
"iam:DeleteRolePolicy"
],
"Resource": [
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-lookup-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-file-publishing-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-image-publishing-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-cfn-exec-role-{aws-account-number}-{aws-region}",
"arn:aws:iam::{aws-account-number}:role/cdk-{qualifier}-deploy-role-{aws-account-number}-{aws-region}"
]
},
{
"Sid": "S3Permissions",
"Effect": "Allow",
"Action": [
"s3:PutBucketPublicAccessBlock",
"s3:CreateBucket",
"s3:DeleteBucketPolicy",
"s3:PutEncryptionConfiguration",
"s3:GetEncryptionConfiguration",
"s3:PutBucketPolicy",
"s3:DeleteBucket",
"s3:PutBucketVersioning"
],
"Resource": [
"arn:aws:s3:::{qualifier}-cdk-bucket"
]
},
{
"Sid": "SSMPermissions",
"Effect": "Allow",
"Action": [
"ssm:DeleteParameter",
"ssm:AddTagsToResource",
"ssm:GetParameters",
"ssm:PutParameter"
],
"Resource": "arn:aws:ssm:{aws-region}:{aws-account-number}:parameter/cdk-bootstrap/{qualifier}/version"
}
]
}
- Create an IAM managed policy
CoffeebeansCoreCdkExecutionAccess
to be used bycdk-{qualifier}-cfn-exec-role-{aws-account-number}-{aws-region}
which is gonna be created by CDK
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Permissions",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::{qualifier}-cdk-bucket",
"arn:aws:s3:::{qualifier}-cdk-bucket/*"
]
},
{
"Sid": "AGWPermissions",
"Effect": "Allow",
"Action": [
"apigateway:POST",
"apigateway:DELETE",
"apigateway:GET",
"apigateway:PATCH",
"apigateway:PUT"
],
"Resource": [
"arn:aws:apigateway:{aws-region}::/restapis",
"arn:aws:apigateway:{aws-region}::/restapis/*",
"arn:aws:apigateway:{aws-region}::/account"
]
},
{
"Sid": "SNSPermissions",
"Effect": "Allow",
"Action": [
"SNS:CreateTopic",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:GetTopicAttributes",
"SNS:ListSubscriptionsByTopic",
"SNS:Unsubscribe",
"SNS:TagResource",
"SNS:UntagResource"
],
"Resource": [
"arn:aws:sns:{aws-region}:{aws-account-number}:spring-native-aws-lambda-function-dead-letter-topic"
]
},
{
"Sid": "LambdaPermissions",
"Effect": "Allow",
"Action": [
"lambda:GetFunction",
"lambda:ListFunctions",
"lambda:DeleteFunction",
"lambda:CreateFunction",
"lambda:TagResource",
"lambda:AddPermission",
"lambda:RemovePermission",
"lambda:PutFunctionEventInvokeConfig",
"lambda:DeleteFunctionEventInvokeConfig",
"lambda:UpdateFunctionEventInvokeConfig",
"lambda:UpdateFunctionCode",
"lambda:ListTags",
"lambda:UpdateFunctionConfiguration"
],
"Resource": [
"arn:aws:lambda:{aws-region}:{aws-account-number}:function:spring-native-aws-lambda-function",
"arn:aws:lambda:{aws-region}:{aws-account-number}:function:spring-native-aws-lambda-function:$LATEST"
]
},
{
"Sid": "SSMPermissions",
"Effect": "Allow",
"Action": [
"ssm:GetParameters"
],
"Resource": [
"arn:aws:ssm:{aws-region}:{aws-account-number}:parameter/cdk-bootstrap/{qualifier}/version"
]
},
{
"Sid": "IAMPermissions",
"Effect": "Allow",
"Action": [
"iam:PassRole",
"iam:GetRole",
"iam:GetRolePolicy",
"iam:CreateRole",
"iam:PutRolePolicy",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy"
],
"Resource": [
"arn:aws:iam::{aws-account-number}:role/spring-native-aws-lambda-springnativeawslambdafun-*",
"arn:aws:iam::{aws-account-number}:role/spring-native-aws-lambda-springnativeawslambdares-4FVJBBHF9EL2",
"arn:aws:iam::{aws-account-number}:role/spring-native-aws-lambda-function-rest-api/CloudWatchRole"
]
},
{
"Sid": "CFNPermissions",
"Effect": "Allow",
"Action": "cloudformation:DescribeStacks",
"Resource": "arn:aws:cloudformation:{aws-region}:{aws-account-number}:stack/{qualifier}-example-function-dev-stack/*"
}
]
}
- Run the following command to bootstrap the CDK
cdk bootstrap aws://{aws-account-number}/{aws-region} --profile cdk \
--role-arn arn:aws:iam::{aws-account-number}:role/CDKBootstrapForCoffeebeansCore \
--cloudformation-execution-policies "arn:aws:iam::{aws-account-number}:policy/CoffeebeansCoreCdkExecutionAccess" \
--toolkit-stack-name cdk-{qualifier}-toolkit \
--toolkit-bucket-name {qualifier}-cdk-bucket \
--qualifier {qualifier} \
--tags COST_CENTRE=coffeebeans-core
NOTE: notice that the policy passed to --cloudformation-execution-policies
option is the one
we created
in step 4
Now that the setup is done you can deploy to AWS.
- Create a new release in Github releases page, the github action will start and a deployment to AWS environment.
- Test via curl
$ curl --location --request POST 'https://{api-id}.execute-api.ap-southeast-2.amazonaws.com/dev/name' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "CoffeeBeans" }'
- Et voila! It runs with 500 ms for cold start.