Cameleer

Cameleer / Use cases / Serverless

Serverless and scale to zero

Integration routes as functions, without the cold start

Integrations sit idle, then get busy all at once: the load serverless is priced for, and the load a JVM handles worst. Cameleer starts its routes in milliseconds, is its own AWS Lambda runtime, and runs the same route file in a container on Cloud Run, Knative or Azure Container Apps.

3 msfrom process start to routes running; Apache Camel on the JVM: 1.1 s, on Quarkus native: 30 ms
0layers, adapters or runtime libraries: the binary speaks the Lambda Runtime API
11.8 MBstatic function build with the cloud family; 7.5 MB with core
1 filethe same route runs on Lambda, in a container and as a binary

How the Lambda runtime works

When Lambda sets AWS_LAMBDA_RUNTIME_API, cameleer run starts the routes and then loops over the Runtime API instead of waiting for a signal. Nothing else changes in the route.

Events

  • HTTP events (API Gateway REST and HTTP APIs, function URLs, ALB) go to your platform-http routes as if they had come over a socket; the HTTP response becomes the proxy-integration response.
  • Other events (S3, SQS, EventBridge, direct invokes) go request-reply to the handler endpoint with the event JSON as the body; the reply body is the function result. The handler is the function's Handler setting when it is an endpoint URI (direct:orders), else camel.main.lambda-handler, else direct:lambda.
  • Headers: CamelAwsLambdaRequestId, CamelAwsLambdaDeadlineMs, CamelAwsLambdaFunctionArn, CamelAwsLambdaTraceId.

Failures and shutdown

  • A failed exchange is reported to the invocation's /error endpoint with the exception kind as errorType.
  • A startup failure (a bad route file, an unknown component) goes to /init/error.
  • Lambda sends SIGTERM before it retires a sandbox; routes stop gracefully. Status files are off; logs go to CloudWatch through stderr.

A handler route and its deployment

# orders.camel.yaml: an S3 or EventBridge event in, a JSON summary out
- route:
    from:
      uri: direct:lambda
      steps:
        - setBody:
            simple: '{"bucket":"${jsonpath($.Records[0].s3.bucket.name)}","ok":true}'
scripts/package-lambda.sh --arch x86_64 --features cloud --out function.zip orders.camel.yaml
aws lambda create-function --function-name orders --runtime provided.al2023 \
  --architectures x86_64 --handler direct:lambda --zip-file fileb://function.zip \
  --role arn:aws:iam::<account>:role/<role>

The zip holds bootstrap (the cameleer binary under the name Lambda starts) and your route files. --features keeps only the component families the routes use. Full details: AWS Lambda in the deployment guide.

Startup and size

runtime, same routestime to a started contextmemory at startup
Cameleer2.5 ms8 MB
Apache Camel (JVM)1106 ms114 MB
Apache Camel (Quarkus native)30 ms69 MB

Function builds

build (Linux x86-64)binaryHTTP route readyrun-once job donememory, HTTP route
all components, glibc23.9 MB1.17 ms2.15 ms10.4 MB
--features cloud, static musl11.8 MB0.75 ms1.48 ms5.3 MB
--features core, static musl7.5 MB0.69 ms1.41 ms4.2 MB

The first table is from the cloud benchmark (three identical machines, method in how we tested); the second from cameleer-bench coldstart on Linux x86-64, medians of 40 runs. In AWS's provided:al2023 image with the Lambda Runtime Interface Emulator, init took 3.5–5.2 ms and warm invocations 0.7–1.3 ms. Lambda's own sandbox start is added on top for every runtime. Details: BENCHMARKS.

Cloud Run, Knative, Container Apps, Fly.io

These run the image as it is: one native binary on distroless, non-root, fine with a read-only root filesystem, for linux/amd64 and linux/arm64.

What to set

  • Cloud Run sends requests to PORT, 8080 by default; if you change it, add --prop camel.server.port={{env:PORT:8080}}.
  • Health: /q/health/live and /q/health/ready with camel.server.healthCheckEnabled=true.
  • Images run with CAMEL_LOCAL_STATUS=false, so no status files are written.

What a 3 ms start buys

  • Scale to zero with no practical cold-start cost from Cameleer itself; min-instances can stay at 0.
  • Pack many small integrations onto one node: tens of MB each instead of hundreds.
  • Deploys and rollbacks that finish in the time a JVM takes to boot.

Common questions

Do I need a Lambda layer, adapter or runtime library?

No. When Lambda sets AWS_LAMBDA_RUNTIME_API, cameleer run starts the routes and serves the Runtime API itself on the provided.al2023 runtime. The zip holds the binary as bootstrap plus your route files.

Which events reach which routes?

API Gateway REST and HTTP APIs, function URLs and ALB events go to your platform-http routes in process, and the HTTP response becomes the proxy-integration response. Other events (S3, SQS, EventBridge, direct invokes) go request-reply to the handler endpoint: the function's Handler setting when it is an endpoint URI, else camel.main.lambda-handler, else direct:lambda.

How fast is a cold start?

In the cloud benchmark, routes are running 3 ms after the process starts (Apache Camel on the JVM: 1.1 s; on Quarkus native: 30 ms). In AWS's provided:al2023 image with the Lambda Runtime Interface Emulator, init took 3.5 to 5.2 ms and warm invocations 0.7 to 1.3 ms. Lambda's own sandbox start is added on top on every platform.

Does the same route run on Cloud Run or Kubernetes?

Yes. The same route file runs on Lambda, in the container on Cloud Run, Knative, Azure Container Apps, Fly.io, ECS and Kubernetes, and as a plain binary. Cloud Run sends requests to PORT, 8080 by default.

How small can the function be?

scripts/package-lambda.sh takes --features to keep only the component families the routes use. A static musl build with the cloud family is 11.8 MB and has an HTTP route ready in 0.75 ms; core alone is 7.5 MB.

Try it locally first

Run the route in the container, then package it for Lambda with the component families it needs.

docker run --rm -p 8080:8080 -v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/hello-api.camel.yaml
scripts/package-lambda.sh --arch arm64 --features cloud --out function.zip hello-api.camel.yaml