ci: validate runner before registration
ci / verify (pull_request) Failing after 6m9s

This commit is contained in:
2026-07-17 15:08:37 +08:00
parent 1f8c5a3d03
commit 06f95c5d86
2 changed files with 50 additions and 32 deletions
+39 -30
View File
@@ -195,12 +195,20 @@ printf '%s\n' "$runner_runtime_image" | grep -Eq '^sha256:[0-9a-f]{64}$' || \
require_free_space "$MIN_POST_INSTALL_FREE_GIB" "completed runner image pull"
docker volume create "$RUNNER_VOLUME" >/dev/null
# The registered runner state and the nested rootless daemon cache share one
# dedicated volume. Persisting the pinned job image lets validation finish
# before registration and avoids racing the first queued workflow for layers.
docker run --rm --pull=never --user 0:0 \
--volume "$RUNNER_VOLUME:/data" \
--entrypoint /bin/sh "$runner_runtime_image" \
-ec 'chown 1000:1000 /data && chmod 0700 /data'
install -d -m 0755 /etc/easyai-gateway-ci-v2
if [ -n "$NESTED_DOCKER_REGISTRY_MIRROR" ]; then
printf '{"registry-mirrors":["%s"]}\n' "$NESTED_DOCKER_REGISTRY_MIRROR" \
printf '{"data-root":"/data/docker","registry-mirrors":["%s"]}\n' "$NESTED_DOCKER_REGISTRY_MIRROR" \
> /etc/easyai-gateway-ci-v2/daemon.json
else
printf '{}\n' > /etc/easyai-gateway-ci-v2/daemon.json
printf '{"data-root":"/data/docker"}\n' > /etc/easyai-gateway-ci-v2/daemon.json
fi
chmod 0644 /etc/easyai-gateway-ci-v2/daemon.json
@@ -235,7 +243,9 @@ else
fi
docker run --detach --rm --pull=never \
--name "$PROBE_CONTAINER" --privileged --pids-limit 4096 "$@" \
--volume "$RUNNER_VOLUME:/data" \
--volume /etc/easyai-gateway-ci-v2/daemon.json:/home/rootless/.config/docker/daemon.json:ro \
--volume "$PREFIX:$PREFIX:ro" \
--env DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns \
--env DOCKERD_ROOTLESS_ROOTLESSKIT_MTU=65520 \
--env DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--pidns \
@@ -254,6 +264,29 @@ done
fail "rootless Docker-in-Docker probe is not uid 1000"
docker exec "$PROBE_CONTAINER" docker info --format '{{range .SecurityOptions}}{{println .}}{{end}}' | \
grep -Fq 'name=rootless' || fail "rootless Docker-in-Docker probe is not rootless"
[ "$(docker exec "$PROBE_CONTAINER" docker info --format '{{.DockerRootDir}}')" = /data/docker ] || \
fail "rootless Docker-in-Docker probe is not using its persistent dedicated data root"
# Complete every slow and capability-sensitive validation before registration;
# otherwise a queued workflow can race the installer for the same image layers.
docker exec "$PROBE_CONTAINER" docker pull "$JOB_IMAGE"
outer_pidns=$(docker exec "$PROBE_CONTAINER" readlink /proc/1/ns/pid)
inner_host_pidns=$(docker exec "$PROBE_CONTAINER" docker run --rm --pull=never \
--pid=host --entrypoint readlink "$JOB_IMAGE" /proc/1/ns/pid)
[ "$outer_pidns" != "$inner_host_pidns" ] || \
fail "nested --pid=host can see the outer runner PID namespace"
docker exec "$PROBE_CONTAINER" docker run --rm --pull=never \
--volume "$PREFIX:$PREFIX:ro" \
--entrypoint /bin/sh "$JOB_IMAGE" -ec '
export PATH=/opt/easyai-gateway-ci/bin:/opt/easyai-gateway-ci/toolchains/go/bin:/opt/easyai-gateway-ci/toolchains/node/bin:$PATH
go version
node --version
pnpm --version
docker-compose version
shellcheck --version
trivy --version
govulncheck -version
'
cleanup_probe
trap - EXIT HUP INT TERM
@@ -265,13 +298,6 @@ printf 'RUNNER_SECURITY_OPTIONS="%s"\nRUNNER_IMAGE_REF="%s"\n' \
install -m 0644 "$ROOT/deploy/ci/easyai-gateway-ci-v2-runner.service" \
/etc/systemd/system/easyai-gateway-ci-v2-runner.service
# The image runs as uid 1000. Initialize only the dedicated named volume as
# root, then register and operate the runner as that image's rootless user.
docker run --rm --pull=never --user 0:0 \
--volume "$RUNNER_VOLUME:/data" \
--entrypoint /bin/sh "$runner_runtime_image" \
-ec 'chown 1000:1000 /data && chmod 0700 /data'
runner_is_registered() {
docker run --rm --pull=never \
--volume "$RUNNER_VOLUME:/data" \
@@ -344,27 +370,10 @@ if docker inspect --format '{{range .Mounts}}{{println .Source}}{{end}}' "$RUNNE
fi
docker exec "$RUNNER_CONTAINER" docker info --format '{{range .SecurityOptions}}{{println .}}{{end}}' | \
grep -Fq 'name=rootless' || fail "nested Docker daemon is not rootless"
# Pre-pull through the nested daemon to prove the digest is reachable and make
# the first real CI job independent of an additional large image pull.
docker exec "$RUNNER_CONTAINER" docker pull "$JOB_IMAGE"
outer_pidns=$(docker exec "$RUNNER_CONTAINER" readlink /proc/1/ns/pid)
inner_host_pidns=$(docker exec "$RUNNER_CONTAINER" docker run --rm --pull=never \
--pid=host --entrypoint readlink "$JOB_IMAGE" /proc/1/ns/pid)
[ "$outer_pidns" != "$inner_host_pidns" ] || \
fail "nested --pid=host can see the outer runner PID namespace"
docker exec "$RUNNER_CONTAINER" docker run --rm --pull=never \
--volume /opt/easyai-gateway-ci:/opt/easyai-gateway-ci:ro \
--entrypoint /bin/sh "$JOB_IMAGE" -ec '
export PATH=/opt/easyai-gateway-ci/bin:/opt/easyai-gateway-ci/toolchains/go/bin:/opt/easyai-gateway-ci/toolchains/node/bin:$PATH
go version
node --version
pnpm --version
docker-compose version
shellcheck --version
trivy --version
govulncheck -version
'
[ "$(docker exec "$RUNNER_CONTAINER" docker info --format '{{.DockerRootDir}}')" = /data/docker ] || \
fail "nested Docker daemon is not using its persistent dedicated data root"
docker exec "$RUNNER_CONTAINER" docker image inspect "$JOB_IMAGE" >/dev/null || \
fail "validated pinned job image is unavailable after runner activation"
if ! require_free_space "$MIN_POST_INSTALL_FREE_GIB" "completed CI runner installation"; then
fail "CI runner was stopped because the post-install disk reserve was not met"
fi