Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
410 changes: 410 additions & 0 deletions .github/workflows/publish-release.yml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ __pycache__/

# AWS SAM
.aws-sam/
/bootstrap/template.release.yaml
/release/

# Benchmark output
benchmark-results/
Expand Down
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ SAM_DEPLOY_FLAGS ?= --resolve-s3 --capabilities CAPABILITY_IAM --no-confirm-chan
BOOTSTRAP_STACK_NAME ?= khone-bootstrap
BOOTSTRAP_TEMPLATE ?= bootstrap/template.yaml
BOOTSTRAP_BUCKET ?=
GATEWAY_CODE_S3_BUCKET ?=
GATEWAY_CODE_S3_KEY ?=
GATEWAY_CODE_S3_OBJECT_VERSION ?=

.PHONY: help
help:
Expand Down Expand Up @@ -60,7 +63,10 @@ print-vars: check
"EXAMPLE_TEMPLATE_DIR=$(EXAMPLE_TEMPLATE_DIR)" \
"BOOTSTRAP_STACK_NAME=$(BOOTSTRAP_STACK_NAME)" \
"BOOTSTRAP_TEMPLATE=$(BOOTSTRAP_TEMPLATE)" \
"BOOTSTRAP_BUCKET=$(BOOTSTRAP_BUCKET)"
"BOOTSTRAP_BUCKET=$(BOOTSTRAP_BUCKET)" \
"GATEWAY_CODE_S3_BUCKET=$(GATEWAY_CODE_S3_BUCKET)" \
"GATEWAY_CODE_S3_KEY=$(GATEWAY_CODE_S3_KEY)" \
"GATEWAY_CODE_S3_OBJECT_VERSION=$(GATEWAY_CODE_S3_OBJECT_VERSION)"

.PHONY: check-example-template
check-example-template:
Expand Down Expand Up @@ -115,6 +121,9 @@ bootstrap-deploy: check bootstrap-build
export AWS_REGION="$(AWS_REGION)" AWS_DEFAULT_REGION="$(AWS_REGION)"; \
params=(); \
if [[ -n "$(BOOTSTRAP_BUCKET)" ]]; then params+=("UseExistingBucket=$(BOOTSTRAP_BUCKET)"); fi; \
if [[ -n "$(GATEWAY_CODE_S3_BUCKET)" ]]; then params+=("GatewayCodeS3Bucket=$(GATEWAY_CODE_S3_BUCKET)"); fi; \
if [[ -n "$(GATEWAY_CODE_S3_KEY)" ]]; then params+=("GatewayCodeS3Key=$(GATEWAY_CODE_S3_KEY)"); fi; \
if [[ -n "$(GATEWAY_CODE_S3_OBJECT_VERSION)" ]]; then params+=("GatewayCodeS3ObjectVersion=$(GATEWAY_CODE_S3_OBJECT_VERSION)"); fi; \
deploy_args=( \
--stack-name "$(BOOTSTRAP_STACK_NAME)" \
--template-file bootstrap/.aws-sam/build/template.yaml \
Expand Down
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,34 @@ caveats, and links to the sanitized reports.

## Current Deployment Model

- The `KhoneGateway` macro publishes the gateway config/spec artifact to S3.
- User templates define the gateway as an explicit `AWS::Serverless::Function`.
- The gateway reads `KHONE_CONFIG_URI` from `!GetAtt <GatewayConfig>.ConfigS3Uri`.
- SAM `CapacityProviderConfig` attaches an existing LMI capacity provider.
- `FunctionUrlConfig.InvokeMode: RESPONSE_STREAM` exposes the HTTP interface.
- The `KhoneGateway` macro expands `Khone::Gateway::Service` into the gateway Lambda,
Function URL, execution role, and config publisher.
- Application stacks still bring an existing LMI capacity provider ARN.
- The SAR-installed bootstrap stack carries the versioned gateway Lambda zip location.
- `Khone::Gateway::Service` configures gateway memory, scaling, environment, and route spec.
- The generated Function URL uses `InvokeMode: RESPONSE_STREAM` and defaults to `AuthType: NONE`.

Deployment resources stay explicit in your SAM template; the macro is only responsible for the
gateway config artifact.
The gateway source package no longer needs to be part of each application deployment path.

## Quick Start

```bash
make bootstrap-deploy
cargo lambda build --release --arm64 --output-format zip -p khone-gateway
aws s3 cp target/lambda/khone-gateway/bootstrap.zip \
"s3://$GATEWAY_ARTIFACT_BUCKET/khone/dev/gateway/bootstrap.zip"
make bootstrap-deploy \
GATEWAY_CODE_S3_BUCKET="$GATEWAY_ARTIFACT_BUCKET" \
GATEWAY_CODE_S3_KEY="khone/dev/gateway/bootstrap.zip"
make examples-sam-deploy GATEWAY_CAPACITY_PROVIDER_ARN=arn:aws:lambda:...
```

`examples-sam-deploy` defaults to the Node adapter, Mode B template. Set
`EXAMPLE_TEMPLATE` to `adapter-node`, `adapter-rust`, `layer-proxy-node`,
`layer-proxy-python`, or `native-batch-node` to deploy a specific example.

SAM Rust builds require `cargo-lambda` and `SAM_CLI_BETA_RUST_CARGO_LAMBDA=1`.
Released SAR bootstrap installs already set the gateway artifact location, so the source-built zip
step is only needed when deploying the bootstrap stack directly from this checkout. SAM Rust builds
require `cargo-lambda` and `SAM_CLI_BETA_RUST_CARGO_LAMBDA=1`.

## Documentation

Expand Down
92 changes: 27 additions & 65 deletions benchmark/sam/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,27 @@ Resources:
GatewayService:
Type: Khone::Gateway::Service
Properties:
CapacityProviderArn: !Ref GatewayCapacityProviderArn
FunctionName: !Sub '${AWS::StackName}-gateway'
Description: Khone benchmark router running on Lambda Managed Instances.
MemorySize: 2048
Timeout: 90
ExecutionEnvironmentMemoryGiBPerVCpu: 2.0
PerExecutionEnvironmentMaxConcurrency: 64
MinExecutionEnvironments: 4
MaxExecutionEnvironments: 4
Environment:
RUST_LOG: info
KHONE_DEBUG_RESPONSE_HEADERS: "1"
KHONE_EMF_METRICS: !If [EmfMetricsEnabledCondition, "1", !Ref AWS::NoValue]
KHONE_EMF_NAMESPACE: !If [EmfMetricsEnabledCondition, KhoneBenchmark, !Ref AWS::NoValue]
KHONE_EMF_HIGH_RES: !If [EmfMetricsEnabledCondition, "1", !Ref AWS::NoValue]
KHONE_OBSERVABILITY_VENDOR: !If [ObservabilityEnabledCondition, AWSXRAY, !Ref AWS::NoValue]
OTEL_PROPAGATORS: !If [ObservabilityEnabledCondition, "xray,tracecontext,baggage", !Ref AWS::NoValue]
OTEL_METRICS_EXPORTER: !If [ObservabilityEnabledCondition, "none", !Ref AWS::NoValue]
OTEL_SERVICE_NAME: !If [ObservabilityEnabledCondition, !Sub '${AWS::StackName}-gateway', !Ref AWS::NoValue]
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: !If [ObservabilityEnabledCondition, !Ref OtelTracesEndpoint, !Ref AWS::NoValue]
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: !If [ObservabilityEnabledCondition, !Ref OtelTracesProtocol, !Ref AWS::NoValue]
ConfigPrefix: !Sub 'khone/${AWS::StackName}/gateway/'
GatewayConfig:
DefaultTimeoutMs: 2000
Expand Down Expand Up @@ -376,65 +397,6 @@ Resources:
smoothingSamples: 10
warmupProbes: 3

GatewayFunction:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: rust-cargolambda
Properties:
CodeUri: ../../gateway
Handler: bootstrap
Runtime: provided.al2023
PackageType: Zip
FunctionName: !Sub '${AWS::StackName}-gateway'
Description: Khone benchmark router running on Lambda Managed Instances.
Architectures:
- arm64
MemorySize: 2048
Timeout: 90
CapacityProviderConfig:
Arn: !Ref GatewayCapacityProviderArn
ExecutionEnvironmentMemoryGiBPerVCpu: 2.0
PerExecutionEnvironmentMaxConcurrency: 64
FunctionScalingConfig:
MinExecutionEnvironments: 4
MaxExecutionEnvironments: 4
FunctionUrlConfig:
AuthType: NONE
InvokeMode: RESPONSE_STREAM
Environment:
Variables:
RUST_LOG: info
KHONE_CONFIG_URI: !GetAtt GatewayService.ConfigS3Uri
KHONE_DEBUG_RESPONSE_HEADERS: "1"
KHONE_EMF_METRICS: !If [EmfMetricsEnabledCondition, "1", !Ref AWS::NoValue]
KHONE_EMF_NAMESPACE: !If [EmfMetricsEnabledCondition, KhoneBenchmark, !Ref AWS::NoValue]
KHONE_EMF_HIGH_RES: !If [EmfMetricsEnabledCondition, "1", !Ref AWS::NoValue]
KHONE_OBSERVABILITY_VENDOR: !If [ObservabilityEnabledCondition, AWSXRAY, !Ref AWS::NoValue]
OTEL_PROPAGATORS: !If [ObservabilityEnabledCondition, "xray,tracecontext,baggage", !Ref AWS::NoValue]
OTEL_METRICS_EXPORTER: !If [ObservabilityEnabledCondition, "none", !Ref AWS::NoValue]
OTEL_SERVICE_NAME: !If [ObservabilityEnabledCondition, !Sub '${AWS::StackName}-gateway', !Ref AWS::NoValue]
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: !If [ObservabilityEnabledCondition, !Ref OtelTracesEndpoint, !Ref AWS::NoValue]
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: !If [ObservabilityEnabledCondition, !Ref OtelTracesProtocol, !Ref AWS::NoValue]
Policies:
- AWSLambdaBasicExecutionRole
- Statement:
- Sid: ReadGatewayConfig
Effect: Allow
Action: s3:GetObject
Resource: !Sub
- 'arn:${AWS::Partition}:s3:::${Bucket}/${Prefix}*'
- Bucket: !GetAtt GatewayService.BucketName
Prefix: !GetAtt GatewayService.Prefix
- Sid: InvokeTargetLambdas
Effect: Allow
Action:
- lambda:InvokeFunction
- lambda:InvokeWithResponseStream
Resource:
- !GetAtt SteadyFunction.Arn
- !GetAtt AdaptiveFunction.Arn
- !GetAtt TargetAwareFunction.Arn

Outputs:
BenchmarkBackendUrl:
Value: !GetAtt BackendFunctionUrl.FunctionUrl
Expand All @@ -443,7 +405,7 @@ Outputs:
Value: "steady,adaptive,target-aware,standard"

BenchmarkTargetsJson:
Value: !Sub '[{"name":"steady","url":"${GatewayFunctionUrl.FunctionUrl}steady"},{"name":"adaptive","url":"${GatewayFunctionUrl.FunctionUrl}adaptive"},{"name":"target-aware","url":"${GatewayFunctionUrl.FunctionUrl}target-aware"},{"name":"standard","url":"https://${DirectHttpApi}.execute-api.${AWS::Region}.amazonaws.com/std"}]'
Value: !Sub '[{"name":"steady","url":"${GatewayServiceKhoneFunctionUrl.FunctionUrl}steady"},{"name":"adaptive","url":"${GatewayServiceKhoneFunctionUrl.FunctionUrl}adaptive"},{"name":"target-aware","url":"${GatewayServiceKhoneFunctionUrl.FunctionUrl}target-aware"},{"name":"standard","url":"https://${DirectHttpApi}.execute-api.${AWS::Region}.amazonaws.com/std"}]'

SteadyFunctionArn:
Value: !GetAtt SteadyFunction.Arn
Expand All @@ -458,19 +420,19 @@ Outputs:
Value: !GetAtt STDFunction.Arn

GatewayFunctionUrl:
Value: !GetAtt GatewayFunctionUrl.FunctionUrl
Value: !GetAtt GatewayServiceKhoneFunctionUrl.FunctionUrl

GatewayServiceConfigS3Uri:
Value: !GetAtt GatewayService.ConfigS3Uri
Value: !GetAtt GatewayServiceKhoneConfigPublisher.ConfigS3Uri

SteadyUrl:
Value: !Sub "${GatewayFunctionUrl.FunctionUrl}steady"
Value: !Sub "${GatewayServiceKhoneFunctionUrl.FunctionUrl}steady"

AdaptiveUrl:
Value: !Sub "${GatewayFunctionUrl.FunctionUrl}adaptive"
Value: !Sub "${GatewayServiceKhoneFunctionUrl.FunctionUrl}adaptive"

TargetAwareUrl:
Value: !Sub "${GatewayFunctionUrl.FunctionUrl}target-aware"
Value: !Sub "${GatewayServiceKhoneFunctionUrl.FunctionUrl}target-aware"

StandardUrl:
Value: !Sub "https://${DirectHttpApi}.execute-api.${AWS::Region}.amazonaws.com/std"
2 changes: 1 addition & 1 deletion benchmark/src/charts/echarts/specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ function backendDelayLabel(metrics: MetricsBundle): string | null {
}

function gatewayLmiLabel(metrics: MetricsBundle): string | null {
const gateway = functionMetadata(metrics, ['GatewayFunction']);
const gateway = functionMetadata(metrics, ['GatewayService']);
if (!gateway) {
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion benchmark/test/render.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ test('latency distribution title includes run configuration context', async () =
},
functions: [
{
logical_id: 'GatewayFunction',
logical_id: 'GatewayService',
function_name: 'test-gateway',
function_arn: null,
runtime: 'provided.al2023',
Expand Down
6 changes: 3 additions & 3 deletions benchmark/test/report.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ test('report includes workload and deployed Lambda configuration', async () => {
},
functions: [
{
logical_id: 'GatewayFunction',
logical_id: 'GatewayService',
function_name: 'test-gateway',
function_arn: 'arn:aws:lambda:us-east-1:123456789012:function:test-gateway',
runtime: 'provided.al2023',
Expand Down Expand Up @@ -139,7 +139,7 @@ test('report includes workload and deployed Lambda configuration', async () => {
assert.match(text, /From rps/);
assert.match(text, /BenchmarkHandlerMemorySize/);
assert.match(text, /512/);
assert.match(text, /GatewayFunction/);
assert.match(text, /GatewayService/);
assert.match(text, /2048 MB/);
assert.match(text, /1\/4 envs/);
assert.match(text, /64 conc\/env/);
Expand Down Expand Up @@ -224,7 +224,7 @@ test('metrics json redacts infrastructure identifiers from public report data',
},
functions: [
{
logical_id: 'GatewayFunction',
logical_id: 'GatewayService',
function_name: 'test-gateway',
function_arn: 'arn:aws:lambda:us-east-1:123456789012:function:test-gateway',
runtime: 'provided.al2023',
Expand Down
4 changes: 4 additions & 0 deletions bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ The bootstrap stack installs the account/region resources used by application st
- `Custom::KhoneConfigPublisher`.
- `KhoneGateway` CloudFormation macro.
- shared Mode A runtime API proxy layers.
- versioned gateway Lambda artifact settings used by the macro.

See [Bootstrap macro](../docs/reference/bootstrap-macro.md) for the resource contract and
[SAM gateway](../docs/deploy/sam-gateway.md) for the application-stack pattern.

SAR release templates set the gateway artifact bucket/key defaults. Source deployments can pass
`GatewayCodeS3Bucket`, `GatewayCodeS3Key`, and optional `GatewayCodeS3ObjectVersion` explicitly.

Deploy from the repository root:

```bash
Expand Down
Loading