# Rust on Cloud Run: the container, the build, the first second, and the bill

> How we run Rust on Cloud Run: $PORT and SIGTERM, a two-stage Dockerfile for an 11 MB image, where to compile, why 256 MiB means the first generation, start times, and three setups' bills.

Published 2026-10-12 · Updated 2026-10-13 · [By Exodus team](https://exodus.elim.io/about) · Stacks, Performance
<https://exodus.elim.io/blog/rust-on-cloud-run>

Rust runs on Cloud Run as one binary in a two-stage Docker image, 11.3 MB on distroless in our sample, because Google's buildpacks do not build Rust. The server listens on 0.0.0.0 at $PORT and stops on SIGTERM. Our Rust API's container starts in a median 94 ms at 256 MiB, and at low traffic its compute stays inside the free tier.

## In short

- Listen on `0.0.0.0` at `$PORT`, handle SIGTERM within the 10 seconds before SIGKILL, and log one JSON object per line with a `severity` field.
- Build in two stages: our sample image is 11.3 MB on `distroless/cc` and 31.0 MB on `debian:trixie-slim`.
- Compile where a cache survives: a 228-crate API of ours took 59 seconds with 8 jobs and 170 with 2, and Cloud Build compiles every crate on every deploy.
- Start at 1 vCPU and 512 MiB; at 256 MiB the service runs on the first generation, and memory is under 5% of an instance's price.
- Our Rust API on Postgres bills $9.79 a month, of which Cloud SQL is $9.34; Cloud Run's compute is inside the free tier.

Measurements are from our build machine and our own services, October 5-12, 2026; prices are Google's list prices, read October 12, 2026.

![The build stage compiles with the Rust toolchain, the run stage copies one binary onto distroless, the 11.3 MB image goes to Artifact Registry and Cloud Run runs it with 1 vCPU and 256 MiB, logging JSON lines and stopping on SIGTERM](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-c01484647979fc99f62a3e00504274f100fdf89fa1c02091bf5821f987afde42-680x340-svg/bytes "The shape: compile in one stage, ship one file in the next, and keep the three rules of the runtime")

## What Rust changes on Cloud Run

Every backend we ship is Rust, in a two-stage Dockerfile, and several of them run on Cloud Run; this guide is what we do, and it assumes you know [what Cloud Run is](https://exodus.elim.io/blog/what-cloud-run-is). Cloud Run runs any container that answers HTTP, so Rust needs no special support. What it does not get is a buildpack. When you deploy from source, Cloud Run uses a Dockerfile if it finds one, and otherwise asks Google's buildpacks to detect the language; the list is Go, Node.js, Python, Java, Kotlin, Groovy, Scala, .NET, Ruby and PHP. A Rust repository without a Dockerfile does not deploy. The [guide to Node, Python, Rails and Go on Cloud Run](https://exodus.elim.io/blog/node-python-rails-and-go-on-cloud-run) covers the stacks on that list. That is the one piece of work Node or Python teams skip and Rust teams do not.

The rest mostly works in Rust's favor. The binary links a few system libraries at most, so the image can be tiny. It starts as fast as the process can bind a socket. And a typical API spends its time waiting on a database, so one small instance handles a lot of concurrent requests. Our measured numbers are below; first, the code.

## Step 1: the server

Cloud Run's container contract asks three things of a service. It must listen on `0.0.0.0` on the port Cloud Run sends requests to, which is 8080 unless you change it and arrives in `$PORT`. A server bound to `127.0.0.1` is invisible from outside the container, and the deploy fails with "Container failed to start". When Cloud Run stops an instance, it sends SIGTERM, waits 10 seconds and sends SIGKILL; requests in flight should finish in that window. And logs go to stdout, where a line of JSON becomes a structured entry.

Here is the whole sample, an Axum service. It is `src/main.rs` of the sample in our research folder, and it ran as printed:

```
use std::{net::SocketAddr, time::Duration};

use axum::{Router, routing::get};
use tokio::signal::unix::{SignalKind, signal};

// One JSON object per line on stdout: Cloud Logging takes `severity` and `message` from it.
fn log(severity: &str, message: &str) {
    println!("{}", serde_json::json!({ "severity": severity, "message": message }));
}

#[tokio::main]
async fn main() {
    // Cloud Run passes the port in $PORT; the server must listen on 0.0.0.0, not 127.0.0.1.
    let port: u16 = std::env::var("PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(8080);
    let app = Router::new()
        .route("/", get(|| async { "hello\n" }))
        .route("/slow", get(|| async {
            tokio::time::sleep(Duration::from_secs(3)).await;
            "done\n"
        }));
    let listener = tokio::net::TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], port)))
        .await
        .expect("bind");
    log("INFO", &format!("listening on {port}"));

    // On SIGTERM stop accepting, let requests in flight finish, then exit.
    axum::serve(listener, app)
        .with_graceful_shutdown(async {
            signal(SignalKind::terminate()).expect("SIGTERM handler").recv().await;
            log("INFO", "SIGTERM, finishing requests in flight");
        })
        .await
        .expect("serve");
    log("INFO", "stopped");
}
```

The dependencies are `axum = "0.8"`, `serde_json = "1"` and `tokio` with the `macros`, `net`, `rt-multi-thread`, `signal` and `time` features.

Two details are worth knowing. The SIGTERM handler matters more than it looks: the binary is process 1 in its container, and Linux delivers a signal to process 1 only if it has a handler for it, so a Rust server with no handler never sees SIGTERM and runs until SIGKILL. Google's page says those 10 seconds are billed either way. In our test, the naive version took 10.3 seconds to stop and died with exit code 137; the sample above finished a 3-second request and exited in 2.8 seconds.

The logging line is the other detail. The popular `tracing-subscriber` crate with its `json` feature writes `"level":"ERROR"` and nests the text under `fields.message`. Cloud Logging reads the level only from a top-level field named `severity`, and an entry without one keeps the default severity, so your errors are not stored as errors and a filter on ERROR finds nothing. Either write the fields yourself as above, or use a formatter that names them `severity` and `message`. The [logs and alerts guide](https://exodus.elim.io/blog/logs-metrics-and-alerts-for-a-cloud-run-app) shows what to do with them next.

![Terminal output of run.sh: three images built, sizes 11.3, 31.0 and 0.7 MB, first answers in 260 to 281 ms, RSS under 1.2 MiB, a graceful stop in 2.8 seconds with the request answered, and the naive binary unreachable and killed after 10.3 seconds](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-b8e4987228e26e7257ba4a3fc1d4870ca0220850bb76523c6580905fb660c684-680x340-svg/bytes "Our sample on our build machine, each container held to 1 CPU and 256 MiB: the graceful version finishes its request, the naive one is unreachable and gets SIGKILL")

## Step 2: the Dockerfile

Two stages. The first has the Rust toolchain and compiles; the second gets one file, the binary:

```dockerfile
# build: the full Rust toolchain, never shipped
FROM rust:1.95-trixie AS build
WORKDIR /src
COPY . .
# cache mounts keep crates and builds between runs on one machine
RUN \
    --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/src/target \
    cargo build \
      --release \
      --locked \
      --bin hello \
    && cp target/release/hello /hello

# run: glibc, libgcc, CA certificates and a nonroot user, no shell
FROM gcr.io/distroless/cc-debian13:nonroot
COPY \
    --from=build /hello /hello
ENTRYPOINT ["/hello"]
```

Add a `.dockerignore` with `target` in it, or Docker sends your local build directory, which can run to gigabytes, as the build context. The `cp` out of the cache mount is needed because the mount does not exist in the image layer.

Which run image? We measured the same service on three. `debian:trixie-slim` gave a 31.0 MB image and has a shell and `apt`, which helps when you need a system package. `gcr.io/distroless/cc-debian13` gave 11.3 MB: it carries glibc, libgcc, libssl, CA certificates and time zone data, and nothing to log in with. A static build with musl on Alpine, copied onto the empty `scratch` image, gave 0.7 MB, but `scratch` has no CA certificates, so any HTTPS call out fails unless you copy certificates in or the binary carries its own.

![Bar chart of image size for the same Axum service: debian trixie-slim 31.0 MB, distroless cc 11.3 MB, scratch with musl 0.7 MB; first answers in 260, 281 and 268 ms](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-18eec5e304e490dac132735e8d52e1163ae4ea3e55ff09bf3cf88c158e854a98-680x360-svg/bytes "Image size by run stage. The time to the first answer did not follow the size: three runs gave 250 to 285 ms for all three")

We use distroless. The size did not change start time in our local runs, so the reason is what is missing: no shell and no package manager means less to patch and less to break into. If your binary links OpenSSL through `native-tls`, distroless `cc` already has libssl; on `scratch` it would not.

## Step 3: where to compile

A Rust build is the slow part of a deploy. A real API of ours with 228 crates in its lock file took 59 seconds to compile from nothing with 8 parallel jobs on our build machine, and 170 seconds with 2. There are three places to do it.

**Cloud Build, through a source deploy.** Run `gcloud run deploy` with the source flag in a folder with the Dockerfile, and Cloud Build builds it on its default machine, `e2-standard-2` with 2 CPUs. Each build starts on a fresh machine, so the cache mounts above are empty every time and every deploy compiles every crate, about three minutes or more for a project like ours. The money is small: 2,500 build-minutes a month are free on that machine, and past that a minute costs $0.006. To get caching back on Cloud Build, use cargo-chef, which compiles only the dependencies in a layer of their own, and point Docker's cache-from option at the previous image, so that layer is reused while `Cargo.lock` does not change. When we moved a Rust API, worker and web app, the first day's builds on Cloud Build cost $2.10 on a larger machine; we have built on our own machine since.

**Your machine or CI, then push.** Build with Docker where the cache persists, push to Artifact Registry and deploy the image. A one-line change rebuilt in 2 to 6 seconds in our test. Two warnings. Cloud Run runs only x86_64 Linux binaries, so on a Mac with Apple silicon give `docker build` the platform `linux/amd64`, as in step 4. And deploy from a commit, not from whatever is in your working tree; the [GitHub deploy guide](https://exodus.elim.io/blog/deploying-from-github-without-keys) shows a CI that does both.

**A prebuilt binary, no image at all.** Cloud Run can take a compiled binary and run it on Google's `osonly24` base image, which is Ubuntu 24.04 with glibc 2.39, supported until April 30, 2029:

```shell
cargo build \
  --release
mkdir -p deploy && cp target/release/hello deploy/
cd deploy
gcloud beta run deploy hello \
  --source . \
  --no-build \
  --base-image=osonly24 \
  --command=./hello \
  --region=europe-west1
```

This skips Docker and Cloud Build, but the binary must not need a newer glibc than the base image has. Ours, built on Debian 13 with glibc 2.41, needs only `GLIBC_2.34` and ran on the `osonly24` image; check yours with `objdump -T` and look for the highest `GLIBC_` version, or build static with musl.

## Step 4: deploy

With an image built on your machine, the first deploy is five commands. Replace `PROJECT_ID` with your project:

```shell
gcloud artifacts repositories create app \
  --repository-format=docker \
  --location=europe-west1
gcloud auth configure-docker europe-west1-docker.pkg.dev
docker build \
  --platform linux/amd64 \
  -t europe-west1-docker.pkg.dev/PROJECT_ID/app/hello:v1 .
docker push europe-west1-docker.pkg.dev/PROJECT_ID/app/hello:v1
gcloud run deploy hello \
  --image=europe-west1-docker.pkg.dev/PROJECT_ID/app/hello:v1 \
  --region=europe-west1 \
  --cpu=1 \
  --memory=512Mi \
  --max-instances=3 \
  --allow-unauthenticated
```

The allow-unauthenticated flag makes the service public; leave it out for an internal one and read the [IAM guide](https://exodus.elim.io/blog/iam-for-a-cloud-run-app). The max-instances flag caps the bill as well as the scale. The registry keeps every version you push: Artifact Registry gives 0.5 GiB free per billing account, then about $0.10 per GiB a month, and a Rust image of ours is about 16.4 MB compressed, so 30 versions fit in the free part.

## Memory, CPU and the execution environment

Cloud Run gives a service 512 MiB unless you say otherwise, and a Rust API rarely needs it. Our API runs at 256 MiB: over the week of Oct 5-12, 2026, its 99th percentile of memory use was 15% of that, about 38 MiB, and its CPU use 2.5%. Going below 512 MiB has a consequence that is easy to miss. Cloud Run has two execution environments. The first generation runs on gVisor, emulates most system calls and starts faster; the second is a microVM with full Linux compatibility and faster CPU and network under sustained load. They cost the same. The second generation needs at least 512 MiB, so a service at 256 MiB runs on the first; one at 512 MiB or more that sets no environment gets whichever Cloud Run picks. Jobs and worker pools only use the second generation, with 512 MiB at least.

For most HTTP APIs, the first generation is the right one anyway. Choose the second, by setting the execution environment to `gen2` with 512 MiB or more, if your code needs a system call gVisor does not emulate, a network file system, or sustained CPU.

Memory is not where the money is. At request-based prices in Tier 1 regions, a vCPU-second costs $0.000024 and a GiB-second $0.0000025, so 512 MiB is under 5% of the price of a 1 vCPU instance, and halving it saves 2.5%. Two more limits matter. Below 1 vCPU, Cloud Run forces a concurrency of 1, which throws away what an async server is good at, so keep 1 vCPU. And the container's filesystem lives in memory: a file written to `/tmp` counts against those 256 MiB until it is deleted.

## The first second: cold starts, measured

When a request arrives and no instance is free, Cloud Run starts one and the request waits, for up to 3.5 times the service's average startup time or 10 seconds, whichever is greater. For a Rust service that wait is short. Cloud Monitoring's container startup latency metric (Beta) for our API, at 1 vCPU and 256 MiB with startup CPU boost on, recorded 17 instance starts over Oct 5-12, 2026: a median of 94 ms, a mean of 103 ms, and none slower than 280 ms. [Cloud Run cold starts, measured](https://exodus.elim.io/blog/cloud-run-cold-start-measured) puts that next to other languages and platforms.

That is the container. The user sees more. When we measured another Rust API we moved, on Oct 5, 2026 in europe-west1, the requests that started an instance spent 0.36 to 0.57 seconds in the server and took 0.79 to 1.69 seconds to the first byte at the client. The difference between the 94 ms and the 0.36 seconds is the app's own first work: opening the database connection, fetching a token from the metadata server, loading configuration. The [agent backend guide](https://exodus.elim.io/blog/an-ai-agent-backend-on-cloud-run) saw a first database query take 3.75 seconds against 7 ms after it.

So the work that remains is in your code, not in Rust. Open the connection pool lazily or in the background, keep startup free of network calls you can postpone, and if the first request after a quiet hour matters, [min instances and startup CPU boost](https://exodus.elim.io/blog/min-instances-and-startup-cpu-boost) set out what one idle instance costs. Boost doubles the CPU of a 1 vCPU instance during startup and for 10 seconds after, and that CPU is billed; with a binary that starts in 100 ms, it has less to speed up than it has for a runtime that loads code.

## Google APIs and the database

Google publishes official Rust client libraries, more than 140 APIs as crates named `google-cloud-*` (storage, Secret Manager, Pub/Sub, Agent Platform and others), with Application Default Credentials built in. They need Rust 1.91 or newer. On Cloud Run, the credentials come from the metadata server as the service's own service account, so the code holds no key. Check the crate list for the API you need before you write a REST client by hand; we wrote small REST clients of our own before the official crates covered what we use, and both ways work.

For Cloud SQL, attach the instance to the service and connect through the Unix socket Cloud Run mounts:

```shell
gcloud run services update hello \
  --region=europe-west1 \
  --add-cloudsql-instances=PROJECT_ID:europe-west1:INSTANCE
```

The socket is at `/cloudsql/PROJECT_ID:europe-west1:INSTANCE/.s.PGSQL.5432`. With sqlx, give `PgConnectOptions::socket` the directory, `/cloudsql/PROJECT_ID:europe-west1:INSTANCE`, and it adds the file name itself. Keep the pool small: each instance holds its own pool, so the maximum is the pool size times max instances, and that number must fit the database. The [Cloud SQL connection guide](https://exodus.elim.io/blog/connecting-cloud-run-to-cloud-sql) and the [connection pooling guide](https://exodus.elim.io/blog/connection-pooling-on-cloud-run) cover the private IP route and the limits.

## What it costs

Rust's share of the bill is small, and the free tier usually covers it. Two of our setups, measured on the billing export in October 2026, show where the money goes:

- **A Rust API on a document database, with a scheduled call every minute**, at 1 vCPU and 512 MiB. A month is 70,879 vCPU-seconds, 35,440 GiB-seconds and 589,110 requests. At list prices that is $1.70 of CPU, $0.09 of memory and $0.24 of requests, $2.03 in all; inside the free tier (180,000 vCPU-seconds, 360,000 GiB-seconds and 2 million requests a month per billing account) the compute bills $0, and the whole project billed $0.13, mostly a secret and egress.
- **A Rust API, worker and web app on Postgres.** $9.79 a month, of which the smallest Cloud SQL instance and its 10 GB disk are $9.34. Cloud Run's compute was again inside the free tier.

![Bar chart of one steady month of a Rust API, worker and web app on Postgres: Cloud SQL instance $7.67, its storage $1.67, Cloud Storage writes $0.17, egress $0.10, eight small lines $0.19, Cloud Run $0 inside the free tier](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-3b9950a80de6c0b8ce2e7e579d634d082f5f9f9647c9fe5dfe75d21f68ad6381-680x360-svg/bytes "A month of our Rust services on Postgres: the database is the bill, Cloud Run's compute is inside the free tier")

The same pattern holds for any small service, in any language that idles cheaply: the database and the fixed lines cost money, the compute does not. Past the free tier, the [worked examples by traffic](https://exodus.elim.io/blog/cloud-run-costs-worked-examples-by-traffic) show how the compute line grows. The one cost that is Rust's own is build time, and as above it is minutes, not dollars.

## What breaks

- **No Dockerfile.** A Rust repository deployed from source without one fails, because no buildpack covers Rust.
- **Binding 127.0.0.1 or a fixed port.** The revision never becomes ready; the error names the PORT variable.
- **No SIGTERM handler.** The process ignores SIGTERM as process 1, requests in flight are cut by SIGKILL after 10 seconds, and those seconds are billed.
- **An ARM image.** Built on Apple silicon without the `linux/amd64` platform, it does not run.
- **No CA certificates.** On `scratch`, every HTTPS call out fails with a certificate error.
- **Logs without `severity`.** Errors are stored with the default severity; alerts on ERROR never fire.
- **Memory under 512 MiB with a second-generation feature.** Cloud Run refuses the combination; pick one.
- **Files in `/tmp`.** They use the instance's memory, and at 256 MiB an export written to disk ends in an out-of-memory restart.
- **A large pool times max instances.** Twenty connections each across ten instances is 200; check that against the database's connection limit before you raise either.

## Checklist

1. The server reads `$PORT`, binds `0.0.0.0` and stops gracefully on SIGTERM.
1. Logs are one JSON object per line with `severity` and `message`.
1. A two-stage Dockerfile, `.dockerignore` with `target`, a run image of `distroless/cc` or `debian:trixie-slim`.
1. Builds happen where the cache survives, or with cargo-chef and a cache-from image on Cloud Build.
1. The image is built for `linux/amd64` and deployed from a commit.
1. 1 vCPU; 512 MiB, or 256 MiB if you accept the first generation.
1. A max-instances limit set, and pool size times instances fits the database.
1. Startup does no network work it can postpone; first-request time measured after deploy.

## Where Exodus comes in

`exodus audit` reads `Cargo.toml` and names the stack and the web framework; on our sample it printed "Rust, Axum 0.8" and found the process from the Dockerfile. The report then says what the container will be, "Your Dockerfile, on debian slim or distroless", and puts "Dockerfile and a health check route" first in the plan. `exodus check` looks for what breaks or idles on Cloud Run and can run in CI. The steps above, the server, the image, the build and the deploy, are what your coding agent does with that plan.

## FAQ

### Can Cloud Run build a Rust app from source without a Dockerfile?

No. A source deploy uses a Dockerfile when it finds one and otherwise Google's buildpacks, which cover Go, Node.js, Python, Java, Kotlin, Groovy, Scala, .NET, Ruby and PHP, not Rust. Write a two-stage Dockerfile, or compile the binary yourself and deploy it on the osonly24 base image with no build.

### Why does my Rust server take 10 seconds to stop on Cloud Run?

The binary is process 1 in its container, and Linux delivers SIGTERM to process 1 only if it has a handler. A Rust server with none ignores the signal and runs until SIGKILL 10 seconds later, and those seconds are billed. In our test the naive version stopped in 10.3 seconds, the one with a handler in 2.8.

### Why are my Rust errors not marked as errors in Cloud Logging?

Cloud Logging reads the level only from a top-level field named severity. The tracing-subscriber JSON output writes a level field and nests the text under fields.message, so errors keep the default severity and a filter on ERROR finds nothing. Write severity and message yourself, or use a formatter that names them that way.

### How much memory does a Rust service need on Cloud Run?

Less than the 512 MiB default in our case. Our API runs at 256 MiB, and its 99th percentile of memory use over a week was about 38 MiB. Below 512 MiB the service runs on the first generation environment, and memory is under 5% of a 1 vCPU instance's price, so there is little to save.

## Sources

1. [Container runtime contract, Cloud Run, Google (listen on 0.0.0.0, not 127.0.0.1; requests go to 8080 by default; executables for Linux 64-bit, the x86_64 ABI; a request pends for up to 3.5 times the average startup time or 10 seconds, whichever is greater; SIGTERM, then 10 seconds, then SIGKILL, CPU billed in between; the filesystem is in memory; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/container-contract)
2. [Select an execution environment for services, Cloud Run, Google (first generation on gVisor with faster cold starts, second generation a microVM with faster CPU and network; same price; a service with no setting gets either; the second generation needs at least 512 MiB; jobs and worker pools use only the second; an unhandled SIGTERM still gets 10 billed seconds; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/configuring/execution-environments)
3. [Configure memory limits for services, Cloud Run, Google (512 MiB by default; at least 128 MiB on the first generation and 512 MiB on the second; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/configuring/services/memory-limits)
4. [Configure CPU limits for services, Cloud Run, Google (from 0.08 vCPU; under 1 vCPU concurrency must be 1 and the first generation is required; startup CPU boost raises 0-1 vCPU to 2 during startup and for 10 seconds after, and the boosted CPU is billed; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/configuring/services/cpu)
5. [Deploy services from source code, Cloud Run, Google (a Dockerfile in the source is used when present; buildpacks cover Go, Node.js, Python, Java, Kotlin, Groovy, Scala, .NET, Ruby and PHP; prebuilt source with --no-build and --base-image=osonly24; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/deploying-source-code)
6. [Configure the OS only runtime, Google Cloud's buildpacks (base Ubuntu without a language runtime, for precompiled binaries; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/docs/buildpacks/osonly)
7. [Supported language runtimes and base images, Cloud Run, Google (osonly24 supported until April 30, 2029; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/configuring/services/runtime-base-images)
8. [Cloud Build pricing, Google (2,500 free build-minutes a month per billing account on e2-standard-2 in the default pool; e2-standard-2 $0.006 a minute; read Oct 12, 2026)](https://cloud.google.com/build/pricing)
9. [Build configuration file schema, Cloud Build, Google (the default machine is e2-standard-2 with 2 CPUs; the default timeout is 60 minutes; updated Oct 5, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/build/docs/build-config-file-schema)
10. [Best practices for speeding up builds, Cloud Build, Google (--cache-from a pushed image rebuilds every layer after the first changed one; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/build/docs/optimize-builds/speeding-up-builds)
11. [Artifact Registry pricing, Google (0.5 GiB-month free per billing account, then $0.000136986 per GiB-hour, about $0.10 per GiB-month; read Oct 12, 2026)](https://cloud.google.com/artifact-registry/pricing)
12. [Cloud Run pricing, Google (request-based billing in Tier 1 regions: $0.000024 per vCPU-second, $0.0000025 per GiB-second, $0.40 per million requests; free each month 180,000 vCPU-seconds, 360,000 GiB-seconds and 2 million requests per billing account; read Oct 12, 2026)](https://cloud.google.com/run/pricing)
13. [Logging and viewing logs in Cloud Run, Google (a line of serialized JSON becomes jsonPayload; a severity field becomes the entry's severity; message is the main display text; read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/logging)
14. [LogEntry, Cloud Logging API reference, Google (severity defaults to DEFAULT; updated Sep 4, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry)
15. [General development tips, Cloud Run, Google (startup time adds to request latency; files written to disk use memory and can cause out-of-memory errors; read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/tips/general)
16. [Connect from Cloud Run, Cloud SQL for PostgreSQL, Google (--add-cloudsql-instances; the socket is at /cloudsql/INSTANCE_CONNECTION_NAME, and Postgres adds /.s.PGSQL.5432; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/sql/docs/postgres/connect-run)
17. [PgConnectOptions, sqlx-postgres 0.9.0 on docs.rs (socket() takes the directory of a Unix socket; read Oct 12, 2026)](https://docs.rs/sqlx/latest/sqlx/postgres/struct.PgConnectOptions.html)
18. [Google Cloud client libraries for Rust, Google on GitHub (the official crates; minimum Rust 1.91; read Oct 12, 2026)](https://github.com/googleapis/google-cloud-rust)
19. [Now available: Rust SDK for Google Cloud, Google Cloud blog (more than 140 APIs; Application Default Credentials and service accounts; read Oct 12, 2026)](https://cloud.google.com/blog/topics/developers-practitioners/now-available-rust-sdk-for-google-cloud)
20. [Distroless container images, GoogleContainerTools on GitHub (cc-debian13 with nonroot tags; static has ca-certificates, a passwd entry, /tmp and tzdata; base adds glibc and libssl; cc adds libgcc; read Oct 12, 2026)](https://github.com/GoogleContainerTools/distroless)
21. [cargo-chef, on GitHub (prepare and cook; the dependency layer stays cached while the recipe does not change; read Oct 12, 2026)](https://github.com/lukemathwalker/cargo-chef)
22. [axum graceful-shutdown example, tokio-rs on GitHub (with_graceful_shutdown and a SIGTERM future; read Oct 12, 2026)](https://github.com/tokio-rs/axum/blob/main/examples/graceful-shutdown/src/main.rs)
23. [Google Cloud metrics P-Z, Cloud Monitoring (run.googleapis.com/container/startup_latencies, Beta, a distribution in ms; read Oct 12, 2026)](https://docs.cloud.google.com/monitoring/api/metrics_gcp_p_z)
24. [gcloud CLI reference, Google (run deploy with --image, --cpu, --memory, --execution-environment, --[no-]cpu-boost, --max-instances, --add-cloudsql-instances; beta run deploy with --no-build, --base-image, --command; artifacts repositories create; gcloud 587.0.0, read Oct 12, 2026)](https://docs.cloud.google.com/sdk/gcloud/reference/run/deploy)
25. [Troubleshoot Cloud Run issues, Google (Container failed to start: listen on 0.0.0.0, not 127.0.0.1, on the PORT variable; the image must be compiled for 64-bit Linux; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/troubleshooting)
26. [Speed up builds with cache images, Google Cloud's buildpacks (builds in ephemeral environments such as Cloud Build reuse a previous build only through a cache image; updated Sep 24, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/docs/buildpacks/cache-images)
27. [pid_namespaces(7), Linux man-pages (the init process of a PID namespace receives only signals it has a handler for; SIGKILL from an ancestor namespace is delivered anyway; read Oct 12, 2026)](https://man7.org/linux/man-pages/man7/pid_namespaces.7.html)
28. Exodus team: the sample in this guide (axum 0.8.9, tokio 1.53.2) built three ways and run with 1 CPU and 256 MiB on our build machine, Oct 12, 2026; a cold release build of a 228-crate Rust API of ours with 8 and 2 jobs; Cloud Monitoring of a Rust API of ours, Oct 5-12, 2026; first-request times of another Rust API we moved, Oct 5, 2026; the monthly bills of two Rust setups of ours, Oct 2026; tracing-subscriber 0.3.23 JSON output; exodus 0.1.1 on the sample
