Skip to content

ci: move the shipped binaries to AlmaLinux 8, get the test images off EOL Debian - #790

Open
rkennke wants to merge 4 commits into
mainfrom
ci/bump-eol-base-images
Open

rkennke wants to merge 4 commits into
mainfrom
ci/bump-eol-base-images

Conversation

@rkennke

@rkennke rkennke commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Spun out of the CI investigation on #786. Gets the GitLab pipeline off end-of-life base images, and moves the shipped binaries onto a toolchain that still receives security rebuilds.

Root cause of the current failures

bullseye-security's pool files have been pruned upstream while the index still advertises them — Debian 11 left LTS on 2026-08-31. So apt-get update succeeds and apt-get install then 404s on the individual .debs:

E: Failed to fetch http://deb.debian.org/debian-security/pool/updates/main/g/glibc/libc6-dev_2.31-13+deb11u14_amd64.deb  404  Not Found
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?

Reproduced outside CI, straight from Fastly with no proxy in the path, so it is neither the fabric egress gateway nor a stale mirror. The +deb11uNN versions and glibc 2.31 also identify the running image as bullseye.

Bullseye cannot be rescued in place: bullseye-security is not published on archive.debian.org under either its own name or the older bullseye/updates name, and the main archive alone leaves held broken packages. A bullseye image can no longer even be rebuilt, since its own apt-get install layer fails. Verified: the job's exact package list installs cleanly on trixie.

Why the shipped-binary image matters more than it looks

Release builds link -static-libstdc++ -static-libgcc (ConfigurationPresets.kt:121-122), so the C++ runtime and unwinder in the shipped libjavaProfiler.so come out of the build image's toolchain. The build image's support status is therefore a property of the artifact, not just of CI.

On CentOS 7 those objects can never get another security rebuild. Worse for consistency: no gcc newer than devtoolset-10 was ever built for aarch64 anywhere in the EL7 ecosystem — the dts-11 collection ships binutils 2.36.1, elfutils, dwz and its own toolchain metapackage for aarch64, but no compiler. Confirmed against CentOS vault altarch, Oracle's SCL repo and the CentOS SIG buildlogs. Oracle Linux 7 is the best-maintained EL7 derivative (live CDN, both arches, working collections) but its public repos sit at the same 7.9 package levels, with later content behind an ELS subscription.

Changes

1. Shipped binaries: AlmaLinux 8 + gcc-toolset-14, both arches — new .gitlab/base/el8/Dockerfile, replacing .gitlab/base/centos7/Dockerfile and its vault.centos.org / Rocky-mirror repository plumbing. Supported until 2029, and the toolset is published for x86_64 and aarch64 alike, so one image definition covers both architectures with one compiler version. almalinux:8 is a multi-arch OCI index (amd64, arm64, ppc64le, s390x), so a single BASE_IMAGE_GLIBC digest serves both.

2. Test/tooling images: Debian 13 trixie, both arches. With the shipped arm64 build moved off the Debian image, that image no longer sets a customer-facing floor, so it moves to current stable alongside amd64 — which is what restores apt on the arm64 sanitizer jobs.

3. The archived buster default is gone with centos7/Dockerfile. It defaulted to openjdk:11-slim-buster; buster's repos are archived (does not have a Release file) and rebuild-images.sh reaches that default whenever the base-image variable is unset, since it only log_warns.

4. .gitlab/base/Dockerfile: no more swallowed install failures. Both the apt-get install and apk add lines ended in || true, so a total package-install failure produced a "successful" image whose tools were simply missing. The apk branch was dead — Alpine/musl has its own Dockerfile.musl.

5. Names describe purpose, not a version that has now changed twice: BUILD_IMAGE_{X64,ARM64}_GLIBC, BASE_IMAGE_GLIBC, tag suffixes {x64,arm64}-glibc-base.

The glibc floor: measured, not assumed

The real profiler was built inside the new image on genuine x86_64 and aarch64, and the artifact inspected:

x86_64 aarch64
max required symbol version GLIBC_2.27 GLIBC_2.27
symbols above 2.17 expf (2.27), getentropy (2.25) same
dynamic dependencies libc, libdl, libm, libpthread, librt same
GLIBCXX / CXXABI references none none

The floor moves 2.17 → 2.27, not to the base image's 2.28 — symbol versions are per-function, so building on glibc 2.28 does not make the artifact require 2.28. No libstdc++ dynamic dependency, confirming the static link still works with the toolset's own libstdc++.a.

platform glibc under a 2.27 floor
Ubuntu 18.04 LTS (ESM to 2028) 2.27 still supported — exactly at the boundary
Amazon Linux 2 (EOL Jun 2026) 2.26 dropped
SLES 15 SP1 2.26 dropped
RHEL/CentOS 7 (EOL Jun 2024) 2.17 dropped

Amazon Linux 2 is the only meaningful casualty, and it is not forced: both binding symbols are addressable with a .symver pin (expf → an older version, getentropy → a direct SYS_getrandom syscall) if a lower floor is needed. Do not "fix" expf by switching to double exp, which carries its own GLIBC_2.29 version.

This floor change needs a decision, and is the one thing here that reaches customers. Everything else is CI-internal.

Images rebuilt and repinned

The images were rebuilt from this branch's definitions in pipeline 137281788 and the digests are pinned here. Each was verified by pulling it:

pin contents
x64-glibc-base, arm64-glibc-base AlmaLinux 8.10, glibc 2.28, gcc 14.2.1
x64-base, arm64-base Debian 13 trixie, glibc 2.41, clang 19.1.7

The musl, datadog-ci and benchmark images come from the same rebuild; their definitions are unchanged on this branch.

For the record on why the pins are here rather than in the image-update PR that rebuild opened against main (#791, closed): main has no BUILD_IMAGE_*_GLIBC variables, so the two shipped-binary pins silently did nothing there, while BUILD_IMAGE_ARM64 — which main still uses for build:arm64 and stresstest:arm64 — would have moved the shipped arm64 binary onto a trixie image and its glibc 2.41 floor.

Worth knowing for the future: the pins live in this repo, and every rebuild creates new pipeline-ID-prefixed tags rather than overwriting old ones, so rebuilding affects no branch until a repin is merged.

Verified locally

  • .gitlab/base/el8/Dockerfile builds for both platforms; gcc-toolset-14 provides libstdc++.a/libgcc.a, the profiler's exact link flags succeed, and jq needs no EPEL.
  • ./gradlew :ddprof-lib:buildRelease succeeds inside the image on both architectures, and the measurements above come from those artifacts.
  • buster's apt repos fail as described; bullseye's install fails as described; trixie's succeeds.

Also noticed, not changed

  • DOCKER_IMAGE: …/images/docker:24.0.4-gbi-focal (images.yml) is Ubuntu 20.04, past standard support since April 2025. Left alone because I cannot enumerate replacement tags in that ECR registry.
  • .gitlab/fuzzing/.gitlab-ci.yml:20 and .gitlab/jdk-integration/.gitlab-ci.yml:32 also apt-get install at job time, so they depend on a live archive on every run, exactly as the sanitizer jobs do. Moving those packages into the images would make the pipeline independent of archive availability.
  • GitHub Actions is unaffected: ubuntu-latest/ubuntu-22.04 runners and alpine:3.23 containers are all still supported.

🤖 Generated with Claude Code

@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Pipelines

Unblock PR with BitsAI

⚠️ Warnings

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 2 Pipeline jobs failed

DataDog/java-profiler | integration-test-x64-musl: [openj9, 21] — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

DataDog/java-profiler | post-pr-comment — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 7bfc401 | Docs | View more details | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Scan-Build Report

User:runner@runnervmlun5p
Working Directory:/home/runner/work/java-profiler/java-profiler/ddprof-lib/src/test/make
Command Line:make -j4 all
Clang Version:Ubuntu clang version 18.1.3 (1ubuntu1)
Date:Mon Sep 14 15:37:22 2026

Bug Summary

Bug TypeQuantityDisplay?
All Bugs1
Logic error
Dereference of null pointer1

Reports

Bug Group Bug Type ▾ File Function/Method Line Path Length
Logic errorDereference of null pointerfaultInjection.cppcrashNow242

The x64-2.17 image's Dockerfile defaulted to openjdk:11-slim-buster. Debian 10
buster left even LTS support in June 2024 and its repositories are archived, so
`apt-get update` against them now fails with "does not have a Release file" --
and rebuild-images.sh builds without --build-arg BASE_IMAGE whenever
BASE_IMAGE_LIBC_2_17 is unset, which reaches that default. The body of the file
is yum-based, so a Debian base cannot work there at all; the default now names
what CI actually passes (centos:7), with the glibc 2.17 rationale for staying
on an EOL distro recorded next to the vault mirror URLs it already needs.

The amd64 build image moves to Debian 13 trixie, the current stable release.
It compiles no shipped native code -- build:x64 uses the glibc 2.17 image -- so
its glibc is not a customer-facing floor. The arm64 image stays on bullseye: it
is where build:arm64 compiles the shipped linux-arm64 libjavaProfiler.so, so
that glibc (2.31) is the runtime floor for arm64 customers and trixie would
raise it to 2.41. Both variables now say which of the two they are and why.

Also drop the `|| true` from the base image's package install, and with it the
dead `apk` branch -- Alpine has its own Dockerfile.musl. As written, a total
install failure produced a "successful" image whose tools were simply missing,
surfacing later as an unrelated job failure.

Verified against the real archives: buster's apt repositories fail as
described, bullseye's still resolve, and the full package list installs on
trixie with hexdump present (bsdmainutils is still a real package there).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rkennke
rkennke force-pushed the ci/bump-eol-base-images branch from bd98bb8 to 5386860 Compare September 14, 2026 10:15
@dd-octo-sts

dd-octo-sts Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

CI Test Results

Run: #34863155419 | Commit: 811585c | Duration: 14m 55s (longest job)

All 32 test jobs passed

Status Overview

JDK glibc-aarch64/debug glibc-amd64/debug musl-aarch64/debug musl-amd64/debug
8 - - -
8-ibm - - -
8-j9 - -
8-librca - -
8-orcl - - -
11 - - -
11-j9 - -
11-librca - -
17 - -
17-graal - -
17-j9 - -
17-librca - -
21 - -
21-graal - -
21-librca - -
25 - -
25-graal - -
25-librca - -

Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled

Summary: Total: 32 | Passed: 32 | Failed: 0


Updated: 2026-09-14 15:53:19 UTC

Release builds link -static-libstdc++ -static-libgcc, so the C++ runtime and
unwinder in the shipped libjavaProfiler.so come out of the build image's
toolchain. That makes the build image's support status a property of the
artifact, not just of CI: on CentOS 7 those objects can never receive another
security rebuild, and no gcc newer than devtoolset-10 was ever built for
aarch64 there (the dts-11 collection ships binutils, elfutils and its own
metapackage for aarch64, but no compiler).

AlmaLinux 8 with gcc-toolset-14 is supported until 2029 and publishes the
toolset for x86_64 and aarch64 alike, so one image definition now covers both
architectures with one compiler version, replacing the hand-rolled CentOS 7
image and its vault/Rocky mirror repositories. almalinux:8 is a multi-arch
manifest, so a single BASE_IMAGE_GLIBC serves both.

Measured on the real artifact, built in this image for both architectures:

  max required symbol version   GLIBC_2.27  (both x86_64 and aarch64)
  symbols above 2.17            expf (2.27), getentropy (2.25)
  dynamic dependencies          libc, libdl, libm, libpthread, librt
  GLIBCXX/CXXABI references     none

So the runtime floor moves 2.17 -> 2.27, not to the base image's 2.28: symbol
versions are per-function. 2.27 keeps Ubuntu 18.04 (glibc 2.27) in support and
drops RHEL 7 (2.17), Amazon Linux 2 (2.26) and SLES 15 SP1 (2.26). Both
symbols are addressable with a .symver pin if a lower floor is needed later.

With the shipped arm64 build moved off the Debian image, that image no longer
sets a customer-facing floor, so it moves to trixie alongside amd64 -- which
also restores apt on the arm64 sanitizer jobs.

Names now describe the purpose rather than a version that has changed twice:
BUILD_IMAGE_{X64,ARM64}_GLIBC and BASE_IMAGE_GLIBC, with tag suffixes
{x64,arm64}-glibc-base. The variables still hold the current images until
rebuild-images.sh publishes the new tags.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rkennke rkennke changed the title ci: drop the archived buster base default, bump the amd64 build image ci: move the shipped binaries to AlmaLinux 8, get the test images off EOL Debian Sep 14, 2026
rkennke and others added 2 commits September 14, 2026 16:25
The sanitizer jobs installed cmake, libgtest-dev, libgmock-dev, binutils,
libc6-dbg and llvm in a before_script, which made every run depend on the
distro archive still serving them, and which does not survive the move to
trixie: sanitizer/asan_interface.h is no longer part of the llvm package
there, so compiling linearAllocator.cpp fails with

  fatal error: 'sanitizer/asan_interface.h' file not found

The header comes from libclang-rt-<n>-dev. The packages now live in the image
instead, using the unversioned libclang-rt-dev metapackage so the right clang
runtime is picked up on whatever release the image is built from.

Dropping the before_script override also stops these jobs bypassing the
pipeline default, so they get the CANCELLED guard and the maven proxy export
that every other job already had.

Verified on a locally built trixie image (clang 19.1.7, gtest 1.16.0),
aarch64: buildGtestAsan and buildGtestTsan both compile, and all 62 asan and
62 tsan binaries pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pins from the rebuild in pipeline 137281788, which built every image from the
definitions on this branch. Verified by pulling each digest:

  x64-glibc-base    AlmaLinux 8.10, glibc 2.28, gcc 14.2.1
  arm64-glibc-base  AlmaLinux 8.10, glibc 2.28, gcc 14.2.1
  x64-base          Debian 13 trixie, glibc 2.41, clang 19.1.7
  arm64-base        Debian 13 trixie

The musl, datadog-ci and benchmark images come from the same rebuild; their
definitions did not change on this branch.

These pins belong here rather than in the image-update PR the rebuild opened
against main: main has no BUILD_IMAGE_*_GLIBC variables, so the two
shipped-binary pins silently did nothing there, while BUILD_IMAGE_ARM64 -- which
main still uses for build:arm64 and stresstest:arm64 -- would have moved the
shipped arm64 binary onto a trixie image and its glibc 2.41 floor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dd-octo-sts

dd-octo-sts Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

39 passed, 1 failed out of 40 configurations

Test Matrix

Platform JDK 8 JDK 11 JDK 17 JDK 21 JDK 25
glibc-x64-hotspot
glibc-x64-openj9
glibc-arm64-hotspot
glibc-arm64-openj9
musl-x64-hotspot
musl-x64-openj9
musl-arm64-hotspot
musl-arm64-openj9

Failure Details

musl-x64-openj9-jdk21

Tracer+profiler:

"  This may indicate tracer is not capturing any requests"
""
"[7/8] Checking for unexpected events..."
"  ✓ No unexpected events found"
""
"[8/8] Scenario-specific validation (ddprof_with_tracer)..."
"  Validating tracer+profiler scenario..."
"  ✓ Tracer+profiler scenario checks passed"
""
"=== Validation Summary ==="
"ExecutionSample:            0.0 events (datadog.ExecutionSample)"
"Stack traces:               0.0 samples"
"Thread diversity:           0.0 threads"
"Allocation samples:         0 events (jdk.ObjectAllocationSample)"
"ThreadAllocationStatistics: 52 events"
""
"VALIDATION_FAILED: One or more checks did not pass"

Script executed successfully: 425 commands
VALIDATION_FAILED: Validation checks did not pass

Links

@rkennke
rkennke marked this pull request as ready for review September 14, 2026 17:16
@rkennke
rkennke requested a review from a team as a code owner September 14, 2026 17:16

@datadog-datadog-prod-us1 datadog-datadog-prod-us1 Bot 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.

Datadog Autotest: PASS

More details

The CI jobs and rebuild scripts use consistent new image names. The Bullseye fallback already fails on the base branch, so it is not a regression from this PR.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Datadog Autotest · Commit 7bfc401 · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7bfc40165c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .gitlab/base/Dockerfile
Comment on lines +1 to +4
# CI always passes BASE_IMAGE explicitly (OPENJDK_BASE_IMAGE /
# OPENJDK_BASE_IMAGE_ARM64), and the two arches deliberately differ -- see the
# comments on those variables. This default is the more conservative of the
# two so a hand-built image matches the arm64 glibc floor.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update the default Debian base along with the CI pins

When this Dockerfile is built directly, or when .gitlab/scripts/rebuild-images.sh reaches its documented unset-variable fallback, BASE_IMAGE still resolves to the Bullseye digest on line 5 rather than the new Trixie image. The added comment is therefore incorrect—both CI architecture variables now use Trixie—and, because this commit also makes the package installation fatal, the fallback encounters the same unavailable Bullseye packages this change is intended to avoid. Update the default to the pinned Trixie base or require BASE_IMAGE explicitly.

AGENTS.md reference: AGENTS.md:L450-L454

Useful? React with 👍 / 👎.

@@ -0,0 +1,37 @@
# Build image for the shipped glibc binaries, both architectures.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add required copyright notices to touched files

This newly added Dockerfile has no Datadog copyright notice; the other non-deleted files modified by this commit likewise lack one. Add the required current-year Datadog notice to each touched file before merging.

AGENTS.md reference: AGENTS.md:L382-L384

Useful? React with 👍 / 👎.

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