## page was renamed from AWS/Localstack <> = Localstack = https://github.com/localstack/localstack [[AWS/LocalStack|LocalStack]] is a cloud service emulator that runs in a single container on your laptop or in your CI environment. With [[AWS/LocalStack|LocalStack]], you can run your AWS applications or Lambdas entirely on your local machine without connecting to a remote cloud provider == AWS CLI installation == {{{#!highlight sh # https://aws.amazon.com/cli/ cd ~/Downloads curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install /usr/local/bin/aws --version # aws-cli/2.33.12 Python/3.13.11 Linux/6.1.0-42-amd64 exe/x86_64.debian.12 export AWS_ACCESS_KEY_ID="test" export AWS_SECRET_ACCESS_KEY="test" export AWS_DEFAULT_REGION="us-east-1" export AWS_ENDPOINT_URL="http://localhost:4566/" }}} == Localstack in Debian == {{{#!highlight sh docker run --rm -it -p 127.0.0.1:4566:4566 -p 127.0.0.1:4510-4559:4510-4559 \ -v /var/run/docker.sock:/var/run/docker.sock --name localstack localstack/localstack # LocalStack version: 4.13.1.dev6 sudo apt install jq curl http://localhost:4566/_localstack/health | jq . export AWS_ACCESS_KEY_ID="test" export AWS_SECRET_ACCESS_KEY="test" export AWS_DEFAULT_REGION="us-east-1" export AWS_ENDPOINT_URL="http://localhost:4566/" aws s3 ls aws s3api create-bucket --bucket my-bucket # https://docs.aws.amazon.com/cli/latest/reference/s3api/ echo "test" > test.txt aws s3api put-object --bucket my-bucket --key dir-1/test.txt --body test.txt aws s3api get-object --bucket my-bucket --key dir-1/test.txt test2.txt cat test2.txt }}} == Python lambda and s3 == === run.sh === {{{#!highlight sh export AWS_ACCESS_KEY_ID="test" export AWS_SECRET_ACCESS_KEY="test" export AWS_DEFAULT_REGION="us-east-1" export AWS_ENDPOINT_URL="http://localhost:4566/" zip py-my-function.zip lambda_function.py aws lambda delete-function --function-name py-my-function aws lambda create-function --function-name py-my-function \ --zip-file fileb://py-my-function.zip --handler lambda_function.lambda_handler \ --runtime python3.13 --role arn:aws:iam::000000000000:role/lambda-ex \ --timeout 30 PAYLOAD=$( echo "{ \"first_name\": \"Bob\",\"last_name\":\"Squarepants\" }" | base64 ) aws lambda invoke --function-name py-my-function \ --payload $PAYLOAD \ response.json cat response.json aws s3api get-object --bucket examplebucket --key examplebucket/response.txt r.txt }}} === lambda_function.py === {{{#!highlight python import boto3 import os def lambda_handler(event, context): message = 'Hello {} {}!'.format(event['first_name'], event['last_name']) session = boto3.session.Session() s3 = session.client( service_name='s3' ) buckets=[] for bucket in s3.list_buckets()['Buckets']: buckets.append(bucket['Name']) response = s3.create_bucket(Bucket='examplebucket') body = { 'message' : message, 'buckets' : buckets, 'AWS_ACCESS_KEY_ID' : os.environ["AWS_ACCESS_KEY_ID"], 'AWS_SECRET_ACCESS_KEY' : os.environ["AWS_SECRET_ACCESS_KEY"], 'AWS_DEFAULT_REGION' : os.environ["AWS_DEFAULT_REGION"], 'AWS_ENDPOINT_URL': os.environ['AWS_ENDPOINT_URL'] } s3.put_object(Body=str(body), Bucket='examplebucket', Key='examplebucket/response.txt') return body }}} == Access localstack from docker container == {{{#!highlight bash docker run -d --name localstack --rm -it -p 4566:4566 -p 4571:4571 -v /var/run/docker.sock:/var/run/docker.sock localstack/localstack # run container docker exec -it localstack bash # connect to container cat /etc/os-release | grep -i pretty # PRETTY_NAME="Debian GNU/Linux 13 (trixie)" curl http://localhost:4566/_localstack/health awslocal s3api list-buckets awslocal s3api create-bucket --bucket my-bucket echo "test" > test.txt awslocal s3api put-object --bucket my-bucket --key dir-1/test.txt --body test.txt awslocal s3api get-object --bucket my-bucket --key dir-1/test.txt test2.txt cat test2.txt apt install nano vim yajl-tools -y # https://hub.docker.com/r/localstack/localstack # https://github.com/localstack/localstack node -v # v22.22.0 python -V # Python 3.13.11 pip3 freeze curl http://localhost:4566/_localstack/health | json_reformat awslocal ec2 run-instances --image-id prod-df2jln3gjtwps --count 1 --instance-type t2.micro awslocal ec2 describe-instances --filters "Name=instance-type,Values=t2.micro" --query "Reservations[].Instances[].InstanceId" awslocal ec2 describe-instances }}} == Java8 lambda handler == Lambda image https://github.com/aws/aws-lambda-base-images/tree/java21 * public.ecr.aws/lambda/java:21 === Steps === {{{#!highlight sh mkdir -p ~/Documents/Java8LambdaHandler cd ~/Documents/Java8LambdaHandler mkdir -p src/main/java/com/mooo/bitarus/ }}} === build.sh === {{{#!highlight sh FUNCTION_NAME=lambda-function aws lambda delete-function --function-name $FUNCTION_NAME sleep 5 mvn clean install sleep 5 aws lambda create-function --function-name $FUNCTION_NAME \ --zip-file fileb://target/lambda-function-1.0-SNAPSHOT.jar \ --handler com.mooo.bitarus.Handler --runtime java21 \ --role arn:aws:iam::000000000000:role/lambda-ex --timeout 30 #awslocal lambda update-function-configuration --function-name $FUNCTION_NAME \ # --timeout 15 sleep 15 }}} === latest_log.sh === {{{#!highlight sh LOG_GROUP="/aws/lambda/lambda-function" LOG_STREAM=$(aws logs describe-log-streams \ --log-group-name $LOG_GROUP \ --order-by LastEventTime --descending | \ grep logStreamName | head -1 | awk '//{print $2}' | sed "s/,//g" | sed 's/\"//g' ) echo $LOG_GROUP echo $LOG_STREAM aws logs get-log-events --log-group-name $LOG_GROUP \ --log-stream-name "$LOG_STREAM" \ | grep message | sed 's/"message"\://g' | sed 's/ //g' }}} === pom.xml === {{{#!highlight xml 4.0.0 com.mooo.bitarus lambda-function jar 1.0-SNAPSHOT lambda-function UTF-8 21 21 com.amazonaws aws-lambda-java-core 1.3.0 com.google.code.gson gson 2.10.1 maven-surefire-plugin 2.22.2 org.apache.maven.plugins maven-shade-plugin 3.2.2 false package shade org.apache.maven.plugins maven-compiler-plugin 3.8.1 21 21 }}} === run.sh === {{{#!highlight sh PAYLOAD=$( echo "{\"first_name\": \"Bob\",\"last_name\":\"Marley\"}" | base64 ) #aws lambda wait function-active-v2 --function-name lambda-function aws lambda invoke --function-name lambda-function \ --payload $PAYLOAD response.json cat response.json }}} === src/main/java/com/mooo/bitarus/Handler.java === {{{#!highlight java package com.mooo.bitarus; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.Map; import java.util.HashMap; public class Handler implements RequestHandler, String>{ Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(Map event, Context context) { LambdaLogger logger = context.getLogger(); System.out.println(">>> sout test"); logger.log("Stuff logged"); String response = "Java Lambda invocation response 20260131"; logger.log( event.get("first_name") ); logger.log("EVENT TYPE: " + event.getClass()); Map hashReturn = new java.util.HashMap(); hashReturn.put("response",response); return gson.toJson(hashReturn); } } }}} == SPA app + API gateway + lambda function == To host a SPA (Single Page Application) in LocalStack that uses API Gateway, we must simulate the AWS environment where Amazon S3 acts as a static file web server and API Gateway acts as the backend calling lambda functions. Localstack complete flow: * The user goes to S3 URL in the browser * The browser downloads index.html and the SPA JavaScript from S3 (LocalStack). * The SPA makes a POST call to an API Gateway endpoint (LocalStack). * API Gateway triggers a Lambda Java (that makes the sent string uppercase). * Lambda returns a JSON and the SPA updates its screen with the JSON data