diff --git a/CHANGELOG.md b/CHANGELOG.md index ce63b4f..5e22578 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Consolidated `commitlint`, `format`, and `lint` CI jobs into a single `lint` job (#42) +- `[profile.release]` tuned in `Cargo.toml` with `lto = true`, `codegen-units = 1`, `strip = true`, `panic = "abort"` for smaller binary size (#60) +- `Dockerfile` builder stage updated to compile against `x86_64-unknown-linux-musl` via `musl-tools` for a fully static binary; runtime stage switched from `debian:bookworm-slim` to `alpine` (#57) - `get_all`, `get_by_id`, `get_by_squad_number`, and `delete` in `player_service` now return `Result` instead of `Result`, aligning with the `CreateError`/`UpdateError` pattern (#56) - `codecov.yml` `ignore` list extended with `src/**/mod.rs` to exclude module re-exports from coverage reporting (#78) - `codecov.yml` comment updated to reflect goal of maximum coverage on business logic layers (#78) diff --git a/Cargo.toml b/Cargo.toml index 1aa4773..7ba3fd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,9 @@ diesel_migrations = "2.3" libsqlite3-sys = { version = "0.30", features = ["bundled"] } rocket_okapi = { version = "0.9.0", features = ["swagger"] } schemars = { version = "1.2" } + +[profile.release] +lto = true # link-time optimisation — reduces binary size and improves inlining +codegen-units = 1 # single codegen unit — required for full LTO +strip = true # strip debug symbols (Rust 1.59+) +panic = "abort" # remove unwinding machinery — smaller binary, faster panics diff --git a/Dockerfile b/Dockerfile index f34350f..3cdc027 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,78 +2,80 @@ # Stage 1: Builder # This stage builds the application and its dependencies. # ------------------------------------------------------------------------------ -FROM rust:1.88-slim-bookworm AS builder +FROM --platform=linux/amd64 rust:1.88-slim-bookworm AS builder -# Install build dependencies required by rusqlite (bundled feature compiles -# SQLite from source via the cc crate and needs a C compiler) +# -- Install system packages --------------------------------------------------- +# gcc / pkg-config: required by libsqlite3-sys (bundled feature compiles from +# source via the cc crate) +# musl-tools: provides musl-gcc, the C linker required for the +# x86_64-unknown-linux-musl target RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ pkg-config \ + musl-tools \ && rm -rf /var/lib/apt/lists/* +RUN rustup target add x86_64-unknown-linux-musl + WORKDIR /app -# Copy dependency manifests first to leverage layer caching +# -- Pre-build dependencies (cached) ------------------------------------------ +# Copy only the manifests and a stub main.rs so Cargo can compile all +# dependencies in isolation. This layer is cached and only invalidated when +# Cargo.toml or Cargo.lock change — not when application source changes. COPY Cargo.toml Cargo.lock ./ - -# Stub out a minimal src/main.rs so Cargo can resolve and compile dependencies -# without the real application sources — this layer is only invalidated when -# Cargo.toml or Cargo.lock change. RUN mkdir src && echo "fn main() {}" > src/main.rs RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/app/target \ - cargo build --release - -# Overlay with the real application sources + CC_x86_64_unknown_linux_musl=musl-gcc \ + cargo build --release --target x86_64-unknown-linux-musl + +# -- Build application --------------------------------------------------------- +# Overlay with the real sources. The stub main.rs is overwritten by the COPY, +# but Cargo uses mtime to detect changes — touching main.rs after the COPY +# ensures Cargo recompiles the application crate without re-compiling +# dependencies (which remain in the cache-mounted target/). COPY src/ ./src/ COPY migrations/ ./migrations/ COPY Rocket.toml ./ -# Touch main.rs so Cargo detects the change, rebuild only app code, then copy -# the binary out of the cache-mounted target/ into the image layer. RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/app/target \ touch src/main.rs && \ - cargo build --release && \ - cp target/release/rust-samples-rocket-restful /app/rust-samples-rocket-restful + CC_x86_64_unknown_linux_musl=musl-gcc \ + cargo build --release --target x86_64-unknown-linux-musl && \ + cp target/x86_64-unknown-linux-musl/release/rust-samples-rocket-restful /app/rust-samples-rocket-restful # ------------------------------------------------------------------------------ # Stage 2: Runtime # This stage creates the final, minimal image to run the application. # ------------------------------------------------------------------------------ -FROM debian:bookworm-slim AS runtime - -# Install curl for health check -RUN apt-get update && apt-get install -y --no-install-recommends \ - curl \ - && rm -rf /var/lib/apt/lists/* +FROM --platform=linux/amd64 alpine:3.23 AS runtime WORKDIR /app -# Metadata labels for the image. These are useful for registries and inspection. +# -- Install system packages --------------------------------------------------- +RUN apk add --no-cache curl + +# -- Metadata ------------------------------------------------------------------ LABEL org.opencontainers.image.title="🧪 RESTful API with Rust and Rocket" LABEL org.opencontainers.image.description="Proof of Concept for a RESTful API made with Rust and Rocket" LABEL org.opencontainers.image.licenses="MIT" LABEL org.opencontainers.image.source="https://github.com/nanotaboada/rust-samples-rocket-restful" LABEL org.sonarsource.docker.dockerfile="/Dockerfile" -# https://rules.sonarsource.com/docker/RSPEC-6504/ - -# Copy application binary and Rocket configuration +# -- Copy artifacts ------------------------------------------------------------ COPY --from=builder /app/rust-samples-rocket-restful . COPY --from=builder /app/Rocket.toml ./Rocket.toml - -# Copy metadata docs for container registries (e.g.: GitHub Container Registry) COPY --chmod=444 README.md ./ - -# Copy entrypoint and healthcheck scripts COPY --chmod=555 scripts/entrypoint.sh ./entrypoint.sh COPY --chmod=555 scripts/healthcheck.sh ./healthcheck.sh -# Add system user and prepare volume mount point -RUN addgroup --system rocket && \ - adduser --system --ingroup rocket rocket && \ +# -- Configure runtime --------------------------------------------------------- +# https://rules.sonarsource.com/docker/RSPEC-6504/ +RUN addgroup -S rocket && \ + adduser -S -G rocket rocket && \ mkdir -p /storage && \ chown -R rocket:rocket /storage