Backend Rust Axum Quickstarter (be-rust-axum)
The project supports generation of Rust programming language based projects, with the Axum web framework by default, and quick installation and integration within OpenShift Jenkins CICD pipelines within the [OpenDevStack](https://www.opendevstack.org/) context.
For Database/Postgres integration it is recommended to use SQLx. Check the Axum with SQLx example. Enjoy a full async, safe and high performant setup!
Purpose of this quickstarter
This is a Rust project with a common Rust project folder and files structure, with its main.rs
file for the final binary to be built, and that makes use of the lib.rs
file, which exposes the crates (AKA modules or packages) of the project (where the business logic happens). Similar to Python project structures.
What files / architecture is generated?
βββ π .config - The local Rust project config folder β βββ π nextest.toml - The local Nextest config file (required for Jenkins CICD) βββ π chart - The Helm chart folder β βββ π templates - The resource files to define in your project (i.e.: deployment.yml, service.yml,...) β β βββ π tests - Helm tests folder β β β βββ π test-connection.yaml - Helm test connection to app service after a new release β β βββ π _helpers.tpl - Helm helpers template β β βββ π deployment.yaml - The k8s Deployment template for the app to release β β βββ π NOTES.txt - The release notes processed on each release β β βββ π service.yaml - The k8s Service template for the app to release β βββ π .helmignore - The Helm ignore file β βββ π Chart.yaml - The Helm Chart main config file β βββ π values.yaml - The values to process on your Helm chart βββ π docker - The docker context to build β βββ π Dockerfile - The docker file to deploy and run βββ π€ Jenkinsfile - This file contains Jenkins build configuration settings βββ π src β βββ π api β β βββ π routes β β β βββ π¦ mod.rs - The routes module file β β β βββ π¦ status.rs β β βββ π¦ mod.rs - The api module file β β βββ π¦ router.rs - The router API routes file β βββ π config β β βββ π¦ mod.rs - The config module file β β βββ π¦ settings.rs - The settings file β βββ π models β β βββ π¦ mod.rs - The models module file β β βββ π¦ status.rs - The status model example file β βββ π¦ lib.rs - The component's library exposing this project's crates to the main.rs β βββ π¦ main.rs - The component's binary compilation βββ π target - The target folder where all builds (debug, release, ...) are stored (do not commit to git!) βββ π tests - Integration tests folder for all exposed component's crates within the lib.rs β βββ π¦ common.rs - Common util implementations and functions β βββ π¦ status_test.rs - Testing the status endpoint example βββ π .editorconfig - To share with your team IDEs some files formatting defaults βββ π .gitignore - The Git ignore file, with some Rust defaults βββ π .pre-commit-config.yaml - The pre-commit tool config file, prepared for a Rust project. βββ π Cargo.lock - The Rust dependency hash tree of this project βββ π Cargo.toml - The Rust project config file βββ π deny.toml - Cargo Deny TOML configuration based on defaults βββ π metadata.yml - Component metadata βββ π README.md - The README file βββ π release-manager.yml - Configuration file for the Release Manager βββ π rustfmt.toml - The Rust formatter configuration file (for cargo fmt) βββ π sonar-project.properties - This file contains SonarQube configuration settings
Usage - how do you start after you provisioned this quickstarter
The project is production ready when deployed in OpenShift.
Rust community and official resources are great to get to it, see learn Rust.
To get Rust ready on your local environment you just require installing rustup
(see install Rust)
# Get the Rustup CLI and already install target computer toolchain and latest stable Rust version
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# If you are new to Rust (also check the rustlings TUI)
rustup doc --book
# Run Unit, Integration and Documentation tests in isolated processes on each test
cargo install cargo-nextest # install nextest!
cargo nextest run
# Cargo format source code
cargo fmt
# Cargo run locally
cargo run
# Cargo run Rust linters
cargo clippy
# Cargo generate documentation
cargo doc [--document-private-items] --open
One can also extend the cargo
features by installing cargo
extensions like:
# Live reload locally
cargo install cargo-watch # https://github.com/watchexec/cargo-watch
# Then you can live reload by:
cargo watch -x run
# Audit Cargo.lock against the advisory DB. The [RustSec Advisory Database](https://github.com/rustsec/rustsec) is a repository of security advisories filed against Rust crates published via crates.io.
cargo install cargo-audit
#Β Audit you dependencies on Licenses, Bans, Advisories and Sources, with [cargo-deny](https://github.com/EmbarkStudios/cargo-deny)
cargo install cargo-deny
# ...
Metadata
The following are typical metadata values that can be used for components based on this quickstarter: Note that the OpenShift resources will be labeled based on this metadata.
name: <the component id (this is the default, if omitted)>
description: "Some microservice implemented in Rust with Axum web framework"
supplier: https://example.com
version: 1.0.1
type: ods
role: backend
runtime: rust
runtimeVersion: 1.83.0
How this quickstarter is built through Jenkins
The Jenkinsfile is provisioned with this quick starter to ease CI/CD process. In Jenkinsfile, there are various stages:
-
Cargo Check - Checks we can compile:
cargo check --all-targets
-
Cargo Format - Checks code is properly formatted:
cargo fmt --all -- --check
-
Cargo Clippy - Collection of lints to catch common mistakes and improve your Rust code (output is also used on SonarQube reports):
cargo clippy --all-features
-
Cargo Deny - Collection of lints to catch dependency graph issues related to licenses, bans, advisories and sources:
cargo deny --all-features check
-
Cargo Test - Runs nextest (instead of
cargo test
, see above why) with xUnit test report generation (see .config/nextest.toml) and code coverage reports with LLVM coverage tool:cargo nextest run --profile ci cargo llvm-cov nextest --profile ci --lcov
-
Build - Builds the release target binary and moves it to the docker folder:
cargo build --release
include::partials$secret-scanning-with-gitleaks.adoc
Technologies in use
The following main Rust technologies are in use when running this boilerplate:
-
Axum: Web application framework that focuses on ergonomics and modularity.
-
Tokio: Runtime for writing reliable, asynchronous, and slim applications.
-
Tower: Library of modular and reusable components for building robust networking clients and servers.
-
Hyper: A fast and correct HTTP implementation for Rust.
Known limitations
First of all, please, let us know if you find any limitation or issue to comment on, thanks!
Building with OpenSSL crate or using alternatives
Recommended first approach
Most of the crates out there, that require cryptographic related features, come with openssl
crate as a default dependency feature, but
one can check the crate’s docs in regards available features and disable openssl and/or default-features and enable provided alternatives,
like rustls`
.
See some examples of known crates that can be configured to skip requiring OpenSSL C library:
SQLx crate without openssl dependency
With the sqlx crate, one can avoid openssl
dependency by enabling the dependency feature tls-rustls
which makes use of the crate rustls
, like:
[dependencies]
sqlx = { version = "0.8", features = [ "runtime-tokio", "tls-rustls", "postgres", "uuid", "json", "chrono", "macros", "migrate" ] }
See SQLx’s TLS features list support, or all SQLx feature flags, for further learning.
Reqwest crate without openssl dependency
With the reqwest crate, one can avoid openssl
dependency by enabling the dependency feature rustls-tls
,
which makes use of the crate rustls
and disabling default features, like:
[dependencies]
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
See reqwest’s features list for further learning.
Using openssl crate
In some cases one might not be able to skip requiring OpenSSL nor LibreSSL C libraries (see issue), but requires compiling them.
To have a lean compilation and shipping experience with Rust, ODS Jenkins Rust agent provides already the dependencies to build OpenSSL from source and statically link them, hence avoiding any mismatch with existing/multiple OS libraries or none (at build or runtime), by enabling statically linking of the dependency within the binary.
The only missing piece required is to enable the vendored
feature in the crate in your Cargo.toml
, see example:
[dependencies]
openssl = { version = "0.10", features = ["vendored"] }
By doing so, cargo
will locally build OpenSSL and statically link the openssl dependencies into the binarie(s) generated, hence avoiding any OS existence nor dependency of the openssl library.