diff --git a/.dockerignore b/.dockerignore index f4bdf33d7..30f93a461 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,6 +5,7 @@ !/*.go !/go.* !/cmd/* +!/docker/entrypoint.sh !/internal/* !/helpers/* !/VERSION diff --git a/changelog/unreleased/pull-5448 b/changelog/unreleased/pull-5448 new file mode 100644 index 000000000..e0cafd43e --- /dev/null +++ b/changelog/unreleased/pull-5448 @@ -0,0 +1,11 @@ +Enhancement: Allow nice and ionice configuration for restic containers + +The official restic docker now supports the following environment variables: + +`NICE`: set the desired nice scheduling. See `man nice`. +`IONICE_CLASS`: set the desired I/O scheduling class. See `man ionice`. Note that real time support requires the invoker to manually add the `SYS_NICE` capability. +`IONICE_PRIORITY`: set the prioritization for ionice in the given `IONICE_CLASS`. This does nothing without `IONICE_CLASS`, but defaults to `4` (no priority, no penalties). + +See https://restic.readthedocs.io/en/stable/020_installation.html#docker-container for further details. + +https://github.com/restic/restic/pull/5448 \ No newline at end of file diff --git a/doc/020_installation.rst b/doc/020_installation.rst index 60908116a..34cf62f81 100644 --- a/doc/020_installation.rst +++ b/doc/020_installation.rst @@ -289,6 +289,23 @@ Restic relies on the hostname for various operations. Make sure to set a static hostname using `--hostname` when creating a Docker container, otherwise Docker will assign a random hostname each time. +The container additionally honors traditional ``nice`` `(man page) `__ and ``ionice`` `(man page) `__ directives via the following environment variables. +This allows restic to be scheduled as a background process to reduce latency for the system while running. + +* ``NICE``: If set, this adjusts the CPU prioritization via ``nice -n``. This defaults to no adjustment - standard CPU priority. +* ``IONICE_CLASS``: If set, this adjusts the IO prioritization of the restic process via ``ionice -c`` for the available classes. + Note: if you attempt to set `real-time`, you *will* have to add the ``SYS_NICE`` capability (`see capabilities manpage `__) to allow using this IO class. +* ``IONICE_PRIORITY``: This defaults to 4 (no prioritization or penalties); this is the prioritization within the given ``IONICE_CLASS``. + +The following example runs restic such that other CPU and IO requests have higher priority. This effectively perturbs the system as minimally as possible while ``restic`` runs. + +.. code-block:: console + + # docker run -e NICE=20 -e IONICE_CLASS=2 -e IONICE_PRIORITY=7 ghcr.io/restic/restic + +*Remember* that this invocation is explicitly telling your CPU and IO scheduler to deprioritize restic. This typically will result in a longer runtime. For a system with heavy load, this can be drastically longer. + + From Source *********** diff --git a/docker/Dockerfile b/docker/Dockerfile index 4c031ebac..921bd8414 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,11 +8,17 @@ RUN go mod download COPY . . RUN go run build.go - FROM alpine:latest AS restic - RUN apk add --no-cache ca-certificates fuse openssh-client tzdata jq COPY --from=builder /go/src/github.com/restic/restic/restic /usr/bin +COPY ./docker/entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/usr/bin/restic"] +# IO class default is "none"- 0, however busybox reject ionice `-c0 -n` +# since priority has no meaning for no scheduler. +# Thus the entrypoint script below is necessary +ENV IONICE_CLASS= +ENV IONICE_PRIORITY=4 +ENV NICE=0 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/Dockerfile.release b/docker/Dockerfile.release index 615f4aec8..5f40236c7 100644 --- a/docker/Dockerfile.release +++ b/docker/Dockerfile.release @@ -1,6 +1,6 @@ # the official binaries are cross-built from Linux running on an AMD64 host # other architectures also seem to generate identical binaries but stay on the safe side -FROM --platform=linux/amd64 restic/builder:latest as helper +FROM --platform=linux/amd64 restic/builder:latest AS helper ARG TARGETOS ARG TARGETARCH @@ -19,6 +19,14 @@ LABEL org.opencontainers.image.documentation="https://restic.readthedocs.io" LABEL org.opencontainers.image.source="https://github.com/restic/restic" COPY --from=helper /output/restic /usr/bin +COPY ./docker/entrypoint.sh /entrypoint.sh RUN apk add --no-cache ca-certificates fuse openssh-client tzdata jq -ENTRYPOINT ["/usr/bin/restic"] +# IO class default is "none"- 0, however busybox rejects ionice `-c0 -n` +# since priority has no meaning for no scheduler. +# Thus the entrypoint script below is necessary. +ENV IONICE_CLASS= +ENV IONICE_PRIORITY=4 +ENV NICE=0 + +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/docker/build.sh b/docker/build.sh index bd4477951..f4a8fad55 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -1,4 +1,6 @@ #!/bin/sh +root="$(readlink -f "$0")" +root="$(dirname "$(dirname "${root}")")" set -e @@ -8,6 +10,6 @@ echo "Build docker image restic/restic:latest" docker build \ --rm \ --pull \ - --file docker/Dockerfile \ + --file "${root}"/docker/Dockerfile \ --tag restic/restic:latest \ - . + "${root}" "$@" diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 000000000..8d8b4f3a6 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,10 @@ +#!/bin/sh -e + +# This must be tested against busybox sh, since there are quirks in its +# implementation of tooling. Busybox rejects `ionice -c0 -n` for example. +set -- /usr/bin/restic "$@" +if [ -n "${IONICE_CLASS}" ]; then + set -- ionice -c "${IONICE_CLASS}" -n "${IONICE_PRIORITY:-4}" "$@" +fi + +exec nice -n "${NICE:-0}" "$@"