Skip to content

[TASK] Run CI containers with docker - #69

Merged
sbuerk merged 2 commits into
mainfrom
task/ci-run-containers-with-docker
Jul 30, 2026
Merged

[TASK] Run CI containers with docker#69
sbuerk merged 2 commits into
mainfrom
task/ci-run-containers-with-docker

Conversation

@sbuerk

@sbuerk sbuerk commented Jul 30, 2026

Copy link
Copy Markdown
Member

Why

GitHub hosted runners ship both podman and docker. Since 2026-07-29 their
podman/crun combination intermittently aborts the first container start of a
job
with

Error: OCI runtime error: crun: unknown version specified

exit code 126. It is independent of the job, the core version and the PHP
version, and a rerun on another host clears it. Neither the runner image nor the
TYPO3 testing image changed, so this is variance in the GitHub host fleet.

The change

Build/Scripts/runTests.sh prefers podman whenever it is present and only falls
back to docker. That default is correct for the script — podman-only machines
are exactly what it is built for — so it stays. The GitHub hosted runners are
the single place these workflows meet the broken combination, so the override
belongs in the workflows.

Every runTests.sh call now passes -b docker, with the reasoning in the
workflow header so the flag can be dropped knowingly once GitHub stops producing
the mismatch.

This mirrors what is already merged across the deepl* extension family, and
originates from fgtclb/academic-extensions.

Companion fixes

Selecting docker exposes defects that podman masked. Only the ones that apply to
this repository are included — see the summary below.

  • sqlite tmpfs mode=1777 — docker runs the container as
    --user $HOST_UID with group 0, while the tmpfs inherits the mode of its host
    mountpoint (0755 root:root at a runner's umask). No test database can be
    created, and every functional sqlite test fails with unable to open database file. Rootless podman is root inside its user namespace and passes no
    --user, which is why this never showed. mode=1777 fixes it for both
    runtimes and makes the suite umask-independent.
  • hardcoded -it — the documentation rendering run hardcoded -it on top of
    the interactivity the script already manages. docker rejects -t without a
    TTY, so that suite cannot run under docker in CI.
  • waitFor() readiness cap — the poll aborted after ~11 s. mysql:8.0
    needs 12–13 s to become ready under docker versus 7 s under podman, and
    mariadb 8.2 s. The cap is 60 s now. The abort itself also never fired in CI,
    because kill -SIGINT -$$ relies on a SIGINT trap that is only installed when
    CI is not "true" — so the suite ran against a database that was not
    listening and reported misleading Connection refused errors.

Applied here

  • -b docker on 39 runTests.sh calls across .github/workflows/testcore13.yml,
    .github/workflows/testcore14.yml, .github/workflows/documentation.yml,
    .github/workflows/publish.yml — 38 gained the flag, 1 already passed
    -b podman (documentation.yml) and was switched over.
    .github/workflows/testcore12.yml has no runTests.sh call and is untouched.
  • sqlite tmpfs mode=1777: yes
  • hardcoded -it removed: yes (renderDocumentation) — release-critical here,
    because publish.yml runs that suite to build the documentation artefact that
    is attached to the GitHub release
  • waitFor cap 11s -> 60s: yes (second commit)

sbuerk added 2 commits July 30, 2026 11:15
GitHub hosted runners ship both podman and docker. Since 2026-07-29
their podman/crun combination intermittently aborts the first container
start of a job with "OCI runtime error: crun: unknown version
specified" (exit code 126), independent of the job, the core version or
the PHP version. Neither the runner image nor the TYPO3 testing image
changed, and a rerun on another host clears it.

runTests.sh prefers podman whenever it is present and only falls back
to docker. That default is correct for the script and is kept, since
podman-only machines are exactly what it is built for. GitHub hosted
runners are the single place these workflows meet the broken
combination, so the override belongs in the workflows: every
"runTests.sh" call passes "-b docker" now, with the reasoning noted in
the workflow header so the flag can be dropped knowingly later.

Selecting docker exposes a second, unrelated defect. docker runs the
container as "--user $HOST_UID" with group 0, while the sqlite tmpfs
inherits the mode of its host mountpoint -- 0755 and owned by root at
the umask a runner uses. No test database can be created then, and
every functional sqlite test fails with "unable to open database file".
Rootless podman is root inside its user namespace and passes no
"--user", which is why this never showed before. The tmpfs is mounted
with "mode=1777" now, which docker needs, podman does not mind, and
which keeps the suite independent of the umask in use.

The documentation rendering container run hardcoded "-it" on top of the
interactive flags the script already manages. docker rejects "-t"
without a TTY, so that suite could not run once docker is selected. The
redundant flag is dropped: CI mode stays non-interactive, while local
runs keep the "-it --init" the script adds itself.
waitFor() capped the readiness poll at 11 iterations of "sleep 1", so
roughly 11 seconds. Measured against the same images, the time from
"run -d" until the port accepts connections is:

  mysql:8.0      podman 7.0-7.2s    docker 12.2-13.2s
  mariadb:10.4   podman 7.8s        docker 8.2s
  postgres:10    podman 1.3s        docker 1.5s

Only mysql crosses that limit, and only under docker, whose entrypoint
needs about twice as long to initialise a fresh data directory. The
workflows select docker now, so the functional mysql suites began to
abort intermittently. The cap is 60 seconds instead, which also leaves
mariadb a sensible margin.

The abort also did not abort. "kill -SIGINT -$$" relies on the SIGINT
trap, and that trap is only installed when CI is not "true". In CI the
kill was a no-op, so the script carried on and ran the test suite
against a database that was not listening, which then reported dozens
of "Connection refused" errors instead of the readiness timeout that
had actually occurred. waitFor() cleans up and exits directly now.
@github-actions

Copy link
Copy Markdown

Documentation rendering

You can find files attached to the below linked Workflow Run URL (Logs).

Please note that files only stay for around 5 days!

Name Link
Commit cc137e7
Logs https://github.com/web-vision/deepl-write/actions/runs/30530158291
Documentation https://github.com/web-vision/deepl-write/actions/runs/30530158291/artifacts/8754355660

@sbuerk
sbuerk merged commit 9b9ceb6 into main Jul 30, 2026
8 checks passed
@sbuerk
sbuerk deleted the task/ci-run-containers-with-docker branch July 30, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant