Files
2025-11-29 18:25:52 +08:00

665 lines
15 KiB
Markdown

---
description: Set up Infrastructure as Code for Rust Lambda functions using SAM, Terraform, or CDK
---
You are helping the user set up Infrastructure as Code (IaC) for their Rust Lambda functions.
## Your Task
Guide the user through deploying and managing Lambda infrastructure using their preferred IaC tool.
## Infrastructure as Code Options
### Option 1: AWS SAM (Serverless Application Model)
**Best for**:
- Serverless-focused projects
- Quick prototyping
- Built-in local testing
- Teams familiar with CloudFormation
**Advantages**:
- Official AWS support for Rust with cargo-lambda
- Built-in local testing with `sam local`
- Simpler for pure serverless applications
- Good integration with Lambda features
#### Basic SAM Template
Create `template.yaml`:
```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Rust Lambda Function
Globals:
Function:
Timeout: 30
MemorySize: 512
Runtime: provided.al2023
Architectures:
- arm64
Environment:
Variables:
RUST_LOG: info
Resources:
MyRustFunction:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: rust-cargolambda
BuildProperties:
Binary: my-function
Properties:
CodeUri: .
Handler: bootstrap
Events:
ApiEvent:
Type: Api
Properties:
Path: /hello
Method: get
Policies:
- AWSLambdaBasicExecutionRole
ComputeFunction:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: rust-cargolambda
Properties:
CodeUri: .
Handler: bootstrap
MemorySize: 2048
Timeout: 300
Events:
S3Event:
Type: S3
Properties:
Bucket: !Ref ProcessingBucket
Events: s3:ObjectCreated:*
ProcessingBucket:
Type: AWS::S3::Bucket
Outputs:
ApiUrl:
Description: "API Gateway endpoint URL"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
```
#### SAM Commands
```bash
# Build
sam build
# Test locally
sam local invoke MyRustFunction -e events/test.json
# Start local API
sam local start-api
# Deploy
sam deploy --guided
# Deploy with parameters
sam deploy \
--stack-name my-rust-lambda \
--capabilities CAPABILITY_IAM \
--region us-east-1
```
#### Multi-Function SAM Template
```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: provided.al2023
Architectures:
- arm64
Environment:
Variables:
RUST_LOG: info
Resources:
# API Handler - IO-optimized
ApiHandler:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: rust-cargolambda
BuildProperties:
Binary: api-handler
Properties:
CodeUri: .
Handler: bootstrap
MemorySize: 512
Timeout: 30
Events:
GetUsers:
Type: Api
Properties:
Path: /users
Method: get
Environment:
Variables:
DATABASE_URL: !Sub "{{resolve:secretsmanager:${DBSecret}:SecretString:connection_string}}"
Policies:
- AWSLambdaBasicExecutionRole
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: !Ref DBSecret
# Data Processor - Compute-optimized
DataProcessor:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: rust-cargolambda
BuildProperties:
Binary: data-processor
Properties:
CodeUri: .
Handler: bootstrap
MemorySize: 3008
Timeout: 300
Events:
S3Upload:
Type: S3
Properties:
Bucket: !Ref DataBucket
Events: s3:ObjectCreated:*
Filter:
S3Key:
Rules:
- Name: prefix
Value: raw/
Policies:
- AWSLambdaBasicExecutionRole
- S3ReadPolicy:
BucketName: !Ref DataBucket
- S3WritePolicy:
BucketName: !Ref DataBucket
# Event Consumer - SQS triggered
EventConsumer:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: rust-cargolambda
BuildProperties:
Binary: event-consumer
Properties:
CodeUri: .
Handler: bootstrap
MemorySize: 1024
Timeout: 60
Events:
SQSEvent:
Type: SQS
Properties:
Queue: !GetAtt EventQueue.Arn
BatchSize: 10
Policies:
- AWSLambdaBasicExecutionRole
- SQSPollerPolicy:
QueueName: !GetAtt EventQueue.QueueName
DataBucket:
Type: AWS::S3::Bucket
EventQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 360
DBSecret:
Type: AWS::SecretsManager::Secret
Properties:
Description: Database connection string
GenerateSecretString:
SecretStringTemplate: '{"username": "admin"}'
GenerateStringKey: "password"
PasswordLength: 32
Outputs:
ApiEndpoint:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
DataBucket:
Value: !Ref DataBucket
QueueUrl:
Value: !Ref EventQueue
```
### Option 2: Terraform
**Best for**:
- Multi-cloud or hybrid infrastructure
- Complex infrastructure requirements
- Teams already using Terraform
- More control over AWS resources
**Advantages**:
- Broader ecosystem (300+ providers)
- State management
- Module reusability
- Better for mixed workloads (Lambda + EC2 + RDS, etc.)
#### Basic Terraform Configuration
Create `main.tf`:
```hcl
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
# IAM Role for Lambda
resource "aws_iam_role" "lambda_role" {
name = "${var.function_name}-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "lambda_basic" {
role = aws_iam_role.lambda_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
# Lambda Function
resource "aws_lambda_function" "rust_function" {
filename = "target/lambda/${var.function_name}/bootstrap.zip"
function_name = var.function_name
role = aws_iam_role.lambda_role.arn
handler = "bootstrap"
source_code_hash = filebase64sha256("target/lambda/${var.function_name}/bootstrap.zip")
runtime = "provided.al2023"
architectures = ["arm64"]
memory_size = var.memory_size
timeout = var.timeout
environment {
variables = {
RUST_LOG = var.log_level
}
}
tracing_config {
mode = "Active"
}
}
# CloudWatch Log Group
resource "aws_cloudwatch_log_group" "lambda_logs" {
name = "/aws/lambda/${var.function_name}"
retention_in_days = 14
}
# API Gateway (Optional)
resource "aws_apigatewayv2_api" "lambda_api" {
name = "${var.function_name}-api"
protocol_type = "HTTP"
}
resource "aws_apigatewayv2_stage" "lambda_stage" {
api_id = aws_apigatewayv2_api.lambda_api.id
name = "prod"
auto_deploy = true
}
resource "aws_apigatewayv2_integration" "lambda_integration" {
api_id = aws_apigatewayv2_api.lambda_api.id
integration_type = "AWS_PROXY"
integration_uri = aws_lambda_function.rust_function.invoke_arn
}
resource "aws_apigatewayv2_route" "lambda_route" {
api_id = aws_apigatewayv2_api.lambda_api.id
route_key = "GET /hello"
target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}"
}
resource "aws_lambda_permission" "api_gateway" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.rust_function.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.lambda_api.execution_arn}/*/*"
}
# Outputs
output "function_arn" {
value = aws_lambda_function.rust_function.arn
}
output "api_endpoint" {
value = aws_apigatewayv2_stage.lambda_stage.invoke_url
}
```
Create `variables.tf`:
```hcl
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "function_name" {
description = "Lambda function name"
type = string
}
variable "memory_size" {
description = "Lambda memory size in MB"
type = number
default = 512
}
variable "timeout" {
description = "Lambda timeout in seconds"
type = number
default = 30
}
variable "log_level" {
description = "Rust log level"
type = string
default = "info"
}
```
#### Terraform Module for Rust Lambda
Create `modules/rust-lambda/main.tf`:
```hcl
resource "aws_iam_role" "lambda_role" {
name = "${var.function_name}-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "lambda_basic" {
role = aws_iam_role.lambda_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
resource "aws_lambda_function" "function" {
filename = var.zip_file
function_name = var.function_name
role = aws_iam_role.lambda_role.arn
handler = "bootstrap"
source_code_hash = filebase64sha256(var.zip_file)
runtime = "provided.al2023"
architectures = [var.architecture]
memory_size = var.memory_size
timeout = var.timeout
environment {
variables = var.environment_variables
}
dynamic "vpc_config" {
for_each = var.vpc_config != null ? [var.vpc_config] : []
content {
subnet_ids = vpc_config.value.subnet_ids
security_group_ids = vpc_config.value.security_group_ids
}
}
tracing_config {
mode = var.enable_xray ? "Active" : "PassThrough"
}
}
resource "aws_cloudwatch_log_group" "lambda_logs" {
name = "/aws/lambda/${var.function_name}"
retention_in_days = var.log_retention_days
}
```
Usage:
```hcl
module "api_handler" {
source = "./modules/rust-lambda"
function_name = "api-handler"
zip_file = "target/lambda/api-handler/bootstrap.zip"
memory_size = 512
timeout = 30
architecture = "arm64"
enable_xray = true
log_retention_days = 7
environment_variables = {
RUST_LOG = "info"
DATABASE_URL = data.aws_secretsmanager_secret_version.db.secret_string
}
}
module "data_processor" {
source = "./modules/rust-lambda"
function_name = "data-processor"
zip_file = "target/lambda/data-processor/bootstrap.zip"
memory_size = 3008
timeout = 300
architecture = "arm64"
enable_xray = true
log_retention_days = 7
environment_variables = {
RUST_LOG = "info"
}
}
```
#### Terraform Commands
```bash
# Initialize
terraform init
# Plan
terraform plan -var="function_name=my-rust-lambda"
# Apply
terraform apply -var="function_name=my-rust-lambda" -auto-approve
# Destroy
terraform destroy -var="function_name=my-rust-lambda"
```
### Option 3: AWS CDK (TypeScript/Python)
**Best for**:
- Type-safe infrastructure definitions
- Complex constructs and patterns
- Teams comfortable with programming languages
- Reusable infrastructure components
#### CDK Example (TypeScript)
```typescript
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigatewayv2';
import * as integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations';
export class RustLambdaStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const rustFunction = new lambda.Function(this, 'RustFunction', {
runtime: lambda.Runtime.PROVIDED_AL2023,
handler: 'bootstrap',
code: lambda.Code.fromAsset('target/lambda/my-function/bootstrap.zip'),
architecture: lambda.Architecture.ARM_64,
memorySize: 512,
timeout: cdk.Duration.seconds(30),
environment: {
RUST_LOG: 'info',
},
tracing: lambda.Tracing.ACTIVE,
});
const api = new apigateway.HttpApi(this, 'RustApi', {
defaultIntegration: new integrations.HttpLambdaIntegration(
'RustIntegration',
rustFunction
),
});
new cdk.CfnOutput(this, 'ApiUrl', {
value: api.url!,
});
}
}
```
## Comparison Table
| Feature | SAM | Terraform | CDK |
|---------|-----|-----------|-----|
| Learning Curve | Low | Medium | Medium-High |
| Rust Support | Excellent | Good | Good |
| Local Testing | Built-in | Limited | Limited |
| Multi-Cloud | No | Yes | No |
| Type Safety | No | HCL | Yes |
| Community | AWS-focused | Large | Growing |
| State Management | CloudFormation | Terraform State | CloudFormation |
## Integration with cargo-lambda
All IaC tools work well with cargo-lambda:
```bash
# Build for deployment
cargo lambda build --release --arm64 --output-format zip
# Then deploy with your IaC tool
sam deploy
# or
terraform apply
# or
cdk deploy
```
## Best Practices
1. **Version Control**: Store IaC templates in Git
2. **Separate Environments**: Use workspaces/stages for dev/staging/prod
3. **Secrets Management**: Use AWS Secrets Manager, never hardcode
4. **Outputs**: Export important values (ARNs, URLs)
5. **Modules**: Create reusable components
6. **Testing**: Validate templates before deployment
7. **CI/CD**: Automate IaC deployment
8. **State Management**: Secure Terraform state (S3 + DynamoDB)
9. **Documentation**: Comment complex configurations
10. **Tagging**: Tag resources for cost tracking
## Local Testing with SAM
```bash
# Test function locally
sam local invoke MyRustFunction -e events/test.json
# Start local API Gateway
sam local start-api
# Start local Lambda endpoint
sam local start-lambda
# Generate sample events
sam local generate-event apigateway aws-proxy > event.json
sam local generate-event s3 put > s3-event.json
```
## Using with LocalStack
For full local AWS emulation:
```bash
# Install LocalStack
pip install localstack
# Start LocalStack
localstack start
# Deploy to LocalStack with SAM
samlocal deploy
# Or with Terraform
terraform apply \
-var="aws_region=us-east-1" \
-var="endpoint=http://localhost:4566"
```
## Migration Path
**Starting fresh**:
- Choose SAM for pure serverless, simple projects
- Choose Terraform for complex, multi-service infrastructure
- Choose CDK for type-safe, programmatic definitions
**Existing infrastructure**:
- Import existing resources into Terraform/CDK
- Use CloudFormation template generation from SAM
- Gradual migration with hybrid approach
## Recommended Structure
```
my-rust-lambda/
├── src/
│ └── main.rs
├── Cargo.toml
├── template.yaml # SAM
├── terraform/ # Terraform
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── cdk/ # CDK
│ ├── lib/
│ │ └── stack.ts
│ └── bin/
│ └── app.ts
└── events/ # Test events
├── api-event.json
└── s3-event.json
```
Help the user choose the right IaC tool based on their needs and guide them through setup and deployment.