Skip to content

Distroless builds - rust http servers - #452

Open
cosmintanasa47 wants to merge 44 commits into
unikraft-cloud:mainfrom
cosmintanasa47:distroless
Open

Distroless builds - rust http servers#452
cosmintanasa47 wants to merge 44 commits into
unikraft-cloud:mainfrom
cosmintanasa47:distroless

Conversation

@cosmintanasa47

Copy link
Copy Markdown

Created distroless build for rust http server that uses tokio. Details in commit messages. Needs review.

The files that should not be sent to docker daemon.
Same Cargo.lock as for the non-distroless version
Same Cargo.toml as for the non-distroless version
Same Kraftfile as for the non-distroless version
Almost same README as for the non-distroless version. Just modified the names and command examples.
Same src as for the non-distroless version
Almost same test file as for the non-distroless version. Just modified the names so it fits the new context.
…erfile

First stage compiles/builds the static executable, the second imports a lightweight distroless image for static executables and languages like Rust or Go and gets the executable from the builder stage and runs it.

I think that it's worth mentioning that if the user wants to extend the capabilities of the server he/she has to add CA certificates via Dockerfile to the second stage so the server can communicate with other servers or DBs.
If the reviewer also considers that this is worth mentioning in the README, tell me so I can modify the README. Considering that it is just an example, some may consider that it should just work and be as light-weight
as possible so CA certs are not necessary.
Add multi-stage dockerfile that builds static executable (first stage)
and runs it using a distroless image for rust and go executables.
Add list of files to be ignored by docker daemon.
Slightly modified the old (non-distroless version) README.md.
Slightly modified the non-ditroless test file for rust1.91 http server.
Add the non-distroless Kraftfile as this variant do not require
modifications to Kraftfile.
Kept the old non-distroless variant of server.rs.
@cosmintanasa47 cosmintanasa47 changed the title Distroless builds - httpserver-rust1.75-tokio-distroless Distroless builds - rust http servers Aug 27, 2026
Forgot to add "distroless" in some places.
Add multi-stage dockerfile. First stage builds static executable.
Second stage runs it with distroless image of debian13 for rust
and go static executables.
Instead of py_file-distroless.py it was py_file.py
Kept the old file from the non-distroless version.
Slightly modified the old version's by adding "-distroless" in some
places and some new examples for running and listing unikraft instances.
…file

Slightly modified the test file by adding "-distroless" in some places.
… dockerfile

Add multi-stage dockerfile to build and run (first and second stage) the rust http server.
Kept the .gitignore from the original version.
Kept old Kraftfile from non-distroless version.
Slightly modified the previous version adding some command examples and "-distroless".
… file

Slightly modified test file to fit to the new distroless example.
Slightly modify previous versions's by changing entry-point to fit
with new distroless image.
Slightly modify old README to fit to distroless version.
…ootfs, shared_lib directories

The same as in non-distroless variant.
… file

Slightly modify to fit to this version.
… Dockerfile

First stage builds the executable and the second one runs it.

Didn't use a Google distroless image. I used the distrolessdevops/nginx-distroless:1.25.3 image
because it was the same as the one used in the second stage of the non-distroless Dockerfile,
so it had perfect compatibility with the built executable. I have also used the digest
of the image to get the working variant even if it gets modified by the publisher.

I have also taken into consideration using the Chainguard variant but I could have only
imported the latest version for free (not a fix one, or a previous one), so I couldn't
know if the image would still work after being updated.
Eliminate unnecessary docker commands like EXPOSE,
CMD and ENTRYPOINT from those dockerfiles.
The commands are written already in Kraftfile.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are confirmed functional correctness issues (e.g., a non-compiling Rust server thread spawn and an incorrect rootfs copy path) plus a few packaging/docs mistakes that should be fixed before merging.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces multiple Rust-based HTTP server examples packaged as distroless images for Unikraft Cloud deployments, along with end-to-end tests and deployment instructions.

Changes:

  • Added new distroless Rust HTTP server examples (plain Rust, Tokio, Actix Web, Rocket, and a Trunk/Leptos static site served via Nginx).
  • Added Kraftfile + Dockerfile build definitions and README deployment guides for each example.
  • Added end-to-end Python tests that build, deploy, and verify responses from each deployed service.
File summaries
File Description
httpserver-rust1.91-distroless/test_httpserver-rust1.91-distroless.py E2E test that deploys the example and asserts “Hello, World!”
httpserver-rust1.91-distroless/server.rs Minimal HTTP server implementation for the example
httpserver-rust1.91-distroless/README.md Deployment/run instructions and expected outputs
httpserver-rust1.91-distroless/Kraftfile Unikraft Cloud build/run spec for the example
httpserver-rust1.91-distroless/Dockerfile Distroless build pipeline for the example binary
httpserver-rust1.91-distroless/.gitignore Ignores build artifacts
httpserver-rust1.91-distroless/.dockerignore Reduces Docker build context for the example
httpserver-rust1.88-rocket0.5-distroless/test_httpserver-rust1.88-rocket0.5-distroless.py E2E test that hits a Rocket route and validates response
httpserver-rust1.88-rocket0.5-distroless/src/main.rs Rocket-based HTTP server implementation
httpserver-rust1.88-rocket0.5-distroless/Rocket.toml Rocket bind address/port config
httpserver-rust1.88-rocket0.5-distroless/README.md Deployment/run instructions for the Rocket example
httpserver-rust1.88-rocket0.5-distroless/Kraftfile Unikraft Cloud build/run spec for Rocket example
httpserver-rust1.88-rocket0.5-distroless/Dockerfile Distroless build pipeline for Rocket binary
httpserver-rust1.88-rocket0.5-distroless/Cargo.toml Rocket example crate manifest
httpserver-rust1.88-rocket0.5-distroless/Cargo.lock Rocket example dependency lockfile
httpserver-rust1.88-rocket0.5-distroless/.gitignore Ignores Cargo build artifacts
httpserver-rust1.88-rocket0.5-distroless/.dockerignore Reduces Docker build context for Rocket example
httpserver-rust1.88-actix-web4-distroless/test_httpserver-rust1.88-actix-web4-distroless.py E2E test for Actix endpoints (/ and /hey)
httpserver-rust1.88-actix-web4-distroless/src/main.rs Actix Web HTTP server implementation
httpserver-rust1.88-actix-web4-distroless/README.md Deployment/run instructions for the Actix example
httpserver-rust1.88-actix-web4-distroless/Kraftfile Unikraft Cloud build/run spec for Actix example
httpserver-rust1.88-actix-web4-distroless/Dockerfile Distroless build pipeline for Actix binary
httpserver-rust1.88-actix-web4-distroless/Cargo.toml Actix example crate manifest
httpserver-rust1.88-actix-web4-distroless/Cargo.lock Actix example dependency lockfile
httpserver-rust1.88-actix-web4-distroless/.gitignore Ignores Cargo build artifacts
httpserver-rust1.88-actix-web4-distroless/.dockerignore Reduces Docker build context for Actix example
httpserver-rust1.75-tokio-distroless/test_httpserver-rust1.75-tokio-distroless.py E2E test for Tokio-based server example
httpserver-rust1.75-tokio-distroless/src/main.rs Tokio-based TCP HTTP response loop
httpserver-rust1.75-tokio-distroless/README.md Deployment/run instructions for Tokio example
httpserver-rust1.75-tokio-distroless/Kraftfile Unikraft Cloud build/run spec for Tokio example
httpserver-rust1.75-tokio-distroless/Dockerfile Distroless build pipeline for Tokio binary
httpserver-rust1.75-tokio-distroless/Cargo.toml Tokio example crate manifest
httpserver-rust1.75-tokio-distroless/Cargo.lock Tokio example dependency lockfile
httpserver-rust1.75-tokio-distroless/.dockerignore Reduces Docker build context for Tokio example
httpserver-rust-trunkrs-leptos-distroless/test_httpserver-rust-trunkrs-leptos-distroless.py E2E test that verifies a 200 response from the deployed service
httpserver-rust-trunkrs-leptos-distroless/shared_lib/src/lib.rs Shared library used by the frontend (with unit tests)
httpserver-rust-trunkrs-leptos-distroless/shared_lib/Cargo.toml Shared library crate manifest
httpserver-rust-trunkrs-leptos-distroless/shared_lib/Cargo.lock Shared library lockfile
httpserver-rust-trunkrs-leptos-distroless/rootfs/rootfs/wwwroot/index.html Static web root content included in the image rootfs
httpserver-rust-trunkrs-leptos-distroless/rootfs/rootfs/etc/nginx/nginx.conf Nginx configuration included in the image rootfs
httpserver-rust-trunkrs-leptos-distroless/README.md Deployment/run instructions for Trunk/Leptos example
httpserver-rust-trunkrs-leptos-distroless/Kraftfile Unikraft Cloud build/run spec for Nginx-based example
httpserver-rust-trunkrs-leptos-distroless/frontend/Trunk.toml Trunk build configuration
httpserver-rust-trunkrs-leptos-distroless/frontend/src/main.rs Leptos CSR frontend code
httpserver-rust-trunkrs-leptos-distroless/frontend/nginx.conf Nginx config used/overlaid for serving the built frontend
httpserver-rust-trunkrs-leptos-distroless/frontend/index.html Trunk entry HTML
httpserver-rust-trunkrs-leptos-distroless/frontend/Cargo.toml Frontend crate manifest
httpserver-rust-trunkrs-leptos-distroless/Dockerfile Builds frontend assets with Trunk and packages into distroless Nginx image
httpserver-rust-trunkrs-leptos-distroless/.gitignore Ignores build artifacts
Review details

Suppressed comments (3)

httpserver-rust1.91-distroless/server.rs:21

  • stream.write(response) may perform a partial write, which can result in truncated HTTP responses. Use write_all() (and ideally include Content-Length/Connection: close) to ensure the full response is sent.
    httpserver-rust1.91-distroless/server.rs:40
  • The spawned thread closure needs to capture stream by value (move) to satisfy the 'static bound, and JoinHandle is #[must_use] so dropping it without binding may trigger warnings. Capture with move and explicitly discard the handle.
    httpserver-rust1.88-actix-web4-distroless/README.md:103
  • Typo in the sample legacy output: service name loral-water-sndspsy3 should match the domain shown above (floral-water-sndspsy3).
  • Files reviewed: 45/50 changed files
  • Comments generated: 8
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

#FROM distrolessdevops/nginx-distroless:1.25.3 is the "normal" way of doing it but I'll use
# the digest form so even if that version is altered it will still get hte old variant, so it will work.

COPY ./rootfs/ /
Comment on lines +15 to +35
view! {
<p>
<div>
<button
on:click=move |_| set_count.set(shared_lib::add(count.get(), 1))
>
"Click to add one"
</button>
</div>
<div>
<button
on:click=move |_| set_count.set(shared_lib::subtract(count.get(), 1))
>
"Click to remove one"
</button>
</div>
<div>
<span>Count: {count}</span>
</div>
</p>
}
Comment on lines +6 to +15
fn handle_read(mut stream: &TcpStream) {
let mut buf = [0u8 ;4096];
match stream.read(&mut buf) {
Ok(_) => {
let req_str = String::from_utf8_lossy(&buf);
println!("{}", req_str);
},
Err(e) => println!("Unable to read stream: {}", e),
}
}
Comment thread httpserver-rust1.88-actix-web4-distroless/.dockerignore

**Using the unikraft CLI (Recommended)**
```bash title="unikraft"
unikraft build . --output <my-org>/httpserver-rust188-actix-web4-dsitroless:latest
@@ -0,0 +1,3 @@
Kraftfile
README.md
test_httpserver-rust1.91.py

```ansi title="unikraft"
METRO NAME STATE IMAGE ARGS MEMORY VCPUS FQDN CREATED
fra httpserver-rust191-dsitroless-pinzf standby <my-org>/httpserver-rust191-dsitroless 384MiB 1 snowy-feather-k4pfgl8t.fra.unikraft.app 2 minutes ago
Comment on lines +1 to +3
use std::net::{TcpStream, TcpListener};
use std::io::{Read, Write};
use std::thread;
Fix the issues that Copilot found and I considered
them actual mistakes.
@cosmintanasa47

Copy link
Copy Markdown
Author

I have fixed the typos. I do not consider the COPY rootfs "mistake" detected by Copilot as an actual problem. The previous non-distroless dockerfile did the same thing and worked just well. Same for the distroless version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants