diff --git a/.gitea/workflows/build-distroless.yml b/.gitea/workflows/build-distroless.yml deleted file mode 100644 index f0dcb0d..0000000 --- a/.gitea/workflows/build-distroless.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Build Distroless rTorrent - -on: - workflow_dispatch: - -jobs: - build: - runs-on: kube - if: github.ref == 'refs/heads/main' - env: - DOCKER_BUILD_RECORD_UPLOAD: 'false' - DOCKER_BUILD_SUMMARY: 'false' - steps: - - name: Checkout code - uses: https://github.com/actions/checkout@v4 - with: - persist-credentials: false - - - name: Install Docker CLI - run: | - apt-get update - apt-get install -y --no-install-recommends docker.io - rm -rf /var/lib/apt/lists/* - - - name: Log in to Docker Hub - uses: https://github.com/docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_TOKEN }} - - - name: Set up temporary builder - uses: https://github.com/docker/setup-buildx-action@v3 - with: - driver: docker-container - cache-binary: false - keep-state: false - cleanup: true - - - name: Build and push to Docker Hub - uses: https://github.com/docker/build-push-action@v6 - with: - context: . - file: Dockerfile.distroless - platforms: linux/amd64 - pull: true - push: true - load: false - tags: docker.io/k2patel/rtorrent:distroless - labels: | - org.opencontainers.image.source=https://git.k2patel.in/k2patel/docker-rtorrent - org.opencontainers.image.revision=${{ github.sha }} diff --git a/Dockerfile b/Dockerfile index 78219be..de7d803 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,21 @@ -FROM alpine:3.24 - -RUN mkdir /myconfig -RUN mkdir /home/nfs_download -RUN mkdir /root || true - -# create file and ignore if it fails -RUN touch /root/.rtorrent.rc || true -COPY install/rtorrent.sh /rtorrent.sh - -RUN apk add --no-cache bash rtorrent curl libcurl ncurses +# Keep Alpine's musl ABI and rTorrent version; export only runtime dependencies. +FROM alpine:3.24 AS runtime +RUN apk add --no-cache rtorrent ca-certificates tzdata \ + build-base lddtreepax python3 +COPY install/rtorrent-entrypoint.c /build/rtorrent-entrypoint.c +RUN cc -Os -Wall -Wextra -Werror -o /usr/local/bin/rtorrent-entrypoint /build/rtorrent-entrypoint.c \ + && strip /usr/local/bin/rtorrent-entrypoint +COPY build/runtime-root.py /build/runtime-root.py +RUN python3 /build/runtime-root.py /runtime /usr/bin/rtorrent /usr/local/bin/rtorrent-entrypoint +COPY tests/rtorrent-smoke.c /build/rtorrent-smoke.c +RUN cc -static -Os -Wall -Wextra -Werror -o /build/rtorrent-smoke /build/rtorrent-smoke.c +FROM scratch +COPY --from=runtime /runtime/ / +ENV HOME=/root PATH=/usr/local/bin:/usr/bin:/bin TERM=xterm +RUN --mount=type=bind,from=runtime,source=/build/rtorrent-smoke,target=/ci-smoke ["/ci-smoke"] VOLUME ["/home/nfs_download"] EXPOSE 5001/tcp -ENTRYPOINT ["/rtorrent.sh"] +HEALTHCHECK --interval=10s --timeout=10s --start-period=90s --retries=5 \ + CMD ["/usr/local/bin/rtorrent-entrypoint", "--healthcheck"] +ENTRYPOINT ["/usr/local/bin/rtorrent-entrypoint"] diff --git a/Dockerfile.distroless b/Dockerfile.distroless deleted file mode 100644 index de7d803..0000000 --- a/Dockerfile.distroless +++ /dev/null @@ -1,21 +0,0 @@ -# Keep Alpine's musl ABI and rTorrent version; export only runtime dependencies. -FROM alpine:3.24 AS runtime -RUN apk add --no-cache rtorrent ca-certificates tzdata \ - build-base lddtreepax python3 -COPY install/rtorrent-entrypoint.c /build/rtorrent-entrypoint.c -RUN cc -Os -Wall -Wextra -Werror -o /usr/local/bin/rtorrent-entrypoint /build/rtorrent-entrypoint.c \ - && strip /usr/local/bin/rtorrent-entrypoint -COPY build/runtime-root.py /build/runtime-root.py -RUN python3 /build/runtime-root.py /runtime /usr/bin/rtorrent /usr/local/bin/rtorrent-entrypoint -COPY tests/rtorrent-smoke.c /build/rtorrent-smoke.c -RUN cc -static -Os -Wall -Wextra -Werror -o /build/rtorrent-smoke /build/rtorrent-smoke.c - -FROM scratch -COPY --from=runtime /runtime/ / -ENV HOME=/root PATH=/usr/local/bin:/usr/bin:/bin TERM=xterm -RUN --mount=type=bind,from=runtime,source=/build/rtorrent-smoke,target=/ci-smoke ["/ci-smoke"] -VOLUME ["/home/nfs_download"] -EXPOSE 5001/tcp -HEALTHCHECK --interval=10s --timeout=10s --start-period=90s --retries=5 \ - CMD ["/usr/local/bin/rtorrent-entrypoint", "--healthcheck"] -ENTRYPOINT ["/usr/local/bin/rtorrent-entrypoint"] diff --git a/README.md b/README.md index 7b35703..ceecff0 100644 --- a/README.md +++ b/README.md @@ -24,26 +24,32 @@ are uploaded to Gitea, and no local container builds are required. # Latest 0.16 version caveat - since version 0.16 explicitly set `network.bind_address.set = 0.0.0.0`, when ipv6 is disabled on kernel. -## Distroless variant +## Distroless runtime -`docker.io/k2patel/rtorrent:distroless` is built separately using the manual -**Build Distroless rTorrent** workflow. It preserves the Alpine 3.24 rTorrent -binary, musl libraries, CA certificates and timezone/terminal data in a `scratch` -final image. It contains no shell, package manager, BusyBox, or build tools. -A small native launcher removes the stale session lock and execs rTorrent, -so signals go directly to rTorrent. It also provides the shell-free TCP healthcheck. +`docker.io/k2patel/rtorrent:latest` is the only maintained image variant. +The default Dockerfile exports the Alpine 3.24 rTorrent binary, musl libraries, +CA certificates and timezone/terminal data into a `scratch` image. It contains +no shell, package manager, BusyBox, or build tools. The native launcher removes +the stale session lock and execs rTorrent; it also supplies the TCP health check. +CI starts rTorrent and verifies an SCGI XML-RPC request before publication. -CI tests the assembled filesystem by starting rTorrent and making an SCGI XML-RPC -request before publishing. The working `latest` tag is independent. - -Your mounted `rtorrent.rc` must not depend on shell commands or utilities missing -from this image (including `execute` hooks). Review those hooks before switching. -Existing mount paths, SCGI port 5001, root UID and `HOME=/root` are preserved. -Use the Compose overlay to replace the shell-based healthcheck: +Use the default Compose file with the existing `.env` and mounted data: ```sh -docker compose -f docker-compose.yml -f docker-compose.distroless.yml up -d +docker compose pull +docker compose up -d --force-recreate ``` -The overlay also selects the separate Flood distroless image. Keep the same `.env` -values and mounted data. To roll back, use the base Compose file with `:latest`. +For an existing custom Compose file, use `:latest` for both images and replace +any shell-based rTorrent health check with: + +```yaml +healthcheck: + test: ["CMD", "/usr/local/bin/rtorrent-entrypoint", "--healthcheck"] +``` + +The separate `:distroless` tag and Compose overlay are retired. Both services in +the default Compose file now use distroless `:latest`. Root UID, HOME=/root, +SCGI port 5001, download paths and the session volume remain supported. +Mounted `rtorrent.rc` execute hooks must use programs available in the image; +shell commands and arbitrary external utilities are unavailable. diff --git a/docker-compose.distroless.yml b/docker-compose.distroless.yml deleted file mode 100644 index ddd3f09..0000000 --- a/docker-compose.distroless.yml +++ /dev/null @@ -1,12 +0,0 @@ -# Use alongside docker-compose.yml after checking rtorrent.rc for external commands. -services: - rtorrent: - image: docker.io/k2patel/rtorrent:distroless - environment: - - HOME=/root - volumes: - - "${TORRENTSESSION}:/home/nfs_download/rsession:rw" - healthcheck: - test: ["CMD", "/usr/local/bin/rtorrent-entrypoint", "--healthcheck"] - floodui: - image: docker.io/k2patel/floodui:distroless diff --git a/docker-compose.yml b/docker-compose.yml index 2ba420a..0f4e095 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,14 +5,16 @@ services: container_name: rtorrent environment: - TZ=${TZ} + - HOME=/root volumes: - "${TORRENT_LOCATION}:/home/nfs_download:rw" - "${TORRENTRC}:/root/.rtorrent.rc" + - "${TORRENTSESSION}:/home/nfs_download/rsession:rw" ports: - 5001 restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "nc -z localhost 5001 || exit 1"] + test: ["CMD", "/usr/local/bin/rtorrent-entrypoint", "--healthcheck"] interval: 10s # Check every 10 seconds timeout: 10s # Allow the command 5 seconds to complete retries: 5 # Number of consecutive failures before marking as 'unhealthy' @@ -36,4 +38,4 @@ services: restart: unless-stopped depends_on: rtorrent: - condition: service_healthy \ No newline at end of file + condition: service_healthy diff --git a/install/rtorrent.sh b/install/rtorrent.sh deleted file mode 100755 index 5254073..0000000 --- a/install/rtorrent.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -set -e - -CLEANUP_FILE="/home/nfs_download/rsession/rtorrent.lock" - -# Remove stale lock at startup -if [ -f "$CLEANUP_FILE" ]; then - echo "️Stale lock file found. Removing..." - rm -f "$CLEANUP_FILE" -fi - -cleanup() { - echo "Caught shutdown signal. Cleaning up..." - rm -f "$CLEANUP_FILE" - echo "Cleanup complete." -} - -trap cleanup INT TERM EXIT - -echo "Starting rtorrent..." - -exec rtorrent \ No newline at end of file