2 Commits
Author SHA1 Message Date
jklein b0eca80b2a probe: both charts, both code paths
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Successful in 7s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Successful in 5s
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Successful in 12s
Validate Helm Charts / Install-test ${{ fromJSON(needs.detect-changed-charts.outputs.install-charts) }} (pull_request) Failing after 5m32s
Workflow byte-identical to PR #253. cyberchef and freesailarr in the
matrix; this same branch also goes to GitHub as a throwaway PR, so the
containerised and the host branch of the cluster-creation step are both
exercised.
2026-09-17 00:29:20 +02:00
jklein 31e4260580 install-test: reach the k3d cluster when the job itself is a container
Closes the last gap from #227. k3d publishes the API server port on the
Docker HOST. On GitHub's hosted runners the job is that host, so the
https://0.0.0.0:<port> k3d writes into the kubeconfig works. Every Gitea
Actions job is itself a container, and there the host is the dind
container: 0.0.0.0 points at the job container, where nothing listens.
The cluster comes up cleanly and the first kubectl call is refused - as
measured, surfacing two steps later as a validation error on the
fixtures, which named nothing useful.

The case is decided on whether THIS job runs in a container, not on
which forge it runs on. github.server_url would pick the right branch
today and still be wrong: a self-hosted GitHub runner in a container has
the identical problem, and a condition that says GitHub while meaning
not-containerised is the kind of lie this repo exists to remove. The
detection is the same question the fix needs answered anyway - ask the
daemon about ourselves. In a container it returns our network, k3d joins
it, and Docker's DNS resolves the node names; on a host it returns
nothing and the previous path is taken unchanged.

kubectl cluster-info and get nodes now run inside the create step, so a
cluster that is up but unreachable fails where it is caused instead of
two steps downstream.
2026-09-17 00:29:08 +02:00
+49 -1
View File
@@ -404,7 +404,55 @@ jobs:
echo "::error::chart name '$CLUSTER' is ${#CLUSTER} characters and k3d allows at most 32 for a cluster name."
exit 1
fi
k3d cluster create "$CLUSTER" --image "$K3S_IMAGE" --wait --timeout 180s
# Does THIS job run inside a container? That, and not which forge we
# are on, is what decides whether k3d's cluster is reachable (#227).
#
# k3d publishes the API server port on the Docker *host*. When the
# job runs straight on the host - GitHub's hosted runners - that is
# the same machine, and the "https://0.0.0.0:<port>" k3d writes into
# the kubeconfig works. When the job itself is a container, as every
# Gitea Actions job is, the host is the dind container and 0.0.0.0
# points at the job container itself, where nothing listens. The
# cluster comes up fine and the first kubectl call is refused.
#
# Deliberately NOT keyed on github.server_url, although that would
# pick the right branch today: a self-hosted GitHub runner in a
# container has exactly this problem, and a condition that says
# "GitHub" while meaning "not containerised" is the kind of lie this
# repo exists to remove. So the state is detected instead of
# inferred, and the detection is the same question the fix needs
# answered anyway: ask the daemon about ourselves. Inside a
# container that the daemon knows, this returns our network and k3d
# joins it, which puts k3s and this job on one bridge where Docker's
# own DNS resolves the container names. On a host it returns nothing,
# because the hostname is not a container, and the old path is taken
# unchanged.
# The "|| true" is load-bearing: this step runs under `bash -e -o
# pipefail`, and on a host `docker inspect` exits non-zero, which
# would abort the step instead of taking the else branch.
JOB_NET="$(docker inspect -f '{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}' "$(hostname)" 2>/dev/null | awk '{print $1}' || true)"
if [ -n "$JOB_NET" ]; then
echo "Containerised job: $(hostname) on docker network '$JOB_NET' - k3d joins it."
k3d cluster create "$CLUSTER" --image "$K3S_IMAGE" --network "$JOB_NET" --wait --timeout 180s
# Same reason: the published port is useless from in here, so the
# kubeconfig is pointed at the load balancer container by name,
# over the shared network. If the API server certificate did not
# carry that name this would fail on the TLS handshake and the
# cluster-info below would say so - it holds without an extra
# --tls-san, measured on the probe PR of #225.
kubectl config set-cluster "k3d-$CLUSTER" --server="https://k3d-$CLUSTER-serverlb:6443"
else
echo "Job runs on the docker host - k3d's published port is reachable as written."
k3d cluster create "$CLUSTER" --image "$K3S_IMAGE" --wait --timeout 180s
fi
# Proves reachability here rather than letting it surface two steps
# later as a validation error on the fixtures, which is where it
# showed up before and named nothing useful.
kubectl cluster-info
kubectl get nodes
# Every chart reaching this step is one the exclusion filter let through,
# so the script's SKIP branch is never taken here - it exists for local
# runs. The variables below are empty for every chart but the one that