On December 7, 2023, Google released the following video on using Rust for Cloud Run applications. This is an excellent getting started video. I have been working directly with the Google Cloud Run team since the beta release. I thought I would write an article taking their video, and JK Gunnink’s repository and article and take it to the next level.
This article is Part 2 of a three-part article. The first part implements container multi-stage builds. The second part updates the application to use the latest version of the Cargo package Hyper. The third part extends the application with new features.
Note: I am very experienced with Google Cloud and Docker, but I am a beginner with the Rust language.
Objectives
- Update the version of the
hyper
Cargo package used to build the Cloud Run application. The article uses Hyper version 0.14. The latest version is 1.0.1.
Endpoint Summary
- / – Return the
Hello, Rustless!
message.
Clone the repository
I will start by cloning JK Gunnink’s repository.
1 |
git clone https://github.com/jgunnink/rustless_webserver_demo.git |
Next, we need to update the dependencies to support hyper version 1.
Original Cargo.toml
1 2 3 4 5 6 7 8 9 10 |
[package] name = "rustless" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] hyper = { version = "0.14", features = ["full"] } tokio = { version = "1", features = ["full"] } |
Modified Cargo.toml
1 2 3 4 5 6 7 8 9 10 11 12 |
[package] name = "rustless" version = "0.1.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] tokio = { version = "1", features = ["full"] } hyper = { version = "1", features = ["full"] } http-body-util = "0.1" hyper-util = { version = "0.1", features = ["full"] } |
The modified version adds two dependencies:
- hyper-body-util
- hyper-util
HTTP Body (hyper-body-util) is a trait representing asynchronous operations on an HTTP body. The cargo information page is here.
Hyper Utilities (hyper-util) is a collection of utilities to do common things with hyper. The cargo information page is here.
Those dependencies are required to use hyper version 1.
Use improved multi-stage Dockerfile
This step is not required. This step does provide for a significant reduction in container image size.
Copy the Dockerfile that I modified in part 1 of this article series.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
FROM rust as builder WORKDIR /myapp COPY . . RUN cargo install --path . FROM debian:bookworm-slim RUN rm -rf /var/lib/apt/lists/* WORKDIR /myapp COPY --from=builder /myapp/target/release/rustless /myapp EXPOSE 8080:8080 CMD [ "/myapp/rustless" ] |
Replace the source code in the file src/main.rs
with this content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#![deny(warnings)] use std::convert::Infallible; use std::net::SocketAddr; use http_body_util::Full; use hyper::body::Bytes; use hyper::server::conn::http1; use hyper::service::service_fn; use hyper::{Request, Response}; use hyper_util::rt::TokioIo; use tokio::net::TcpListener; async fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> { Ok(Response::new(Full::new(Bytes::from("Hello, Restless!")))) } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); // We create a TcpListener and bind it to 0.0.0.0:8080 let listener = TcpListener::bind(addr).await?; // We start a loop to continuously accept incoming connections loop { let (stream, _) = listener.accept().await?; // Use an adapter to access something implementing `tokio::io` traits as if they implement // `hyper::rt` IO traits. let io = TokioIo::new(stream); // Spawn a tokio task to serve multiple connections concurrently tokio::task::spawn(async move { // Finally, we bind the incoming connection to our `hello` service if let Err(err) = http1::Builder::new() // `service_fn` converts our function in a `Service` .serve_connection(io, service_fn(hello)) .await { println!("Error serving connection: {:?}", err); } }); } } |
The new source code provides the same features as the original but is updated to fit the new features in hyper version 1.
Build the container
1 2 |
cd rustless_websever_demo docker build -t rust-hello-world-v3 . |
Run the container
1 |
docker run -d --rm -p 8080:8080 rust-hello-world-v3 |
Test the container
1 2 3 |
curl localhost:8080 Hello, Rustless! |
Excellent, the new source code works correctly.
Build and Deploy to Cloud Run
1 |
gcloud builds submit . |
Go to the Cloud Run Service URL. In my case it is https://rustless-e2v2ixiywa-uc.a.run.app/
Summary
This article shows how to update the repository source code to use the new version of hyper. Hyper version 1 made many changes that required a rewrite of the application.
More Information
- JK Gunnink: Serverless Rust with Cloud Run
- JK Gunnink: GitHub repository for his article
- Google Cloud: YouTube: Rust on Cloud Run
- Hyper: Cargo HTTP package
- Hyper documentation
Photography Credit
I write free articles about technology. Recently, I learned about Pexels.com which provides free images. The image in this article is courtesy of Pixabay at Pexels. Note: This is the same image used in JK Gunnink’s article.
I design software for enterprise-class systems and data centers. My background is 30+ years in storage (SCSI, FC, iSCSI, disk arrays, imaging) virtualization. 20+ years in identity, security, and forensics.
For the past 14+ years, I have been working in the cloud (AWS, Azure, Google, Alibaba, IBM, Oracle) designing hybrid and multi-cloud software solutions. I am an MVP/GDE with several.
1 Pingback