From c7e585e21d578192d175381b4f17b562540485d6 Mon Sep 17 00:00:00 2001 From: Lemon-miaow Date: Wed, 23 Sep 2026 19:23:44 +0800 Subject: [PATCH] fix(bootstrap): mirror the image batch under ONE docker start/stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live re-run: the per-image systemctl start/stop docker cycles tripped systemd's start rate limit after three fast pushes — "Start request repeated too quickly / start-limit-hit" — and the fourth image (the paper base) silently never reached the registry while the installer aborted. docker.service is socket-triggered, so every cycle counts against the burst limit twice. push_images_to_registry now starts docker once for the whole batch and stops it once at the end; push_image_to_registry itself no longer touches systemd. bootstrap_test.sh pins the wrap (exactly one start, one stop, four pushes). --- deploy/bootstrap.sh | 10 ++++++++-- deploy/bootstrap_test.sh | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/deploy/bootstrap.sh b/deploy/bootstrap.sh index 3217e66..802590a 100644 --- a/deploy/bootstrap.sh +++ b/deploy/bootstrap.sh @@ -2395,24 +2395,30 @@ push_image_to_registry() { return 0 ;; esac - systemctl start docker log "mirroring ${ref} into the internal registry" docker tag "$ref" "$push_ref" || die "could not tag ${ref} as ${push_ref} — is docker healthy?" docker push "$push_ref" || die "could not mirror ${ref} into the internal registry — check the registry Deployment/pod and its PVC" docker rmi "$push_ref" >/dev/null 2>&1 || true - systemctl stop docker docker.socket 2>/dev/null || true } # Every image this installer builds is hosted in the registry, so the copies it # imported into containerd are a first-boot cache, not the only copy: kubelet # re-pulls from the registry after any image GC. Runs AFTER deploy_bundle — the # registry it pushes into does not exist before that. +# +# Docker is started once for the whole batch and stopped once at the end. A +# start/stop pair per image trips systemd's start rate limit — observed live on +# a re-run: three fast pushes, then "Start request repeated too quickly / +# start-limit-hit" and the fourth image never got mirrored. docker.service is +# socket-triggered, so each cycle counts twice against the burst limit. push_images_to_registry() { local img + systemctl start docker for img in "$FELIS_IMAGE" "$FELIS_LIMBO_IMAGE" "$FELIS_LOBBY_IMAGE" "$FELIS_PAPER_IMAGE"; do [ -n "$img" ] || continue push_image_to_registry "$img" done + systemctl stop docker docker.socket 2>/dev/null || true } # The login/lobby images use mutable :demo tags. Importing/pushing a replacement diff --git a/deploy/bootstrap_test.sh b/deploy/bootstrap_test.sh index 5f312bd..456c0ce 100644 --- a/deploy/bootstrap_test.sh +++ b/deploy/bootstrap_test.sh @@ -704,6 +704,24 @@ esac out="$(run_push registry.felis.svc:5000/felis/felis:demo 1)" expect "a failed push fails the install loudly" "DIE: could not mirror" "$out" +# docker must be started ONCE for the whole batch: a start/stop pair per image trips +# systemd's start rate limit ("start-limit-hit" — observed live; the 4th image was never +# mirrored because docker.service is socket-triggered and each cycle counts twice). +wiblock="$(awk '/^push_images_to_registry\(\) \{/,/^}/' "$BS")" +[ -n "$wiblock" ] || { echo "FAIL: no push_images_to_registry found in $BS"; exit 1; } +out="$( + FELIS_IMAGE=a FELIS_LIMBO_IMAGE=b FELIS_LOBBY_IMAGE=c FELIS_PAPER_IMAGE=d bash -c ' + systemctl() { printf "SYSTEMCTL %s\n" "$*"; } + push_image_to_registry() { printf "PUSH %s\n" "$1"; } + '"$wiblock"' + push_images_to_registry' +)" +starts="$(printf '%s\n' "$out" | grep -c 'SYSTEMCTL start docker')" +stops="$(printf '%s\n' "$out" | grep -c 'SYSTEMCTL stop docker')" +[ "$starts" = 1 ] && [ "$stops" = 1 ] && [ "$(printf '%s\n' "$out" | grep -c '^PUSH')" = 4 ] \ + && echo "PASS the batch wraps all four pushes in ONE docker start/stop" \ + || { echo "FAIL: expected 1 start / 1 stop / 4 pushes, got:"; printf '%s\n' "$out"; fails=$((fails + 1)); } + # --- the registry's own image must not be re-pulled on every run -------------------------- iblock="$(awk '/^import_registry_image\(\) \{/,/^}/' "$BS")" [ -n "$iblock" ] || { echo "FAIL: no import_registry_image found in $BS"; exit 1; }