diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/.DS_Store differ diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..45060a52 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.github/** +.git/** +.git* diff --git a/.gitattributes b/.gitattributes index 14a11226..778f645e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,2 @@ /*/**/Dockerfile linguist-generated /*/**/docker-entrypoint.sh linguist-generated -/Dockerfile*.template linguist-language=Dockerfile diff --git a/.github/actions/build-and-tag-locally/action.yml b/.github/actions/build-and-tag-locally/action.yml new file mode 100644 index 00000000..149661d7 --- /dev/null +++ b/.github/actions/build-and-tag-locally/action.yml @@ -0,0 +1,211 @@ +name: Build and Test + +inputs: + distribution: + description: "Distribution flavor" + default: "debian" + platform: + description: "Platform" + required: true + publish_image: + description: "Publish image to Docker Hub" + default: "false" + registry_username: + description: "Docker Hub username" + required: false + registry_password: + description: "Docker Hub password" + required: false + registry_repository: + description: 'Repository to push the image to' + required: false + +runs: + using: "composite" + steps: + - name: Install QEMU + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y qemu-user-static + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Calculate architecture name + id: platform + shell: bash + run: | + case ${{ inputs.platform }} in + linux/amd64) + plaform_name="amd64" + ;; + linux/arm64) + plaform_name="arm64" + ;; + linux/arm/v5) + plaform_name="arm-v5" + ;; + linux/arm/v7) + plaform_name="arm-v7" + ;; + linux/i386) + plaform_name="i386" + ;; + linux/mips64le) + plaform_name="mips64le" + ;; + linux/ppc64le) + plaform_name="ppc64le" + ;; + linux/s390x) + plaform_name="s390x" + ;; + *) + echo "Architecture not supported: ${{ inputs.platform }}" + exit 1 + ;; + esac + echo "display_name=$plaform_name" >> "$GITHUB_OUTPUT" + + - name: Clean up + shell: bash + run: | + docker rm -f sanity-test-${{ steps.platform.outputs.display_name }} || true + docker rmi -f ${{ github.sha }}:${{ steps.platform.outputs.display_name }} || true + + - name: Docker Login + uses: docker/login-action@v3 + if: inputs.publish_image == 'true' + with: + registry: ${{ inputs.registry_repository }} + username: ${{ inputs.registry_username }} + password: ${{ inputs.registry_password }} + + - name: Build + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ inputs.distribution }}/Dockerfile + push: false + load: true + platforms: ${{ inputs.platform }} + tags: ${{ github.sha }}:${{ steps.platform.outputs.display_name }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Save image + shell: bash + run: | + docker save -o /tmp/image-${{ steps.platform.outputs.display_name }}.tar ${{ github.sha }}:${{ steps.platform.outputs.display_name }} + + - name: Upload image + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.platform.outputs.display_name }}-docker-image.tar + path: /tmp/image-${{ steps.platform.outputs.display_name }}.tar + retention-days: 45 + + - name: Run container + shell: bash + if: ${{ contains(fromJSON('["amd64", "arm64", "i386"]'), steps.platform.outputs.display_name) }} + run: | + docker run -d --name sanity-test-${{ steps.platform.outputs.display_name }} ${{ github.sha }}:${{ steps.platform.outputs.display_name }} + + - name: Container Logs + if: ${{ contains(fromJSON('["amd64", "arm64", "i386"]'), steps.platform.outputs.display_name) }} + shell: bash + run: | + docker logs sanity-test-${{ steps.platform.outputs.display_name }} + + - name: Sanity Tests + if: ${{ contains(fromJSON('["amd64", "arm64", "i386"]'), steps.platform.outputs.display_name) }} + shell: bash + run: | + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli ping + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli info server + + - name: Verify installed modules + if: ${{ contains(fromJSON('["amd64", "arm64",]'), steps.platform.outputs.display_name) }} + shell: bash + run: | + modules=$(docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli module list) + echo "Installed modules:" + echo "$modules" + missing_modules=() + for module in "bf" "search" "timeseries" "ReJSON"; do + if ! echo "$modules" | grep -q "$module"; then + missing_modules+=("$module") + fi + done + if [ ${#missing_modules[@]} -eq 0 ]; then + echo "All required modules are installed" + else + echo "The following modules are missing: ${missing_modules[*]}" + exit 1 + fi + + - name: Test RedisBloom + if: ${{ contains(fromJSON('["amd64", "arm64"]'), steps.platform.outputs.display_name) }} + shell: bash + run: | + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli BF.ADD popular_keys "redis:hash" + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli BF.ADD popular_keys "redis:set" + [ "$(docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli BF.EXISTS popular_keys "redis:hash")" = "1" ] || { echo "RedisBloom test failed: 'redis:hash' not found"; exit 1; } + [ "$(docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli BF.EXISTS popular_keys "redis:list")" = "0" ] || { echo "RedisBloom test failed: 'redis:list' found unexpectedly"; exit 1; } + echo "RedisBloom test passed successfully" + + - name: Test RediSearch + if: ${{ contains(fromJSON('["amd64", "arm64"]'), steps.platform.outputs.display_name) }} + shell: bash + run: | + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli FT.CREATE redis_commands ON HASH PREFIX 1 cmd: SCHEMA name TEXT SORTABLE description TEXT + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli HSET cmd:set name "SET" description "Set the string value of a key" + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli HSET cmd:get name "GET" description "Get the value of a key" + result=$(docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli FT.SEARCH redis_commands "value") + if echo "$result" | grep -q "Set the string value of a key" && echo "$result" | grep -q "Get the value of a key"; then + echo "RediSearch test passed successfully" + else + echo "RediSearch test failed: expected commands not found in search results" + exit 1 + fi + + - name: Test RedisTimeSeries + if: ${{ contains(fromJSON('["amd64", "arm64"]'), steps.platform.outputs.display_name) }} + shell: bash + run: | + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli TS.CREATE redis:cpu:usage RETENTION 86400 + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli TS.ADD redis:cpu:usage "*" 80 + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli TS.ADD redis:cpu:usage "*" 65 + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli TS.ADD redis:cpu:usage "*" 70 + result=$(docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli TS.RANGE redis:cpu:usage - + COUNT 3) + if echo "$result" | grep -q "80" && echo "$result" | grep -q "65" && echo "$result" | grep -q "70"; then + echo "RedisTimeSeries test passed successfully" + else + echo "RedisTimeSeries test failed: expected values not found in time series" + exit 1 + fi + + - name: Test ReJSON + if: ${{ contains(fromJSON('["amd64", "arm64"]'), steps.platform.outputs.display_name) }} + shell: bash + run: | + docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli JSON.SET redis:config $ '{"maxmemory":"2gb","maxmemory-policy":"allkeys-lru"}' + result=$(docker exec sanity-test-${{ steps.platform.outputs.display_name }} redis-cli JSON.GET redis:config $.maxmemory-policy) + cleaned_result=$(echo $result | tr -d '[]"') + if [ "$cleaned_result" = "allkeys-lru" ]; then + echo "ReJSON test passed successfully" + else + echo "ReJSON test failed: expected 'allkeys-lru', got $result" + exit 1 + fi + + - name: Push image + uses: docker/build-push-action@v6 + if: ${{ inputs.publish_image == 'true' && contains(fromJSON('["amd64","arm64"]'), steps.platform.outputs.display_name) }} + with: + context: . + file: ${{ inputs.distribution }}/Dockerfile + push: true + tags: ${{ inputs.registry_repository }}:${{ github.sha }}-${{ inputs.distribution }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml new file mode 100644 index 00000000..566cdcd1 --- /dev/null +++ b/.github/workflows/pre-merge.yml @@ -0,0 +1,54 @@ +name: Build and Test +on: + pull_request: + branches: + - master + - release/* + +jobs: + build-and-test: + runs-on: [ubuntu-latest] + strategy: + matrix: + distribution: + - debian + #- alpine + platform: + - linux/amd64 + - linux/i386 + - linux/arm/v5 + - linux/arm/v7 + - linux/mips64le + - linux/ppc64le + - linux/s390x + steps: + - name: Checkout code + uses: actions/checkout@v4 + - uses: ./.github/actions/build-and-tag-locally + with: + distribution: ${{ matrix.distribution }} + platform: ${{ matrix.platform }} + registry_username: ${{ vars.REGISTRY_USERNAME }} + registry_password: ${{ secrets.REGISTRY_PASSWORD }} + publish_image: ${{ vars.PUBLISH_IMAGE }} + registry_repository: ${{ vars.REGISTRY_REPOSITORY }} + + # build-and-test-arm64: + # runs-on: ARM64 + # strategy: + # matrix: + # distribution: + # - debian + # platform: + # - linux/arm64 + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - uses: ./.github/actions/build-and-tag-locally + # with: + # distribution: ${{ matrix.distribution }} + # platform: ${{ matrix.platform }} + # registry_username: ${{ vars.REGISTRY_USERNAME }} + # registry_password: ${{ secrets.REGISTRY_PASSWORD }} + # publish_image: ${{ vars.PUBLISH_IMAGE }} + # registry: ${{ vars.REGISTRY_URL }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index d548f66d..8b137891 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -.jq-template.awk + diff --git a/README.md b/README.md index b3dea943..27af2288 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # https://github.com/docker-library/redis -## Maintained by: [the Docker Community](https://github.com/docker-library/redis) +## Maintained by: [Redis LTD](https://redis.io/) -This is the Git repo of the [Docker "Official Image"](https://github.com/docker-library/official-images#what-are-official-images) for [`redis`](https://hub.docker.com/_/redis/) (not to be confused with any official `redis` image provided by `redis` upstream). See [the Docker Hub page](https://hub.docker.com/_/redis/) for the full readme on how to use this Docker image and for information regarding contributing and issues. +This is the Git repo of the [Docker "Official Image"](https://github.com/docker-library/official-images#what-are-official-images) for [`redis`](https://hub.docker.com/_/redis/). See [the Docker Hub page](https://hub.docker.com/_/redis/) for the full `README` on how to use this Docker image and for information regarding contributing and issues. The [full image description on Docker Hub](https://hub.docker.com/_/redis/) is generated/maintained over in [the docker-library/docs repository](https://github.com/docker-library/docs), specifically in [the `redis` directory](https://github.com/docker-library/docs/tree/master/redis). @@ -22,5 +22,3 @@ For outstanding `redis` image PRs, check [PRs with the "library/redis" label on | [![amd64 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/amd64/job/redis.svg?label=amd64)](https://doi-janky.infosiftr.net/job/multiarch/job/amd64/job/redis/) | [![arm32v5 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm32v5/job/redis.svg?label=arm32v5)](https://doi-janky.infosiftr.net/job/multiarch/job/arm32v5/job/redis/) | [![arm32v6 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm32v6/job/redis.svg?label=arm32v6)](https://doi-janky.infosiftr.net/job/multiarch/job/arm32v6/job/redis/) | [![arm32v7 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm32v7/job/redis.svg?label=arm32v7)](https://doi-janky.infosiftr.net/job/multiarch/job/arm32v7/job/redis/) | | [![arm64v8 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/arm64v8/job/redis.svg?label=arm64v8)](https://doi-janky.infosiftr.net/job/multiarch/job/arm64v8/job/redis/) | [![i386 build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/i386/job/redis.svg?label=i386)](https://doi-janky.infosiftr.net/job/multiarch/job/i386/job/redis/) | [![mips64le build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/mips64le/job/redis.svg?label=mips64le)](https://doi-janky.infosiftr.net/job/multiarch/job/mips64le/job/redis/) | [![ppc64le build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/ppc64le/job/redis.svg?label=ppc64le)](https://doi-janky.infosiftr.net/job/multiarch/job/ppc64le/job/redis/) | | [![s390x build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/multiarch/job/s390x/job/redis.svg?label=s390x)](https://doi-janky.infosiftr.net/job/multiarch/job/s390x/job/redis/) | [![put-shared build status badge](https://img.shields.io/jenkins/s/https/doi-janky.infosiftr.net/job/put-shared/job/light/job/redis.svg?label=put-shared)](https://doi-janky.infosiftr.net/job/put-shared/job/light/job/redis/) | - - diff --git a/alpine/Dockerfile b/alpine/Dockerfile new file mode 100644 index 00000000..9c2a3747 --- /dev/null +++ b/alpine/Dockerfile @@ -0,0 +1,154 @@ +ARG BASE_IMAGE=alpine:3.20 +FROM ${BASE_IMAGE} AS sources +ARG REDIS_VERSION=8.0-m01 +ARG REDIS_DOWNLOAD_URL=https://github.com/redis/redis/archive/refs/tags/${REDIS_VERSION}.tar.gz +ARG REDIS_DOWNLOAD_SHA=4c77c2218747505c50c43a45d12a067a3631a26d9397929da180e183b03e862c +WORKDIR /files +ADD --checksum=sha256:${REDIS_DOWNLOAD_SHA} ${REDIS_DOWNLOAD_URL} . +RUN tar -xvf *.tar.gz && mv redis-${REDIS_VERSION} redis + +FROM ${BASE_IMAGE} + +# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added +RUN set -eux; \ +# alpine already has a gid 999, so we'll use the next id + addgroup -S -g 1000 redis; \ + adduser -S -G redis -u 999 redis + +# runtime dependencies +RUN set -eux; \ + apk add --no-cache \ +# add tzdata for https://github.com/docker-library/redis/issues/138 + tzdata \ + ; + +# grab gosu for easy step-down from root +# https://github.com/tianon/gosu/releases +ENV GOSU_VERSION=1.17 +RUN set -eux; \ + apk add --no-cache --virtual .gosu-fetch gnupg; \ + arch="$(apk --print-arch)"; \ + case "$arch" in \ + 'x86_64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-amd64'; sha256='bbc4136d03ab138b1ad66fa4fc051bafc6cc7ffae632b069a53657279a450de3' ;; \ + 'aarch64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-arm64'; sha256='c3805a85d17f4454c23d7059bcb97e1ec1af272b90126e79ed002342de08389b' ;; \ + 'armhf') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armhf'; sha256='e5866286277ff2a2159fb9196fea13e0a59d3f1091ea46ddb985160b94b6841b' ;; \ + 'x86') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-i386'; sha256='087dbb8fe479537e64f9c86fa49ff3b41dee1cbd28739a19aaef83dc8186b1ca' ;; \ + 'ppc64le') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-ppc64el'; sha256='1891acdcfa70046818ab6ed3c52b9d42fa10fbb7b340eb429c8c7849691dbd76' ;; \ + 'riscv64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-riscv64'; sha256='38a6444b57adce135c42d5a3689f616fc7803ddc7a07ff6f946f2ebc67a26ba6' ;; \ + 's390x') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-s390x'; sha256='69873bab588192f760547ca1f75b27cfcf106e9f7403fee6fd0600bc914979d0' ;; \ + 'armv7') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armhf'; sha256='e5866286277ff2a2159fb9196fea13e0a59d3f1091ea46ddb985160b94b6841b' ;; \ + *) echo >&2 "error: unsupported gosu architecture: '$arch'"; exit 1 ;; \ + esac; \ + wget -O /usr/local/bin/gosu.asc "$url.asc"; \ + wget -O /usr/local/bin/gosu "$url"; \ + echo "$sha256 */usr/local/bin/gosu" | sha256sum -c -; \ + export GNUPGHOME="$(mktemp -d)"; \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ + gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ + gpgconf --kill all; \ + rm -f "$GNUPGHOME" /usr/local/bin/gosu.asc; \ + apk del --no-network .gosu-fetch; \ + chmod +x /usr/local/bin/gosu; \ + gosu --version; \ + gosu nobody true + +RUN --mount=type=bind,from=sources,source=/files/redis,target=/usr/src/redis,rw set -eux; \ + \ + apk add --no-cache --virtual .build-deps \ + coreutils \ + dpkg-dev dpkg \ + gcc \ + linux-headers \ + make \ + musl-dev \ + openssl-dev \ + ; \ + \ + arch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + case "$arch" in \ + 'amd64') export BUILD_WITH_MODULES=yes; export INSTALL_RUST_TOOLCHAIN=yes; export DISABLE_WERRORS=yes ;; \ + 'arm64') export BUILD_WITH_MODULES=yes; export INSTALL_RUST_TOOLCHAIN=yes; export DISABLE_WERRORS=yes ;; \ + *) echo >&2 "Modules are NOT supported! unsupported architecture: '$arch'"; export BUILD_WITH_MODULES=no ;; \ + esac; \ + if [ "$BUILD_WITH_MODULES" = "yes" ]; then \ + apk add --no-cache --virtual .module-build-deps \ + git \ + cmake \ + curl \ + python3 \ + py3-pip \ + py3-virtualenv \ + python3-dev \ + unzip \ + rsync \ + clang \ + automake \ + autoconf \ + libtool \ + g++ \ + libgcc \ + ;\ + fi; \ + \ +# disable Redis protected mode [1] as it is unnecessary in context of Docker +# (ports are not automatically exposed when running inside Docker, but rather explicitly by specifying -p / -P) +# [1]: https://github.com/redis/redis/commit/edd4d555df57dc84265fdfb4ef59a4678832f6da + grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' /usr/src/redis/src/config.c; \ + sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' /usr/src/redis/src/config.c; \ + grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' /usr/src/redis/src/config.c; \ +# for future reference, we modify this directly in the source instead of just supplying a default configuration flag because apparently "if you specify any argument to redis-server, [it assumes] you are going to specify everything" +# see also https://github.com/docker-library/redis/issues/4#issuecomment-50780840 +# (more exactly, this makes sure the default behavior of "save on SIGTERM" stays functional by default) + \ +# https://github.com/jemalloc/jemalloc/issues/467 -- we need to patch the "./configure" for the bundled jemalloc to match how Debian compiles, for compatibility +# (also, we do cross-builds, so we need to embed the appropriate "--build=xxx" values to that "./configure" invocation) + gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \ + extraJemallocConfigureFlags="--build=$gnuArch"; \ +# https://salsa.debian.org/debian/jemalloc/-/blob/c0a88c37a551be7d12e4863435365c9a6a51525f/debian/rules#L8-23 + dpkgArch="$(dpkg --print-architecture)"; \ + case "${dpkgArch##*-}" in \ + amd64 | i386 | x32) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=12" ;; \ + *) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=16" ;; \ + esac; \ + extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-hugepage=21"; \ + grep -F 'cd jemalloc && ./configure ' /usr/src/redis/deps/Makefile; \ + sed -ri 's!cd jemalloc && ./configure !&'"$extraJemallocConfigureFlags"' !' /usr/src/redis/deps/Makefile; \ + grep -F "cd jemalloc && ./configure $extraJemallocConfigureFlags " /usr/src/redis/deps/Makefile; \ + \ + export BUILD_TLS=yes; \ + make -C /usr/src/redis -j "$(nproc)" all; \ + make -C /usr/src/redis install; \ + \ +# TODO https://github.com/redis/redis/pull/3494 (deduplicate "redis-server" copies) + serverMd5="$(md5sum /usr/local/bin/redis-server | cut -d' ' -f1)"; export serverMd5; \ + find /usr/local/bin/redis* -maxdepth 0 \ + -type f -not -name redis-server \ + -exec sh -eux -c ' \ + md5="$(md5sum "$1" | cut -d" " -f1)"; \ + test "$md5" = "$serverMd5"; \ + ' -- '{}' ';' \ + -exec ln -svfT 'redis-server' '{}' ';' \ + ; \ + \ + make -C /usr/src/redis distclean; \ + \ + runDeps="$( \ + scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \ + | tr ',' '\n' \ + | sort -u \ + | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ + )"; \ + apk add --no-network --virtual .redis-rundeps $runDeps; \ + apk del --no-network .build-deps; \ + \ + redis-cli --version; \ + redis-server --version; +RUN mkdir /data && chown redis:redis /data +VOLUME /data +WORKDIR /data + +COPY alpine/docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +EXPOSE 6379 +CMD ["redis-server"] diff --git a/alpine/docker-entrypoint.sh b/alpine/docker-entrypoint.sh new file mode 100755 index 00000000..77e274f9 --- /dev/null +++ b/alpine/docker-entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/sh +set -e + +# first arg is `-f` or `--some-option` +# or first arg is `something.conf` +if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then + set -- redis-server "$@" +fi + +# allow the container to be started with `--user` +if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then + find . \! -user redis -exec chown redis '{}' + + exec gosu redis "$0" "$@" +fi + +# set an appropriate umask (if one isn't set already) +# - https://github.com/docker-library/redis/issues/305 +# - https://github.com/redis/redis/blob/bb875603fb7ff3f9d19aad906bd45d7db98d9a39/utils/systemd-redis_server.service#L37 +um="$(umask)" +if [ "$um" = '0022' ]; then + umask 0077 +fi + +modules_dir="/usr/local/lib/redis/modules/" +command="exec \"\$@\"" + +if [ -n "$(ls -A $modules_dir)" ]; then + for module in "$modules_dir"/*.so; + do + command="$command --loadmodule $module" + done +fi + +eval "$command" \ No newline at end of file diff --git a/debian/Dockerfile b/debian/Dockerfile new file mode 100644 index 00000000..9b57bb6e --- /dev/null +++ b/debian/Dockerfile @@ -0,0 +1,167 @@ +ARG BASE_IMAGE=debian:bookworm-slim +FROM ${BASE_IMAGE} AS sources +ARG REDIS_VERSION=8.0-m01 +ARG REDIS_DOWNLOAD_URL=https://github.com/redis/redis/archive/refs/tags/${REDIS_VERSION}.tar.gz +ARG REDIS_DOWNLOAD_SHA=4c77c2218747505c50c43a45d12a067a3631a26d9397929da180e183b03e862c +WORKDIR /files +ADD --checksum=sha256:${REDIS_DOWNLOAD_SHA} ${REDIS_DOWNLOAD_URL} . +RUN apt-get update && apt-get install -y tar patch +RUN tar -xvf *.tar.gz && mv redis-${REDIS_VERSION} redis + +FROM ${BASE_IMAGE} + +# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added +RUN set -eux; \ + groupadd -r -g 999 redis; \ + useradd -r -g redis -u 999 redis + +# runtime dependencies +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ +# add tzdata explicitly for https://github.com/docker-library/redis/issues/138 (see also https://bugs.debian.org/837060 and related) + tzdata \ + ; \ + rm -rf /var/lib/apt/lists/* + +# grab gosu for easy step-down from root +# https://github.com/tianon/gosu/releases +ENV GOSU_VERSION=1.17 +RUN set -eux; \ + savedAptMark="$(apt-mark showmanual)"; \ + apt-get update; \ + apt-get install -y --no-install-recommends ca-certificates gnupg wget; \ + rm -rf /var/lib/apt/lists/*; \ + arch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + case "$arch" in \ + 'amd64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-amd64'; sha256='bbc4136d03ab138b1ad66fa4fc051bafc6cc7ffae632b069a53657279a450de3' ;; \ + 'arm64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-arm64'; sha256='c3805a85d17f4454c23d7059bcb97e1ec1af272b90126e79ed002342de08389b' ;; \ + 'armel') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armel'; sha256='f9969910fa141140438c998cfa02f603bf213b11afd466dcde8fa940e700945d' ;; \ + 'i386') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-i386'; sha256='087dbb8fe479537e64f9c86fa49ff3b41dee1cbd28739a19aaef83dc8186b1ca' ;; \ + 'mips64el') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-mips64el'; sha256='87140029d792595e660be0015341dfa1c02d1181459ae40df9f093e471d75b70' ;; \ + 'ppc64el') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-ppc64el'; sha256='1891acdcfa70046818ab6ed3c52b9d42fa10fbb7b340eb429c8c7849691dbd76' ;; \ + 'riscv64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-riscv64'; sha256='38a6444b57adce135c42d5a3689f616fc7803ddc7a07ff6f946f2ebc67a26ba6' ;; \ + 's390x') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-s390x'; sha256='69873bab588192f760547ca1f75b27cfcf106e9f7403fee6fd0600bc914979d0' ;; \ + 'armhf') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armhf'; sha256='e5866286277ff2a2159fb9196fea13e0a59d3f1091ea46ddb985160b94b6841b' ;; \ + *) echo >&2 "error: unsupported gosu architecture: '$arch'"; exit 1 ;; \ + esac; \ + wget -O /usr/local/bin/gosu.asc "$url.asc"; \ + wget -O /usr/local/bin/gosu "$url"; \ + echo "$sha256 */usr/local/bin/gosu" | sha256sum -c -; \ + export GNUPGHOME="$(mktemp -d)"; \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ + gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ + apt-mark auto '.*' > /dev/null; \ + [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + chmod +x /usr/local/bin/gosu; \ + gosu --version; \ + gosu nobody true + +RUN --mount=type=bind,from=sources,source=/files/redis,target=/usr/src/redis,rw set -eux; \ + \ + savedAptMark="$(apt-mark showmanual)"; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + wget \ + dpkg-dev \ + gcc \ + libc6-dev \ + libssl-dev \ + make \ + ; \ + \ + arch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + case "$arch" in \ + 'amd64') export BUILD_WITH_MODULES=yes; export INSTALL_RUST_TOOLCHAIN=yes; export DISABLE_WERRORS=yes ;; \ + 'arm64') export BUILD_WITH_MODULES=yes; export INSTALL_RUST_TOOLCHAIN=yes; export DISABLE_WERRORS=yes ;; \ + *) echo >&2 "Modules are NOT supported! unsupported architecture: '$arch'"; export BUILD_WITH_MODULES=no ;; \ + esac; \ + if [ "$BUILD_WITH_MODULES" = "yes" ]; then \ + apt-get install -y --no-install-recommends \ + git \ + cmake \ + python3 \ + python3-pip \ + python3-venv \ + python3-dev \ + unzip \ + rsync \ + clang \ + automake \ + autoconf \ + libtool \ + g++; \ + fi; \ + \ + rm -rf /var/lib/apt/lists/*; \ + \ +# disable Redis protected mode [1] as it is unnecessary in context of Docker +# (ports are not automatically exposed when running inside Docker, but rather explicitly by specifying -p / -P) +# [1]: https://github.com/redis/redis/commit/edd4d555df57dc84265fdfb4ef59a4678832f6da + grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' /usr/src/redis/src/config.c; \ + sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' /usr/src/redis/src/config.c; \ + grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' /usr/src/redis/src/config.c; \ +# for future reference, we modify this directly in the source instead of just supplying a default configuration flag because apparently "if you specify any argument to redis-server, [it assumes] you are going to specify everything" +# see also https://github.com/docker-library/redis/issues/4#issuecomment-50780840 +# (more exactly, this makes sure the default behavior of "save on SIGTERM" stays functional by default) + \ +# https://github.com/jemalloc/jemalloc/issues/467 -- we need to patch the "./configure" for the bundled jemalloc to match how Debian compiles, for compatibility +# (also, we do cross-builds, so we need to embed the appropriate "--build=xxx" values to that "./configure" invocation) + gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \ + extraJemallocConfigureFlags="--build=$gnuArch"; \ +# https://salsa.debian.org/debian/jemalloc/-/blob/c0a88c37a551be7d12e4863435365c9a6a51525f/debian/rules#L8-23 + case "${arch##*-}" in \ + amd64 | i386 | x32) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=12" ;; \ + *) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=16" ;; \ + esac; \ + extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-hugepage=21"; \ + grep -F 'cd jemalloc && ./configure ' /usr/src/redis/deps/Makefile; \ + sed -ri 's!cd jemalloc && ./configure !&'"$extraJemallocConfigureFlags"' !' /usr/src/redis/deps/Makefile; \ + grep -F "cd jemalloc && ./configure $extraJemallocConfigureFlags " /usr/src/redis/deps/Makefile; \ + \ + export BUILD_TLS=yes; \ + make -C /usr/src/redis -j "$(nproc)" all; \ + make -C /usr/src/redis install; \ + \ +# TODO https://github.com/redis/redis/pull/3494 (deduplicate "redis-server" copies) + serverMd5="$(md5sum /usr/local/bin/redis-server | cut -d' ' -f1)"; export serverMd5; \ + find /usr/local/bin/redis* -maxdepth 0 \ + -type f -not -name redis-server \ + -exec sh -eux -c ' \ + md5="$(md5sum "$1" | cut -d" " -f1)"; \ + test "$md5" = "$serverMd5"; \ + ' -- '{}' ';' \ + -exec ln -svfT 'redis-server' '{}' ';' \ + ; \ + \ + make -C /usr/src/redis distclean; \ + \ + apt-mark auto '.*' > /dev/null; \ + [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \ + find /usr/local -type f -executable -exec ldd '{}' ';' \ + | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); printf "*%s\n", so }' \ + | sort -u \ + | xargs -r dpkg-query --search \ + | cut -d: -f1 \ + | sort -u \ + | xargs -r apt-mark manual \ + ; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + rm -rf /var/cache/debconf/*; \ + \ + redis-cli --version; \ + redis-server --version + +RUN mkdir /data && chown redis:redis /data +VOLUME /data +WORKDIR /data + +COPY debian/docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +EXPOSE 6379 +CMD ["redis-server"] diff --git a/debian/docker-entrypoint.sh b/debian/docker-entrypoint.sh new file mode 100755 index 00000000..77e274f9 --- /dev/null +++ b/debian/docker-entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/sh +set -e + +# first arg is `-f` or `--some-option` +# or first arg is `something.conf` +if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then + set -- redis-server "$@" +fi + +# allow the container to be started with `--user` +if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then + find . \! -user redis -exec chown redis '{}' + + exec gosu redis "$0" "$@" +fi + +# set an appropriate umask (if one isn't set already) +# - https://github.com/docker-library/redis/issues/305 +# - https://github.com/redis/redis/blob/bb875603fb7ff3f9d19aad906bd45d7db98d9a39/utils/systemd-redis_server.service#L37 +um="$(umask)" +if [ "$um" = '0022' ]; then + umask 0077 +fi + +modules_dir="/usr/local/lib/redis/modules/" +command="exec \"\$@\"" + +if [ -n "$(ls -A $modules_dir)" ]; then + for module in "$modules_dir"/*.so; + do + command="$command --loadmodule $module" + done +fi + +eval "$command" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/legacy-templating-scripts/.github/workflows/ci.yml similarity index 100% rename from .github/workflows/ci.yml rename to legacy-templating-scripts/.github/workflows/ci.yml diff --git a/.github/workflows/verify-templating.yml b/legacy-templating-scripts/.github/workflows/verify-templating.yml similarity index 100% rename from .github/workflows/verify-templating.yml rename to legacy-templating-scripts/.github/workflows/verify-templating.yml diff --git a/6.2/alpine/Dockerfile b/legacy-templating-scripts/6.2/alpine/Dockerfile similarity index 100% rename from 6.2/alpine/Dockerfile rename to legacy-templating-scripts/6.2/alpine/Dockerfile diff --git a/6.2/alpine/docker-entrypoint.sh b/legacy-templating-scripts/6.2/alpine/docker-entrypoint.sh similarity index 100% rename from 6.2/alpine/docker-entrypoint.sh rename to legacy-templating-scripts/6.2/alpine/docker-entrypoint.sh diff --git a/6.2/debian/Dockerfile b/legacy-templating-scripts/6.2/debian/Dockerfile similarity index 100% rename from 6.2/debian/Dockerfile rename to legacy-templating-scripts/6.2/debian/Dockerfile diff --git a/6.2/debian/docker-entrypoint.sh b/legacy-templating-scripts/6.2/debian/docker-entrypoint.sh similarity index 100% rename from 6.2/debian/docker-entrypoint.sh rename to legacy-templating-scripts/6.2/debian/docker-entrypoint.sh diff --git a/7.0/alpine/Dockerfile b/legacy-templating-scripts/7.0/alpine/Dockerfile similarity index 100% rename from 7.0/alpine/Dockerfile rename to legacy-templating-scripts/7.0/alpine/Dockerfile diff --git a/7.0/alpine/docker-entrypoint.sh b/legacy-templating-scripts/7.0/alpine/docker-entrypoint.sh similarity index 100% rename from 7.0/alpine/docker-entrypoint.sh rename to legacy-templating-scripts/7.0/alpine/docker-entrypoint.sh diff --git a/7.0/debian/Dockerfile b/legacy-templating-scripts/7.0/debian/Dockerfile similarity index 100% rename from 7.0/debian/Dockerfile rename to legacy-templating-scripts/7.0/debian/Dockerfile diff --git a/7.0/debian/docker-entrypoint.sh b/legacy-templating-scripts/7.0/debian/docker-entrypoint.sh similarity index 100% rename from 7.0/debian/docker-entrypoint.sh rename to legacy-templating-scripts/7.0/debian/docker-entrypoint.sh diff --git a/7.2/alpine/Dockerfile b/legacy-templating-scripts/7.2/alpine/Dockerfile similarity index 100% rename from 7.2/alpine/Dockerfile rename to legacy-templating-scripts/7.2/alpine/Dockerfile diff --git a/7.2/alpine/docker-entrypoint.sh b/legacy-templating-scripts/7.2/alpine/docker-entrypoint.sh similarity index 100% rename from 7.2/alpine/docker-entrypoint.sh rename to legacy-templating-scripts/7.2/alpine/docker-entrypoint.sh diff --git a/7.2/debian/Dockerfile b/legacy-templating-scripts/7.2/debian/Dockerfile similarity index 100% rename from 7.2/debian/Dockerfile rename to legacy-templating-scripts/7.2/debian/Dockerfile diff --git a/7.2/debian/docker-entrypoint.sh b/legacy-templating-scripts/7.2/debian/docker-entrypoint.sh similarity index 100% rename from 7.2/debian/docker-entrypoint.sh rename to legacy-templating-scripts/7.2/debian/docker-entrypoint.sh diff --git a/7.4-rc/alpine/Dockerfile b/legacy-templating-scripts/7.4-rc/alpine/Dockerfile similarity index 100% rename from 7.4-rc/alpine/Dockerfile rename to legacy-templating-scripts/7.4-rc/alpine/Dockerfile diff --git a/7.4-rc/alpine/docker-entrypoint.sh b/legacy-templating-scripts/7.4-rc/alpine/docker-entrypoint.sh similarity index 100% rename from 7.4-rc/alpine/docker-entrypoint.sh rename to legacy-templating-scripts/7.4-rc/alpine/docker-entrypoint.sh diff --git a/7.4-rc/debian/Dockerfile b/legacy-templating-scripts/7.4-rc/debian/Dockerfile similarity index 100% rename from 7.4-rc/debian/Dockerfile rename to legacy-templating-scripts/7.4-rc/debian/Dockerfile diff --git a/7.4-rc/debian/docker-entrypoint.sh b/legacy-templating-scripts/7.4-rc/debian/docker-entrypoint.sh similarity index 100% rename from 7.4-rc/debian/docker-entrypoint.sh rename to legacy-templating-scripts/7.4-rc/debian/docker-entrypoint.sh diff --git a/BUILD.md b/legacy-templating-scripts/BUILD.md similarity index 100% rename from BUILD.md rename to legacy-templating-scripts/BUILD.md diff --git a/Dockerfile.template b/legacy-templating-scripts/Dockerfile.template similarity index 100% rename from Dockerfile.template rename to legacy-templating-scripts/Dockerfile.template diff --git a/apply-templates.sh b/legacy-templating-scripts/apply-templates.sh similarity index 100% rename from apply-templates.sh rename to legacy-templating-scripts/apply-templates.sh diff --git a/docker-entrypoint.sh b/legacy-templating-scripts/docker-entrypoint.sh similarity index 100% rename from docker-entrypoint.sh rename to legacy-templating-scripts/docker-entrypoint.sh diff --git a/generate-stackbrew-library-mac.sh b/legacy-templating-scripts/generate-stackbrew-library-mac.sh similarity index 100% rename from generate-stackbrew-library-mac.sh rename to legacy-templating-scripts/generate-stackbrew-library-mac.sh diff --git a/generate-stackbrew-library.sh b/legacy-templating-scripts/generate-stackbrew-library.sh similarity index 100% rename from generate-stackbrew-library.sh rename to legacy-templating-scripts/generate-stackbrew-library.sh diff --git a/update.sh b/legacy-templating-scripts/update.sh similarity index 100% rename from update.sh rename to legacy-templating-scripts/update.sh diff --git a/versions.json b/legacy-templating-scripts/versions.json similarity index 100% rename from versions.json rename to legacy-templating-scripts/versions.json diff --git a/versions.sh b/legacy-templating-scripts/versions.sh similarity index 100% rename from versions.sh rename to legacy-templating-scripts/versions.sh