Skip to content

perf(docker): share reactor build across images - #3171

Open
imbajin wants to merge 1 commit into
apache:masterfrom
hugegraph:perf/docker-build-bake
Open

perf(docker): share reactor build across images#3171
imbajin wants to merge 1 commit into
apache:masterfrom
hugegraph:perf/docker-build-bake

Conversation

@imbajin

@imbajin imbajin commented Aug 25, 2026

Copy link
Copy Markdown
Member

Summary

  • make the Maven build stage identical across PD, Store, HStore Server, and
    standalone Server
  • add a Buildx Bake graph that executes the source-revision-isolated reactor
    once and fans out four amd64/arm64 runtime images
  • export one shared registry cache instead of four duplicate per-image caches
  • keep individual Dockerfile builds supported and add CI guards for the shared
    stage and Bake graph

Companion publishing-workflow PR:
hugegraph/actions#27

Before → After

flowchart LR
    subgraph Before["Before: serial images, repeated heavy work"]
        direction LR
        B0["source"] --> B1["PD<br/>Maven reactor"]
        B1 --> B2["PD cache export"]
        B2 --> B3["Store runtime"]
        B3 --> B4["Store cache export"]
        B4 --> B5["HStore<br/>Maven reactor"]
        B5 --> B6["HStore cache export"]
        B6 --> B7["Standalone<br/>Maven reactor"]
        B7 --> B8["Standalone cache export"]
    end

    subgraph After["After: one heavy build, controlled fan-out"]
        direction LR
        A0["source"] --> A1["shared Maven reactor<br/>runs once"]
        A1 --> A2["PD runtime"]
        A1 --> A3["Store runtime"]
        A1 --> A4["HStore runtime"]
        A1 --> A5["Standalone runtime"]
        A1 --> A6["one shared<br/>cache export"]
        A2 --> A7["health + graph +<br/>Gremlin validation"]
        A3 --> A7
        A4 --> A7
        A5 --> A7
        A7 --> A8["ordered image push"]
    end
Loading

The optimization is deliberately not unrestricted parallelism. The expensive
native Maven reactor is deduplicated; only the lightweight runtime-image stages
fan out. Functional tests and final publication remain gated and ordered.

Performance

Baseline:
https://github.com/hugegraph/actions/actions/runs/32802972691

Scenario Candidate build Change Total Change
Before: serial baseline 29m14s 32m11s
After: Bake dry-run 5m30s −81.2% 7m54s −75.5%
After: first real publish 8m21s −71.4% 11m13s −65.1%

The real-publish measurement includes the first shared-cache preparation and
registry export, plus publication of all four multi-platform image indexes.

The baseline's 29m14s candidate-build step was distributed as follows:

Image Time Main reason
PD 9m20s full Maven reactor + runtime + cache export
Store 2m42s runtime work + separate cache export
HStore Server 9m27s divergent Maven reactor + runtime + cache export
Standalone Server 7m45s another Maven reactor + runtime + cache export

Core design

Concern Implementation
Build deduplication All four Dockerfiles use the same native build stage, allowing BuildKit to execute one Maven LLB node
Source correctness SOURCE_REVISION isolates the locked Maven cache so SNAPSHOT artifacts cannot leak across source revisions
Maven behavior All images use mvn install -Dmaven.test.skip=true, preserving the source-artifact correctness guard introduced in #3159
Safe parallelism Bake fans out runtime stages only after the shared build node
Cache writes One build-cache target exports hugegraph/hugegraph:shared-<channel>; runtime targets do not compete to write it
Upgrade compatibility The graph still reads the previous per-image caches during migration
Standalone compatibility Every Dockerfile remains directly buildable outside Bake
Regression prevention Docker CI verifies identical build stages and asserts the evaluated Bake target/platform/output contract

Validation

  • local fresh BuildKit build: one Maven reactor followed by parallel runtime
    targets
  • local repeated build: 51s with Maven/runtime layers cached
  • local multi-platform build: all four tags contain linux/amd64 and
    linux/arm64
  • local PD/Store/HStore Compose health checks and bundled example import:
    6V/6E
  • local Gremlin create/delete: 7V/7E, then restored to 6V/6E
  • local standalone /versions: API 0.71.0.0
  • dry-run end-to-end:
    https://github.com/hugegraph/actions/actions/runs/32808565083
    (7m54s total / 5m30s build; no cache export or push)
  • publishing end-to-end:
    https://github.com/hugegraph/actions/actions/runs/32809155691
    (11m13s total / 8m21s build including first shared-cache export)
  • Docker Build CI:
    https://github.com/apache/hugegraph/actions/runs/32819922901
    (Bake graph guard and all four standalone Dockerfile builds passed)
  • Docker Hub inspection confirmed amd64 and arm64 variants for all four
    published test indexes

Rollout and compatibility

The actions workflow uses this graph only when the selected source revision
contains docker-bake.hcl. Older releases and branches automatically keep the
existing serial per-Dockerfile path, so merging either PR first is safe. Merging
this source PR first enables the fast path as soon as the companion actions PR
lands.

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. ci-cd Build or deploy perf labels Aug 25, 2026
@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 37.44%. Comparing base (0951d45) to head (c522d73).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3171      +/-   ##
============================================
+ Coverage     37.42%   37.44%   +0.01%     
- Complexity     6441     6444       +3     
============================================
  Files           800      800              
  Lines         68595    68595              
  Branches       9100     9100              
============================================
+ Hits          25674    25682       +8     
+ Misses        39906    39900       -6     
+ Partials       3015     3013       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@imbajin
imbajin force-pushed the perf/docker-build-bake branch 3 times, most recently from 085106c to 8954c99 Compare August 25, 2026 06:25

@bitflicker64 bitflicker64 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independently re-verified the core claims. The build stage is byte-identical across all four Dockerfiles at c522d73 (no pre-FROM ARGs, single root .dockerignore), SOURCE_REVISION reaches every Bake target and expands in the cache mount id at runtime, and only the build-cache target writes the shared cache. The timing table matches raw job-step timestamps from the linked hugegraph/actions runs: 1754s -> 330s (dry-run) / 501s (first publish) on the same runner class, with the Maven stage fully rebuilt in both candidate runs. Those runs built 89a2586, whose Dockerfiles and docker-bake.hcl are byte-identical to this head; the strengthened CI guard is covered by the Docker Build CI run on the head itself. Ran buildx bake --print locally: the jq assertion fails on platform or output mutations, and the awk stage-diff catches a divergent mvn line. One hardening nit inline; non-blocking.

Two observations, no action needed in this PR:

  • The per-module buildcache-* refs are read but no longer refreshed on the Bake path, so runtime-stage layers will slowly go stale and eventually rebuild each run. If that ever shows in timings, runtime targets could export a cache gated on EXPORT_CACHE.
  • Local builds share id=hugegraph-maven-local across revisions, and mvn install writes SNAPSHOTs into that shared .m2. A full-reactor build resolves modules from the reactor, so the practical risk is low; worth a doc line at most.

' "$1"
}

reference="hugegraph-pd/Dockerfile"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the stage header ever changes casing or name (as build is valid Dockerfile syntax), extract_build_stage returns empty for every file and the diffs pass vacuously, so the guard silently stops guarding. Reproduced this: rewriting AS build to as build in all four files makes the check pass even with divergent mvn lines. A partial rename is still caught. Cheap fix: assert the reference extraction is non-empty first.

Suggested change
reference="hugegraph-pd/Dockerfile"
reference="hugegraph-pd/Dockerfile"
[ -n "$(extract_build_stage "$reference")" ] || {
echo "ERROR: no 'AS build' stage found in $reference; guard would pass vacuously"
exit 1
}

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The default multi-platform Bake graph configures every runtime target to use the single-platform Docker exporter, so it cannot produce the claimed amd64/arm64 images. Evidence: docker buildx bake --print at c522d73 expands the runtime targets with platforms=[linux/amd64,linux/arm64] and output type=docker; the Docker exporter supports single-platform results.

Comment thread docker-bake.hcl
inherits = ["_common"]
dockerfile = "hugegraph-pd/Dockerfile"
tags = ["hugegraph/pd:${IMAGE_TAG}"]
output = ["type=docker"]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

‼️ critical — _common supplies both linux/amd64 and linux/arm64, but this target fixes the output to type=docker (and the other three runtime targets do the same). Buildx's Docker exporter only writes a single-platform image; with these two platforms the target cannot export the required manifest list, so the default Bake group cannot build the claimed multi-platform images. Please use a multi-platform-capable registry/image exporter for the publishing graph, or split out a single-platform local target, and make the CI guard validate the actual export contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cd Build or deploy perf size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants