Skip to content

Commit bf807c0

Browse files
committed
Add Exercise 5.2.1: Lettuce Crop AWS
1 parent f150ff7 commit bf807c0

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
- [Rust for Web]()
2323
- [Rust for Web Servers](rust-for-web-servers.md)
24+
- [Rust in the Cloud](rust-in-the-cloud.md)
2425

2526
- [Rust for Systems Programming]()
2627
- [Foreign Function Interface](foreign-function-interface.md)

book/src/rust-in-the-cloud.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Unit 5.2 - Rust in the Cloud
2+
3+
## Exercise 5.2.1: Lettuce Crop AWS
4+
In this exercise, we will port our Lettuce Crop website from exercise 5.1.1 to the cloud using [AWS Lambda](https://aws.amazon.com/lambda/). AWS Lambda allows you to run code in the cloud in a serverless configuration. This means that machines in Amazon's data centers will automatically start running your code when needed, which means you do not have to worry about managing servers, and you only pay for the compute time you use.
5+
6+
<div class="warning">
7+
8+
For this exercise, the [AWS free tier](https://aws.amazon.com/free/) should be sufficient. However, please do remember to shut off your Lambdas once you are done testing to avoid any unexpected costs! See the [free tier page](https://console.aws.amazon.com/billing/home#/freetier) in the billing and cost management section of the AWS console to see how much of the free tier quotas you have left this month.
9+
10+
</div>
11+
12+
### 3.2.1.A Setting up Cargo Lambda
13+
To build for AWS Lambda with Rust, we will use [Cargo Lambda](https://www.cargo-lambda.info/). You can install Cargo Lambda with [Cargo Binstall](https://github.com/cargo-bins/cargo-binstall):
14+
```
15+
cargo binstall cargo-lambda
16+
```
17+
You may also need to install [Zig](https://ziglang.org/), which is used for [cross-compilation](https://www.cargo-lambda.info/guide/cross-compiling.html). Cargo Lambda will inform you if Zig is not installed when building your Lambda, in which case it will attempt to help you install it automatically via `pip` or `npm`.
18+
19+
20+
Alternatively, you can use any of the other installation methods for Cargo Lambda found [here](https://www.cargo-lambda.info/guide/installation.html).
21+
22+
### 3.2.1.B Axum router with Lambda HTTP
23+
The [`lambda_runtime`](https://crates.io/crates/lambda_runtime/) crate provides the runtime for AWS Lambdas written in Rust. The [`lambda_http`](https://crates.io/crates/lambda_http) crate provides an abstraction layer on top of the `lambda_runtime` to make it easy to develop HTTP servers on AWS Lambda with Rust, which is ideal for small dynamic websites or REST APIs.
24+
25+
Add `lambda_http` to the Rust project with:
26+
```
27+
cargo add lambda_http
28+
```
29+
30+
Since `lambda_http` is able to run `axum` routers, we only really need to change the main function to convert our Lettuce Crop server to a Lambda. We create our `Router` as usual, but instead of serving it with `axum::serve`, we run the `Router` with the `run` function from `lambda_http`:
31+
```rust
32+
use lambda_http::{run, tracing, Error};
33+
34+
#[tokio::main]
35+
async fn main() -> Result<(), Error> {
36+
// required to enable CloudWatch error logging by the runtime
37+
tracing::init_default_subscriber();
38+
39+
let app = Router::new()
40+
.route("/crop", post(crop_image))
41+
.fallback_service(ServeDir::new("assets"));
42+
43+
run(app).await
44+
}
45+
```
46+
Update the main function as above and then try out the Lambda with:
47+
```
48+
cargo lambda watch
49+
```
50+
This will emulate the Lambda locally on your device, serving it on [http://localhost:9000/](http://localhost:9000/) by default.
51+
52+
### 3.2.1.C Setting up a Lambda function in the AWS console
53+
Now that we've tested our Lambda locally, let's create a Lambda function in the AWS console. Go to the [AWS Lambda page](https://console.aws.amazon.com/lambda/home) in the AWS console, and click "Create a function". Then, configure it as follows:
54+
55+
1. Select "Author from scratch"
56+
2. Give it a name, for example "lettuce-crop"
57+
3. Select the "Amazon Linux 2023" runtime
58+
4. Select "arm64" architecture (which offers lower costs compared to x86_64)
59+
5. In "Additional Configurations" enable "Enable function URL", and select Auth type "NONE" to get a publicly accessible URL for your Lambda function
60+
61+
Finally, click "Create function" and wait a few seconds for your Lambda to be created.
62+
63+
### 3.2.1.D Building & deploying our Lambda function
64+
Before we deploy our Lambda, we first have to build our project with the appropriate architecture:
65+
```
66+
cargo lambda build --release --arm64 --output-format zip
67+
```
68+
This will generate a `bootstrap.zip` in the `target/lambda/{project name}` folder, which we can upload in the AWS console to deploy our Lambda.
69+
70+
However, this zip file does not contain our assets. If we want our Lambda to be able to serve our HTML document and the corresponding CSS file and image, we have to include these assets. Let's create a `CargoLambda.toml` config file to specify how we want to build our Lambda, and include the following:
71+
```toml
72+
[build]
73+
arm64 = true
74+
output_format = "zip"
75+
include = ["assets/index.html", "assets/styles.css", "assets/crop.webp"]
76+
```
77+
If we now build our Lambda with `cargo lambda build --release` we will get a zip that also contains our assets (we no longer need the `--arm64` and `--output-format` command line arguments, as these are now set in our config file).
78+
79+
Alternatively, if you are using [memory-serve](https://docs.rs/memory-serve/latest/memory_serve/) to serve the assets, as described in exercise 5.1.1.G, you will not need to include the assets in the zip, as they already will be included in the binary.
80+
81+
To deploy the Lambda, click the "Upload from" button in the "Code" tab for our Lambda in the AWS console. Then, upload the `bootstrap.zip` file. Now, the Lambda should be live! Open the function URL listed in the function overview at the top of the page to try it out!
82+
83+
You can also use `cargo lambda deploy` to deploy your Lambda via the CLI. However, this does require you to set up [AWS credentials](https://www.cargo-lambda.info/guide/automating-deployments.html) first.
84+
85+
Note that AWS Lambda only accepts files up to 50 MB, for larger projects you can instead upload to an [S3 bucket](https://aws.amazon.com/s3/). S3 does not have a free tier, but it does have a 12-month free trial.
86+
87+
### 3.2.1.E Analyzing Lambda usage via CloudWatch
88+
Now that our Lambda is up and running, let's take a look around the AWS console. If you go to the "Monitor" tab, you can see some metrics about the requests handled by the Lambda function. These basic metrics are automatically gathered by CloudWatch free of charge.
89+
90+
If you scroll down to CloudWatch Logs, you will see recent invocations of the Lambda function. If you click on the log stream of one of these requests, you will see the logs produced while handling the request. The outputs from any `println!`'s or logs from the [`tracing`](https://docs.rs/tracing/latest/tracing/) crate should show up here. The free tier of CloudWatch allows you to store up to 5 GB of log data for free.
91+
92+
You can also see a list of the most expensive invocations on the "Monitor" tab. The cost is measured in gigabyte-seconds, which is the amount of memory used for the duration it took to handle the request. The free tier for AWS Lambda gives you 1,000,000 requests and 400,000 gigabyte-seconds for free per month.
93+
94+
By default, Lambdas are configured with 128 MB of memory, which can be increased in the "Configuration" tab (but it cannot be set lower than 128 MB). In this tab you can also configure the timeout for handling requests. By default, the Lambda will time out after 3 seconds, but this can be changed if needed.
95+
96+
#### Where to go from here?
97+
98+
- The [Rust Runtime for AWS Lambda GitHub repository](https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/examples) contains a bunch of useful examples, which show for example how to [interact with S3 buckets](https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/examples/basic-s3-thumbnail) or how to [create Lambda extensions](https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/examples/extension-custom-service).
99+
- The [AWS SDK for Rust](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/welcome.html) allows you to interact with AWS services via Rust.
100+
101+
Remember to throttle or delete the Lambda function once you are done testing to prevent unexpected costs!

0 commit comments

Comments
 (0)