This project is created to demonstrate how-to deploy to AWS using IaC (Java and CDK).
We start simpe by just deploying a simple lambda function. Going on to deploy an Quarks application with MicroProfile to get an REST endpoint.
As we like to persist data in our REST endpoint we add DynamoDb.
By default AWS do not support JDK 17 and we add a JDK 17 layer to be able to use JDK 17 in our application.
As we expect our application to really take of we add an ApplicationLoadBalancer in front and see how we now have done a "hot deployment" via the health endpoint.
All code in this demo will be in Java - IaC and the application.
-
Introduction to AWS CDK
-
aws-cdk-demo-simple-lambda
-
aws-cdk-demo-hello-world-http
-
aws-cdk-demo-hello-world-rest
-
todo-app-h2
-
aws-cdk-demo-st
-
aws-cdk-demo
-
aws-cdk-demo-dynamodb-todo
-
aws-cdk-demo-dynamodb-todo-jdk17
-
aws-cdk-demo-dynamodb-todo-jdk17-alb
-
aws-cdk-demo-dynamodb-todo-jdk17-sam (only on request)
The AWS Cloud Development Kit (AWS CDK) is an open-source software development framework to define your cloud application resources using familiar programming languages.
An AWS CDK app is an application written in TypeScript, JavaScript, Python, Java, C# or Go that uses the AWS CDK to define AWS infrastructure. An app defines one or more stacks. Stacks (equivalent to AWS CloudFormation stacks) contain constructs, each of which defines one or more concrete AWS resources, such as Amazon S3 buckets, Lambda functions, Amazon DynamoDB tables, and so on.
The AWS CDK has first-class support for TypeScript, JavaScript, Python, Java, C#, and Go. Other JVM and .NET CLR languages may also be used, at least in theory, but we are unable to offer support for them at this time.
Deploying stacks with the AWS CDK requires dedicated Amazon S3 buckets and other containers to be available to AWS CloudFormation during deployment. Creating these is called bootstrapping.
cdk bootstrap --profile lambda_user
-
Show the lambda funtion
-
Show lambda handler
-
Show the CKD code (including cdk.json)
-
Show
cdk diff
after change to function -
Do live deployment to AWS
-
Use/Test lambda function
public String onEvent(Map<String, String> event) {
System.out.println("received: " + event);
return event
.entrySet()
.stream()
.map(e -> e.getKey() + "->" + e.getValue())
.collect(Collectors.joining(","));
}
static String lambdaHandler = "dk.jarry.aws.lambda.greetings.boundary.Greetings::onEvent";
#!/bin/sh
set -e
echo "building functions"
mvn clean package
echo "building and deploy - CDK"
cd cdk && mvn clean package && cdk deploy $PROFILE
cdk diff
after change to function (mvn clean package)Stack aws-lambda-cdk-plain Resources [~] AWS::Lambda::Function dk_jarry_aws_lambda_greetings_boundary_Greetings dkjarryawslambdagreetingsboundaryGreetingsDCA7FDA8 ├─ [~] Code │ └─ [~] .S3Key: │ ├─ [-] 4efad5ac647d6e70d8b21628811edfdb86f9042902d462bcb70ccd8bf4c1ab98.jar │ └─ [+] 8a6de566201c0ce68f1b15fab8bad8ed5215fa850b74d7325af9bb8b1493691e.jar └─ [~] Metadata └─ [~] .aws:asset:path: ├─ [-] asset.4efad5ac647d6e70d8b21628811edfdb86f9042902d462bcb70ccd8bf4c1ab98.jar └─ [+] asset.8a6de566201c0ce68f1b15fab8bad8ed5215fa850b74d7325af9bb8b1493691e.jar
-
UnitTest
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo-simple-lambda && code -n .
-
Show the Quarkus app with MicroProfile
-
Show how to test the app on localhost
-
Show the CKD code (http)
-
Show lambda handler
mvn io.quarkus.platform:quarkus-maven-plugin:2.11.2.Final:create \ -DprojectGroupId=dk.jarry.aws \ -DprojectArtifactId=aws-cdk-demo-hello-world-http \ -DclassName="dk.jarry.aws.HelloResource" \ -Dpath="/hello" \ -Dextensions="quarkus-resteasy"
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-lambda-http</artifactId>
</dependency>
@Path("/hello")
public class HelloResource {
@Inject
@ConfigProperty(defaultValue = "hello, quarkus on localhost", name="message")
String message;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return message;
}
}
Expected output : hello, quarkus on localhost
Expected output : Hello World - Quarkus as AWS Lambda
static String lambdaHandler = "io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest";
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo-hello-world-http && code -n .
-
Show the CKD code (rest)
mvn io.quarkus.platform:quarkus-maven-plugin:2.11.2.Final:create \ -DprojectGroupId=dk.jarry.aws \ -DprojectArtifactId=aws-cdk-demo-hello-world-http \ -DclassName="dk.jarry.aws.HelloResource" \ -Dpath="/hello" \ -Dextensions="quarkus-resteasy"
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-lambda-rest</artifactId>
</dependency>
@Path("/hello")
public class HelloResource {
@Inject
@ConfigProperty(defaultValue = "hello, quarkus on localhost", name="message")
String message;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return message;
}
}
var apiGateway = LambdaRestApi.Builder
.create(this, "RestApiGateway")
.handler(function)
.build();
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo-hello-world-rest && code -n .
-
Introduce the ToDo Quarkus application.
-
Start the ToDo Quarkus application on localhost.
mvn compile quarkus:dev
cd ~/git/jarrydk/aws-cdk-demo/todo-app-h2 && code -n .
Tip
|
todo-app-h2 app need to be up running before going forward. |
-
Introduce the ToDo SystemTest.
mvn compile quarkus:dev
mvn compile quarkus:dev -Dquarkus.rest-client.extensions-api.url=http://localhost:8080
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo-st && code -n .
Tip
|
Upload the java17layer.zip to the bucket aws-cdk-demo-lamda-layers with the script s3_upload_java17layers_to_aws-cdk-demo-lamda-layers.sh before creating the layer.
|
-
Show how to create a DynamoDB table (L1)
-
Show how to create a Role (L2)
-
Show how to create a Bucket (L1)
-
Show how to create a Layer (L1)
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo && code -n .
-
Show how the app is using DynamoDB
-
Show how to test the app on localhost
-
Show how to create the DynamoDB database and table for AWS
-
Show how to create a Role for AWS and use it
podman run -it \
--publish 8000:8000 \
amazon/dynamodb-local:1.11.477 \
-jar DynamoDBLocal.jar -inMemory -sharedDb
Access : http://localhost:8000/shell
var params = {
TableName: 'ToDos',
KeySchema: [{ AttributeName: 'uuid', KeyType: 'HASH' }],
AttributeDefinitions: [{ AttributeName: 'uuid', AttributeType: 'S', }],
ProvisionedThroughput: { ReadCapacityUnits: 1, WriteCapacityUnits: 1, }
};
dynamodb.createTable(params, function(err, data) {
if (err) ppJson(err);
else ppJson(data);
});
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo-dynamodb-todo && code -n .
-
Show how to add a java17 layer
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo-dynamodb-todo-jdk17 && code -n .
-
Show how to setup ApplicationLoadBalancer
-
Manual enable
enable-multi-value-header
cd ~/git/jarrydk/aws-cdk-demo/aws-cdk-demo-dynamodb-todo-jdk17-alb && code -n .
Same as aws-cdk-demo-dynamodb-todo-jdk17
but deployed via SAM.
Build the java17layer layer from https://github.com/msailes/lambda-java17-layer or use the one in this project.
curl -X POST http://localhost:8080/todos \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"subject":"Hello from Quarkus","body":"Content"}'
./create_todo.sh http://localhost:8080/todos
curl http://localhost:8080/todos/db50ec51-99cf-4972-a435-50ea3701c78a
./read_todo.sh http://localhost:8080/todos db50ec51-99cf-4972-a435-50ea3701c78a
-
cdk bootstrap
deploy AWS CDK into AWS into environment -
cdk ls
list all stacks in the app -
cdk synth
emits the synthesized CloudFormation template -
cdk deploy
deploy this stack to your default AWS account/region -
cdk diff
compare deployed stack with current state -
cdk docs
open CDK documentation
[default] aws_access_key_id = Tm90IGEgSm9rZSEh aws_secret_access_key = QXJlIHlvdSBraWRkaW5nIG1l [lambda_user] aws_access_key_id = Tm90IGEgSm9rZSEh aws_secret_access_key = QXJlIHlvdSBraWRkaW5nIG1l
[default] region = eu-central-1 output = json
import com.pulumi.Pulumi;
import com.pulumi.aws.s3.Bucket;
public class App {
public static void main(String[] args) {
Pulumi.run(ctx -> {
// Create an AWS resource (S3 Bucket)
var bucket = new Bucket("my-bucket");
// Export the name of the bucket
ctx.export("bucketName", bucket.getId());
});
}
}
-
https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html
-
https://github.com/aws-samples/aws-cdk-examples/tree/master/java
-
https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html
-
https://thorben-janssen.com/generate-uuids-primary-keys-hibernate/
-
https://stackoverflow.com/questions/6356834/using-hibernate-uuidgenerator-via-annotations