Files
arr/Dockerfile
Miguel Palhas a9848fddce
ci / web (push) Successful in 33s
ci / rust (push) Successful in 1m9s
ci / image (push) Successful in 4m59s
ci: build the production image in CI
Dokploy built from source on the host, so every deploy paid a full cold
cargo build and the layer cache died with the builder. CI now builds and
pushes to the Gitea registry, and the deploy is a pull.

The Gitea push webhook fires before Actions starts, so autoDeploy on the
Dokploy application is off and this job triggers the deploy itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 15:37:50 +01:00

72 lines
3.1 KiB
Docker

# Build the SPA first so build.rs embeds web/dist via ARR_WEB_DIST.
FROM node:22-bookworm-slim AS web
WORKDIR /src
ENV CI=true
RUN corepack enable && corepack prepare pnpm@11.21.0 --activate
COPY web/package.json web/pnpm-lock.yaml ./web/
RUN pnpm -C web install --frozen-lockfile --config.dangerouslyAllowAllBuilds=true
COPY web ./web
RUN pnpm -C web build
# Every translation backend is a default-off cargo feature (DESIGN.md §15), so
# a build without these ships an image that cannot translate at all. All four
# go in: which one is in use is a database setting, and the point of the
# feature switches is the build, not the deployment.
#
# The dependency build and the workspace build are split with cargo-chef so a
# source-only change reuses the dependency layer. The two `cargo` invocations
# must carry identical flags or the cook output is not reusable.
FROM lukemathwalker/cargo-chef:latest-rust-1-bookworm AS chef
WORKDIR /src
ENV ARR_FEATURES=translate-openai,translate-deepl,translate-google,translate-command
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM chef AS build
COPY --from=planner /src/recipe.json recipe.json
# cargo-chef's skeleton keeps build scripts, and arr-daemon's panics in release
# when it can find no SPA bundle. A stub satisfies it; the real bundle arrives
# below and the changed ARR_WEB_DIST reruns only that one build script.
RUN mkdir -p /stub/dist && printf '<!doctype html>stub\n' > /stub/dist/index.html
ENV ARR_WEB_DIST=/stub/dist
RUN cargo chef cook --release -p arr-daemon --features "$ARR_FEATURES" \
--recipe-path recipe.json
COPY . .
COPY --from=web /src/web/dist ./web/dist
ENV ARR_WEB_DIST=/src/web/dist
RUN cargo build --release -p arr-daemon --features "$ARR_FEATURES"
# §15 runs `alass` over every fetched and every translated subtitle, and it is
# not in Debian — a release binary is the only way in. Its own stage so the
# runtime image needs no download tool, and so a source change does not refetch
# it. The digest is pinned: an unverified binary from a release page is not
# something to run over the library. The asset is x86-64 only, which is what
# this image targets.
FROM debian:bookworm-slim AS alass
ARG ALASS_VERSION=2.0.0
ARG ALASS_SHA256=7bd0b9ae7e035d3ba940eacffb21243614df36231d47f21f0b4ce42001ab7fcd
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fsSL -o /usr/local/bin/alass \
"https://github.com/kaegi/alass/releases/download/v${ALASS_VERSION}/alass-linux64" \
&& echo "${ALASS_SHA256} /usr/local/bin/alass" | sha256sum -c - \
&& chmod +x /usr/local/bin/alass \
&& alass --version
FROM debian:bookworm-slim
# ffmpeg covers both `ffprobe` for arr-probe and the audio extraction `alass`
# shells out to.
RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=alass /usr/local/bin/alass /usr/local/bin/alass
COPY --from=build /src/target/release/arr /usr/local/bin/arr
ENV ARR_BIND_ADDR=0.0.0.0:7878 \
ARR_DATABASE_PATH=/data/arr.db
VOLUME /data
EXPOSE 7878
ENTRYPOINT ["arr"]