├── 28 ├── cli │ ├── Dockerfile │ ├── docker-entrypoint.sh │ └── modprobe.sh ├── dind-rootless │ └── Dockerfile ├── dind │ ├── Dockerfile │ └── dockerd-entrypoint.sh └── windows │ ├── windowsservercore-ltsc2022 │ └── Dockerfile │ └── windowsservercore-ltsc2025 │ └── Dockerfile ├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ └── verify-templating.yml ├── .gitignore ├── Dockerfile-cli.template ├── Dockerfile-dind-rootless.template ├── Dockerfile-dind.template ├── Dockerfile-windows-servercore.template ├── LICENSE ├── README.md ├── apply-templates.sh ├── docker-entrypoint.sh ├── dockerd-entrypoint.sh ├── generate-stackbrew-library.sh ├── modprobe.sh ├── shared.jq ├── update.sh ├── versions.json └── versions.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | /*/**/Dockerfile linguist-generated 2 | /*/**/docker-entrypoint.sh linguist-generated 3 | /*/**/dockerd-entrypoint.sh linguist-generated 4 | /*/**/modprobe.sh linguist-generated 5 | /Dockerfile*.template linguist-language=Dockerfile 6 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: GitHub CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: 0 0 * * 0 9 | 10 | defaults: 11 | run: 12 | shell: 'bash -Eeuo pipefail -x {0}' 13 | 14 | concurrency: 15 | group: ${{ github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | 20 | generate-jobs: 21 | name: Generate Jobs 22 | runs-on: ubuntu-latest 23 | outputs: 24 | strategy: ${{ steps.generate-jobs.outputs.strategy }} 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: docker-library/bashbrew@HEAD 28 | - id: generate-jobs 29 | name: Generate Jobs 30 | run: | 31 | strategy="$("$BASHBREW_SCRIPTS/github-actions/generate.sh")" 32 | 33 | EOF="EOF-$RANDOM-$RANDOM-$RANDOM" 34 | echo "strategy<<$EOF" >> "$GITHUB_OUTPUT" 35 | jq <<<"$strategy" . | tee -a "$GITHUB_OUTPUT" 36 | echo "$EOF" >> "$GITHUB_OUTPUT" 37 | 38 | test: 39 | needs: generate-jobs 40 | strategy: ${{ fromJson(needs.generate-jobs.outputs.strategy) }} 41 | name: ${{ matrix.name }} 42 | runs-on: ${{ matrix.os }} 43 | steps: 44 | - uses: actions/checkout@v4 45 | - name: Prepare Environment 46 | run: ${{ matrix.runs.prepare }} 47 | - name: Pull Dependencies 48 | run: ${{ matrix.runs.pull }} 49 | - name: Build ${{ matrix.name }} 50 | run: ${{ matrix.runs.build }} 51 | - name: History ${{ matrix.name }} 52 | run: ${{ matrix.runs.history }} 53 | - name: Test ${{ matrix.name }} 54 | run: ${{ matrix.runs.test }} 55 | - name: '"docker images"' 56 | run: ${{ matrix.runs.images }} 57 | -------------------------------------------------------------------------------- /.github/workflows/verify-templating.yml: -------------------------------------------------------------------------------- 1 | name: Verify Templating 2 | 3 | on: 4 | pull_request: 5 | push: 6 | workflow_dispatch: 7 | 8 | defaults: 9 | run: 10 | shell: 'bash -Eeuo pipefail -x {0}' 11 | 12 | jobs: 13 | apply-templates: 14 | name: Check For Uncomitted Changes 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - run: ./apply-templates.sh 19 | - run: git diff --exit-code 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .jq-template.awk 2 | -------------------------------------------------------------------------------- /28/cli/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" 3 | # 4 | # PLEASE DO NOT EDIT IT DIRECTLY. 5 | # 6 | 7 | FROM alpine:3.22 8 | 9 | RUN apk add --no-cache \ 10 | ca-certificates \ 11 | # DOCKER_HOST=ssh://... -- https://github.com/docker/cli/pull/1014 12 | openssh-client \ 13 | # https://github.com/docker-library/docker/issues/482#issuecomment-2197116408 14 | git 15 | 16 | # ensure that nsswitch.conf is set up for Go's "netgo" implementation (which Docker explicitly uses) 17 | # - https://github.com/moby/moby/blob/v24.0.6/hack/make.sh#L111 18 | # - https://github.com/golang/go/blob/go1.19.13/src/net/conf.go#L227-L303 19 | # - docker run --rm debian:stretch grep '^hosts:' /etc/nsswitch.conf 20 | RUN [ -e /etc/nsswitch.conf ] && grep '^hosts: files dns' /etc/nsswitch.conf 21 | 22 | # pre-add a "docker" group for socket usage 23 | RUN set -eux; \ 24 | addgroup -g 2375 -S docker 25 | 26 | ENV DOCKER_VERSION 28.2.2 27 | 28 | RUN set -eux; \ 29 | \ 30 | apkArch="$(apk --print-arch)"; \ 31 | case "$apkArch" in \ 32 | 'x86_64') \ 33 | url='https://download.docker.com/linux/static/stable/x86_64/docker-28.2.2.tgz'; \ 34 | ;; \ 35 | 'armhf') \ 36 | url='https://download.docker.com/linux/static/stable/armel/docker-28.2.2.tgz'; \ 37 | ;; \ 38 | 'armv7') \ 39 | url='https://download.docker.com/linux/static/stable/armhf/docker-28.2.2.tgz'; \ 40 | ;; \ 41 | 'aarch64') \ 42 | url='https://download.docker.com/linux/static/stable/aarch64/docker-28.2.2.tgz'; \ 43 | ;; \ 44 | *) echo >&2 "error: unsupported 'docker.tgz' architecture ($apkArch)"; exit 1 ;; \ 45 | esac; \ 46 | \ 47 | wget -O 'docker.tgz' "$url"; \ 48 | \ 49 | tar --extract \ 50 | --file docker.tgz \ 51 | --strip-components 1 \ 52 | --directory /usr/local/bin/ \ 53 | --no-same-owner \ 54 | 'docker/docker' \ 55 | ; \ 56 | rm docker.tgz; \ 57 | \ 58 | docker --version 59 | 60 | ENV DOCKER_BUILDX_VERSION 0.24.0 61 | RUN set -eux; \ 62 | \ 63 | apkArch="$(apk --print-arch)"; \ 64 | case "$apkArch" in \ 65 | 'x86_64') \ 66 | url='https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-amd64'; \ 67 | sha256='c41ed17ec05b6ebb50eeb02fb26cce90f16cd260b8d26ce73963428c6b2d6508'; \ 68 | ;; \ 69 | 'armhf') \ 70 | url='https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-arm-v6'; \ 71 | sha256='591abb51afe942814a45f4f3d0f1a97fe8c5c212142bded66025ae019136bac8'; \ 72 | ;; \ 73 | 'armv7') \ 74 | url='https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-arm-v7'; \ 75 | sha256='69a3afa3d22867ea67b87e5f205574478e7a795599c471b61575bacf455452ae'; \ 76 | ;; \ 77 | 'aarch64') \ 78 | url='https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-arm64'; \ 79 | sha256='ad33819d085a635e3b4400a412bd2b4e943bfbc830366d78f50579bae48f8053'; \ 80 | ;; \ 81 | 'ppc64le') \ 82 | url='https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-ppc64le'; \ 83 | sha256='90c02625d1e52abd8e6089854208963651ea727028aaca58b29847dc594c01f8'; \ 84 | ;; \ 85 | 'riscv64') \ 86 | url='https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-riscv64'; \ 87 | sha256='3031cf533e015ea77425446e4bc87173f1316447ed3369c2898f73ac353de404'; \ 88 | ;; \ 89 | 's390x') \ 90 | url='https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-s390x'; \ 91 | sha256='821ea62254a7be6cab51c5ebefc9ba74b7e2dd902c78d16b268850dc29869ca2'; \ 92 | ;; \ 93 | *) echo >&2 "warning: unsupported 'docker-buildx' architecture ($apkArch); skipping"; exit 0 ;; \ 94 | esac; \ 95 | \ 96 | wget -O 'docker-buildx' "$url"; \ 97 | echo "$sha256 *"'docker-buildx' | sha256sum -c -; \ 98 | \ 99 | plugin='/usr/local/libexec/docker/cli-plugins/docker-buildx'; \ 100 | mkdir -p "$(dirname "$plugin")"; \ 101 | mv -vT 'docker-buildx' "$plugin"; \ 102 | chmod +x "$plugin"; \ 103 | \ 104 | docker buildx version 105 | 106 | ENV DOCKER_COMPOSE_VERSION 2.37.0 107 | RUN set -eux; \ 108 | \ 109 | apkArch="$(apk --print-arch)"; \ 110 | case "$apkArch" in \ 111 | 'x86_64') \ 112 | url='https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-x86_64'; \ 113 | sha256='e6e471b1e7bf0443592d3987dea6073f08db3e48ba0580199109aa7a44257e54'; \ 114 | ;; \ 115 | 'armhf') \ 116 | url='https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-armv6'; \ 117 | sha256='f09294bd81119701f051733b45be487d55faa29d20fb9c54412975a6c7fd8696'; \ 118 | ;; \ 119 | 'armv7') \ 120 | url='https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-armv7'; \ 121 | sha256='b1b592889f15f50ddc77685ed499c69599117e52240b196447cb82821da3f7f8'; \ 122 | ;; \ 123 | 'aarch64') \ 124 | url='https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-aarch64'; \ 125 | sha256='664e8c532ac0dd54d14af4eb3fe4edce86ce27d970ec832a96b55bc2ef1dffdf'; \ 126 | ;; \ 127 | 'ppc64le') \ 128 | url='https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-ppc64le'; \ 129 | sha256='83c7cf5afffcc7944e23ba5c1c038aff4f2d760f08681d76b5271b66c9e2af5d'; \ 130 | ;; \ 131 | 'riscv64') \ 132 | url='https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-riscv64'; \ 133 | sha256='0e6047d2b0f745f0bbb13d707cfb945295bf45e397e67ff756f8551043a1f5bc'; \ 134 | ;; \ 135 | 's390x') \ 136 | url='https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-s390x'; \ 137 | sha256='381b5b77e6a91075e746167ac160062a1adf4d2a1121e433f1ca731ad08e2353'; \ 138 | ;; \ 139 | *) echo >&2 "warning: unsupported 'docker-compose' architecture ($apkArch); skipping"; exit 0 ;; \ 140 | esac; \ 141 | \ 142 | wget -O 'docker-compose' "$url"; \ 143 | echo "$sha256 *"'docker-compose' | sha256sum -c -; \ 144 | \ 145 | plugin='/usr/local/libexec/docker/cli-plugins/docker-compose'; \ 146 | mkdir -p "$(dirname "$plugin")"; \ 147 | mv -vT 'docker-compose' "$plugin"; \ 148 | chmod +x "$plugin"; \ 149 | \ 150 | ln -sv "$plugin" /usr/local/bin/; \ 151 | docker-compose --version; \ 152 | docker compose version 153 | 154 | COPY modprobe.sh /usr/local/bin/modprobe 155 | COPY docker-entrypoint.sh /usr/local/bin/ 156 | 157 | # https://github.com/docker-library/docker/pull/166 158 | # dockerd-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-generating TLS certificates 159 | # docker-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-setting DOCKER_TLS_VERIFY and DOCKER_CERT_PATH 160 | # (For this to work, at least the "client" subdirectory of this path needs to be shared between the client and server containers via a volume, "docker cp", or other means of data sharing.) 161 | ENV DOCKER_TLS_CERTDIR=/certs 162 | # also, ensure the directory pre-exists and has wide enough permissions for "dockerd-entrypoint.sh" to create subdirectories, even when run in "rootless" mode 163 | RUN mkdir /certs /certs/client && chmod 1777 /certs /certs/client 164 | # (doing both /certs and /certs/client so that if Docker does a "copy-up" into a volume defined on /certs/client, it will "do the right thing" by default in a way that still works for rootless users) 165 | 166 | ENTRYPOINT ["docker-entrypoint.sh"] 167 | CMD ["sh"] 168 | -------------------------------------------------------------------------------- /28/cli/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | # first arg is `-f` or `--some-option` 5 | if [ "${1#-}" != "$1" ]; then 6 | set -- docker "$@" 7 | fi 8 | 9 | # if our command is a valid Docker subcommand, let's invoke it through Docker instead 10 | # (this allows for "docker run docker ps", etc) 11 | if docker help "$1" > /dev/null 2>&1; then 12 | set -- docker "$@" 13 | fi 14 | 15 | _should_tls() { 16 | [ -n "${DOCKER_TLS_CERTDIR:-}" ] \ 17 | && [ -s "$DOCKER_TLS_CERTDIR/client/ca.pem" ] \ 18 | && [ -s "$DOCKER_TLS_CERTDIR/client/cert.pem" ] \ 19 | && [ -s "$DOCKER_TLS_CERTDIR/client/key.pem" ] 20 | } 21 | 22 | # if we have no DOCKER_HOST but we do have the default Unix socket (standard or rootless), use it explicitly 23 | if [ -z "${DOCKER_HOST:-}" ] && [ -S /var/run/docker.sock ]; then 24 | export DOCKER_HOST=unix:///var/run/docker.sock 25 | elif [ -z "${DOCKER_HOST:-}" ] && XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" && [ -S "$XDG_RUNTIME_DIR/docker.sock" ]; then 26 | export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock" 27 | fi 28 | 29 | # if DOCKER_HOST isn't set (no custom setting, no default socket), let's set it to a sane remote value 30 | if [ -z "${DOCKER_HOST:-}" ]; then 31 | if _should_tls || [ -n "${DOCKER_TLS_VERIFY:-}" ]; then 32 | export DOCKER_HOST='tcp://docker:2376' 33 | else 34 | export DOCKER_HOST='tcp://docker:2375' 35 | fi 36 | fi 37 | if [ "${DOCKER_HOST#tcp:}" != "$DOCKER_HOST" ] \ 38 | && [ -z "${DOCKER_TLS_VERIFY:-}" ] \ 39 | && [ -z "${DOCKER_CERT_PATH:-}" ] \ 40 | && _should_tls \ 41 | ; then 42 | export DOCKER_TLS_VERIFY=1 43 | export DOCKER_CERT_PATH="$DOCKER_TLS_CERTDIR/client" 44 | fi 45 | 46 | if [ "$1" = 'dockerd' ]; then 47 | cat >&2 <<-'EOW' 48 | 49 | 📎 Hey there! It looks like you're trying to run a Docker daemon. 50 | 51 | You probably should use the "dind" image variant instead, something like: 52 | 53 | docker run --privileged --name some-docker ... docker:dind ... 54 | 55 | See https://hub.docker.com/_/docker/ for more documentation and usage examples. 56 | 57 | EOW 58 | sleep 3 59 | fi 60 | 61 | exec "$@" 62 | -------------------------------------------------------------------------------- /28/cli/modprobe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | # "modprobe" without modprobe 5 | # https://twitter.com/lucabruno/status/902934379835662336 6 | 7 | # this isn't 100% fool-proof, but it'll have a much higher success rate than simply using the "real" modprobe 8 | 9 | # Docker often uses "modprobe -va foo bar baz" 10 | # so we ignore modules that start with "-" 11 | for module; do 12 | if [ "${module#-}" = "$module" ]; then 13 | ip link show "$module" || true 14 | lsmod | grep "$module" || true 15 | fi 16 | done 17 | 18 | # remove /usr/local/... from PATH so we can exec the real modprobe as a last resort 19 | export PATH='/usr/sbin:/usr/bin:/sbin:/bin' 20 | exec modprobe "$@" 21 | -------------------------------------------------------------------------------- /28/dind-rootless/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" 3 | # 4 | # PLEASE DO NOT EDIT IT DIRECTLY. 5 | # 6 | 7 | FROM docker:28-dind 8 | 9 | # busybox "ip" is insufficient: 10 | # [rootlesskit:child ] error: executing [[ip tuntap add name tap0 mode tap] [ip link set tap0 address 02:50:00:00:00:01]]: exit status 1 11 | RUN apk add --no-cache iproute2 fuse-overlayfs 12 | 13 | # "/run/user/UID" will be used by default as the value of XDG_RUNTIME_DIR 14 | RUN mkdir /run/user && chmod 1777 /run/user 15 | 16 | # create a default user preconfigured for running rootless dockerd 17 | RUN set -eux; \ 18 | adduser -h /home/rootless -g 'Rootless' -D -u 1000 rootless; \ 19 | echo 'rootless:100000:65536' >> /etc/subuid; \ 20 | echo 'rootless:100000:65536' >> /etc/subgid 21 | 22 | RUN set -eux; \ 23 | \ 24 | apkArch="$(apk --print-arch)"; \ 25 | case "$apkArch" in \ 26 | 'x86_64') \ 27 | url='https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-28.2.2.tgz'; \ 28 | ;; \ 29 | 'aarch64') \ 30 | url='https://download.docker.com/linux/static/stable/aarch64/docker-rootless-extras-28.2.2.tgz'; \ 31 | ;; \ 32 | *) echo >&2 "error: unsupported 'rootless.tgz' architecture ($apkArch)"; exit 1 ;; \ 33 | esac; \ 34 | \ 35 | wget -O 'rootless.tgz' "$url"; \ 36 | \ 37 | tar --extract \ 38 | --file rootless.tgz \ 39 | --strip-components 1 \ 40 | --directory /usr/local/bin/ \ 41 | 'docker-rootless-extras/rootlesskit' \ 42 | 'docker-rootless-extras/vpnkit' \ 43 | ; \ 44 | rm rootless.tgz; \ 45 | \ 46 | rootlesskit --version; \ 47 | vpnkit --version 48 | 49 | # pre-create "/var/lib/docker" for our rootless user 50 | RUN set -eux; \ 51 | mkdir -p /home/rootless/.local/share/docker; \ 52 | chown -R rootless:rootless /home/rootless/.local/share/docker 53 | VOLUME /home/rootless/.local/share/docker 54 | USER rootless 55 | -------------------------------------------------------------------------------- /28/dind/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" 3 | # 4 | # PLEASE DO NOT EDIT IT DIRECTLY. 5 | # 6 | 7 | FROM docker:28-cli 8 | 9 | # https://github.com/moby/moby/blob/0eecd59153c03ced5f5ddd79cc98f29e4d86daec/project/PACKAGERS.md#runtime-dependencies 10 | # https://github.com/docker/docker-ce-packaging/blob/963aa02666035d4e268f33c63d7868d6cdd1d34c/deb/common/control#L28-L41 11 | RUN set -eux; \ 12 | apk add --no-cache \ 13 | btrfs-progs \ 14 | e2fsprogs \ 15 | e2fsprogs-extra \ 16 | git \ 17 | ip6tables \ 18 | iptables \ 19 | openssl \ 20 | pigz \ 21 | shadow-uidmap \ 22 | xfsprogs \ 23 | xz \ 24 | zfs \ 25 | ; 26 | 27 | # dind might be used on systems where the nf_tables kernel module isn't available. In that case, 28 | # we need to switch over to xtables-legacy. See https://github.com/docker-library/docker/issues/463 29 | RUN set -eux; \ 30 | apk add --no-cache iptables-legacy; \ 31 | # set up a symlink farm we can use PATH to switch to legacy with 32 | mkdir -p /usr/local/sbin/.iptables-legacy; \ 33 | # https://gitlab.alpinelinux.org/alpine/aports/-/blob/a7e1610a67a46fc52668528efe01cee621c2ba6c/main/iptables/APKBUILD#L77 34 | for f in \ 35 | iptables \ 36 | iptables-save \ 37 | iptables-restore \ 38 | ip6tables \ 39 | ip6tables-save \ 40 | ip6tables-restore \ 41 | ; do \ 42 | # "iptables-save" -> "iptables-legacy-save", "ip6tables" -> "ip6tables-legacy", etc. 43 | # https://pkgs.alpinelinux.org/contents?branch=v3.22&name=iptables-legacy&arch=x86_64 44 | b="$(command -v "${f/tables/tables-legacy}")"; \ 45 | "$b" --version; \ 46 | ln -svT "$b" "/usr/local/sbin/.iptables-legacy/$f"; \ 47 | done; \ 48 | # verify it works (and gets us legacy) 49 | export PATH="/usr/local/sbin/.iptables-legacy:$PATH"; \ 50 | iptables --version | grep legacy 51 | 52 | # set up subuid/subgid so that "--userns-remap=default" works out-of-the-box 53 | RUN set -eux; \ 54 | addgroup -S dockremap; \ 55 | adduser -S -G dockremap dockremap; \ 56 | echo 'dockremap:165536:65536' >> /etc/subuid; \ 57 | echo 'dockremap:165536:65536' >> /etc/subgid 58 | 59 | RUN set -eux; \ 60 | \ 61 | apkArch="$(apk --print-arch)"; \ 62 | case "$apkArch" in \ 63 | 'x86_64') \ 64 | url='https://download.docker.com/linux/static/stable/x86_64/docker-28.2.2.tgz'; \ 65 | ;; \ 66 | 'armhf') \ 67 | url='https://download.docker.com/linux/static/stable/armel/docker-28.2.2.tgz'; \ 68 | ;; \ 69 | 'armv7') \ 70 | url='https://download.docker.com/linux/static/stable/armhf/docker-28.2.2.tgz'; \ 71 | ;; \ 72 | 'aarch64') \ 73 | url='https://download.docker.com/linux/static/stable/aarch64/docker-28.2.2.tgz'; \ 74 | ;; \ 75 | *) echo >&2 "error: unsupported 'docker.tgz' architecture ($apkArch)"; exit 1 ;; \ 76 | esac; \ 77 | \ 78 | wget -O 'docker.tgz' "$url"; \ 79 | \ 80 | tar --extract \ 81 | --file docker.tgz \ 82 | --strip-components 1 \ 83 | --directory /usr/local/bin/ \ 84 | --no-same-owner \ 85 | # we exclude the CLI binary because we already extracted that over in the "docker:28-cli" image that we're FROM and we don't want to duplicate those bytes again in this layer 86 | --exclude 'docker/docker' \ 87 | ; \ 88 | rm docker.tgz; \ 89 | \ 90 | dockerd --version; \ 91 | containerd --version; \ 92 | ctr --version; \ 93 | runc --version 94 | 95 | # https://github.com/docker/docker/tree/master/hack/dind 96 | ENV DIND_COMMIT 8d9e3502aba39127e4d12196dae16d306f76993d 97 | 98 | RUN set -eux; \ 99 | wget -O /usr/local/bin/dind "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind"; \ 100 | chmod +x /usr/local/bin/dind 101 | 102 | COPY dockerd-entrypoint.sh /usr/local/bin/ 103 | 104 | VOLUME /var/lib/docker 105 | EXPOSE 2375 2376 106 | 107 | ENTRYPOINT ["dockerd-entrypoint.sh"] 108 | CMD [] 109 | -------------------------------------------------------------------------------- /28/dind/dockerd-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | _tls_ensure_private() { 5 | local f="$1"; shift 6 | [ -s "$f" ] || openssl genrsa -out "$f" 4096 7 | } 8 | _tls_san() { 9 | { 10 | ip -oneline address | awk '{ gsub(/\/.+$/, "", $4); print "IP:" $4 }' 11 | { 12 | cat /etc/hostname 13 | echo 'docker' 14 | echo 'localhost' 15 | hostname -f 16 | hostname -s 17 | } | sed 's/^/DNS:/' 18 | [ -z "${DOCKER_TLS_SAN:-}" ] || echo "$DOCKER_TLS_SAN" 19 | } | sort -u | xargs printf '%s,' | sed "s/,\$//" 20 | } 21 | _tls_generate_certs() { 22 | local dir="$1"; shift 23 | 24 | # if server/{ca,key,cert}.pem && !ca/key.pem, do NOTHING except verify (user likely managing CA themselves) 25 | # if ca/key.pem || !ca/cert.pem, generate CA public if necessary 26 | # if ca/key.pem, generate server public 27 | # if ca/key.pem, generate client public 28 | # (regenerating public certs every startup to account for SAN/IP changes and/or expiration) 29 | 30 | if [ -s "$dir/server/ca.pem" ] && [ -s "$dir/server/cert.pem" ] && [ -s "$dir/server/key.pem" ] && [ ! -s "$dir/ca/key.pem" ]; then 31 | openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem" 32 | return 0 33 | fi 34 | 35 | # https://github.com/FiloSottile/mkcert/issues/174 36 | local certValidDays='825' 37 | 38 | if [ -s "$dir/ca/key.pem" ] || [ ! -s "$dir/ca/cert.pem" ]; then 39 | # if we either have a CA private key or do *not* have a CA public key, then we should create/manage the CA 40 | mkdir -p "$dir/ca" 41 | _tls_ensure_private "$dir/ca/key.pem" 42 | openssl req -new -key "$dir/ca/key.pem" \ 43 | -out "$dir/ca/cert.pem" \ 44 | -subj '/CN=docker:dind CA' \ 45 | -x509 \ 46 | -days "$certValidDays" \ 47 | -addext keyUsage=critical,digitalSignature,keyCertSign 48 | fi 49 | 50 | if [ -s "$dir/ca/key.pem" ]; then 51 | # if we have a CA private key, we should create/manage a server key 52 | mkdir -p "$dir/server" 53 | _tls_ensure_private "$dir/server/key.pem" 54 | openssl req -new -key "$dir/server/key.pem" \ 55 | -out "$dir/server/csr.pem" \ 56 | -subj '/CN=docker:dind server' 57 | cat > "$dir/server/openssl.cnf" <<-EOF 58 | [ x509_exts ] 59 | extendedKeyUsage = serverAuth 60 | subjectAltName = $(_tls_san) 61 | EOF 62 | openssl x509 -req \ 63 | -in "$dir/server/csr.pem" \ 64 | -CA "$dir/ca/cert.pem" \ 65 | -CAkey "$dir/ca/key.pem" \ 66 | -CAcreateserial \ 67 | -out "$dir/server/cert.pem" \ 68 | -days "$certValidDays" \ 69 | -extfile "$dir/server/openssl.cnf" \ 70 | -extensions x509_exts 71 | cp "$dir/ca/cert.pem" "$dir/server/ca.pem" 72 | openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem" 73 | fi 74 | 75 | if [ -s "$dir/ca/key.pem" ]; then 76 | # if we have a CA private key, we should create/manage a client key 77 | mkdir -p "$dir/client" 78 | _tls_ensure_private "$dir/client/key.pem" 79 | chmod 0644 "$dir/client/key.pem" # openssl defaults to 0600 for the private key, but this one needs to be shared with arbitrary client contexts 80 | openssl req -new \ 81 | -key "$dir/client/key.pem" \ 82 | -out "$dir/client/csr.pem" \ 83 | -subj '/CN=docker:dind client' 84 | cat > "$dir/client/openssl.cnf" <<-'EOF' 85 | [ x509_exts ] 86 | extendedKeyUsage = clientAuth 87 | EOF 88 | openssl x509 -req \ 89 | -in "$dir/client/csr.pem" \ 90 | -CA "$dir/ca/cert.pem" \ 91 | -CAkey "$dir/ca/key.pem" \ 92 | -CAcreateserial \ 93 | -out "$dir/client/cert.pem" \ 94 | -days "$certValidDays" \ 95 | -extfile "$dir/client/openssl.cnf" \ 96 | -extensions x509_exts 97 | cp "$dir/ca/cert.pem" "$dir/client/ca.pem" 98 | openssl verify -CAfile "$dir/client/ca.pem" "$dir/client/cert.pem" 99 | fi 100 | } 101 | 102 | # no arguments passed 103 | # or first arg is `-f` or `--some-option` 104 | if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then 105 | # set "dockerSocket" to the default "--host" *unix socket* value (for both standard or rootless) 106 | uid="$(id -u)" 107 | if [ "$uid" = '0' ]; then 108 | dockerSocket='unix:///var/run/docker.sock' 109 | else 110 | # if we're not root, we must be trying to run rootless 111 | : "${XDG_RUNTIME_DIR:=/run/user/$uid}" 112 | dockerSocket="unix://$XDG_RUNTIME_DIR/docker.sock" 113 | fi 114 | case "${DOCKER_HOST:-}" in 115 | unix://*) 116 | dockerSocket="$DOCKER_HOST" 117 | ;; 118 | esac 119 | 120 | # add our default arguments 121 | if [ -n "${DOCKER_TLS_CERTDIR:-}" ]; then 122 | _tls_generate_certs "$DOCKER_TLS_CERTDIR" 123 | # generate certs and use TLS if requested/possible (default in 19.03+) 124 | set -- dockerd \ 125 | --host="$dockerSocket" \ 126 | --host=tcp://0.0.0.0:2376 \ 127 | --tlsverify \ 128 | --tlscacert "$DOCKER_TLS_CERTDIR/server/ca.pem" \ 129 | --tlscert "$DOCKER_TLS_CERTDIR/server/cert.pem" \ 130 | --tlskey "$DOCKER_TLS_CERTDIR/server/key.pem" \ 131 | "$@" 132 | DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2376:2376/tcp" 133 | else 134 | # TLS disabled (-e DOCKER_TLS_CERTDIR='') or missing certs 135 | set -- dockerd \ 136 | --host="$dockerSocket" \ 137 | --host=tcp://0.0.0.0:2375 \ 138 | "$@" 139 | DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2375:2375/tcp" 140 | fi 141 | fi 142 | 143 | if [ "$1" = 'dockerd' ]; then 144 | # explicitly remove Docker's default PID file to ensure that it can start properly if it was stopped uncleanly (and thus didn't clean up the PID file) 145 | find /run /var/run -iname 'docker*.pid' -delete || : 146 | 147 | # XXX inject "docker-init" (tini) as pid1 to workaround https://github.com/docker-library/docker/issues/318 (zombie container-shim processes) 148 | set -- docker-init -- "$@" 149 | 150 | iptablesLegacy= 151 | if [ -n "${DOCKER_IPTABLES_LEGACY+x}" ]; then 152 | # let users choose explicitly to legacy or not to legacy 153 | iptablesLegacy="$DOCKER_IPTABLES_LEGACY" 154 | if [ -n "$iptablesLegacy" ]; then 155 | modprobe ip_tables || : 156 | modprobe ip6_tables || : 157 | else 158 | modprobe nf_tables || : 159 | fi 160 | elif ( 161 | # https://git.netfilter.org/iptables/tree/iptables/nft-shared.c?id=f5cf76626d95d2c491a80288bccc160c53b44e88#n420 162 | # https://github.com/docker-library/docker/pull/468#discussion_r1442131459 163 | for f in /proc/net/ip_tables_names /proc/net/ip6_tables_names /proc/net/arp_tables_names; do 164 | if b="$(cat "$f")" && [ -n "$b" ]; then 165 | exit 0 166 | fi 167 | done 168 | exit 1 169 | ); then 170 | # if we already have any "legacy" iptables rules, we should always use legacy 171 | iptablesLegacy=1 172 | elif ! iptables -nL > /dev/null 2>&1; then 173 | # if iptables fails to run, chances are high the necessary kernel modules aren't loaded (perhaps the host is using xtables, for example) 174 | # https://github.com/docker-library/docker/issues/350 175 | # https://github.com/moby/moby/issues/26824 176 | # https://github.com/docker-library/docker/pull/437#issuecomment-1854900620 177 | modprobe nf_tables || : 178 | if ! iptables -nL > /dev/null 2>&1; then 179 | # might be host has no nf_tables, but Alpine is all-in now (so let's try a legacy fallback) 180 | modprobe ip_tables || : 181 | modprobe ip6_tables || : 182 | if /usr/local/sbin/.iptables-legacy/iptables -nL > /dev/null 2>&1; then 183 | iptablesLegacy=1 184 | fi 185 | fi 186 | fi 187 | if [ -n "$iptablesLegacy" ]; then 188 | # see https://github.com/docker-library/docker/issues/463 (and the dind Dockerfile where this directory is set up) 189 | export PATH="/usr/local/sbin/.iptables-legacy:$PATH" 190 | fi 191 | iptables --version # so users can see whether it's legacy or not 192 | 193 | uid="$(id -u)" 194 | if [ "$uid" != '0' ]; then 195 | # if we're not root, we must be trying to run rootless 196 | if ! command -v rootlesskit > /dev/null; then 197 | echo >&2 "error: attempting to run rootless dockerd but missing 'rootlesskit' (perhaps the 'docker:dind-rootless' image variant is intended?)" 198 | exit 1 199 | fi 200 | user="$(id -un 2>/dev/null || :)" 201 | if ! grep -qE "^($uid${user:+|$user}):" /etc/subuid || ! grep -qE "^($uid${user:+|$user}):" /etc/subgid; then 202 | echo >&2 "error: attempting to run rootless dockerd but missing necessary entries in /etc/subuid and/or /etc/subgid for $uid" 203 | exit 1 204 | fi 205 | : "${XDG_RUNTIME_DIR:=/run/user/$uid}" 206 | export XDG_RUNTIME_DIR 207 | if ! mkdir -p "$XDG_RUNTIME_DIR" || [ ! -w "$XDG_RUNTIME_DIR" ] || ! mkdir -p "$HOME/.local/share/docker" || [ ! -w "$HOME/.local/share/docker" ]; then 208 | echo >&2 "error: attempting to run rootless dockerd but need writable HOME ($HOME) and XDG_RUNTIME_DIR ($XDG_RUNTIME_DIR) for user $uid" 209 | exit 1 210 | fi 211 | if [ -f /proc/sys/kernel/unprivileged_userns_clone ] && unprivClone="$(cat /proc/sys/kernel/unprivileged_userns_clone)" && [ "$unprivClone" != '1' ]; then 212 | echo >&2 "error: attempting to run rootless dockerd but need 'kernel.unprivileged_userns_clone' (/proc/sys/kernel/unprivileged_userns_clone) set to 1" 213 | exit 1 214 | fi 215 | if [ -f /proc/sys/user/max_user_namespaces ] && maxUserns="$(cat /proc/sys/user/max_user_namespaces)" && [ "$maxUserns" = '0' ]; then 216 | echo >&2 "error: attempting to run rootless dockerd but need 'user.max_user_namespaces' (/proc/sys/user/max_user_namespaces) set to a sufficiently large value" 217 | exit 1 218 | fi 219 | # TODO overlay support detection? 220 | exec rootlesskit \ 221 | --net="${DOCKERD_ROOTLESS_ROOTLESSKIT_NET:-vpnkit}" \ 222 | --mtu="${DOCKERD_ROOTLESS_ROOTLESSKIT_MTU:-1500}" \ 223 | --disable-host-loopback \ 224 | --port-driver=builtin \ 225 | --copy-up=/etc \ 226 | --copy-up=/run \ 227 | ${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} \ 228 | "$@" 229 | elif [ -x '/usr/local/bin/dind' ]; then 230 | # if we have the (mostly defunct now) Docker-in-Docker wrapper script, use it 231 | set -- '/usr/local/bin/dind' "$@" 232 | fi 233 | else 234 | # if it isn't `dockerd` we're trying to run, pass it through `docker-entrypoint.sh` so it gets `DOCKER_HOST` set appropriately too 235 | set -- docker-entrypoint.sh "$@" 236 | fi 237 | 238 | exec "$@" 239 | -------------------------------------------------------------------------------- /28/windows/windowsservercore-ltsc2022/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" 3 | # 4 | # PLEASE DO NOT EDIT IT DIRECTLY. 5 | # 6 | 7 | FROM mcr.microsoft.com/windows/servercore:ltsc2022 8 | 9 | # $ProgressPreference: https://github.com/PowerShell/PowerShell/issues/2138#issuecomment-251261324 10 | SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] 11 | 12 | # PATH isn't actually set in the Docker image, so we have to set it from within the container 13 | RUN $newPath = ('{0}\docker;{1}' -f $env:ProgramFiles, $env:PATH); \ 14 | Write-Host ('Updating PATH: {0}' -f $newPath); \ 15 | [Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine); 16 | # doing this first to share cache across versions more aggressively 17 | 18 | ENV DOCKER_VERSION 28.2.2 19 | ENV DOCKER_URL https://download.docker.com/win/static/stable/x86_64/docker-28.2.2.zip 20 | # TODO ENV DOCKER_SHA256 21 | # https://github.com/docker/docker-ce/blob/5b073ee2cf564edee5adca05eee574142f7627bb/components/packaging/static/hash_files !! 22 | # (no SHA file artifacts on download.docker.com yet as of 2017-06-07 though) 23 | 24 | RUN Write-Host ('Downloading {0} ...' -f $env:DOCKER_URL); \ 25 | Invoke-WebRequest -Uri $env:DOCKER_URL -OutFile 'docker.zip'; \ 26 | \ 27 | Write-Host 'Expanding ...'; \ 28 | Expand-Archive docker.zip -DestinationPath $env:ProgramFiles; \ 29 | # (this archive has a "docker/..." directory in it already) 30 | \ 31 | Write-Host 'Removing ...'; \ 32 | Remove-Item @( \ 33 | 'docker.zip', \ 34 | ('{0}\docker\dockerd.exe' -f $env:ProgramFiles) \ 35 | ) -Force; \ 36 | \ 37 | Write-Host 'Verifying install ("docker --version") ...'; \ 38 | docker --version; \ 39 | \ 40 | Write-Host 'Complete.'; 41 | 42 | # https://github.com/docker-library/docker/issues/409#issuecomment-1462868414 43 | ENV DOCKER_BUILDX_VERSION 0.24.0 44 | ENV DOCKER_BUILDX_URL https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.windows-amd64.exe 45 | ENV DOCKER_BUILDX_SHA256 8dec102c8eb14f434707cc05a8f0e366c090ded6ad74d9c5f8a64a9c0b766140 46 | RUN $dir = ('{0}\docker\cli-plugins' -f $env:ProgramFiles); \ 47 | Write-Host ('Creating {0} ...' -f $dir); \ 48 | New-Item -ItemType Directory $dir -Force; \ 49 | \ 50 | $plugin = ('{0}\docker-buildx.exe' -f $dir); \ 51 | Write-Host ('Downloading {0} ...' -f $env:DOCKER_BUILDX_URL); \ 52 | Invoke-WebRequest -Uri $env:DOCKER_BUILDX_URL -OutFile $plugin; \ 53 | \ 54 | Write-Host ('Verifying sha256 ({0}) ...' -f $env:DOCKER_BUILDX_SHA256); \ 55 | if ((Get-FileHash $plugin -Algorithm sha256).Hash -ne $env:DOCKER_BUILDX_SHA256) { \ 56 | Write-Host 'FAILED!'; \ 57 | exit 1; \ 58 | }; \ 59 | \ 60 | Write-Host 'Verifying install ("docker buildx version") ...'; \ 61 | docker buildx version; \ 62 | \ 63 | Write-Host 'Complete.'; 64 | ENV DOCKER_COMPOSE_VERSION 2.37.0 65 | ENV DOCKER_COMPOSE_URL https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-windows-x86_64.exe 66 | ENV DOCKER_COMPOSE_SHA256 5ddd1ff588eb7251381cf6257b9be44fbb92c02d984ccfc94b4280e8c33d0f8f 67 | RUN $dir = ('{0}\docker\cli-plugins' -f $env:ProgramFiles); \ 68 | Write-Host ('Creating {0} ...' -f $dir); \ 69 | New-Item -ItemType Directory $dir -Force; \ 70 | \ 71 | $plugin = ('{0}\docker-compose.exe' -f $dir); \ 72 | Write-Host ('Downloading {0} ...' -f $env:DOCKER_COMPOSE_URL); \ 73 | Invoke-WebRequest -Uri $env:DOCKER_COMPOSE_URL -OutFile $plugin; \ 74 | \ 75 | Write-Host ('Verifying sha256 ({0}) ...' -f $env:DOCKER_COMPOSE_SHA256); \ 76 | if ((Get-FileHash $plugin -Algorithm sha256).Hash -ne $env:DOCKER_COMPOSE_SHA256) { \ 77 | Write-Host 'FAILED!'; \ 78 | exit 1; \ 79 | }; \ 80 | \ 81 | Write-Host 'Verifying install ("docker compose version") ...'; \ 82 | docker compose version; \ 83 | \ 84 | $link = ('{0}\docker\docker-compose.exe' -f $env:ProgramFiles); \ 85 | Write-Host ('Linking {0} to {1} ...' -f $plugin, $link); \ 86 | New-Item -ItemType SymbolicLink -Path $link -Target $plugin; \ 87 | \ 88 | Write-Host 'Verifying install ("docker-compose --version") ...'; \ 89 | docker-compose --version; \ 90 | \ 91 | Write-Host 'Complete.'; 92 | -------------------------------------------------------------------------------- /28/windows/windowsservercore-ltsc2025/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" 3 | # 4 | # PLEASE DO NOT EDIT IT DIRECTLY. 5 | # 6 | 7 | FROM mcr.microsoft.com/windows/servercore:ltsc2025 8 | 9 | # $ProgressPreference: https://github.com/PowerShell/PowerShell/issues/2138#issuecomment-251261324 10 | SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] 11 | 12 | # PATH isn't actually set in the Docker image, so we have to set it from within the container 13 | RUN $newPath = ('{0}\docker;{1}' -f $env:ProgramFiles, $env:PATH); \ 14 | Write-Host ('Updating PATH: {0}' -f $newPath); \ 15 | [Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine); 16 | # doing this first to share cache across versions more aggressively 17 | 18 | ENV DOCKER_VERSION 28.2.2 19 | ENV DOCKER_URL https://download.docker.com/win/static/stable/x86_64/docker-28.2.2.zip 20 | # TODO ENV DOCKER_SHA256 21 | # https://github.com/docker/docker-ce/blob/5b073ee2cf564edee5adca05eee574142f7627bb/components/packaging/static/hash_files !! 22 | # (no SHA file artifacts on download.docker.com yet as of 2017-06-07 though) 23 | 24 | RUN Write-Host ('Downloading {0} ...' -f $env:DOCKER_URL); \ 25 | Invoke-WebRequest -Uri $env:DOCKER_URL -OutFile 'docker.zip'; \ 26 | \ 27 | Write-Host 'Expanding ...'; \ 28 | Expand-Archive docker.zip -DestinationPath $env:ProgramFiles; \ 29 | # (this archive has a "docker/..." directory in it already) 30 | \ 31 | Write-Host 'Removing ...'; \ 32 | Remove-Item @( \ 33 | 'docker.zip', \ 34 | ('{0}\docker\dockerd.exe' -f $env:ProgramFiles) \ 35 | ) -Force; \ 36 | \ 37 | Write-Host 'Verifying install ("docker --version") ...'; \ 38 | docker --version; \ 39 | \ 40 | Write-Host 'Complete.'; 41 | 42 | # https://github.com/docker-library/docker/issues/409#issuecomment-1462868414 43 | ENV DOCKER_BUILDX_VERSION 0.24.0 44 | ENV DOCKER_BUILDX_URL https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.windows-amd64.exe 45 | ENV DOCKER_BUILDX_SHA256 8dec102c8eb14f434707cc05a8f0e366c090ded6ad74d9c5f8a64a9c0b766140 46 | RUN $dir = ('{0}\docker\cli-plugins' -f $env:ProgramFiles); \ 47 | Write-Host ('Creating {0} ...' -f $dir); \ 48 | New-Item -ItemType Directory $dir -Force; \ 49 | \ 50 | $plugin = ('{0}\docker-buildx.exe' -f $dir); \ 51 | Write-Host ('Downloading {0} ...' -f $env:DOCKER_BUILDX_URL); \ 52 | Invoke-WebRequest -Uri $env:DOCKER_BUILDX_URL -OutFile $plugin; \ 53 | \ 54 | Write-Host ('Verifying sha256 ({0}) ...' -f $env:DOCKER_BUILDX_SHA256); \ 55 | if ((Get-FileHash $plugin -Algorithm sha256).Hash -ne $env:DOCKER_BUILDX_SHA256) { \ 56 | Write-Host 'FAILED!'; \ 57 | exit 1; \ 58 | }; \ 59 | \ 60 | Write-Host 'Verifying install ("docker buildx version") ...'; \ 61 | docker buildx version; \ 62 | \ 63 | Write-Host 'Complete.'; 64 | ENV DOCKER_COMPOSE_VERSION 2.37.0 65 | ENV DOCKER_COMPOSE_URL https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-windows-x86_64.exe 66 | ENV DOCKER_COMPOSE_SHA256 5ddd1ff588eb7251381cf6257b9be44fbb92c02d984ccfc94b4280e8c33d0f8f 67 | RUN $dir = ('{0}\docker\cli-plugins' -f $env:ProgramFiles); \ 68 | Write-Host ('Creating {0} ...' -f $dir); \ 69 | New-Item -ItemType Directory $dir -Force; \ 70 | \ 71 | $plugin = ('{0}\docker-compose.exe' -f $dir); \ 72 | Write-Host ('Downloading {0} ...' -f $env:DOCKER_COMPOSE_URL); \ 73 | Invoke-WebRequest -Uri $env:DOCKER_COMPOSE_URL -OutFile $plugin; \ 74 | \ 75 | Write-Host ('Verifying sha256 ({0}) ...' -f $env:DOCKER_COMPOSE_SHA256); \ 76 | if ((Get-FileHash $plugin -Algorithm sha256).Hash -ne $env:DOCKER_COMPOSE_SHA256) { \ 77 | Write-Host 'FAILED!'; \ 78 | exit 1; \ 79 | }; \ 80 | \ 81 | Write-Host 'Verifying install ("docker compose version") ...'; \ 82 | docker compose version; \ 83 | \ 84 | $link = ('{0}\docker\docker-compose.exe' -f $env:ProgramFiles); \ 85 | Write-Host ('Linking {0} to {1} ...' -f $plugin, $link); \ 86 | New-Item -ItemType SymbolicLink -Path $link -Target $plugin; \ 87 | \ 88 | Write-Host 'Verifying install ("docker-compose --version") ...'; \ 89 | docker-compose --version; \ 90 | \ 91 | Write-Host 'Complete.'; 92 | -------------------------------------------------------------------------------- /Dockerfile-cli.template: -------------------------------------------------------------------------------- 1 | {{ include "shared" -}} 2 | FROM alpine:3.22 3 | 4 | RUN apk add --no-cache \ 5 | ca-certificates \ 6 | # DOCKER_HOST=ssh://... -- https://github.com/docker/cli/pull/1014 7 | openssh-client \ 8 | # https://github.com/docker-library/docker/issues/482#issuecomment-2197116408 9 | git 10 | 11 | # ensure that nsswitch.conf is set up for Go's "netgo" implementation (which Docker explicitly uses) 12 | # - https://github.com/moby/moby/blob/v24.0.6/hack/make.sh#L111 13 | # - https://github.com/golang/go/blob/go1.19.13/src/net/conf.go#L227-L303 14 | # - docker run --rm debian:stretch grep '^hosts:' /etc/nsswitch.conf 15 | RUN [ -e /etc/nsswitch.conf ] && grep '^hosts: files dns' /etc/nsswitch.conf 16 | 17 | # pre-add a "docker" group for socket usage 18 | RUN set -eux; \ 19 | addgroup -g 2375 -S docker 20 | 21 | ENV DOCKER_VERSION {{ .version }} 22 | 23 | RUN set -eux; \ 24 | \ 25 | {{ 26 | download({ 27 | arches: .arches, 28 | urlKey: "dockerUrl", 29 | # TODO sha256Key (once Docker publishes them 😭) 30 | target: "docker.tgz", 31 | }) 32 | }}; \ 33 | \ 34 | tar --extract \ 35 | --file docker.tgz \ 36 | --strip-components 1 \ 37 | --directory /usr/local/bin/ \ 38 | --no-same-owner \ 39 | 'docker/docker' \ 40 | ; \ 41 | rm docker.tgz; \ 42 | \ 43 | docker --version 44 | {{ 45 | { 46 | buildx: .buildx, 47 | compose: .compose, 48 | } 49 | | to_entries | map( 50 | .key as $key | .value | ( 51 | -}} 52 | 53 | ENV DOCKER_{{ $key | ascii_upcase }}_VERSION {{ .version }} 54 | RUN set -eux; \ 55 | \ 56 | {{ 57 | download({ 58 | arches: .arches, 59 | urlKey: "url", 60 | sha256Key: "sha256", 61 | target: ("docker-" + $key), 62 | missingArchWarning: true, 63 | }) 64 | }}; \ 65 | \ 66 | plugin='/usr/local/libexec/docker/cli-plugins/docker-{{ $key }}'; \ 67 | mkdir -p "$(dirname "$plugin")"; \ 68 | mv -vT {{ "docker-" + $key | @sh }} "$plugin"; \ 69 | chmod +x "$plugin"; \ 70 | \ 71 | {{ if $key == "compose" then ( -}} 72 | ln -sv "$plugin" /usr/local/bin/; \ 73 | docker-{{ $key }} --version; \ 74 | {{ ) else "" end -}} 75 | docker {{ $key }} version 76 | {{ 77 | ) 78 | ) 79 | | add 80 | -}} 81 | 82 | COPY modprobe.sh /usr/local/bin/modprobe 83 | COPY docker-entrypoint.sh /usr/local/bin/ 84 | 85 | # https://github.com/docker-library/docker/pull/166 86 | # dockerd-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-generating TLS certificates 87 | # docker-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-setting DOCKER_TLS_VERIFY and DOCKER_CERT_PATH 88 | # (For this to work, at least the "client" subdirectory of this path needs to be shared between the client and server containers via a volume, "docker cp", or other means of data sharing.) 89 | ENV DOCKER_TLS_CERTDIR=/certs 90 | # also, ensure the directory pre-exists and has wide enough permissions for "dockerd-entrypoint.sh" to create subdirectories, even when run in "rootless" mode 91 | RUN mkdir /certs /certs/client && chmod 1777 /certs /certs/client 92 | # (doing both /certs and /certs/client so that if Docker does a "copy-up" into a volume defined on /certs/client, it will "do the right thing" by default in a way that still works for rootless users) 93 | 94 | ENTRYPOINT ["docker-entrypoint.sh"] 95 | CMD ["sh"] 96 | -------------------------------------------------------------------------------- /Dockerfile-dind-rootless.template: -------------------------------------------------------------------------------- 1 | {{ include "shared" -}} 2 | FROM docker:{{ env.version }}-dind 3 | 4 | # busybox "ip" is insufficient: 5 | # [rootlesskit:child ] error: executing [[ip tuntap add name tap0 mode tap] [ip link set tap0 address 02:50:00:00:00:01]]: exit status 1 6 | RUN apk add --no-cache iproute2 fuse-overlayfs 7 | 8 | # "/run/user/UID" will be used by default as the value of XDG_RUNTIME_DIR 9 | RUN mkdir /run/user && chmod 1777 /run/user 10 | 11 | # create a default user preconfigured for running rootless dockerd 12 | RUN set -eux; \ 13 | adduser -h /home/rootless -g 'Rootless' -D -u 1000 rootless; \ 14 | echo 'rootless:100000:65536' >> /etc/subuid; \ 15 | echo 'rootless:100000:65536' >> /etc/subgid 16 | 17 | RUN set -eux; \ 18 | \ 19 | {{ 20 | download({ 21 | arches: .arches, 22 | urlKey: "rootlessExtrasUrl", 23 | # TODO sha256Key (once Docker publishes them 😭) 24 | target: "rootless.tgz", 25 | }) 26 | }}; \ 27 | \ 28 | tar --extract \ 29 | --file rootless.tgz \ 30 | --strip-components 1 \ 31 | --directory /usr/local/bin/ \ 32 | 'docker-rootless-extras/rootlesskit' \ 33 | 'docker-rootless-extras/vpnkit' \ 34 | ; \ 35 | rm rootless.tgz; \ 36 | \ 37 | rootlesskit --version; \ 38 | vpnkit --version 39 | 40 | # pre-create "/var/lib/docker" for our rootless user 41 | RUN set -eux; \ 42 | mkdir -p /home/rootless/.local/share/docker; \ 43 | chown -R rootless:rootless /home/rootless/.local/share/docker 44 | VOLUME /home/rootless/.local/share/docker 45 | USER rootless 46 | -------------------------------------------------------------------------------- /Dockerfile-dind.template: -------------------------------------------------------------------------------- 1 | {{ include "shared" -}} 2 | FROM docker:{{ env.version }}-cli 3 | 4 | # https://github.com/moby/moby/blob/0eecd59153c03ced5f5ddd79cc98f29e4d86daec/project/PACKAGERS.md#runtime-dependencies 5 | # https://github.com/docker/docker-ce-packaging/blob/963aa02666035d4e268f33c63d7868d6cdd1d34c/deb/common/control#L28-L41 6 | RUN set -eux; \ 7 | apk add --no-cache \ 8 | btrfs-progs \ 9 | e2fsprogs \ 10 | e2fsprogs-extra \ 11 | git \ 12 | ip6tables \ 13 | iptables \ 14 | openssl \ 15 | pigz \ 16 | shadow-uidmap \ 17 | xfsprogs \ 18 | xz \ 19 | zfs \ 20 | ; 21 | 22 | # dind might be used on systems where the nf_tables kernel module isn't available. In that case, 23 | # we need to switch over to xtables-legacy. See https://github.com/docker-library/docker/issues/463 24 | RUN set -eux; \ 25 | apk add --no-cache iptables-legacy; \ 26 | # set up a symlink farm we can use PATH to switch to legacy with 27 | mkdir -p /usr/local/sbin/.iptables-legacy; \ 28 | # https://gitlab.alpinelinux.org/alpine/aports/-/blob/a7e1610a67a46fc52668528efe01cee621c2ba6c/main/iptables/APKBUILD#L77 29 | for f in \ 30 | iptables \ 31 | iptables-save \ 32 | iptables-restore \ 33 | ip6tables \ 34 | ip6tables-save \ 35 | ip6tables-restore \ 36 | ; do \ 37 | # "iptables-save" -> "iptables-legacy-save", "ip6tables" -> "ip6tables-legacy", etc. 38 | # https://pkgs.alpinelinux.org/contents?branch=v3.22&name=iptables-legacy&arch=x86_64 39 | b="$(command -v "${f/tables/tables-legacy}")"; \ 40 | "$b" --version; \ 41 | ln -svT "$b" "/usr/local/sbin/.iptables-legacy/$f"; \ 42 | done; \ 43 | # verify it works (and gets us legacy) 44 | export PATH="/usr/local/sbin/.iptables-legacy:$PATH"; \ 45 | iptables --version | grep legacy 46 | 47 | # set up subuid/subgid so that "--userns-remap=default" works out-of-the-box 48 | RUN set -eux; \ 49 | addgroup -S dockremap; \ 50 | adduser -S -G dockremap dockremap; \ 51 | echo 'dockremap:165536:65536' >> /etc/subuid; \ 52 | echo 'dockremap:165536:65536' >> /etc/subgid 53 | 54 | RUN set -eux; \ 55 | \ 56 | {{ 57 | download({ 58 | arches: .arches, 59 | urlKey: "dockerUrl", 60 | # TODO sha256Key (once Docker publishes them 😭) 61 | target: "docker.tgz", 62 | }) 63 | }}; \ 64 | \ 65 | tar --extract \ 66 | --file docker.tgz \ 67 | --strip-components 1 \ 68 | --directory /usr/local/bin/ \ 69 | --no-same-owner \ 70 | # we exclude the CLI binary because we already extracted that over in the "docker:{{ env.version }}-cli" image that we're FROM and we don't want to duplicate those bytes again in this layer 71 | --exclude 'docker/docker' \ 72 | ; \ 73 | rm docker.tgz; \ 74 | \ 75 | dockerd --version; \ 76 | containerd --version; \ 77 | ctr --version; \ 78 | runc --version 79 | 80 | # https://github.com/docker/docker/tree/master/hack/dind 81 | ENV DIND_COMMIT {{ .dindCommit }} 82 | 83 | RUN set -eux; \ 84 | wget -O /usr/local/bin/dind "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind"; \ 85 | chmod +x /usr/local/bin/dind 86 | 87 | COPY dockerd-entrypoint.sh /usr/local/bin/ 88 | 89 | VOLUME /var/lib/docker 90 | EXPOSE 2375 2376 91 | 92 | ENTRYPOINT ["dockerd-entrypoint.sh"] 93 | CMD [] 94 | -------------------------------------------------------------------------------- /Dockerfile-windows-servercore.template: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/windows/{{ env.windowsVariant }}:{{ env.windowsRelease }} 2 | 3 | # $ProgressPreference: https://github.com/PowerShell/PowerShell/issues/2138#issuecomment-251261324 4 | SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] 5 | 6 | # PATH isn't actually set in the Docker image, so we have to set it from within the container 7 | RUN $newPath = ('{0}\docker;{1}' -f $env:ProgramFiles, $env:PATH); \ 8 | Write-Host ('Updating PATH: {0}' -f $newPath); \ 9 | [Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine); 10 | # doing this first to share cache across versions more aggressively 11 | 12 | ENV DOCKER_VERSION {{ .version }} 13 | ENV DOCKER_URL {{ .arches["windows-amd64"].dockerUrl }} 14 | # TODO ENV DOCKER_SHA256 15 | # https://github.com/docker/docker-ce/blob/5b073ee2cf564edee5adca05eee574142f7627bb/components/packaging/static/hash_files !! 16 | # (no SHA file artifacts on download.docker.com yet as of 2017-06-07 though) 17 | 18 | RUN Write-Host ('Downloading {0} ...' -f $env:DOCKER_URL); \ 19 | Invoke-WebRequest -Uri $env:DOCKER_URL -OutFile 'docker.zip'; \ 20 | \ 21 | Write-Host 'Expanding ...'; \ 22 | Expand-Archive docker.zip -DestinationPath $env:ProgramFiles; \ 23 | # (this archive has a "docker/..." directory in it already) 24 | \ 25 | Write-Host 'Removing ...'; \ 26 | Remove-Item @( \ 27 | 'docker.zip', \ 28 | ('{0}\docker\dockerd.exe' -f $env:ProgramFiles) \ 29 | ) -Force; \ 30 | \ 31 | Write-Host 'Verifying install ("docker --version") ...'; \ 32 | docker --version; \ 33 | \ 34 | Write-Host 'Complete.'; 35 | 36 | # https://github.com/docker-library/docker/issues/409#issuecomment-1462868414 37 | {{ 38 | { 39 | buildx: .buildx, 40 | compose: .compose, 41 | } 42 | | to_entries | map( 43 | .key as $key | ($key | ascii_upcase) as $KEY | .value | ( 44 | -}} 45 | ENV DOCKER_{{ $KEY }}_VERSION {{ .version }} 46 | ENV DOCKER_{{ $KEY }}_URL {{ .arches["windows-amd64"].url }} 47 | ENV DOCKER_{{ $KEY }}_SHA256 {{ .arches["windows-amd64"].sha256 }} 48 | RUN $dir = ('{0}\docker\cli-plugins' -f $env:ProgramFiles); \ 49 | Write-Host ('Creating {0} ...' -f $dir); \ 50 | New-Item -ItemType Directory $dir -Force; \ 51 | \ 52 | $plugin = ('{0}\docker-{{ $key }}.exe' -f $dir); \ 53 | Write-Host ('Downloading {0} ...' -f $env:DOCKER_{{ $KEY }}_URL); \ 54 | Invoke-WebRequest -Uri $env:DOCKER_{{ $KEY }}_URL -OutFile $plugin; \ 55 | \ 56 | Write-Host ('Verifying sha256 ({0}) ...' -f $env:DOCKER_{{ $KEY }}_SHA256); \ 57 | if ((Get-FileHash $plugin -Algorithm sha256).Hash -ne $env:DOCKER_{{ $KEY }}_SHA256) { \ 58 | Write-Host 'FAILED!'; \ 59 | exit 1; \ 60 | }; \ 61 | \ 62 | Write-Host 'Verifying install ("docker {{ $key }} version") ...'; \ 63 | docker {{ $key }} version; \ 64 | {{ if $key == "compose" then ( -}} 65 | \ 66 | $link = ('{0}\docker\docker-{{ $key }}.exe' -f $env:ProgramFiles); \ 67 | Write-Host ('Linking {0} to {1} ...' -f $plugin, $link); \ 68 | New-Item -ItemType SymbolicLink -Path $link -Target $plugin; \ 69 | \ 70 | Write-Host 'Verifying install ("docker-{{ $key }} --version") ...'; \ 71 | docker-{{ $key }} --version; \ 72 | {{ ) else "" end -}} 73 | \ 74 | Write-Host 'Complete.'; 75 | {{ 76 | ) 77 | ) 78 | | add 79 | -}} 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | Copyright 2013 Docker, Inc. 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # https://github.com/docker-library/docker 2 | 3 | ## Maintained by: [Tianon (of the Docker Project)](https://github.com/docker-library/docker) 4 | 5 | This is the Git repo of the [Docker "Official Image"](https://github.com/docker-library/official-images#what-are-official-images) for [`docker`](https://hub.docker.com/_/docker/). See [the Docker Hub page](https://hub.docker.com/_/docker/) for the full readme on how to use this Docker image and for information regarding contributing and issues. 6 | 7 | The [full image description on Docker Hub](https://hub.docker.com/_/docker/) is generated/maintained over in [the docker-library/docs repository](https://github.com/docker-library/docs), specifically in [the `docker` directory](https://github.com/docker-library/docs/tree/master/docker). 8 | 9 | ## See a change merged here that doesn't show up on Docker Hub yet? 10 | 11 | For more information about the full official images change lifecycle, see [the "An image's source changed in Git, now what?" FAQ entry](https://github.com/docker-library/faq#an-images-source-changed-in-git-now-what). 12 | 13 | For outstanding `docker` image PRs, check [PRs with the "library/docker" label on the official-images repository](https://github.com/docker-library/official-images/labels/library%2Fdocker). For the current "source of truth" for [`docker`](https://hub.docker.com/_/docker/), see [the `library/docker` file in the official-images repository](https://github.com/docker-library/official-images/blob/master/library/docker). 14 | 15 | 16 | -------------------------------------------------------------------------------- /apply-templates.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | [ -f versions.json ] # run "versions.sh" first 5 | 6 | jqt='.jq-template.awk' 7 | if [ -n "${BASHBREW_SCRIPTS:-}" ]; then 8 | jqt="$BASHBREW_SCRIPTS/jq-template.awk" 9 | elif [ "$BASH_SOURCE" -nt "$jqt" ]; then 10 | # https://github.com/docker-library/bashbrew/blob/master/scripts/jq-template.awk 11 | wget -qO "$jqt" 'https://github.com/docker-library/bashbrew/raw/9f6a35772ac863a0241f147c820354e4008edf38/scripts/jq-template.awk' 12 | fi 13 | 14 | if [ "$#" -eq 0 ]; then 15 | versions="$(jq -r 'keys | map(@sh) | join(" ")' versions.json)" 16 | eval "set -- $versions" 17 | fi 18 | 19 | generated_warning() { 20 | cat <<-EOH 21 | # 22 | # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" 23 | # 24 | # PLEASE DO NOT EDIT IT DIRECTLY. 25 | # 26 | 27 | EOH 28 | } 29 | 30 | for version; do 31 | export version 32 | 33 | if jq -e '.[env.version] | not' versions.json > /dev/null; then 34 | echo "deleting $version ..." 35 | rm -rf "$version" 36 | continue 37 | fi 38 | 39 | rm -rf "$version" 40 | 41 | variants="$(jq -r '.[env.version].variants | map(@sh) | join(" ")' versions.json)" 42 | eval "variants=( $variants )" 43 | 44 | for variant in "${variants[@]}"; do 45 | dir="$version/$variant" 46 | 47 | case "$variant" in 48 | windows/*) 49 | variant="$(basename "$variant")" # "windowsservercore-1809", etc 50 | windowsVariant="${variant%%-*}" # "windowsservercore", "nanoserver" 51 | windowsRelease="${variant#$windowsVariant-}" # "ltsc2022", "1809", etc 52 | windowsVariant="${windowsVariant#windows}" # "servercore", "nanoserver" 53 | export windowsVariant windowsRelease 54 | template="Dockerfile-windows-$windowsVariant.template" 55 | ;; 56 | 57 | *) 58 | template="Dockerfile-$variant.template" 59 | ;; 60 | esac 61 | 62 | echo "processing $dir ..." 63 | 64 | mkdir -p "$dir" 65 | { 66 | generated_warning 67 | gawk -f "$jqt" "$template" 68 | } > "$dir/Dockerfile" 69 | done 70 | 71 | cp -a docker-entrypoint.sh modprobe.sh "$version/cli/" 72 | cp -a dockerd-entrypoint.sh "$version/dind/" 73 | done 74 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | # first arg is `-f` or `--some-option` 5 | if [ "${1#-}" != "$1" ]; then 6 | set -- docker "$@" 7 | fi 8 | 9 | # if our command is a valid Docker subcommand, let's invoke it through Docker instead 10 | # (this allows for "docker run docker ps", etc) 11 | if docker help "$1" > /dev/null 2>&1; then 12 | set -- docker "$@" 13 | fi 14 | 15 | _should_tls() { 16 | [ -n "${DOCKER_TLS_CERTDIR:-}" ] \ 17 | && [ -s "$DOCKER_TLS_CERTDIR/client/ca.pem" ] \ 18 | && [ -s "$DOCKER_TLS_CERTDIR/client/cert.pem" ] \ 19 | && [ -s "$DOCKER_TLS_CERTDIR/client/key.pem" ] 20 | } 21 | 22 | # if we have no DOCKER_HOST but we do have the default Unix socket (standard or rootless), use it explicitly 23 | if [ -z "${DOCKER_HOST:-}" ] && [ -S /var/run/docker.sock ]; then 24 | export DOCKER_HOST=unix:///var/run/docker.sock 25 | elif [ -z "${DOCKER_HOST:-}" ] && XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" && [ -S "$XDG_RUNTIME_DIR/docker.sock" ]; then 26 | export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock" 27 | fi 28 | 29 | # if DOCKER_HOST isn't set (no custom setting, no default socket), let's set it to a sane remote value 30 | if [ -z "${DOCKER_HOST:-}" ]; then 31 | if _should_tls || [ -n "${DOCKER_TLS_VERIFY:-}" ]; then 32 | export DOCKER_HOST='tcp://docker:2376' 33 | else 34 | export DOCKER_HOST='tcp://docker:2375' 35 | fi 36 | fi 37 | if [ "${DOCKER_HOST#tcp:}" != "$DOCKER_HOST" ] \ 38 | && [ -z "${DOCKER_TLS_VERIFY:-}" ] \ 39 | && [ -z "${DOCKER_CERT_PATH:-}" ] \ 40 | && _should_tls \ 41 | ; then 42 | export DOCKER_TLS_VERIFY=1 43 | export DOCKER_CERT_PATH="$DOCKER_TLS_CERTDIR/client" 44 | fi 45 | 46 | if [ "$1" = 'dockerd' ]; then 47 | cat >&2 <<-'EOW' 48 | 49 | 📎 Hey there! It looks like you're trying to run a Docker daemon. 50 | 51 | You probably should use the "dind" image variant instead, something like: 52 | 53 | docker run --privileged --name some-docker ... docker:dind ... 54 | 55 | See https://hub.docker.com/_/docker/ for more documentation and usage examples. 56 | 57 | EOW 58 | sleep 3 59 | fi 60 | 61 | exec "$@" 62 | -------------------------------------------------------------------------------- /dockerd-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | _tls_ensure_private() { 5 | local f="$1"; shift 6 | [ -s "$f" ] || openssl genrsa -out "$f" 4096 7 | } 8 | _tls_san() { 9 | { 10 | ip -oneline address | awk '{ gsub(/\/.+$/, "", $4); print "IP:" $4 }' 11 | { 12 | cat /etc/hostname 13 | echo 'docker' 14 | echo 'localhost' 15 | hostname -f 16 | hostname -s 17 | } | sed 's/^/DNS:/' 18 | [ -z "${DOCKER_TLS_SAN:-}" ] || echo "$DOCKER_TLS_SAN" 19 | } | sort -u | xargs printf '%s,' | sed "s/,\$//" 20 | } 21 | _tls_generate_certs() { 22 | local dir="$1"; shift 23 | 24 | # if server/{ca,key,cert}.pem && !ca/key.pem, do NOTHING except verify (user likely managing CA themselves) 25 | # if ca/key.pem || !ca/cert.pem, generate CA public if necessary 26 | # if ca/key.pem, generate server public 27 | # if ca/key.pem, generate client public 28 | # (regenerating public certs every startup to account for SAN/IP changes and/or expiration) 29 | 30 | if [ -s "$dir/server/ca.pem" ] && [ -s "$dir/server/cert.pem" ] && [ -s "$dir/server/key.pem" ] && [ ! -s "$dir/ca/key.pem" ]; then 31 | openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem" 32 | return 0 33 | fi 34 | 35 | # https://github.com/FiloSottile/mkcert/issues/174 36 | local certValidDays='825' 37 | 38 | if [ -s "$dir/ca/key.pem" ] || [ ! -s "$dir/ca/cert.pem" ]; then 39 | # if we either have a CA private key or do *not* have a CA public key, then we should create/manage the CA 40 | mkdir -p "$dir/ca" 41 | _tls_ensure_private "$dir/ca/key.pem" 42 | openssl req -new -key "$dir/ca/key.pem" \ 43 | -out "$dir/ca/cert.pem" \ 44 | -subj '/CN=docker:dind CA' \ 45 | -x509 \ 46 | -days "$certValidDays" \ 47 | -addext keyUsage=critical,digitalSignature,keyCertSign 48 | fi 49 | 50 | if [ -s "$dir/ca/key.pem" ]; then 51 | # if we have a CA private key, we should create/manage a server key 52 | mkdir -p "$dir/server" 53 | _tls_ensure_private "$dir/server/key.pem" 54 | openssl req -new -key "$dir/server/key.pem" \ 55 | -out "$dir/server/csr.pem" \ 56 | -subj '/CN=docker:dind server' 57 | cat > "$dir/server/openssl.cnf" <<-EOF 58 | [ x509_exts ] 59 | extendedKeyUsage = serverAuth 60 | subjectAltName = $(_tls_san) 61 | EOF 62 | openssl x509 -req \ 63 | -in "$dir/server/csr.pem" \ 64 | -CA "$dir/ca/cert.pem" \ 65 | -CAkey "$dir/ca/key.pem" \ 66 | -CAcreateserial \ 67 | -out "$dir/server/cert.pem" \ 68 | -days "$certValidDays" \ 69 | -extfile "$dir/server/openssl.cnf" \ 70 | -extensions x509_exts 71 | cp "$dir/ca/cert.pem" "$dir/server/ca.pem" 72 | openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem" 73 | fi 74 | 75 | if [ -s "$dir/ca/key.pem" ]; then 76 | # if we have a CA private key, we should create/manage a client key 77 | mkdir -p "$dir/client" 78 | _tls_ensure_private "$dir/client/key.pem" 79 | chmod 0644 "$dir/client/key.pem" # openssl defaults to 0600 for the private key, but this one needs to be shared with arbitrary client contexts 80 | openssl req -new \ 81 | -key "$dir/client/key.pem" \ 82 | -out "$dir/client/csr.pem" \ 83 | -subj '/CN=docker:dind client' 84 | cat > "$dir/client/openssl.cnf" <<-'EOF' 85 | [ x509_exts ] 86 | extendedKeyUsage = clientAuth 87 | EOF 88 | openssl x509 -req \ 89 | -in "$dir/client/csr.pem" \ 90 | -CA "$dir/ca/cert.pem" \ 91 | -CAkey "$dir/ca/key.pem" \ 92 | -CAcreateserial \ 93 | -out "$dir/client/cert.pem" \ 94 | -days "$certValidDays" \ 95 | -extfile "$dir/client/openssl.cnf" \ 96 | -extensions x509_exts 97 | cp "$dir/ca/cert.pem" "$dir/client/ca.pem" 98 | openssl verify -CAfile "$dir/client/ca.pem" "$dir/client/cert.pem" 99 | fi 100 | } 101 | 102 | # no arguments passed 103 | # or first arg is `-f` or `--some-option` 104 | if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then 105 | # set "dockerSocket" to the default "--host" *unix socket* value (for both standard or rootless) 106 | uid="$(id -u)" 107 | if [ "$uid" = '0' ]; then 108 | dockerSocket='unix:///var/run/docker.sock' 109 | else 110 | # if we're not root, we must be trying to run rootless 111 | : "${XDG_RUNTIME_DIR:=/run/user/$uid}" 112 | dockerSocket="unix://$XDG_RUNTIME_DIR/docker.sock" 113 | fi 114 | case "${DOCKER_HOST:-}" in 115 | unix://*) 116 | dockerSocket="$DOCKER_HOST" 117 | ;; 118 | esac 119 | 120 | # add our default arguments 121 | if [ -n "${DOCKER_TLS_CERTDIR:-}" ]; then 122 | _tls_generate_certs "$DOCKER_TLS_CERTDIR" 123 | # generate certs and use TLS if requested/possible (default in 19.03+) 124 | set -- dockerd \ 125 | --host="$dockerSocket" \ 126 | --host=tcp://0.0.0.0:2376 \ 127 | --tlsverify \ 128 | --tlscacert "$DOCKER_TLS_CERTDIR/server/ca.pem" \ 129 | --tlscert "$DOCKER_TLS_CERTDIR/server/cert.pem" \ 130 | --tlskey "$DOCKER_TLS_CERTDIR/server/key.pem" \ 131 | "$@" 132 | DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2376:2376/tcp" 133 | else 134 | # TLS disabled (-e DOCKER_TLS_CERTDIR='') or missing certs 135 | set -- dockerd \ 136 | --host="$dockerSocket" \ 137 | --host=tcp://0.0.0.0:2375 \ 138 | "$@" 139 | DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2375:2375/tcp" 140 | fi 141 | fi 142 | 143 | if [ "$1" = 'dockerd' ]; then 144 | # explicitly remove Docker's default PID file to ensure that it can start properly if it was stopped uncleanly (and thus didn't clean up the PID file) 145 | find /run /var/run -iname 'docker*.pid' -delete || : 146 | 147 | # XXX inject "docker-init" (tini) as pid1 to workaround https://github.com/docker-library/docker/issues/318 (zombie container-shim processes) 148 | set -- docker-init -- "$@" 149 | 150 | iptablesLegacy= 151 | if [ -n "${DOCKER_IPTABLES_LEGACY+x}" ]; then 152 | # let users choose explicitly to legacy or not to legacy 153 | iptablesLegacy="$DOCKER_IPTABLES_LEGACY" 154 | if [ -n "$iptablesLegacy" ]; then 155 | modprobe ip_tables || : 156 | modprobe ip6_tables || : 157 | else 158 | modprobe nf_tables || : 159 | fi 160 | elif ( 161 | # https://git.netfilter.org/iptables/tree/iptables/nft-shared.c?id=f5cf76626d95d2c491a80288bccc160c53b44e88#n420 162 | # https://github.com/docker-library/docker/pull/468#discussion_r1442131459 163 | for f in /proc/net/ip_tables_names /proc/net/ip6_tables_names /proc/net/arp_tables_names; do 164 | if b="$(cat "$f")" && [ -n "$b" ]; then 165 | exit 0 166 | fi 167 | done 168 | exit 1 169 | ); then 170 | # if we already have any "legacy" iptables rules, we should always use legacy 171 | iptablesLegacy=1 172 | elif ! iptables -nL > /dev/null 2>&1; then 173 | # if iptables fails to run, chances are high the necessary kernel modules aren't loaded (perhaps the host is using xtables, for example) 174 | # https://github.com/docker-library/docker/issues/350 175 | # https://github.com/moby/moby/issues/26824 176 | # https://github.com/docker-library/docker/pull/437#issuecomment-1854900620 177 | modprobe nf_tables || : 178 | if ! iptables -nL > /dev/null 2>&1; then 179 | # might be host has no nf_tables, but Alpine is all-in now (so let's try a legacy fallback) 180 | modprobe ip_tables || : 181 | modprobe ip6_tables || : 182 | if /usr/local/sbin/.iptables-legacy/iptables -nL > /dev/null 2>&1; then 183 | iptablesLegacy=1 184 | fi 185 | fi 186 | fi 187 | if [ -n "$iptablesLegacy" ]; then 188 | # see https://github.com/docker-library/docker/issues/463 (and the dind Dockerfile where this directory is set up) 189 | export PATH="/usr/local/sbin/.iptables-legacy:$PATH" 190 | fi 191 | iptables --version # so users can see whether it's legacy or not 192 | 193 | uid="$(id -u)" 194 | if [ "$uid" != '0' ]; then 195 | # if we're not root, we must be trying to run rootless 196 | if ! command -v rootlesskit > /dev/null; then 197 | echo >&2 "error: attempting to run rootless dockerd but missing 'rootlesskit' (perhaps the 'docker:dind-rootless' image variant is intended?)" 198 | exit 1 199 | fi 200 | user="$(id -un 2>/dev/null || :)" 201 | if ! grep -qE "^($uid${user:+|$user}):" /etc/subuid || ! grep -qE "^($uid${user:+|$user}):" /etc/subgid; then 202 | echo >&2 "error: attempting to run rootless dockerd but missing necessary entries in /etc/subuid and/or /etc/subgid for $uid" 203 | exit 1 204 | fi 205 | : "${XDG_RUNTIME_DIR:=/run/user/$uid}" 206 | export XDG_RUNTIME_DIR 207 | if ! mkdir -p "$XDG_RUNTIME_DIR" || [ ! -w "$XDG_RUNTIME_DIR" ] || ! mkdir -p "$HOME/.local/share/docker" || [ ! -w "$HOME/.local/share/docker" ]; then 208 | echo >&2 "error: attempting to run rootless dockerd but need writable HOME ($HOME) and XDG_RUNTIME_DIR ($XDG_RUNTIME_DIR) for user $uid" 209 | exit 1 210 | fi 211 | if [ -f /proc/sys/kernel/unprivileged_userns_clone ] && unprivClone="$(cat /proc/sys/kernel/unprivileged_userns_clone)" && [ "$unprivClone" != '1' ]; then 212 | echo >&2 "error: attempting to run rootless dockerd but need 'kernel.unprivileged_userns_clone' (/proc/sys/kernel/unprivileged_userns_clone) set to 1" 213 | exit 1 214 | fi 215 | if [ -f /proc/sys/user/max_user_namespaces ] && maxUserns="$(cat /proc/sys/user/max_user_namespaces)" && [ "$maxUserns" = '0' ]; then 216 | echo >&2 "error: attempting to run rootless dockerd but need 'user.max_user_namespaces' (/proc/sys/user/max_user_namespaces) set to a sufficiently large value" 217 | exit 1 218 | fi 219 | # TODO overlay support detection? 220 | exec rootlesskit \ 221 | --net="${DOCKERD_ROOTLESS_ROOTLESSKIT_NET:-vpnkit}" \ 222 | --mtu="${DOCKERD_ROOTLESS_ROOTLESSKIT_MTU:-1500}" \ 223 | --disable-host-loopback \ 224 | --port-driver=builtin \ 225 | --copy-up=/etc \ 226 | --copy-up=/run \ 227 | ${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} \ 228 | "$@" 229 | elif [ -x '/usr/local/bin/dind' ]; then 230 | # if we have the (mostly defunct now) Docker-in-Docker wrapper script, use it 231 | set -- '/usr/local/bin/dind' "$@" 232 | fi 233 | else 234 | # if it isn't `dockerd` we're trying to run, pass it through `docker-entrypoint.sh` so it gets `DOCKER_HOST` set appropriately too 235 | set -- docker-entrypoint.sh "$@" 236 | fi 237 | 238 | exec "$@" 239 | -------------------------------------------------------------------------------- /generate-stackbrew-library.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | self="$(basename "$BASH_SOURCE")" 5 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 6 | 7 | if [ "$#" -eq 0 ]; then 8 | versions="$(jq -r ' 9 | to_entries 10 | # sort version numbers with highest first 11 | | sort_by(.key | split("[.-]"; "") | map(try tonumber // .)) 12 | | reverse 13 | | map(if .value then .key | @sh else empty end) 14 | | join(" ") 15 | ' versions.json)" 16 | eval "set -- $versions" 17 | fi 18 | 19 | # get the most recent commit which modified any of "$@" 20 | fileCommit() { 21 | git log -1 --format='format:%H' HEAD -- "$@" 22 | } 23 | 24 | # get the most recent commit which modified "$1/Dockerfile" or any file COPY'd from "$1/Dockerfile" 25 | dirCommit() { 26 | local dir="$1"; shift 27 | ( 28 | cd "$dir" 29 | fileCommit \ 30 | Dockerfile \ 31 | $(git show HEAD:./Dockerfile | awk ' 32 | toupper($1) == "COPY" { 33 | for (i = 2; i < NF; i++) { 34 | print $i 35 | } 36 | } 37 | ') 38 | ) 39 | } 40 | 41 | getArches() { 42 | local repo="$1"; shift 43 | local officialImagesBase="${BASHBREW_LIBRARY:-https://github.com/docker-library/official-images/raw/HEAD/library}/" 44 | 45 | local parentRepoToArchesStr 46 | parentRepoToArchesStr="$( 47 | find -name 'Dockerfile' -exec awk -v officialImagesBase="$officialImagesBase" ' 48 | toupper($1) == "FROM" && $2 !~ /^('"$repo"'|scratch|.*\/.*)(:|$)/ { 49 | printf "%s%s\n", officialImagesBase, $2 50 | } 51 | ' '{}' + \ 52 | | sort -u \ 53 | | xargs -r bashbrew cat --format '["{{ .RepoName }}:{{ .TagName }}"]="{{ join " " .TagEntry.Architectures }}"' 54 | )" 55 | eval "declare -g -A parentRepoToArches=( $parentRepoToArchesStr )" 56 | } 57 | getArches 'docker' 58 | 59 | versionArches() { 60 | local version="$1"; shift 61 | local variant="${1:-}" 62 | local selector='dockerUrl' 63 | if [[ "$variant" = *rootless ]]; then 64 | selector='rootlessExtrasUrl' 65 | fi 66 | 67 | if [[ "$variant" = windows/* ]]; then 68 | version="$version" jq -r ' 69 | .[env.version].arches 70 | | keys[] 71 | | select(startswith("windows-")) 72 | ' versions.json | sort 73 | return 74 | fi 75 | 76 | local parent parentArches 77 | parent="$(awk 'toupper($1) == "FROM" { print $2 }' "$version/cli/Dockerfile")" 78 | parentArches="${parentRepoToArches[$parent]:-}" 79 | 80 | comm -12 \ 81 | <( 82 | version="$version" jq -r --arg selector "$selector" ' 83 | .[env.version].arches | to_entries[] 84 | | select(.value[$selector]) 85 | | .key 86 | ' versions.json | sort 87 | ) \ 88 | <(xargs -n1 <<<"$parentArches" | sort) 89 | } 90 | 91 | cat <<-EOH 92 | # this file is generated via https://github.com/docker-library/docker/blob/$(fileCommit "$self")/$self 93 | 94 | Maintainers: Tianon Gravi (@tianon), 95 | Joseph Ferguson (@yosifkit) 96 | GitRepo: https://github.com/docker-library/docker.git 97 | Builder: buildkit 98 | EOH 99 | 100 | # prints "$2$1$3$1...$N" 101 | join() { 102 | local sep="$1"; shift 103 | local out; printf -v out "${sep//%/%%}%s" "$@" 104 | echo "${out#$sep}" 105 | } 106 | 107 | # used for auto-detecting the "latest" of each channel (for tagging it appropriately) 108 | # https://blog.docker.com/2017/03/docker-enterprise-edition/ 109 | declare -A latestChannelRelease=() 110 | 111 | for version; do 112 | export version 113 | rcVersion="${version%-rc}" 114 | 115 | if ! fullVersion="$(jq -er '.[env.version] | if . then .version else empty end' versions.json)"; then 116 | # support running "generate-stackbrew-library.sh" on a singular "null" version ("20.10-rc" when the RC is older than the GA release, for example) 117 | continue 118 | fi 119 | 120 | versionAliases=() 121 | if [ "$version" = "$rcVersion" ]; then 122 | while [ "$fullVersion" != "$rcVersion" -a "${fullVersion%[.-]*}" != "$fullVersion" ]; do 123 | versionAliases+=( $fullVersion ) 124 | fullVersion="${fullVersion%[.-]*}" 125 | done 126 | else 127 | versionAliases+=( $fullVersion ) 128 | fi 129 | if [ "$fullVersion" != "$version" ]; then 130 | versionAliases+=( 131 | $version 132 | ) 133 | fi 134 | 135 | # add a few channel/version-related aliases 136 | majorVersion="${version%%.*}" 137 | if [ "$version" != "$rcVersion" ] && [ -z "${latestChannelRelease['rc']:-}" ]; then 138 | versionAliases+=( 'rc' ) 139 | latestChannelRelease['rc']="$version" 140 | fi 141 | if [ "$version" = "$rcVersion" ] && [ -z "${latestChannelRelease[$majorVersion]:-}" ]; then 142 | versionAliases+=( "$majorVersion" ) 143 | latestChannelRelease["$majorVersion"]="$version" 144 | fi 145 | 146 | channel='stable' 147 | if [ "$rcVersion" != "$version" ]; then 148 | channel='test' 149 | fi 150 | # every release goes into the "test" channel, so the biggest numbered release wins (RC or not) 151 | if [ -z "${latestChannelRelease['test']:-}" ]; then 152 | latestChannelRelease['test']="$version" 153 | fi 154 | if [ "$version" = "$rcVersion" ] && [ -z "${latestChannelRelease['latest']:-}" ]; then 155 | versionAliases+=( 'latest' ) 156 | latestChannelRelease['latest']="$version" 157 | fi 158 | 159 | variants="$(jq -r '.[env.version].variants | map(@sh) | join(" ")' versions.json)" 160 | eval "variants=( $variants )" 161 | 162 | for v in "${variants[@]}"; do 163 | dir="$version/$v" 164 | [ -f "$dir/Dockerfile" ] || continue 165 | 166 | commit="$(dirCommit "$dir")" 167 | 168 | variant="$(basename "$v")" 169 | variantAliases=( "${versionAliases[@]/%/-$variant}" ) 170 | variantAliases=( "${variantAliases[@]//latest-/}" ) 171 | 172 | if [ "$variant" = 'cli' ] || [ "$variant" = 'dind' ]; then 173 | parent="$(awk 'toupper($1) == "FROM" { print $2 }' "$version/cli/Dockerfile")" 174 | alpine="${parent#*:}" # "3.14" 175 | suiteAliases=( "${variantAliases[0]}" ) # only "X.Y.Z-foo" 176 | suiteAliases=( "${suiteAliases[@]/%/-alpine$alpine}" ) 177 | suiteAliases=( "${suiteAliases[@]//latest-/}" ) 178 | variantAliases+=( "${suiteAliases[@]}" ) 179 | if [ "$variant" = 'dind' ]; then 180 | # add "latest" aliases 181 | suiteAliases=( "${versionAliases[0]}" ) # only "X.Y.Z-foo" 182 | suiteAliases=( "${suiteAliases[@]/%/-alpine$alpine}" ) 183 | suiteAliases=( "${suiteAliases[@]//latest-/}" ) 184 | variantAliases+=( "${versionAliases[@]}" "${suiteAliases[@]}" ) 185 | fi 186 | fi 187 | 188 | sharedTags=() 189 | if [[ "$variant" == windowsservercore* ]]; then 190 | sharedTags=( "${versionAliases[@]/%/-windowsservercore}" ) 191 | sharedTags=( "${sharedTags[@]//latest-/}" ) 192 | fi 193 | 194 | echo 195 | echo "Tags: $(join ', ' "${variantAliases[@]}")" 196 | if [ "${#sharedTags[@]}" -gt 0 ]; then 197 | echo "SharedTags: $(join ', ' "${sharedTags[@]}")" 198 | fi 199 | cat <<-EOE 200 | Architectures: $(join ', ' $(versionArches "$version" "$v")) 201 | GitCommit: $commit 202 | Directory: $dir 203 | EOE 204 | if [ "$variant" != "$v" ]; then 205 | echo "Constraints: $variant" 206 | echo 'Builder: classic' # no Windows support in BuildKit (yet) 207 | fi 208 | done 209 | done 210 | -------------------------------------------------------------------------------- /modprobe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | # "modprobe" without modprobe 5 | # https://twitter.com/lucabruno/status/902934379835662336 6 | 7 | # this isn't 100% fool-proof, but it'll have a much higher success rate than simply using the "real" modprobe 8 | 9 | # Docker often uses "modprobe -va foo bar baz" 10 | # so we ignore modules that start with "-" 11 | for module; do 12 | if [ "${module#-}" = "$module" ]; then 13 | ip link show "$module" || true 14 | lsmod | grep "$module" || true 15 | fi 16 | done 17 | 18 | # remove /usr/local/... from PATH so we can exec the real modprobe as a last resort 19 | export PATH='/usr/sbin:/usr/bin:/sbin:/bin' 20 | exec modprobe "$@" 21 | -------------------------------------------------------------------------------- /shared.jq: -------------------------------------------------------------------------------- 1 | # converts a bashbrew architecture to apk's strings 2 | def apkArch: 3 | { 4 | # https://dl-cdn.alpinelinux.org/alpine/edge/main/ 5 | # https://wiki.alpinelinux.org/wiki/Architecture#Alpine_Hardware_Architecture_.28.22arch.22.29_Support 6 | # https://pkgs.alpinelinux.org/packages ("Arch" dropdown) 7 | amd64: "x86_64", 8 | arm32v6: "armhf", 9 | arm32v7: "armv7", 10 | arm64v8: "aarch64", 11 | i386: "x86", 12 | ppc64le: "ppc64le", 13 | riscv64: "riscv64", 14 | s390x: "s390x", 15 | }[.] 16 | ; 17 | 18 | # RUN set -eux; \ 19 | # ... 20 | # {{ 21 | # download({ 22 | # arches: .arches, 23 | # urlKey: "dockerUrl", 24 | # #sha256Key: "sha256", 25 | # target: "docker.tgz", 26 | # #missingArchWarning: true, 27 | # }) 28 | # }}; \ 29 | # ... 30 | def download(opts): 31 | (opts.sha256Key | not) as $notSha256 32 | | [ 33 | "apkArch=\"$(apk --print-arch)\"; 34 | case \"$apkArch\" in" 35 | , 36 | ( 37 | opts.arches | to_entries[] 38 | | .key as $bashbrewArch 39 | | ($bashbrewArch | apkArch) as $apkArch 40 | | .value 41 | | .[opts.urlKey] as $url 42 | | (if $notSha256 then "none" else .[opts.sha256Key] end) as $sha256 43 | | select($apkArch and $url and $sha256) 44 | | (" 45 | \($apkArch | @sh)) 46 | url=\($url | @sh);" 47 | + if $notSha256 then "" else " 48 | sha256=\($sha256 | @sh);" 49 | end + " 50 | ;;" 51 | ) 52 | ) 53 | , 54 | " 55 | *) echo >&2 \"\(if opts.missingArchWarning then "warning" else "error" end): unsupported \(opts.target | @sh) architecture ($apkArch)\(if opts.missingArchWarning then "; skipping" else "" end)\"; exit \(if opts.missingArchWarning then 0 else 1 end) ;; 56 | esac; 57 | 58 | wget -O \(opts.target | @sh) \"$url\";" 59 | , 60 | if $notSha256 then "" else " 61 | echo \"$sha256 *\"\(opts.target | @sh) | sha256sum -c -;" 62 | end 63 | ] | add 64 | | rtrimstr(";") 65 | | gsub("(?<=[^[:space:]])\n"; " \\\n") 66 | | gsub("(?<=[[:space:]])\n"; "\\\n") 67 | ; 68 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 5 | 6 | ./versions.sh "$@" 7 | ./apply-templates.sh "$@" 8 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "28": { 3 | "arches": { 4 | "amd64": { 5 | "dockerUrl": "https://download.docker.com/linux/static/stable/x86_64/docker-28.2.2.tgz", 6 | "rootlessExtrasUrl": "https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-28.2.2.tgz" 7 | }, 8 | "arm32v6": { 9 | "dockerUrl": "https://download.docker.com/linux/static/stable/armel/docker-28.2.2.tgz" 10 | }, 11 | "arm32v7": { 12 | "dockerUrl": "https://download.docker.com/linux/static/stable/armhf/docker-28.2.2.tgz" 13 | }, 14 | "arm64v8": { 15 | "dockerUrl": "https://download.docker.com/linux/static/stable/aarch64/docker-28.2.2.tgz", 16 | "rootlessExtrasUrl": "https://download.docker.com/linux/static/stable/aarch64/docker-rootless-extras-28.2.2.tgz" 17 | }, 18 | "windows-amd64": { 19 | "dockerUrl": "https://download.docker.com/win/static/stable/x86_64/docker-28.2.2.zip" 20 | } 21 | }, 22 | "buildx": { 23 | "arches": { 24 | "amd64": { 25 | "file": "buildx-v0.24.0.linux-amd64", 26 | "sha256": "c41ed17ec05b6ebb50eeb02fb26cce90f16cd260b8d26ce73963428c6b2d6508", 27 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-amd64" 28 | }, 29 | "arm32v6": { 30 | "file": "buildx-v0.24.0.linux-arm-v6", 31 | "sha256": "591abb51afe942814a45f4f3d0f1a97fe8c5c212142bded66025ae019136bac8", 32 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-arm-v6" 33 | }, 34 | "arm32v7": { 35 | "file": "buildx-v0.24.0.linux-arm-v7", 36 | "sha256": "69a3afa3d22867ea67b87e5f205574478e7a795599c471b61575bacf455452ae", 37 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-arm-v7" 38 | }, 39 | "arm64v8": { 40 | "file": "buildx-v0.24.0.linux-arm64", 41 | "sha256": "ad33819d085a635e3b4400a412bd2b4e943bfbc830366d78f50579bae48f8053", 42 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-arm64" 43 | }, 44 | "freebsd-amd64": { 45 | "file": "buildx-v0.24.0.freebsd-amd64", 46 | "sha256": "889224cf7885ab6b1890c5019fe798021827ac73cfa6c8f1931418e09a4d8a18", 47 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.freebsd-amd64" 48 | }, 49 | "freebsd-arm64v8": { 50 | "file": "buildx-v0.24.0.freebsd-arm64", 51 | "sha256": "2850060b31468f928cd34a25aa65725944f8969e4d09715499333f063a2f9bca", 52 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.freebsd-arm64" 53 | }, 54 | "netbsd-amd64": { 55 | "file": "buildx-v0.24.0.netbsd-amd64", 56 | "sha256": "2e83d94835a1a19ff90c5a83e4039b445f8e3e1fc13d447a643d87cbbf2645aa", 57 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.netbsd-amd64" 58 | }, 59 | "netbsd-arm64v8": { 60 | "file": "buildx-v0.24.0.netbsd-arm64", 61 | "sha256": "53964d5bfa7b4ed5977f0980f41a365f05808e98c674ce245692409c03897381", 62 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.netbsd-arm64" 63 | }, 64 | "openbsd-amd64": { 65 | "file": "buildx-v0.24.0.openbsd-amd64", 66 | "sha256": "995c03911b43075a84c6310a0cf40d35f3752787e3bec8bb763f048d2036385c", 67 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.openbsd-amd64" 68 | }, 69 | "openbsd-arm64v8": { 70 | "file": "buildx-v0.24.0.openbsd-arm64", 71 | "sha256": "9647a7d528058673ba26acf7d146e253fe2f6029c9a21e73b660659d6e4918b8", 72 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.openbsd-arm64" 73 | }, 74 | "ppc64le": { 75 | "file": "buildx-v0.24.0.linux-ppc64le", 76 | "sha256": "90c02625d1e52abd8e6089854208963651ea727028aaca58b29847dc594c01f8", 77 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-ppc64le" 78 | }, 79 | "riscv64": { 80 | "file": "buildx-v0.24.0.linux-riscv64", 81 | "sha256": "3031cf533e015ea77425446e4bc87173f1316447ed3369c2898f73ac353de404", 82 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-riscv64" 83 | }, 84 | "s390x": { 85 | "file": "buildx-v0.24.0.linux-s390x", 86 | "sha256": "821ea62254a7be6cab51c5ebefc9ba74b7e2dd902c78d16b268850dc29869ca2", 87 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.linux-s390x" 88 | }, 89 | "windows-amd64": { 90 | "file": "buildx-v0.24.0.windows-amd64.exe", 91 | "sha256": "8dec102c8eb14f434707cc05a8f0e366c090ded6ad74d9c5f8a64a9c0b766140", 92 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.windows-amd64.exe" 93 | }, 94 | "windows-arm64v8": { 95 | "file": "buildx-v0.24.0.windows-arm64.exe", 96 | "sha256": "fc0cd1fa1594ad6e0fc907a6f00b618ede1a3958ccc4ddf324dea3500946e046", 97 | "url": "https://github.com/docker/buildx/releases/download/v0.24.0/buildx-v0.24.0.windows-arm64.exe" 98 | } 99 | }, 100 | "version": "0.24.0" 101 | }, 102 | "compose": { 103 | "arches": { 104 | "amd64": { 105 | "file": "docker-compose-linux-x86_64", 106 | "sha256": "e6e471b1e7bf0443592d3987dea6073f08db3e48ba0580199109aa7a44257e54", 107 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-x86_64" 108 | }, 109 | "arm32v6": { 110 | "file": "docker-compose-linux-armv6", 111 | "sha256": "f09294bd81119701f051733b45be487d55faa29d20fb9c54412975a6c7fd8696", 112 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-armv6" 113 | }, 114 | "arm32v7": { 115 | "file": "docker-compose-linux-armv7", 116 | "sha256": "b1b592889f15f50ddc77685ed499c69599117e52240b196447cb82821da3f7f8", 117 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-armv7" 118 | }, 119 | "arm64v8": { 120 | "file": "docker-compose-linux-aarch64", 121 | "sha256": "664e8c532ac0dd54d14af4eb3fe4edce86ce27d970ec832a96b55bc2ef1dffdf", 122 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-aarch64" 123 | }, 124 | "darwin-amd64": { 125 | "file": "docker-compose-darwin-x86_64", 126 | "sha256": "fde5ec3f7034fcd29ec9061d4bd71d41a7b4fa042ceab5b913576db6260899fa", 127 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-darwin-x86_64" 128 | }, 129 | "darwin-arm64v8": { 130 | "file": "docker-compose-darwin-aarch64", 131 | "sha256": "575b0389c77c1ff914aa21f56f4ef68dc5c2322baf819b6ff69dfcae82f8271f", 132 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-darwin-aarch64" 133 | }, 134 | "ppc64le": { 135 | "file": "docker-compose-linux-ppc64le", 136 | "sha256": "83c7cf5afffcc7944e23ba5c1c038aff4f2d760f08681d76b5271b66c9e2af5d", 137 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-ppc64le" 138 | }, 139 | "riscv64": { 140 | "file": "docker-compose-linux-riscv64", 141 | "sha256": "0e6047d2b0f745f0bbb13d707cfb945295bf45e397e67ff756f8551043a1f5bc", 142 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-riscv64" 143 | }, 144 | "s390x": { 145 | "file": "docker-compose-linux-s390x", 146 | "sha256": "381b5b77e6a91075e746167ac160062a1adf4d2a1121e433f1ca731ad08e2353", 147 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-linux-s390x" 148 | }, 149 | "windows-amd64": { 150 | "file": "docker-compose-windows-x86_64.exe", 151 | "sha256": "5ddd1ff588eb7251381cf6257b9be44fbb92c02d984ccfc94b4280e8c33d0f8f", 152 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-windows-x86_64.exe" 153 | }, 154 | "windows-arm64v8": { 155 | "file": "docker-compose-windows-aarch64.exe", 156 | "sha256": "7dbddc0e6fe86b504bba6c342f49725703048bcf1a9dd8a42b457de24bfe51e8", 157 | "url": "https://github.com/docker/compose/releases/download/v2.37.0/docker-compose-windows-aarch64.exe" 158 | } 159 | }, 160 | "version": "2.37.0" 161 | }, 162 | "dindCommit": "8d9e3502aba39127e4d12196dae16d306f76993d", 163 | "variants": [ 164 | "cli", 165 | "dind", 166 | "dind-rootless", 167 | "windows/windowsservercore-ltsc2025", 168 | "windows/windowsservercore-ltsc2022" 169 | ], 170 | "version": "28.2.2" 171 | }, 172 | "28-rc": null 173 | } 174 | -------------------------------------------------------------------------------- /versions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeuo pipefail 3 | 4 | # bashbrew arch to docker-release-arch 5 | declare -A dockerArches=( 6 | ['amd64']='x86_64' 7 | ['arm32v6']='armel' 8 | ['arm32v7']='armhf' 9 | ['arm64v8']='aarch64' 10 | ['ppc64le']='ppc64le' 11 | ['riscv64']='riscv64' 12 | ['s390x']='s390x' 13 | ['windows-amd64']='x86_64' 14 | ) 15 | 16 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 17 | 18 | versions=( "$@" ) 19 | if [ ${#versions[@]} -eq 0 ]; then 20 | versions=( */ ) 21 | json='{}' 22 | else 23 | json="$(< versions.json)" 24 | fi 25 | versions=( "${versions[@]%/}" ) 26 | 27 | scriptPid="$$" # so we can kill the script even from a subshell 28 | _curl() { 29 | exec 42>&1 30 | local code 31 | code="$(curl --silent --location -o /dev/fd/42 --write-out '%{http_code}' "$@")" 32 | case "$code" in 33 | 200) return 0 ;; 34 | 404) return 1 ;; 35 | esac 36 | echo >&2 "error: unexpected status code $code while fetching: $*" 37 | kill "$scriptPid" 38 | exit 1 39 | } 40 | 41 | dindLatest="$( 42 | _curl -H 'Accept: application/json' 'https://github.com/docker/docker/commits/master/hack/dind.atom' \ 43 | | jq -r '.payload | first(.commitGroups[].commits[].oid)' 44 | )" 45 | 46 | dockerVersions="$( 47 | git ls-remote --tags https://github.com/docker/docker.git \ 48 | | cut -d$'\t' -f2 \ 49 | | grep '^refs/tags/v[0-9].*$' \ 50 | | sed 's!^refs/tags/v!!; s!\^{}$!!' \ 51 | | sort -u \ 52 | | gawk ' 53 | { data[lines++] = $0 } 54 | 55 | # "beta" sorts lower than "tp" even though "beta" is a more preferred release, so we need to explicitly adjust the sorting order for RCs 56 | # also, "18.09.0-ce-beta1" vs "18.09.0-beta3" 57 | function docker_version_compare(i1, v1, i2, v2, l, r) { 58 | l = v1; gsub(/-ce/, "", l); gsub(/-tp/, "-alpha", l) 59 | r = v2; gsub(/-ce/, "", r); gsub(/-tp/, "-alpha", r) 60 | patsplit(l, ltemp, /[^.-]+/) 61 | patsplit(r, rtemp, /[^.-]+/) 62 | for (i = 0; i < length(ltemp) && i < length(rtemp); ++i) { 63 | if (ltemp[i] < rtemp[i]) { 64 | return -1 65 | } 66 | if (ltemp[i] > rtemp[i]) { 67 | return 1 68 | } 69 | } 70 | return 0 71 | } 72 | 73 | END { 74 | asort(data, result, "docker_version_compare") 75 | for (i in result) { 76 | print result[i] 77 | } 78 | } 79 | ' 80 | )" 81 | 82 | buildxVersions="$( 83 | git ls-remote --tags https://github.com/docker/buildx.git \ 84 | | cut -d$'\t' -f2 \ 85 | | grep '^refs/tags/v[0-9].*$' \ 86 | | sed 's!^refs/tags/v!!; s!\^{}$!!' \ 87 | | grep -vE -- '-rc' \ 88 | | sort -ruV 89 | )" 90 | buildx= 91 | buildxVersion= 92 | for buildxVersion in $buildxVersions; do 93 | if checksums="$(_curl "https://github.com/docker/buildx/releases/download/v${buildxVersion}/checksums.txt")"; then 94 | buildx="$(jq <<<"$checksums" -csR --arg version "$buildxVersion" ' 95 | rtrimstr("\n") | split("\n") 96 | | map( 97 | split(" [ *]?"; "") 98 | | { 99 | sha256: .[0], 100 | file: .[1], 101 | url: ("https://github.com/docker/buildx/releases/download/v" + $version + "/" + .[1]), 102 | } 103 | | select(.file | test("[.]json$") | not) 104 | | { ( 105 | .file 106 | | capture("[.](?linux|windows|darwin|[a-z0-9]*bsd)-(?[^.]+)(?[.]exe)?$") 107 | // error("failed to parse os-arch from filename: " + .) 108 | | if .os == "linux" then "" else .os + "-" end 109 | + ({ 110 | "amd64": "amd64", 111 | "arm-v6": "arm32v6", 112 | "arm-v7": "arm32v7", 113 | "arm64": "arm64v8", 114 | "ppc64le": "ppc64le", 115 | "riscv64": "riscv64", 116 | "s390x": "s390x", 117 | }[.arch] // error("unknown buildx architecture: " + .arch)) 118 | ): . } 119 | ) 120 | | add 121 | | { 122 | version: $version, 123 | arches: ., 124 | } 125 | ')" 126 | break 127 | fi 128 | done 129 | if [ -z "$buildx" ]; then 130 | echo >&2 'error: failed to determine buildx version!' 131 | exit 1 132 | fi 133 | 134 | composeVersions="$( 135 | git ls-remote --tags https://github.com/docker/compose.git \ 136 | | cut -d$'\t' -f2 \ 137 | | grep '^refs/tags/v[0-9].*$' \ 138 | | sed 's!^refs/tags/v!!; s!\^{}$!!' \ 139 | | grep -vE -- '-[a-zA-Z]' \ 140 | | sort -ruV 141 | )" 142 | compose= 143 | composeVersion= 144 | for composeVersion in $composeVersions; do 145 | if checksums="$(_curl "https://github.com/docker/compose/releases/download/v${composeVersion}/checksums.txt")"; then 146 | compose="$(jq <<<"$checksums" -csR --arg version "$composeVersion" ' 147 | rtrimstr("\n") | split("\n") 148 | | map( 149 | split(" *") 150 | | { 151 | sha256: .[0], 152 | file: .[1], 153 | url: ("https://github.com/docker/compose/releases/download/v" + $version + "/" + .[1]), 154 | } 155 | | select(.file | test("[.]json$") | not) 156 | | { ( 157 | .file 158 | | capture("-(?linux|windows|darwin|freebsd|openbsd)-(?[^.]+)(?[.]exe)?$") 159 | // error("failed to parse os-arch from filename: " + .) 160 | | if .os == "linux" then "" else .os + "-" end 161 | + ({ 162 | aarch64: "arm64v8", 163 | armv6: "arm32v6", 164 | armv7: "arm32v7", 165 | ppc64le: "ppc64le", 166 | riscv64: "riscv64", 167 | s390x: "s390x", 168 | x86_64: "amd64", 169 | }[.arch] // error("unknown compose architecture: " + .arch)) 170 | ): . } 171 | ) 172 | | add 173 | | { 174 | version: $version, 175 | arches: ., 176 | } 177 | ')" 178 | break 179 | fi 180 | done 181 | if [ -z "$compose" ]; then 182 | echo >&2 'error: failed to determine compose version!' 183 | exit 1 184 | fi 185 | 186 | for version in "${versions[@]}"; do 187 | rcVersion="${version%-rc}" 188 | export version rcVersion 189 | channel='stable' 190 | 191 | versionOptions="$(grep "^$rcVersion[.]" <<<"$dockerVersions")" 192 | 193 | rcGrepV='-v' 194 | if [ "$rcVersion" != "$version" ]; then 195 | rcGrepV= 196 | channel='test' 197 | fi 198 | 199 | if ! fullVersion="$(grep $rcGrepV -E -- '-(rc|tp|beta)' <<<"$versionOptions" | tail -1)" || [ -z "$fullVersion" ]; then 200 | if currentNull="$(jq -r '.[env.version] == null' versions.json)" && [ "$currentNull" = 'true' ]; then 201 | echo >&2 "warning: skipping '$version' (does not appear to be released yet)" 202 | json="$(jq <<<"$json" -c '.[env.version] = null')" 203 | continue 204 | fi 205 | echo >&2 "error: cannot find full version for $version" 206 | exit 1 207 | fi 208 | 209 | # if this is a "-rc" release, let's make sure the release it contains isn't already GA (and thus something we should not publish anymore) 210 | if [ "$rcVersion" != "$version" ] && rcFullVersion="$(jq <<<"$json" -r '.[env.rcVersion].version // ""')" && [ -n "$rcFullVersion" ]; then 211 | latestVersion="$({ echo "$fullVersion"; echo "$rcFullVersion"; } | sort -V | tail -1)" 212 | if [[ "$fullVersion" == "$rcFullVersion"* ]] || [ "$latestVersion" = "$rcFullVersion" ]; then 213 | # "x.y.z-rc1" == x.y.z* 214 | echo >&2 "warning: skipping/removing '$version' ('$rcVersion' is at '$rcFullVersion' which is newer than '$fullVersion')" 215 | json="$(jq <<<"$json" -c '.[env.version] = null')" 216 | continue 217 | fi 218 | fi 219 | 220 | echo "$version: $fullVersion (buildx $buildxVersion, compose $composeVersion)" 221 | 222 | export fullVersion dindLatest 223 | doc="$( 224 | jq -nc --argjson buildx "$buildx" --argjson compose "$compose" '{ 225 | version: env.fullVersion, 226 | arches: {}, 227 | dindCommit: env.dindLatest, 228 | buildx: $buildx, 229 | compose: $compose, 230 | }' 231 | )" 232 | 233 | declare -A hasArches=() 234 | for bashbrewArch in "${!dockerArches[@]}"; do 235 | arch="${dockerArches[$bashbrewArch]}" 236 | # check whether the given architecture is supported for this release 237 | case "$bashbrewArch" in 238 | windows-*) url="https://download.docker.com/win/static/$channel/$arch/docker-$fullVersion.zip"; windows=1 ;; 239 | *) url="https://download.docker.com/linux/static/$channel/$arch/docker-$fullVersion.tgz"; windows= ;; 240 | esac 241 | if _curl --head "$url" > /dev/null; then 242 | export bashbrewArch url 243 | doc="$( 244 | jq <<<"$doc" -c '.arches[env.bashbrewArch] = { 245 | dockerUrl: env.url, 246 | }' 247 | )" 248 | else 249 | continue 250 | fi 251 | 252 | hasArches["$bashbrewArch"]=1 253 | 254 | if [ -n "$windows" ]; then 255 | continue # Windows doesn't have rootless extras :) 256 | fi 257 | 258 | # https://github.com/moby/moby/blob/v20.10.7/hack/make/binary-daemon#L24 259 | # "vpnkit is available for x86_64 and aarch64" 260 | case "$bashbrewArch" in 261 | amd64 | arm64v8) 262 | rootlessExtrasUrl="https://download.docker.com/linux/static/$channel/$arch/docker-rootless-extras-$fullVersion.tgz" 263 | if _curl --head "$rootlessExtrasUrl" > /dev/null; then 264 | export rootlessExtrasUrl 265 | doc="$(jq <<<"$doc" -c ' 266 | .arches[env.bashbrewArch].rootlessExtrasUrl = env.rootlessExtrasUrl 267 | ')" 268 | fi 269 | ;; 270 | esac 271 | done 272 | 273 | for alwaysExpectedArch in amd64 arm64v8; do 274 | if [ -z "${hasArches["$alwaysExpectedArch"]:-}" ]; then 275 | echo >&2 "error: missing '$alwaysExpectedArch' for '$version'; cowardly refusing to continue! (because this is almost always a scraping flake or similar bug)" 276 | exit 1 277 | fi 278 | done 279 | 280 | # order here controls the order of the library/ file 281 | for variant in \ 282 | cli \ 283 | dind \ 284 | dind-rootless \ 285 | windows/windowsservercore-ltsc2025 \ 286 | windows/windowsservercore-ltsc2022 \ 287 | ; do 288 | base="${variant%%/*}" # "buster", "windows", etc. 289 | if [ "$base" = 'windows' ] && [ -z "${hasArches['windows-amd64']}" ]; then 290 | continue 291 | fi 292 | export variant 293 | doc="$(jq <<<"$doc" -c '.variants += [ env.variant ]')" 294 | done 295 | 296 | json="$(jq <<<"$json" -c --argjson doc "$doc" ' 297 | .[env.version] = $doc 298 | # make sure both "XX.YY" and "XX.YY-rc" always exist 299 | | .[env.rcVersion] //= null 300 | | .[env.rcVersion + "-rc"] //= null 301 | ')" 302 | done 303 | 304 | jq <<<"$json" -S . > versions.json 305 | --------------------------------------------------------------------------------