#Any tips/tricks on building rust apps?

1 messages · Page 1 of 1 (latest)

hidden carbon
#

Hi everyone!

Looking to build a cargo workspace with multiple microservices and shared dependencies.

Right now we use a bunch of redundant dockerfiles chained together with docker compose. Even though we're using multistage builds with cargo-chef, it can still take over an hour to build 8 backend services when the profile is set to release.

Full disclosure: not a rustacean, just tasked with optimizing the ci/cd pipeline 😅

# workspace cargo.toml
[workspace]
members = ["rest/webhooks-service", "rest/storage-service", "rest/location-service", "kafka/one-fish-consumer", "kafka/two-fish-consumer", "kafka/red-fish-consumer", "kafka/blue-fish-consumer","cli/sql_transfer", "cli/utilities"]
resolver = "1"

[workspace.dependencies]
internal_deps = { path = "internal_deps" }
# internal_deps cargo.toml
[package]
name = "internal_deps"
version = "0.1.4"
edition = "2021"

[dependencies]
anyhow = "1.0.0"
base64 = "0.21.0"
chrono = { version = "0.4.38", features = ["serde"] }
dotenv = "0.15.0"
futures = "0.3.30"
log = "0.4.22"
mongodb = "2.3.0"
num-traits = "0.2.16"
once_cell = "1.17.1"
openapi = {path = "twilio-rust"}
rdkafka = "0.28.0"
redis = "0.22.3"
regex = "1.10.2"
reqwest = {version = "0.11.13", features = ["json"]}
rocket = "=0.5.0-rc.3"
serde = {version = "1.0.144", features = ["derive"]}
serde_json = "1.0.85"
slog = "2.7.0"
slog-async = "2.8.0"
slog-json = "2.6.1"
slog-scope = "4.4.0"
slog-stdlog = "4.1.0"
sqlx = "0.7.1"
tiberius = { version = "0.12.2", features = [] }
tiberius-mappers = "0.6.0"
tokio = "1.21.0"
tokio-util="0.7.10"
#

This is a condensed dockerfile for a kafka consumer

# syntax=docker/dockerfile:1.7.0
FROM lukemathwalker/cargo-chef:0.1.65-rust-1 as planner
WORKDIR /app
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM lukemathwalker/cargo-chef:0.1.65-rust-1 as cook
ARG CARGO_INCREMENTAL=0
ARG RUSTFLAGS=-Awarnings
WORKDIR /app
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
ARG PROFILE=${PROFILE:-release}
ARG CARGO_TARGET_DIR=/app/target/${PROFILE}
ARG APP_NAME=location-service
RUN <<EOF
#!/usr/bin/env bash
cargo build --profile ${PROFILE} --bin ${APP_NAME}
if [ "${PROFILE}" = "dev" ]; then
    mv ${CARGO_TARGET_DIR}/debug/${APP_NAME} /app/
elif [ "${PROFILE}" = "release" ]; then
    mv ${CARGO_TARGET_DIR}/release/${APP_NAME} /app/
else
    echo "Unknown profile: ${PROFILE}"
    exit 1
fi
EOF
FROM debian:12.4-slim AS runner
WORKDIR /app
RUN <<EOF
#!/usr/bin/env bash
apt-get update
apt-get install -y --no-install-recommends ca-certificates tzdata
rm -rf /var/lib/apt/lists/*
EOF
ARG APP_NAME=location-service
COPY --from=cook /app/${APP_NAME} /usr/local/bin/
COPY --from=cook /app/rest/location-service/Rocket.toml Rocket.toml
ARG USR=appuser
ARG UID=1000
ARG GID=1000
RUN <<EOF
#!/usr/bin/env bash
mkdir -p /etc/sudoers.d
if getent group ${USR} >/dev/null; then
    groupmod -g ${GID} ${USR}
else
    addgroup --system --gid ${GID} ${USR}
fi
if id -u ${USR} >/dev/null 2>&1; then
    usermod -u ${UID} -g ${GID} ${USR}
else
    adduser --system --uid ${UID} --ingroup ${USR} ${USR}
fi
echo "${USR} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
echo $USR ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USR
chmod 0440 /etc/sudoers.d/$USR
EOF
USER $USR
CMD ["location-service"]
dense portal
#

Dagger can definitely help with simplifying the mess of dockerfiles and docker compose files. It will probably speed it up along the way. The core rust build is what it is, though. We can make it easier to implement the rust best practices, ie. setup cache volumes in all the right places, filter unnecessary files to only trigger rust builds that are needed, etc. Beyond that, it becomes a core rust issue.

hidden carbon
#

That's totally reasonable. And hi! Big fan of your previous work

dense portal
#

We can help you get turn big ball of scripts into a nice clean API

hidden carbon
#

I searched both cargo and rust and only found a couple of modules. Wasn't sure if there was a canonical solution — now I know haha