Skip to content

Commit b4c1f0a

Browse files
authored
Merge pull request #84 from nanotaboada/perf/docker-build
perf(docker): tune release profile and switch to musl/Alpine
2 parents e1602d6 + e8cb513 commit b4c1f0a

3 files changed

Lines changed: 42 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
### Changed
1818

1919
- Consolidated `commitlint`, `format`, and `lint` CI jobs into a single `lint` job (#42)
20+
- `[profile.release]` tuned in `Cargo.toml` with `lto = true`, `codegen-units = 1`, `strip = true`, `panic = "abort"` for smaller binary size (#60)
21+
- `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)
2022
- `get_all`, `get_by_id`, `get_by_squad_number`, and `delete` in `player_service` now return `Result<T, PlayerServiceError>` instead of `Result<T, diesel::result::Error>`, aligning with the `CreateError`/`UpdateError` pattern (#56)
2123
- `codecov.yml` `ignore` list extended with `src/**/mod.rs` to exclude module re-exports from coverage reporting (#78)
2224
- `codecov.yml` comment updated to reflect goal of maximum coverage on business logic layers (#78)

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ diesel_migrations = "2.3"
1515
libsqlite3-sys = { version = "0.30", features = ["bundled"] }
1616
rocket_okapi = { version = "0.9.0", features = ["swagger"] }
1717
schemars = { version = "1.2" }
18+
19+
[profile.release]
20+
lto = true # link-time optimisation — reduces binary size and improves inlining
21+
codegen-units = 1 # single codegen unit — required for full LTO
22+
strip = true # strip debug symbols (Rust 1.59+)
23+
panic = "abort" # remove unwinding machinery — smaller binary, faster panics

Dockerfile

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,78 +2,80 @@
22
# Stage 1: Builder
33
# This stage builds the application and its dependencies.
44
# ------------------------------------------------------------------------------
5-
FROM rust:1.88-slim-bookworm AS builder
5+
FROM --platform=linux/amd64 rust:1.88-slim-bookworm AS builder
66

7-
# Install build dependencies required by rusqlite (bundled feature compiles
8-
# SQLite from source via the cc crate and needs a C compiler)
7+
# -- Install system packages ---------------------------------------------------
8+
# gcc / pkg-config: required by libsqlite3-sys (bundled feature compiles from
9+
# source via the cc crate)
10+
# musl-tools: provides musl-gcc, the C linker required for the
11+
# x86_64-unknown-linux-musl target
912
RUN apt-get update && apt-get install -y --no-install-recommends \
1013
gcc \
1114
pkg-config \
15+
musl-tools \
1216
&& rm -rf /var/lib/apt/lists/*
1317

18+
RUN rustup target add x86_64-unknown-linux-musl
19+
1420
WORKDIR /app
1521

16-
# Copy dependency manifests first to leverage layer caching
22+
# -- Pre-build dependencies (cached) ------------------------------------------
23+
# Copy only the manifests and a stub main.rs so Cargo can compile all
24+
# dependencies in isolation. This layer is cached and only invalidated when
25+
# Cargo.toml or Cargo.lock change — not when application source changes.
1726
COPY Cargo.toml Cargo.lock ./
18-
19-
# Stub out a minimal src/main.rs so Cargo can resolve and compile dependencies
20-
# without the real application sources — this layer is only invalidated when
21-
# Cargo.toml or Cargo.lock change.
2227
RUN mkdir src && echo "fn main() {}" > src/main.rs
2328

2429
RUN --mount=type=cache,target=/usr/local/cargo/registry \
2530
--mount=type=cache,target=/app/target \
26-
cargo build --release
27-
28-
# Overlay with the real application sources
31+
CC_x86_64_unknown_linux_musl=musl-gcc \
32+
cargo build --release --target x86_64-unknown-linux-musl
33+
34+
# -- Build application ---------------------------------------------------------
35+
# Overlay with the real sources. The stub main.rs is overwritten by the COPY,
36+
# but Cargo uses mtime to detect changes — touching main.rs after the COPY
37+
# ensures Cargo recompiles the application crate without re-compiling
38+
# dependencies (which remain in the cache-mounted target/).
2939
COPY src/ ./src/
3040
COPY migrations/ ./migrations/
3141
COPY Rocket.toml ./
3242

33-
# Touch main.rs so Cargo detects the change, rebuild only app code, then copy
34-
# the binary out of the cache-mounted target/ into the image layer.
3543
RUN --mount=type=cache,target=/usr/local/cargo/registry \
3644
--mount=type=cache,target=/app/target \
3745
touch src/main.rs && \
38-
cargo build --release && \
39-
cp target/release/rust-samples-rocket-restful /app/rust-samples-rocket-restful
46+
CC_x86_64_unknown_linux_musl=musl-gcc \
47+
cargo build --release --target x86_64-unknown-linux-musl && \
48+
cp target/x86_64-unknown-linux-musl/release/rust-samples-rocket-restful /app/rust-samples-rocket-restful
4049

4150
# ------------------------------------------------------------------------------
4251
# Stage 2: Runtime
4352
# This stage creates the final, minimal image to run the application.
4453
# ------------------------------------------------------------------------------
45-
FROM debian:bookworm-slim AS runtime
46-
47-
# Install curl for health check
48-
RUN apt-get update && apt-get install -y --no-install-recommends \
49-
curl \
50-
&& rm -rf /var/lib/apt/lists/*
54+
FROM --platform=linux/amd64 alpine:3.23 AS runtime
5155

5256
WORKDIR /app
5357

54-
# Metadata labels for the image. These are useful for registries and inspection.
58+
# -- Install system packages ---------------------------------------------------
59+
RUN apk add --no-cache curl
60+
61+
# -- Metadata ------------------------------------------------------------------
5562
LABEL org.opencontainers.image.title="🧪 RESTful API with Rust and Rocket"
5663
LABEL org.opencontainers.image.description="Proof of Concept for a RESTful API made with Rust and Rocket"
5764
LABEL org.opencontainers.image.licenses="MIT"
5865
LABEL org.opencontainers.image.source="https://github.com/nanotaboada/rust-samples-rocket-restful"
5966
LABEL org.sonarsource.docker.dockerfile="/Dockerfile"
6067

61-
# https://rules.sonarsource.com/docker/RSPEC-6504/
62-
63-
# Copy application binary and Rocket configuration
68+
# -- Copy artifacts ------------------------------------------------------------
6469
COPY --from=builder /app/rust-samples-rocket-restful .
6570
COPY --from=builder /app/Rocket.toml ./Rocket.toml
66-
67-
# Copy metadata docs for container registries (e.g.: GitHub Container Registry)
6871
COPY --chmod=444 README.md ./
69-
70-
# Copy entrypoint and healthcheck scripts
7172
COPY --chmod=555 scripts/entrypoint.sh ./entrypoint.sh
7273
COPY --chmod=555 scripts/healthcheck.sh ./healthcheck.sh
7374

74-
# Add system user and prepare volume mount point
75-
RUN addgroup --system rocket && \
76-
adduser --system --ingroup rocket rocket && \
75+
# -- Configure runtime ---------------------------------------------------------
76+
# https://rules.sonarsource.com/docker/RSPEC-6504/
77+
RUN addgroup -S rocket && \
78+
adduser -S -G rocket rocket && \
7779
mkdir -p /storage && \
7880
chown -R rocket:rocket /storage
7981

0 commit comments

Comments
 (0)