Repository navigation
Also use the GitHub Actions cache for CI builds - #446
Conversation
|
I re-ran the CI to check that a run can read the GitHub Actions cache written by an earlier run (attempt 2 of run 37440875854). Result: no The PHP 8.3 and 8.4 jobs have no registry cache, since
The few remaining
This shows the gha cache is read back between runs. It doesn't prove yet that the intermittent misses from #430 are gone, since they were random. We'll see over the next runs. |
The registry cache is regularly missed for some layers of the builder image in the CI, silently falling back to a full rebuild (#430). The "ci" context now loads docker-compose.ci.yml, which adds the GitHub Actions cache backend (type=gha) to the frontend and builder images: every CI build reads it and writes it back, with one scope per service and PHP version. The registry cache is kept, it is still needed for local development, and stays the one pushed by "castor docker:push". buildx needs the GitHub runtime to reach this cache, which GitHub only gives to JavaScript actions: a local, dependency-free action (.github/actions/expose-github-runtime) exposes it to the next steps, and selects the v2 cache API. Without it (outside GitHub Actions), buildx silently ignores the type=gha entries. Co-authored-by: Damien Alexandre <dalexandre@jolicode.com>
|
Update: no more external dependency. It re-exports to the next steps the variables buildx needs to reach the GitHub Actions cache ( All of this comes from @damienalexandre's investigation, he's co-author of the commit. Thanks Damien! |
damienalexandre
left a comment
There was a problem hiding this comment.
Reviewed with fresh battle scars from a downstream project where we validated the same mechanics — including the two traps this PR already handles.
Verified working (from this PR's own runs):
- The
CASTOR_CONTEXT: ciworkflow env selects the ci context, sodocker-compose.ci.ymlis loaded: the latest run showsimporting cache manifest from gha:...for both services, builder layersCACHED, and two successive runs went 1m54 -> 1m15. The import side works. - The per-service + per-PHP-version
scopeentries are required here: without them, the three matrix jobs would share the default scope and overwrite each other's cache (last writer wins). Good catch. - The
push()analysis is correct: the mergedcache_fromkeeps the registry entry at index 0, and--set cache-toreplaces the ghacache_toduring the push bake, so the registry cache for local dev is preserved. We verified the same mechanics downstream. - The local action +
ACTIONS_CACHE_SERVICE_V2=truematches what we found: without the v2 flag, buildx selects the legacy cache API (build/opt.goaddGithubToken()) and every import/export fails with an opaque HTTP 400 ("Our services aren't available right now"). Dependency-free and in-repo is the right call for a token handler. - Docs (README + CHANGELOG) look good.
Suggestions (none blocking):
- Downstream footgun: this only works because the workflow sets
CASTOR_CONTEXT: ci. Generated projects often don't — we run the CI with the default context, so there we hook the compose file onGITHUB_ACTIONSin the default context instead. Consider either that variant or a README warning, since the template gets copied around and the failure mode is a silent no-op. routeris not covered: itsCOPY traefik+sedlayers rebuild on every run (~5-10s).worker_messengeris a bareFROM php-base AS workerso there is nothing extra to cache, butrouteris cheap to add.index.cjswrites single-lineNAME=valueentries to$GITHUB_ENV: fine for these values (tokens and URLs are single-line), but if the file ever gets reused for other variables, the heredoc format (NAME<<DELIM ... DELIM) is the defensive form.ignore-error=trueoncache_to: reasonable default, with a known trade-off — a failing export becomes invisible and the cache just goes stale. It can only cause misses, never wrong layers (records match by content hash), so it is acceptable.- Explicit scopes are branch-agnostic: PR runs write the same keys as
main, so a PR can overwrite the cachemainreads. Same conclusion as above: worst case is a miss, never corruption. Fine, just worth knowing.
One extra data point from the same downstream project (out of scope here): once the layers are reliably cached, the remaining CI time went to the dependency installs, which we additionally cache with actions/cache (PHP vendors + tools node_modules, keyed on the lockfiles). That is downstream-project territory, but worth a README note someday.
Refs #430
The registry cache (
type=registry,mode=max) is regularly missed for some layers of thebuilderimage in the CI: no error and no warning, BuildKit just rebuilds the layer and everything after it.As suggested in the issue, CI builds now also use the GitHub Actions cache backend (
type=gha):infrastructure/docker/docker-compose.ci.yml, loaded by thecicontext. It adds atype=ghacache_fromandcache_to(mode=max,ignore-error=true) tofrontendandbuilder. Each service and PHP version gets its ownscope, otherwise they overwrite each other.ci.ymlexposes the GitHub runtime (ACTIONS_RUNTIME_TOKEN,ACTIONS_RESULTS_URL) withcrazy-max/ghaction-github-runtime, which buildx needs to reach this cache from arun:step.castor docker:pushstill pushes it: the gha entries are appended after the registry one, and its--set cache-toreplaces the ghacache_to.Outside GitHub Actions (e.g.
castor -c ci startlocally), buildx silently skipstype=ghaentries when there is no token (isActive()in buildxbuild/opt.go), so nothing breaks.Side effect: the PHP 8.3 and 8.4 matrix jobs now get a cache too. The registry cache is only pushed for 8.5.