Files
cozystack/hack/e2e-compose.yaml
Myasnikov Daniil 186547d835 test(e2e): run the merge-gating lanes on Talos containers
The srv1-srv3 nodes of both lanes that gate a merge -- the same-repo one
in pull-requests.yaml and the fork one in e2e-fork.yaml -- run as Talos
containers instead of QEMU guests, so a tenant worker sits at L2 rather
than L3. Measured in CI on commits where both substrates ran the same
tree: whole-job wall clock down 24-49 minutes, essentially all of it in
Chainsaw, while the two tenant-Kubernetes suites go from 1143-2040s to
466-809s and stop depending on the runner's vgif flag.

The node-join soft-red gate goes with the substrate, which is what it
was for. It existed because nested virtualisation on the shared runners
degraded far enough that a worker registering in minutes elsewhere could
miss any deadline this test could afford; #3513 established that the
discriminator was the host's kvm_amd vgif flag, and removing a nesting
level removes what it acted on. So hack/e2e-node-join-soft-red.sh, the
SOFT-RED-node-join.txt marker and the soft_red job outputs are gone from
all four workflows, and a missed deadline is an ordinary red again. The
::warning annotation survives, because the reason a run went red should
be legible without opening the log, and so does the 124-versus-everything
-else test, because "the workers were slow" and "the wait never ran"
send a reader to different places.

Done by swapping the substrate inside the existing e2e jobs rather than
by promoting a separate container job. Those jobs carry more than a
substrate -- the GitHub App token, the report-overrun guard, the images
list, the SSH breakpoint -- and promoting a job that never had them
would have dropped four features without saying so.

Three properties of container mode drive the design, and each fails
quietly rather than loudly. machine.kernel.modules is a silent no-op --
kernel_module_spec.go returns early on ModeContainer with no error and
no event -- so the host loads openvswitch and zfs before the nodes start
and the workflow step asserts both rather than trusting them; a missing
module surfaces an hour later looking like a CNI or a storage
regression. Docker gives a privileged container its own tmpfs /dev
seeded once at creation, so /dev/kvm works but ZFS zvols created later
never appear and linstor-csi fails ControllerPublishVolume; the compose
file binds the host devtmpfs, which is also why talosctl cluster create
docker can never carry LINSTOR. And there is no ARP VIP, so
192.168.123.11 stands in for the QEMU lane's .10.

The QEMU machinery stays in the tree and keeps running: nightly.yaml and
e2e-tag.yaml still call `make prepare-env`, so DRBD, the replicated
StorageClass, its Immediate binding mode, the tenant StorageClass
propagation that only applies to remotely-accessible classes, and the
Cozystack Talos node image with its extensions all keep nightly and
release-candidate coverage. None of them is exercised per pull request
any more. That is the trade.

Nothing on the PR path builds or downloads a nocloud disk now, so
build-talos drops the talos-nocloud step and the talos-image artifact.
build-talos itself stays: finalize consumes its digest fragment.

One property this does not fix, recorded beside the runner class because
it will be read off a red run eventually: a container node reports the
HOST's CPU and memory as capacity, and hack/e2e-container-up.sh counters
that with kubelet systemReserved. That corrects the scheduler and not
what a pod reads from /proc, so a workload sizing itself from
/proc/cpuinfo or /proc/meminfo is configured for the whole runner.

Also carried here because the same files carry them: the ghcr.io
pull-through mirror removal (see #4007 -- whichever lands first makes the
other a no-op), the authoritative HelmRelease readiness gate, the
backup-credential preflight, the prepull guard against an image-less
container fragment, and folding the two standalone OIDC suites into the
latest-version tenant cluster.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-05 13:19:17 +05:00

144 lines
4.4 KiB
YAML

# Talos nodes as containers, the L2 half of the e2e substrate experiment.
#
# Sits beside hack/e2e-prepare-cluster.bats' QEMU guests rather than replacing
# them. Addressing, CPU and memory deliberately mirror that file so everything
# downstream -- the MetalLB 192.168.123.200-250 pool, hack/e2e-post-install-prep.sh,
# the chainsaw suites -- is unchanged between the two lanes.
#
# NOT `talosctl cluster create docker`: that wrapper forces a single control
# plane (it has --workers but no --controlplanes), has no --disks, and hides the
# container spec. Compose keeps three control planes, as today.
#
# The contract below comes from siderolabs/talos
# pkg/provision/providers/docker/node.go: PLATFORM/TALOSSKU/USERDATA, privileged,
# seccomp:unconfined, read_only, and the tmpfs + volume layout. Two mounts are
# NOT part of that contract and are mandatory anyway -- see the per-mount notes.
name: cozy-e2e
networks:
talos:
driver: bridge
ipam:
config:
- subnet: 192.168.123.0/24
gateway: 192.168.123.1
x-node: &node
image: ghcr.io/siderolabs/talos:v1.13.5@sha256:0535cf71b65c8c9fdb0b745e697be174bfe7394ecac7ccb2621caf4a606fc5a6
privileged: true
security_opt:
- seccomp:unconfined
read_only: true
stop_grace_period: 30s
# Matches the QEMU lane's `-smp 8 -m 24576` so neither lane is given more of
# the runner than the other. Talos reports host capacity in container mode;
# e2e-container-up.sh counterbalances that with dynamic kubelet reservations,
# and e2e-prepare-cluster-container.bats asserts the resulting allocatable.
cpus: ${COZY_E2E_NODE_CPUS:-8}
mem_limit: ${COZY_E2E_NODE_MEMORY_MIB:-24576}m
tmpfs:
- /run
- /system
- /tmp
environment: &node-env
PLATFORM: container
TALOSSKU: ${COZY_E2E_NODE_CPUS:-8}CPU-${COZY_E2E_NODE_MEMORY_MIB:-24576}RAM
USERDATA: ${USERDATA:?USERDATA must be set; hack/e2e-container-up.sh generates it}
# The two host binds every node repeats below, and why each is mandatory:
#
# /dev:/dev Docker gives a privileged container its own 64 MB tmpfs /dev,
# seeded ONCE at creation. /dev/kvm works because it exists at
# start, but ZFS zvols created later never appear, and
# linstor-csi then fails ControllerPublishVolume with "could
# not determine device path". Binding the host devtmpfs fixes
# it, and is why `talosctl cluster create docker` can never
# support LINSTOR.
#
# /run/udev The LINSTOR satellite hostPath-mounts it. In a container /run
# is tmpfs with no udev, so the pod hangs Init:0/1 on
# "hostPath type check failed: /run/udev is not a directory".
#
# Written out per service rather than shared through a YAML anchor: compose
# merges mappings but not sequences, so an anchored list nests instead of
# flattening and is rejected as "volumes.0 must be a string".
services:
srv1:
<<: *node
hostname: srv1
container_name: srv1
environment:
<<: *node-env
networks:
talos:
ipv4_address: 192.168.123.11
volumes:
- /dev:/dev
- /run/udev:/run/udev
- srv1-var:/var
- srv1-state:/system/state
- srv1-cni:/etc/cni
- srv1-k8s:/etc/kubernetes
- srv1-kubelet:/usr/libexec/kubernetes
- srv1-opt:/opt
srv2:
<<: *node
hostname: srv2
container_name: srv2
environment:
<<: *node-env
networks:
talos:
ipv4_address: 192.168.123.12
volumes:
- /dev:/dev
- /run/udev:/run/udev
- srv2-var:/var
- srv2-state:/system/state
- srv2-cni:/etc/cni
- srv2-k8s:/etc/kubernetes
- srv2-kubelet:/usr/libexec/kubernetes
- srv2-opt:/opt
srv3:
<<: *node
hostname: srv3
container_name: srv3
environment:
<<: *node-env
networks:
talos:
ipv4_address: 192.168.123.13
volumes:
- /dev:/dev
- /run/udev:/run/udev
- srv3-var:/var
- srv3-state:/system/state
- srv3-cni:/etc/cni
- srv3-k8s:/etc/kubernetes
- srv3-kubelet:/usr/libexec/kubernetes
- srv3-opt:/opt
volumes:
srv1-var: {}
srv1-state: {}
srv1-cni: {}
srv1-k8s: {}
srv1-kubelet: {}
srv1-opt: {}
srv2-var: {}
srv2-state: {}
srv2-cni: {}
srv2-k8s: {}
srv2-kubelet: {}
srv2-opt: {}
srv3-var: {}
srv3-state: {}
srv3-cni: {}
srv3-k8s: {}
srv3-kubelet: {}
srv3-opt: {}