This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-graalvm-distro.git
The following commit(s) were added to refs/heads/main by this push:
new e7946e2 Native distro packaging, Docker image, and CI pipeline
e7946e2 is described below
commit e7946e270ccedc7ae816e6356007fce216c7fbe9
Author: Wu Sheng <[email protected]>
AuthorDate: Tue Feb 24 16:31:30 2026 +0800
Native distro packaging, Docker image, and CI pipeline
- Add native assembly descriptor (binary + config + logs)
- Add Dockerfile.native for packaging pre-built native binary
- Merge CI and Docker workflows: shared skywalking submodule cache
- Build multi-arch Docker image (amd64 + arm64) to ghcr.io
- Fix javadoc error in FieldsHelper (MethodHandle#invoke reference)
---
.dockerignore | 20 +++
.github/workflows/ci.yml | 163 ++++++++++++++++++++-
Makefile | 16 +-
docker/Dockerfile.native | 47 ++++++
oap-graalvm-native/pom.xml | 18 +++
.../src/main/assembly/native-distribution.xml | 86 +++++++++++
.../oap/server/library/util/FieldsHelper.java | 2 +-
7 files changed, 344 insertions(+), 8 deletions(-)
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..92a6d8b
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,20 @@
+# IDE and OS
+.idea/
+*.iml
+.vscode/
+.DS_Store
+
+# Claude Code
+.claude/
+
+# Git
+.git/
+
+# Exclude everything except the native distro tarball and docker context
+skywalking/
+build-tools/
+oap-graalvm-server/
+oap-libs-for-graalvm/
+
+# Allow native distro tarball through
+!oap-graalvm-native/target/oap-graalvm-native-*-native-dist.tar.gz
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 13bc159..c14c0cb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -20,11 +20,15 @@ on:
branches: [ main ]
pull_request:
branches: [ main ]
+ workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
+env:
+ IMAGE: ghcr.io/apache/skywalking-graal-distro
+
jobs:
license-header:
name: License Header Check
@@ -36,10 +40,12 @@ jobs:
- name: Check license headers
uses: apache/skywalking-eyes/header@main
- build-graal-jvm-distro:
- name: Build GraalVM JVM Distro
+ # ── Shared: build skywalking submodule and cache .m2/repository ──
+ build-skywalking:
+ name: Build SkyWalking Submodule
runs-on: ubuntu-latest
-
+ outputs:
+ cache-key: ${{ steps.cache-key.outputs.key }}
steps:
- name: Checkout with submodules
uses: actions/checkout@v4
@@ -51,12 +57,46 @@ jobs:
with:
java-version: '25'
distribution: 'graalvm'
- cache: 'maven'
+
+ - name: Compute cache key
+ id: cache-key
+ run: echo "key=m2-skywalking-$(git -C skywalking rev-parse HEAD)" >>
"$GITHUB_OUTPUT"
+
+ - name: Restore Maven cache
+ id: cache
+ uses: actions/cache@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ steps.cache-key.outputs.key }}
- name: Build SkyWalking submodule
+ if: steps.cache.outputs.cache-hit != 'true'
run: make build-skywalking
- - name: Style check + Compile + Install
+ # ── CI: compile, javadoc, test, distro ──
+ ci:
+ name: Build & Test
+ runs-on: ubuntu-latest
+ needs: build-skywalking
+ steps:
+ - name: Checkout with submodules
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Set up GraalVM JDK 25
+ uses: graalvm/setup-graalvm@v1
+ with:
+ java-version: '25'
+ distribution: 'graalvm'
+
+ - name: Restore Maven cache
+ uses: actions/cache/restore@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ needs.build-skywalking.outputs.cache-key }}
+
+ - name: Compile & Install
run: make compile
- name: Javadoc
@@ -67,3 +107,116 @@ jobs:
- name: Build distribution
run: make build-distro
+
+ # ── Native image build per architecture ──
+ build-native:
+ name: Native ${{ matrix.arch }}
+ runs-on: ${{ matrix.runner }}
+ needs: build-skywalking
+ if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ strategy:
+ matrix:
+ include:
+ - arch: amd64
+ runner: ubuntu-latest
+ platform: linux/amd64
+ - arch: arm64
+ runner: ubuntu-24.04-arm
+ platform: linux/arm64
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - name: Checkout with submodules
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Set up GraalVM JDK 25
+ uses: graalvm/setup-graalvm@v1
+ with:
+ java-version: '25'
+ distribution: 'graalvm'
+
+ - name: Restore Maven cache
+ uses: actions/cache/restore@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ needs.build-skywalking.outputs.cache-key }}
+
+ - name: Build native image
+ run: make native-image
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to GHCR
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Locate distro tarball
+ id: dist
+ run: echo "path=$(ls
oap-graalvm-native/target/oap-graalvm-native-*-native-dist.tar.gz)" >>
"$GITHUB_OUTPUT"
+
+ - name: Build and push by digest
+ id: build
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ file: docker/Dockerfile.native
+ platforms: ${{ matrix.platform }}
+ build-args: |
+ DIST=${{ steps.dist.outputs.path }}
+ outputs: type=image,name=${{ env.IMAGE
}},push-by-digest=true,name-canonical=true,push=true
+
+ - name: Export digest
+ run: |
+ mkdir -p /tmp/digests
+ digest="${{ steps.build.outputs.digest }}"
+ touch "/tmp/digests/${digest#sha256:}"
+
+ - name: Upload digest
+ uses: actions/upload-artifact@v4
+ with:
+ name: digests-${{ matrix.arch }}
+ path: /tmp/digests/*
+ if-no-files-found: error
+ retention-days: 1
+
+ # ── Merge per-arch images into multi-arch manifest ──
+ docker-manifest:
+ name: Docker Manifest
+ runs-on: ubuntu-latest
+ needs: build-native
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - name: Download digests
+ uses: actions/download-artifact@v4
+ with:
+ path: /tmp/digests
+ pattern: digests-*
+ merge-multiple: true
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to GHCR
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Create and push manifest
+ working-directory: /tmp/digests
+ run: |
+ SHORT_SHA=${GITHUB_SHA::7}
+ docker buildx imagetools create \
+ -t ${{ env.IMAGE }}:latest \
+ -t ${{ env.IMAGE }}:${SHORT_SHA} \
+ $(printf '${{ env.IMAGE }}@sha256:%s ' *)
diff --git a/Makefile b/Makefile
index 011cfb3..3062af1 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ SW_VERSION := $(shell grep '<revision>' skywalking/pom.xml |
head -1 | sed 's/.*
MVN := ./mvnw
MVN_ARGS := -Dskywalking.version=$(SW_VERSION)
-.PHONY: all clean build init-submodules build-skywalking build-distro compile
test javadoc dist info docker-up docker-down boot shutdown native-image
trace-agent
+.PHONY: all clean build init-submodules build-skywalking build-distro compile
test javadoc dist info docker-up docker-down boot shutdown native-image
native-dist trace-agent docker-native
all: build
@@ -60,10 +60,16 @@ build-distro:
# Show the distribution directory
dist: build-distro
- @echo "Distribution created at:"
+ @echo "JVM distribution created at:"
@echo "
oap-graalvm-server/target/oap-graalvm-jvm-distro/oap-graalvm-jvm-distro/"
@echo " oap-graalvm-server/target/oap-graalvm-jvm-distro.tar.gz"
+# Show the native distribution directory
+native-dist: native-image
+ @echo "Native distribution created at:"
+ @ls -d
oap-graalvm-native/target/oap-graalvm-native-*-native-dist/oap-native/
2>/dev/null
+ @ls oap-graalvm-native/target/oap-graalvm-native-*-native-dist.tar.gz
2>/dev/null
+
# Full build: skywalking first, then distro
build: build-skywalking build-distro
@@ -98,6 +104,12 @@ trace-agent: build-distro docker-up
JAVA_OPTS="-Xms256M -Xmx4096M
-agentlib:native-image-agent=config-merge-dir=oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native"
\
oap-graalvm-server/target/oap-graalvm-jvm-distro/oap-graalvm-jvm-distro/bin/oapService.sh
+# Build Docker image with native binary (requires prior: make native-image)
+docker-native:
+ docker build -f docker/Dockerfile.native \
+ --build-arg DIST=$$(ls
oap-graalvm-native/target/oap-graalvm-native-*-native-dist.tar.gz) \
+ -t skywalking-oap-native .
+
# Build distro and boot OAP with BanyanDB
boot: build-distro docker-up
SW_STORAGE_BANYANDB_TARGETS=localhost:17912 \
diff --git a/docker/Dockerfile.native b/docker/Dockerfile.native
new file mode 100644
index 0000000..7aa29fa
--- /dev/null
+++ b/docker/Dockerfile.native
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Packages a pre-built native binary into a minimal runtime image.
+#
+# Prerequisites (host or CI):
+# make build-skywalking # install upstream JARs to .m2
+# make native-image # build native binary + distro tarball
+#
+# Usage:
+# docker build -f docker/Dockerfile.native \
+# --build-arg
DIST=oap-graalvm-native/target/oap-graalvm-native-1.0.0-SNAPSHOT-native-dist.tar.gz
\
+# -t skywalking-oap-native .
+#
+# docker run -e SW_STORAGE_BANYANDB_TARGETS=host.docker.internal:17912
skywalking-oap-native
+
+FROM debian:bookworm-slim
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ zlib1g ca-certificates fontconfig \
+ && rm -rf /var/lib/apt/lists/*
+
+ENV OAP_HOME=/skywalking
+WORKDIR $OAP_HOME
+
+ARG DIST
+COPY ${DIST} /tmp/native-dist.tar.gz
+RUN tar -xzf /tmp/native-dist.tar.gz --strip-components=1 -C . \
+ && rm /tmp/native-dist.tar.gz \
+ && mkdir -p logs \
+ && chmod +x oap-server
+
+EXPOSE 12800 11800 1234
+
+ENTRYPOINT ["./oap-server"]
diff --git a/oap-graalvm-native/pom.xml b/oap-graalvm-native/pom.xml
index 7f4de45..f9b805a 100644
--- a/oap-graalvm-native/pom.xml
+++ b/oap-graalvm-native/pom.xml
@@ -92,6 +92,24 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptors>
+
<descriptor>src/main/assembly/native-distribution.xml</descriptor>
+ </descriptors>
+ </configuration>
+ <executions>
+ <execution>
+ <id>native-dist</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</profile>
diff --git a/oap-graalvm-native/src/main/assembly/native-distribution.xml
b/oap-graalvm-native/src/main/assembly/native-distribution.xml
new file mode 100644
index 0000000..0eefddd
--- /dev/null
+++ b/oap-graalvm-native/src/main/assembly/native-distribution.xml
@@ -0,0 +1,86 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0
+ http://maven.apache.org/xsd/assembly-2.2.0.xsd">
+ <id>native-dist</id>
+ <formats>
+ <format>dir</format>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>oap-native</baseDirectory>
+
+ <fileSets>
+ <!-- Native binary -->
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory>.</outputDirectory>
+ <includes>
+ <include>oap-server</include>
+ </includes>
+ <fileMode>0755</fileMode>
+ </fileSet>
+ <!-- config/ — application.yml -->
+ <fileSet>
+
<directory>${project.basedir}/../oap-graalvm-server/src/main/resources</directory>
+ <outputDirectory>config</outputDirectory>
+ <includes>
+ <include>application.yml</include>
+ </includes>
+ </fileSet>
+ <!-- config/ — production configs from dist-material (same as upstream
apm-dist) -->
+ <fileSet>
+
<directory>${project.basedir}/../skywalking/dist-material</directory>
+ <outputDirectory>config</outputDirectory>
+ <includes>
+ <include>log4j2.xml</include>
+ <include>alarm-settings.yml</include>
+ </includes>
+ </fileSet>
+ <!-- config/ — upstream resource files loaded at runtime.
+ Same set as JVM distro: BanyanDB config, UI templates, rules,
etc. -->
+ <fileSet>
+
<directory>${project.basedir}/../skywalking/oap-server/server-starter/src/main/resources</directory>
+ <outputDirectory>config</outputDirectory>
+ <includes>
+ <include>bydb.yml</include>
+ <include>bydb-topn.yml</include>
+ <include>ui-initialized-templates/**</include>
+ <include>cilium-rules/**</include>
+ <include>openapi-definitions/**</include>
+ <include>component-libraries.yml</include>
+ <include>endpoint-name-grouping.yml</include>
+ <include>gateways.yml</include>
+ <include>hierarchy-definition.yml</include>
+ <include>metadata-service-mapping.yaml</include>
+ <include>service-apdex-threshold.yml</include>
+ <include>trace-sampling-policy-settings.yml</include>
+ </includes>
+ </fileSet>
+ <!-- logs/ — empty directory for runtime logs -->
+ <fileSet>
+ <directory>.</directory>
+ <outputDirectory>logs</outputDirectory>
+ <excludes>
+ <exclude>**/*</exclude>
+ </excludes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java
index b9db45c..b0fb2b0 100644
---
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java
+++
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java
@@ -47,7 +47,7 @@ import java.util.stream.Collectors;
*
* <p>Upstream uses {@code LambdaMetafactory.metafactory()} to create setter
* wrappers at runtime, which fails in GraalVM native images (cannot define
- * classes at runtime). This replacement uses {@link MethodHandle#invoke()}
+ * classes at runtime). This replacement uses {@link MethodHandle}
* directly, which is supported by GraalVM.
*/
@Slf4j