Rust on AWS App Runner - Part2
Published: 2023-09-05 14:01:00

Hey hey hey 🍕!

This is the second part of this series, make sure you've already read [the first part](https://dev.to/aws-builders/rust-on-aws-app-runner-part1-4hpp) :)

In the first part, we saw how to create a basic Rust API with a `GET /pizza` endpoint to retrieve the list of pizza.

In this part, let's see how to containerize our app!

## Let's create our container

Since AWS App Runner is a fully managed container application service, we definitely need a container!

In this section, we will see how to build that container thanks to `Docker` using a `Dockerfile`.

A `Dockerfile` is a text file that contains all the commands needed to build our container, it's often compared to a recipe.

## Rust as the base image

Let's start with 

```Dockerfile
FROM rust:slim-bullseye
WORKDIR /app
COPY ./ /app
RUN cargo build --release
```

The first line describes the base image that we want to use, here the official `rust` one. 

This is really convenient since we don't have to install `rust` or `cargo`: both are already installed in this base image.

Then we define the current working directory, here `/app`

Then we copy our sources (`src` + `Cargo.toml` + `Cargo.lock`) into the container.

Finally we build our API directly inside the container, in release mode, to be sure to have a production-ready binary.

Great, we now have our binary ready in our image!

But wait, we also have `rust`, `cargo` and a bunch of useless tools at runtime. 

It was convenient to use the official `rust` image **to build**, but we don't need it anymore for the **runtime**. Fortunately, Docker supports **multi stage builds**.

## Multi-stage builds

We can specify a base image to build and another one to run! That's exactly what we want!

The idea here is to have the smallest possible image so the cold start would be extremely fast. That's why we are going to use a `distroless` base image.

Those images are built by Google and contain almost nothing: no `bash`, no `ssh`, no utility tools which makes the image extremely small.

Let's modify our Dockerfile:

```Dockerfile
FROM rust:slim-bullseye AS BUILD
COPY ./ /app
RUN cargo build --release

FROM gcr.io/distroless/cc-debian10
COPY --from=BUILD /app/target/release/app-runner-rust / 
CMD ["./app-runner-rust"]
```

Here we name our first image `BUILD` so we can reference that later. Then from the distroless image, we copy our binary from the `BUILD` image! Super convenient! I love Docker :D

Our runtime image is just the `distroless base image` + `rust binary`

Let's finally build it with `docker build . -t maxday/app-runner`

Let's check for our image size: `docker images | grep maxday/app-runner`

```bash
docker images | grep maxday/app-runner
maxday/app-runner                                          latest          e278afc78403   3 minutes ago    20.1MB
```
**20.1MB!!! 🤯 Extremely small!**

Woot woot! We now have a ready to deploy container!

## Local test

Before deploying, let's make sure everything looks fine by running it locally and calling our `GET /pizza` endpoint.

You can run your newly built docker image with:   
`docker run -d -p 8080:8080 maxday/app-runner`

- `-d` means `detached` so the container runs in the background
- `-p 8080:8080` means that you're bridging the host port 8080 to the container port 8080.

You can check that your container is up and running with:  
`docker ps`

```bash
docker ps
CONTAINER ID   IMAGE               COMMAND               CREATED          STATUS          PORTS                    NAMES
e5d8978ee6ee   maxday/app-runner   "./app-runner-rust"   53 seconds ago   Up 53 seconds   0.0.0.0:8080->8080/tcp   pedantic_kare
```

Now you can curl the endpoint:  
`curl http://localhost:8080/pizza`

```bash
curl localhost:8080/pizza
[{"name":"Margherita","toppings":["tomato","fior di latte"],"price":10},{"name":"Veggie","toppings":["green peppers","onion","mushrooms"],"price":12}]
```

Awesome! 🎉

**Our container is now ready to be used by AWS App Runner.** 

See you next week for the final episode of this series to deploy it!

**Like this content? Consider following me for more!**

A question? Feel free to use the comment section ⬇️

You can find me on [LinkedIn](https://www.linkedin.com/in/maxday/), [YouTube](https://www.youtube.com/@maxday_coding) and [Twitter](https://twitter.com/_maxday)!