From 2e52d17337336161c819b34bd7f9becdd5c56dc5 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Mon, 11 May 2026 16:46:36 +0000 Subject: [PATCH 01/11] Test case --- .github/workflows/test-pr-arm64.yaml | 3 +++ src/docker-in-docker/NOTES.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-pr-arm64.yaml b/.github/workflows/test-pr-arm64.yaml index 113ce39b5..6421656e1 100644 --- a/.github/workflows/test-pr-arm64.yaml +++ b/.github/workflows/test-pr-arm64.yaml @@ -8,6 +8,8 @@ on: paths: - "src/powershell/**" - "test/powershell/**" + - "src/docker-in-docker/**" + - "test/docker-in-docker/**" jobs: detect-changes: @@ -23,6 +25,7 @@ jobs: # : ./**//** filters: | powershell: ./**/powershell/** + docker-in-docker: ./**/docker-in-docker/** test: needs: [detect-changes] diff --git a/src/docker-in-docker/NOTES.md b/src/docker-in-docker/NOTES.md index c7fb26137..f55b8ac7e 100644 --- a/src/docker-in-docker/NOTES.md +++ b/src/docker-in-docker/NOTES.md @@ -4,7 +4,7 @@ This docker-in-docker Dev Container Feature is roughly based on the [official do * As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. * The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: ``` - FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:22 ``` See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. From fdd3bdf017c4f9c24acd1686e28d1f1d32fa5824 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Mon, 11 May 2026 16:52:02 +0000 Subject: [PATCH 02/11] Modify the script --- .github/workflows/test-pr-arm64.yaml | 3 +++ src/docker-in-docker/NOTES.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-pr-arm64.yaml b/.github/workflows/test-pr-arm64.yaml index 6421656e1..8091828e8 100644 --- a/.github/workflows/test-pr-arm64.yaml +++ b/.github/workflows/test-pr-arm64.yaml @@ -45,6 +45,9 @@ jobs: "mcr.microsoft.com/devcontainers/base:debian", "mcr.microsoft.com/devcontainers/base:noble" ] + exclude: + - features: docker-in-docker + baseImage: mcr.microsoft.com/devcontainers/base:debian steps: - uses: actions/checkout@v6 diff --git a/src/docker-in-docker/NOTES.md b/src/docker-in-docker/NOTES.md index f55b8ac7e..c7fb26137 100644 --- a/src/docker-in-docker/NOTES.md +++ b/src/docker-in-docker/NOTES.md @@ -4,7 +4,7 @@ This docker-in-docker Dev Container Feature is roughly based on the [official do * As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. * The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: ``` - FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:22 + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 ``` See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. From a97de719f47a8acc7b69946ef0bd558ff81d1305 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Mon, 11 May 2026 16:53:30 +0000 Subject: [PATCH 03/11] Trigger the test --- src/docker-in-docker/NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docker-in-docker/NOTES.md b/src/docker-in-docker/NOTES.md index c7fb26137..104e69679 100644 --- a/src/docker-in-docker/NOTES.md +++ b/src/docker-in-docker/NOTES.md @@ -4,7 +4,7 @@ This docker-in-docker Dev Container Feature is roughly based on the [official do * As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. * The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: ``` - FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:24 ``` See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. From 8b68bf5debcd3b9e14b5dc8e049b67cbc88799b0 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Tue, 12 May 2026 05:45:17 +0000 Subject: [PATCH 04/11] Change installation script to install erofs-utils upfront --- src/docker-in-docker/install.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 5af320b0b..733617d76 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -287,10 +287,13 @@ else fi # Install base dependencies +# Note: erofs-utils provides mkfs.erofs, required by containerd >= 2.3.x snapshotter +# to avoid "failed to check mkfs.erofs availability" errors at dockerd startup +# (see https://github.com/devcontainers/features/issues/1642). base_packages="curl ca-certificates pigz iptables gnupg2 wget jq" case ${ADJUSTED_ID} in debian) - check_packages apt-transport-https $base_packages dirmngr + check_packages apt-transport-https $base_packages dirmngr erofs-utils ;; rhel) check_packages $base_packages tar gawk shadow-utils policycoreutils procps-ng systemd-libs systemd-devel From 17069053e6bda7fa37823fa6c974a0e0dcb80a42 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Tue, 12 May 2026 06:30:04 +0000 Subject: [PATCH 05/11] Install docker-compose v1 with python venv --- src/docker-in-docker/install.sh | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 733617d76..6472a3571 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -719,11 +719,21 @@ if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then err "Docker compose v1 is unavailable for 'bookworm' on Arm64. Kindly switch to use v2" exit 1 else - # Use pip to get a version that runs on this architecture + # Use pip (inside an isolated venv) to get a version that runs on this architecture. + # A dedicated venv avoids PEP 668 "externally-managed-environment" errors on newer + # distros (Debian trixie, Ubuntu noble, etc.) and guarantees we do not modify or + # shadow the distro-managed system Python site-packages. check_packages python3-minimal python3-pip libffi-dev python3-venv - echo "(*) Installing docker compose v1 via pip..." - export PYTHONUSERBASE=/usr/local - pip3 install --disable-pip-version-check --no-cache-dir --user "Cython<3.0" pyyaml wheel docker-compose --no-build-isolation + echo "(*) Installing docker compose v1 via pip into an isolated virtualenv..." + + compose_v1_venv="/usr/local/share/docker-compose-v1-venv" + python3 -m venv "${compose_v1_venv}" + "${compose_v1_venv}/bin/pip" install --disable-pip-version-check --no-cache-dir --upgrade pip setuptools wheel + "${compose_v1_venv}/bin/pip" install --disable-pip-version-check --no-cache-dir "Cython<3.0" pyyaml docker-compose --no-build-isolation + + # Expose the venv's docker-compose entrypoint on PATH at the expected location. + ln -sf "${compose_v1_venv}/bin/docker-compose" "${docker_compose_path}" + chmod +x "${docker_compose_path}" fi else compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} From bc6634c9b6465ed85c1f95d8371d7e431f3d2aca Mon Sep 17 00:00:00 2001 From: Kaniska Date: Wed, 13 May 2026 06:07:18 +0000 Subject: [PATCH 06/11] Force load erofs to replicate the same setup as reported in the issue --- .github/workflows/test-pr-arm64.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-pr-arm64.yaml b/.github/workflows/test-pr-arm64.yaml index 8091828e8..f05048e1b 100644 --- a/.github/workflows/test-pr-arm64.yaml +++ b/.github/workflows/test-pr-arm64.yaml @@ -51,6 +51,9 @@ jobs: steps: - uses: actions/checkout@v6 + - name: "Load erofs module and verify" + run: sudo modprobe erofs && grep erofs /proc/filesystems + - name: "Install latest devcontainer CLI" run: npm install -g @devcontainers/cli From 0e7189f67966d47b0aefe1f9d05e96b936243267 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Wed, 13 May 2026 11:53:54 +0000 Subject: [PATCH 07/11] Disable erofs filesystem --- src/docker-in-docker/install.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 6472a3571..4dd3fda1f 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -874,6 +874,28 @@ if [ "$DISABLE_IP6_TABLES" == true ]; then fi fi +# Workaround for https://github.com/devcontainers/features/issues/1642 +# containerd >= 2.3 ships an erofs snapshotter that requires mkfs.erofs >= 1.7. +# Older distros (Debian 12, Ubuntu 22.04) ship erofs-utils 1.4/1.5, so when the +# host kernel exposes the 'erofs' filesystem the snapshotter fails to initialize +# and dockerd times out waiting for containerd. Disable the plugin so containerd +# always uses overlayfs regardless of distro / mkfs.erofs version. +if command -v containerd >/dev/null 2>&1; then + mkdir -p /etc/containerd + if [ ! -f /etc/containerd/config.toml ]; then + containerd config default > /etc/containerd/config.toml 2>/dev/null || echo "" > /etc/containerd/config.toml + fi + if ! grep -q "io.containerd.snapshotter.v1.erofs" /etc/containerd/config.toml; then + cat >> /etc/containerd/config.toml <<'EOF' + +# Added by devcontainers/features docker-in-docker: disable erofs snapshotter +# to avoid mkfs.erofs version requirements (containerd >= 2.3). +[plugins.'io.containerd.snapshotter.v1.erofs'] + disable = true +EOF + fi +fi + if [ ! -d /usr/local/share ]; then mkdir -p /usr/local/share fi From 0a8e8da7f58f4791f3f0b654b3644141d04e9ca1 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Wed, 13 May 2026 15:20:43 +0000 Subject: [PATCH 08/11] Start own containerd process --- src/docker-in-docker/install.sh | 94 +++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 15 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 4dd3fda1f..0fd4d14f9 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -877,23 +877,53 @@ fi # Workaround for https://github.com/devcontainers/features/issues/1642 # containerd >= 2.3 ships an erofs snapshotter that requires mkfs.erofs >= 1.7. # Older distros (Debian 12, Ubuntu 22.04) ship erofs-utils 1.4/1.5, so when the -# host kernel exposes the 'erofs' filesystem the snapshotter fails to initialize -# and dockerd times out waiting for containerd. Disable the plugin so containerd -# always uses overlayfs regardless of distro / mkfs.erofs version. -if command -v containerd >/dev/null 2>&1; then - mkdir -p /etc/containerd - if [ ! -f /etc/containerd/config.toml ]; then - containerd config default > /etc/containerd/config.toml 2>/dev/null || echo "" > /etc/containerd/config.toml +# host kernel exposes the 'erofs' filesystem the snapshotter fails to +# initialize and dockerd times out waiting for containerd. Disable the plugin +# via the top-level `disabled_plugins` list so containerd always uses +# overlayfs, regardless of distro / mkfs.erofs version. +mkdir -p /etc/containerd +if [ ! -s /etc/containerd/config.toml ]; then + if command -v containerd >/dev/null 2>&1; then + containerd config default > /etc/containerd/config.toml 2>/dev/null || : > /etc/containerd/config.toml + elif [ -x /usr/sbin/containerd ]; then + /usr/sbin/containerd config default > /etc/containerd/config.toml 2>/dev/null || : > /etc/containerd/config.toml + elif [ -x /usr/bin/containerd ]; then + /usr/bin/containerd config default > /etc/containerd/config.toml 2>/dev/null || : > /etc/containerd/config.toml + else + : > /etc/containerd/config.toml fi - if ! grep -q "io.containerd.snapshotter.v1.erofs" /etc/containerd/config.toml; then - cat >> /etc/containerd/config.toml <<'EOF' +fi -# Added by devcontainers/features docker-in-docker: disable erofs snapshotter -# to avoid mkfs.erofs version requirements (containerd >= 2.3). -[plugins.'io.containerd.snapshotter.v1.erofs'] - disable = true -EOF +EROFS_PLUGIN_URI='io.containerd.snapshotter.v1.erofs' +EROFS_MARKER='# devcontainers-features:disable-erofs' + +if ! grep -qF "${EROFS_MARKER}" /etc/containerd/config.toml; then + if grep -qE '^[[:space:]]*disabled_plugins[[:space:]]*=' /etc/containerd/config.toml; then + # Add erofs URI to the existing top-level disabled_plugins list. + # Branches are mutually exclusive and guarded so we never produce + # duplicate entries on re-runs. + if grep -qE '^[[:space:]]*disabled_plugins[[:space:]]*=[[:space:]]*\[[[:space:]]*\]' /etc/containerd/config.toml; then + # disabled_plugins = [] -> insert URI as the only entry. + sed -i -E \ + "s|^([[:space:]]*disabled_plugins[[:space:]]*=[[:space:]]*\[)[[:space:]]*\]|\1\"${EROFS_PLUGIN_URI}\"]|" \ + /etc/containerd/config.toml + elif ! grep -qF "\"${EROFS_PLUGIN_URI}\"" /etc/containerd/config.toml; then + # disabled_plugins = ["existing", ...] -> append URI. + sed -i -E \ + "s|^([[:space:]]*disabled_plugins[[:space:]]*=[[:space:]]*\[)([^]]*[^],[:space:]])[[:space:]]*\]|\1\2, \"${EROFS_PLUGIN_URI}\"]|" \ + /etc/containerd/config.toml + fi + else + # No disabled_plugins key in the config: prepend one. + tmp_cfg="$(mktemp)" + { + printf 'disabled_plugins = ["%s"]\n\n' "${EROFS_PLUGIN_URI}" + cat /etc/containerd/config.toml + } > "${tmp_cfg}" + mv "${tmp_cfg}" /etc/containerd/config.toml fi + # Idempotency marker + printf '\n%s\n' "${EROFS_MARKER}" >> /etc/containerd/config.toml fi if [ ! -d /usr/local/share ]; then @@ -994,8 +1024,42 @@ dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAU DEFAULT_ADDRESS_POOL="--default-address-pool $DOCKER_DEFAULT_ADDRESS_POOL" fi + + # Start our own containerd so it picks up /etc/containerd/config.toml + # (notably the disabled_plugins entry for the erofs snapshotter, see + # https://github.com/devcontainers/features/issues/1642). dockerd's + # built-in containerd child uses an auto-generated config that ignores + # /etc/containerd/config.toml, so we must run containerd ourselves and + # point dockerd at it via --containerd. + CONTAINERD_SOCK="/run/containerd/containerd.sock" + CONTAINERD_BIN="" + for candidate in /usr/local/bin/containerd /usr/bin/containerd /usr/sbin/containerd; do + if [ -x "$candidate" ]; then + CONTAINERD_BIN="$candidate" + break + fi + done + DOCKERD_CONTAINERD_ARG="" + if [ -n "$CONTAINERD_BIN" ] && [ -f /etc/containerd/config.toml ]; then + mkdir -p /run/containerd + if ! pgrep -x containerd > /dev/null 2>&1; then + ( "$CONTAINERD_BIN" --config /etc/containerd/config.toml > /tmp/containerd.log 2>&1 ) & + fi + # Wait up to ~5s for the socket to appear + i=0 + while [ $i -lt 50 ] && [ ! -S "$CONTAINERD_SOCK" ]; do + sleep 0.1 + i=$((i + 1)) + done + if [ -S "$CONTAINERD_SOCK" ]; then + DOCKERD_CONTAINERD_ARG="--containerd $CONTAINERD_SOCK" + else + echo "(*) containerd socket not ready; letting dockerd spawn its own containerd." + fi + fi + # Start docker/moby engine - ( dockerd $CUSTOMDNS $DEFAULT_ADDRESS_POOL $DOCKER_DEFAULT_IP6_TABLES > /tmp/dockerd.log 2>&1 ) & + ( dockerd $DOCKERD_CONTAINERD_ARG $CUSTOMDNS $DEFAULT_ADDRESS_POOL $DOCKER_DEFAULT_IP6_TABLES > /tmp/dockerd.log 2>&1 ) & INNEREOF )" From 4eba6f583a2999b19eb88019c9d3c7e771c8b5a1 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Wed, 13 May 2026 16:07:19 +0000 Subject: [PATCH 09/11] Major version bump --- src/docker-in-docker/README.md | 2 +- src/docker-in-docker/devcontainer-feature.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/docker-in-docker/README.md b/src/docker-in-docker/README.md index 9c5370c4e..c58283317 100644 --- a/src/docker-in-docker/README.md +++ b/src/docker-in-docker/README.md @@ -7,7 +7,7 @@ Create child containers *inside* a container, independent from the host's docker ```json "features": { - "ghcr.io/devcontainers/features/docker-in-docker:2": {} + "ghcr.io/devcontainers/features/docker-in-docker:3": {} } ``` diff --git a/src/docker-in-docker/devcontainer-feature.json b/src/docker-in-docker/devcontainer-feature.json index bdb4cb291..406627f7e 100644 --- a/src/docker-in-docker/devcontainer-feature.json +++ b/src/docker-in-docker/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "docker-in-docker", - "version": "2.17.0", + "version": "3.0.0", "name": "Docker (Docker-in-Docker)", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker", "description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.", From 1bfda864878f8f643a6a1fc5158a51830a154313 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Thu, 14 May 2026 07:33:17 +0000 Subject: [PATCH 10/11] Add docker probe in some cases. --- test/docker-in-docker/dockerIp6tablesDisabledTest.sh | 2 +- test/docker-in-docker/docker_build_older.sh | 2 +- test/docker-in-docker/pin_docker-ce_version_moby_false.sh | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/docker-in-docker/dockerIp6tablesDisabledTest.sh b/test/docker-in-docker/dockerIp6tablesDisabledTest.sh index 977054ffc..5fe8c2a3b 100644 --- a/test/docker-in-docker/dockerIp6tablesDisabledTest.sh +++ b/test/docker-in-docker/dockerIp6tablesDisabledTest.sh @@ -16,7 +16,7 @@ ip6tablesCheck() { echo "❕ip6tables command not found. ❕" fi } - +check "docker ps" bash -c "docker ps" check "ip6tables" ip6tablesCheck check "ip6tables check" bash -c "docker network inspect bridge" check "docker-build" docker build ./ diff --git a/test/docker-in-docker/docker_build_older.sh b/test/docker-in-docker/docker_build_older.sh index d60cd937a..ed9932a84 100644 --- a/test/docker-in-docker/docker_build_older.sh +++ b/test/docker-in-docker/docker_build_older.sh @@ -10,6 +10,6 @@ check "docker-buildx" docker buildx version check "docker-build" docker build ./ check "docker-buildx" bash -c "docker buildx version" check "docker-buildx-path" bash -c "ls -la /usr/libexec/docker/cli-plugins/docker-buildx" - +check "docker ps" bash -c "docker ps" # Report result reportResults diff --git a/test/docker-in-docker/pin_docker-ce_version_moby_false.sh b/test/docker-in-docker/pin_docker-ce_version_moby_false.sh index ec33d1504..4f1eedb84 100644 --- a/test/docker-in-docker/pin_docker-ce_version_moby_false.sh +++ b/test/docker-in-docker/pin_docker-ce_version_moby_false.sh @@ -5,6 +5,7 @@ source dev-container-features-test-lib check "docker-ce" bash -c "docker --version" check "docker-ce-cli" bash -c "docker version" +check "docker ps" bash -c "docker ps" #report result reportResults \ No newline at end of file From 95e8a1b2909a8c3c87cd6cac8dc854ec2d970991 Mon Sep 17 00:00:00 2001 From: Kaniska Date: Thu, 14 May 2026 13:28:01 +0000 Subject: [PATCH 11/11] Support arm64 for azurelinux --- src/docker-in-docker/install.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/docker-in-docker/install.sh b/src/docker-in-docker/install.sh index 1ce6ffbc5..e9740efc5 100755 --- a/src/docker-in-docker/install.sh +++ b/src/docker-in-docker/install.sh @@ -624,9 +624,19 @@ else # Download packages manually using curl since tdnf doesn't support download echo "(*) Downloading Docker CE packages manually..." - + + # Derive repo arch from the current platform. The Docker CE centos + # repo uses 'x86_64' and 'aarch64' as the per-arch directory names, + # which matches the values produced by `rpm --eval '%{_arch}'` / + # `uname -m` for those platforms. + case "${architecture}" in + amd64|x86_64) repo_arch="x86_64" ;; + arm64|aarch64) repo_arch="aarch64" ;; + *) repo_arch="${architecture}" ;; + esac + # Get the repository baseurl - repo_baseurl="https://download.docker.com/linux/centos/9/x86_64/stable" + repo_baseurl="https://download.docker.com/linux/centos/9/${repo_arch}/stable" # Download packages directly cd /tmp/docker-ce-install @@ -643,12 +653,12 @@ else echo "(*) Attempting to download Docker CE packages from repository..." # Try to download latest packages if specific version fails - if ! curl -fsSL "${repo_baseurl}/Packages/docker-ce-${docker_ce_version}.el9.x86_64.rpm" -o docker-ce.rpm 2>/dev/null; then + if ! curl -fsSL "${repo_baseurl}/Packages/docker-ce-${docker_ce_version}.el9.${repo_arch}.rpm" -o docker-ce.rpm 2>/dev/null; then # Fallback: try to get latest available version echo "(*) Specific version not found, trying latest..." - latest_docker=$(curl -s "${repo_baseurl}/Packages/" | grep -o 'docker-ce-[0-9][^"]*\.el9\.x86_64\.rpm' | head -1) - latest_cli=$(curl -s "${repo_baseurl}/Packages/" | grep -o 'docker-ce-cli-[0-9][^"]*\.el9\.x86_64\.rpm' | head -1) - latest_containerd=$(curl -s "${repo_baseurl}/Packages/" | grep -o 'containerd\.io-[0-9][^"]*\.el9\.x86_64\.rpm' | head -1) + latest_docker=$(curl -s "${repo_baseurl}/Packages/" | grep -o "docker-ce-[0-9][^\"]*\.el9\.${repo_arch}\.rpm" | head -1) + latest_cli=$(curl -s "${repo_baseurl}/Packages/" | grep -o "docker-ce-cli-[0-9][^\"]*\.el9\.${repo_arch}\.rpm" | head -1) + latest_containerd=$(curl -s "${repo_baseurl}/Packages/" | grep -o "containerd\.io-[0-9][^\"]*\.el9\.${repo_arch}\.rpm" | head -1) if [ -n "${latest_docker}" ]; then curl -fsSL "${repo_baseurl}/Packages/${latest_docker}" -o docker-ce.rpm