This is an automated email from the ASF dual-hosted git repository.

davidzollo pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 0b9e75a6ce [Improve][Core] Raise minimum Java runtime to 11 and move 
CI to JDK 11/17 (#11545)
0b9e75a6ce is described below

commit 0b9e75a6ceb846cd08b06184127560cbd96c01b1
Author: Daniel <[email protected]>
AuthorDate: Fri Oct 9 01:46:33 2026 -0400

    [Improve][Core] Raise minimum Java runtime to 11 and move CI to JDK 11/17 
(#11545)
    
    Co-authored-by: DanielLeens <[email protected]>
    Co-authored-by: danielnadean 
<[email protected]>
    Co-authored-by: davidzollo <[email protected]>
    Co-authored-by: davidzollo <[email protected]>
    Co-authored-by: Daniel Leens <[email protected]>
    Co-authored-by: Claude Sonnet 5 <[email protected]>
    Co-authored-by: DanielLeens <[email protected]>
---
 .github/workflows/backend.yml                      | 121 ++++++++++++---------
 .github/workflows/benchmarks.yml                   |   2 +-
 .github/workflows/codeql.yaml                      |   8 +-
 .github/workflows/merge_queue.yml                  |   4 +-
 .github/workflows/publish-docker.yaml              |   8 +-
 .github/workflows/upgrade_compatibility.yml        |   6 +-
 config/jvm_client_options                          |  39 +++++++
 config/jvm_master_options                          |  38 +++++++
 config/jvm_options                                 |  38 +++++++
 config/jvm_worker_options                          |  38 +++++++
 docs/en/developer/setup.md                         |   3 +-
 docs/en/developer/shade-guide.md                   |   2 +-
 docs/en/edge-agent/quick-start.md                  |   3 +-
 docs/en/engines/zeta/download-seatunnel.md         |   2 +-
 docs/en/engines/zeta/telemetry.md                  |   2 +-
 docs/en/getting-started/docker/docker.md           |   2 +-
 docs/en/getting-started/kubernetes/kubernetes.mdx  |   2 +-
 docs/en/getting-started/locally/deployment.md      |   4 +-
 docs/en/getting-started/overview.md                |   2 +-
 .../introduction/concepts/incompatible-changes.md  |  17 +++
 docs/zh/developer/setup.md                         |   3 +-
 docs/zh/developer/shade-guide.md                   |   2 +-
 docs/zh/edge-agent/quick-start.md                  |   3 +-
 docs/zh/engines/zeta/download-seatunnel.md         |   2 +-
 docs/zh/engines/zeta/telemetry.md                  |   2 +-
 docs/zh/getting-started/docker/docker.md           |   4 +-
 docs/zh/getting-started/kubernetes/kubernetes.mdx  |   2 +-
 docs/zh/getting-started/locally/deployment.md      |   2 +-
 docs/zh/getting-started/overview.md                |   2 +-
 .../introduction/concepts/incompatible-changes.md  |  17 +++
 pom.xml                                            |  27 ++++-
 seatunnel-ci-tools/pom.xml                         |   3 +-
 .../exception/EdgeSocketConnectorErrorCode.java    |   3 +-
 .../record/EdgeSocketPacketRecordDeserializer.java |  15 ++-
 .../edgesocket/source/EdgeSocketSourceReader.java  |   3 +-
 seatunnel-connectors-v2/connector-fluss/pom.xml    |  37 +++++++
 seatunnel-connectors-v2/connector-iceberg/pom.xml  |   6 +
 .../connectors/seatunnel/kudu/util/KuduUtil.java   |  31 +++++-
 .../paimon/security/PaimonSecurityContext.java     |  29 ++++-
 .../src/main/bin/seatunnel-cluster.sh              |  26 +++++
 .../src/main/bin/seatunnel-connector.sh            |  16 ++-
 .../seatunnel-starter/src/main/bin/seatunnel.sh    |  41 ++++++-
 .../seatunnel/command/ServerExecuteCommand.java    |  28 +----
 .../command/ServerExecuteCommandTest.java          |  16 +--
 seatunnel-dist/src/main/docker/Dockerfile          |   7 +-
 .../connector/amazondynamodb/AmazondynamodbIT.java |   3 +-
 .../connector-cdc-tidb-e2e/pom.xml                 |   1 +
 .../connector-fluss-e2e/pom.xml                    |   3 +-
 .../seatunnel/e2e/connector/python/PythonIT.java   |  35 +++++-
 .../src/test/resources/python_to_assert.conf       |   2 +-
 .../e2e/connector/rabbitmq/RabbitmqIT.java         |   3 +-
 .../connector-tdengine-e2e/pom.xml                 |   1 +
 .../connector-typesense-e2e/pom.xml                |   1 +
 .../src/test/docker/spark/Dockerfile               |   4 +-
 .../flink/AbstractTestFlinkContainer.java          |   4 +-
 .../common/container/flink/Flink13Container.java   |   8 +-
 .../common/container/flink/Flink14Container.java   |   6 +-
 .../common/container/flink/Flink20Container.java   |   7 +-
 .../ConnectorPackageServiceContainer.java          |   4 +-
 .../container/seatunnel/SeaTunnelContainer.java    |  13 ++-
 .../common/container/spark/Spark2Container.java    |   9 +-
 .../common/container/spark/Spark3Container.java    |   8 +-
 .../e2e/common/util/EngineImageJdkUpgrader.java    | 119 ++++++++++++++++++++
 .../edge/agent/e2e/EdgeAgentContainer.java         |   2 +-
 .../src/test/resources/seatunnel_dockerfile        |   4 +-
 .../seatunnel-flink-examples/pom.xml               |   1 +
 .../seatunnel-flink-13-example/pom.xml             |   1 +
 .../seatunnel-flink-15-example/pom.xml             |   1 +
 .../seatunnel-flink-20-example/pom.xml             |   1 +
 .../seatunnel-format-protobuf/pom.xml              |   1 +
 tools/update_modules_check/test_ci_scope.py        |   1 -
 71 files changed, 744 insertions(+), 167 deletions(-)

diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml
index a55d942fb9..43f68c3656 100644
--- a/.github/workflows/backend.yml
+++ b/.github/workflows/backend.yml
@@ -36,6 +36,17 @@ env:
   # GitHub-hosted runners are ephemeral, so CI does not need Ryuk to reap 
containers after tests.
   # Disabling it avoids transient Docker Hub pulls for testcontainers/ryuk 
that can fail unrelated PRs.
   TESTCONTAINERS_RYUK_DISABLED: 'true'
+  # The JDK 9+ module-opens flags Hazelcast and this project's reflective 
helpers need (see
+  # config/jvm_options) no longer live here. Surefire/Failsafe-forked test 
JVMs get them from the
+  # surefire.module.args property in the root pom.xml (appended to the argLine 
next to
+  # surefire.jvm.args; modules that define their own argLine, such as 
connector-lance, still need
+  # the unit-test step's SUREFIRE_JVM_ARGS below), which also keeps a 
contributor's local
+  # `./mvnw test`/`./mvnw verify` on JDK 11/17 in parity with CI. The packaged 
launcher scripts
+  # (seatunnel.sh, seatunnel-cluster.sh) inject the same flags themselves for 
the e2e Docker
+  # containers this workflow spins up, independent of this workflow's own 
environment. Setting
+  # JAVA_TOOL_OPTIONS here applied the flags to every process every job 
happened to run, including
+  # non-test jobs and non-JVM tools, and printed a "Picked up 
JAVA_TOOL_OPTIONS" line from every
+  # child process; scoping it to the two places that actually need it removes 
both problems.
 
 jobs:
   license-header:
@@ -486,7 +497,7 @@ jobs:
       - uses: actions/setup-java@v4
         with:
           distribution: 'temurin'
-          java-version: '8'
+          java-version: '17'
           cache: 'maven'
       - name: Install
         uses: nick-fields/retry@v3
@@ -571,7 +582,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest', 'windows-latest' ]
     # The all-modules unit test build now takes 70-88 minutes on ubuntu-latest 
and keeps growing
     # with every new connector; a 90 minute budget left so little headroom 
that ordinary runner
@@ -589,13 +600,24 @@ jobs:
         run: ./mvnw -B -T 1 clean verify -DskipUT=false -DskipIT=true 
-D"license.skipAddThirdParty"=true -D"skip.ui"=true 
"-Dsurefire.jvm.args=$SUREFIRE_JVM_ARGS" --no-snapshot-updates
         env:
           MAVEN_OPTS: -Xmx1536m -Dfile.encoding=UTF-8
-          SUREFIRE_JVM_ARGS: -Xmx3072m -XX:MaxMetaspaceSize=512m 
-Dfile.encoding=UTF-8
+          # This CLI -Dsurefire.jvm.args replaces surefire.jvm.args in every 
module. The JDK 9+
+          # --add-opens/--add-exports flags (needed by JDK 17 unit tests, JEP 
396) are repeated
+          # here on purpose: the root pom carries them in 
surefire.module.args, but a module that
+          # defines its own surefire <argLine> bypasses the root argLine and 
only sees
+          # surefire.jvm.args. connector-lance does exactly that (Arrow needs
+          # --add-opens=java.base/java.nio on JDK 17), and its unit tests 
failed with
+          # InaccessibleObjectException when these flags were removed from 
this step.
+          # Keep this list in sync with surefire.module.args in the root 
pom.xml. The duplication
+          # is tracked in apache/seatunnel#12655; do not remove these flags 
before that is fixed.
+          SUREFIRE_JVM_ARGS: -Xmx3072m -XX:MaxMetaspaceSize=512m 
-Dfile.encoding=UTF-8 --add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.net=ALL-UNNAMED 
--add-opens=java.base/java.nio=ALL-UNNAMED 
--add-opens=java.base/java.util=ALL-UNNAMED 
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED 
--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED
         if: runner.os != 'Windows'
       - name: run all modules unit test (Windows)
         run: ./mvnw -B -T 1 clean verify -DskipUT=false -DskipIT=true 
-D"license.skipAddThirdParty"=true -D"skip.ui"=true 
"-Dsurefire.jvm.args=$env:SUREFIRE_JVM_ARGS" --no-snapshot-updates
         env:
           MAVEN_OPTS: -Xmx1536m -Dfile.encoding=UTF-8
-          SUREFIRE_JVM_ARGS: -Xmx3072m -XX:MaxMetaspaceSize=512m 
-Dfile.encoding=UTF-8
+          # Keep in sync with the non-Windows step above; see its comment for 
why the module
+          # flags must be repeated here as well as in the pom.xml 
surefire.module.args property.
+          SUREFIRE_JVM_ARGS: -Xmx3072m -XX:MaxMetaspaceSize=512m 
-Dfile.encoding=UTF-8 --add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.net=ALL-UNNAMED 
--add-opens=java.base/java.nio=ALL-UNNAMED 
--add-opens=java.base/java.util=ALL-UNNAMED 
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED 
--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED
         if: runner.os == 'Windows'
       - name: Upload test reports
         if: failure()
@@ -611,7 +633,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     steps:
       - uses: actions/checkout@v4
@@ -661,7 +683,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
@@ -699,7 +721,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
@@ -737,7 +759,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 300
     steps:
@@ -775,7 +797,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 200
     steps:
@@ -812,7 +834,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
@@ -849,7 +871,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 210
     steps:
@@ -886,7 +908,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 210
     steps:
@@ -924,7 +946,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 210
     steps:
@@ -962,7 +984,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -993,7 +1015,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1024,7 +1046,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 45
     steps:
@@ -1067,7 +1089,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     # Part-1 alone takes 99-107 minutes on ubuntu-latest; the UDF E2E module 
adds its own build and tests.
     timeout-minutes: 135
@@ -1102,7 +1124,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     # A green run of this job takes about 149 minutes on ubuntu-latest, so the 
previous 150
     # minute budget cancelled runs that were already on their last test class.
@@ -1140,7 +1162,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1177,7 +1199,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1214,7 +1236,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1251,7 +1273,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1288,7 +1310,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1325,7 +1347,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1362,7 +1384,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1399,7 +1421,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1433,7 +1455,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 150
     steps:
@@ -1467,7 +1489,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     # A green run of this job takes 113-115 minutes on ubuntu-latest 
(JdbcOracleIT alone is
     # about 25 minutes), so the previous 120 minute budget left ordinary 
runner variance no
@@ -1504,7 +1526,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1538,7 +1560,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1572,7 +1594,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1606,7 +1628,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1640,7 +1662,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1674,7 +1696,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1708,7 +1730,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
@@ -1739,7 +1761,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     # Kudu E2E expands each @TestTemplate case across several PR test 
containers.
     timeout-minutes: 90
@@ -1771,7 +1793,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1800,8 +1822,9 @@ jobs:
     if: needs.changes.outputs.api == 'true' || needs.changes.outputs.engine == 
'true' || contains(fromJSON(needs.changes.outputs.it-modules), 
'connector-google-pubsub-e2e')
     runs-on: ${{ matrix.os }}
     strategy:
+      fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1832,7 +1855,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 210
     steps:
@@ -1863,7 +1886,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1894,7 +1917,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
@@ -1925,7 +1948,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -1956,7 +1979,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
@@ -1987,7 +2010,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
@@ -2018,7 +2041,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 210
     steps:
@@ -2054,7 +2077,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -2085,7 +2108,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 120
     steps:
@@ -2116,7 +2139,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 210
     steps:
@@ -2147,7 +2170,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java: [ '8', '11' ]
+        java: [ '11', '17' ]
         os: [ 'ubuntu-latest' ]
     timeout-minutes: 180
     steps:
diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml
index 3d31440bd8..4a9d0e3b2e 100644
--- a/.github/workflows/benchmarks.yml
+++ b/.github/workflows/benchmarks.yml
@@ -71,7 +71,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        java-version: [ '8', '11' ]
+        java-version: [ '11', '17' ]
 
     env:
       BENCHMARK_SUITE: ${{ github.event_name == 'schedule' && 
'benchmarks_core' || '' }}
diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml
index 677e7f52c0..224311b485 100644
--- a/.github/workflows/codeql.yaml
+++ b/.github/workflows/codeql.yaml
@@ -37,11 +37,11 @@ jobs:
         uses: actions/checkout@v2
         with:
           submodules: true
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v2
+      - name: Set up JDK 17
+        uses: actions/setup-java@v4
         with:
-          java-version:  8
-          distribution: 'adopt'
+          java-version: '17'
+          distribution: 'temurin'
       - name: Cache local Maven repository
         uses: actions/cache@v4
         with:
diff --git a/.github/workflows/merge_queue.yml 
b/.github/workflows/merge_queue.yml
index 35b67320bb..6b1c29cf77 100644
--- a/.github/workflows/merge_queue.yml
+++ b/.github/workflows/merge_queue.yml
@@ -36,11 +36,11 @@ jobs:
     steps:
       - name: Checkout merge group
         uses: actions/checkout@v4
-      - name: Set up JDK 8
+      - name: Set up JDK 11
         uses: actions/setup-java@v4
         with:
           distribution: temurin
-          java-version: '8'
+          java-version: '11'
           cache: maven
       # Compile the standard modules with the CI profile.
       - name: Compile main and test sources
diff --git a/.github/workflows/publish-docker.yaml 
b/.github/workflows/publish-docker.yaml
index 98f08f5778..68f4cad308 100644
--- a/.github/workflows/publish-docker.yaml
+++ b/.github/workflows/publish-docker.yaml
@@ -51,11 +51,11 @@ jobs:
           key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
           restore-keys: |
             ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v2
+      - name: Set up JDK 17
+        uses: actions/setup-java@v4
         with:
-          java-version:  8
-          distribution: 'adopt'
+          java-version: '17'
+          distribution: 'temurin'
 
       - name: Log in to the Container registry
         uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # 
v4.6.0
diff --git a/.github/workflows/upgrade_compatibility.yml 
b/.github/workflows/upgrade_compatibility.yml
index 1c3819c08c..367ad3bc4b 100644
--- a/.github/workflows/upgrade_compatibility.yml
+++ b/.github/workflows/upgrade_compatibility.yml
@@ -52,7 +52,11 @@ jobs:
       - uses: actions/setup-java@v4
         with:
           distribution: temurin
-          java-version: "8"
+          # JDK 11, not 17: this job boots the OLD release (2.3.13), whose 
bundled
+          # config/jvm_*_options predate the JDK 9+ --add-opens flags, so 
running it under
+          # JDK 17's strong encapsulation could fail for reasons unrelated to 
upgrade
+          # compatibility. Java 11 is the minimum runtime both versions 
support.
+          java-version: "11"
 
       - name: Test upgrade compatibility tooling
         run: bash tools/upgrade_compatibility/run_upgrade_compatibility_test.sh
diff --git a/config/jvm_client_options b/config/jvm_client_options
index 462e1374c1..aca28cdef5 100644
--- a/config/jvm_client_options
+++ b/config/jvm_client_options
@@ -15,6 +15,45 @@
 # limitations under the License.
 #
 
+# JDK 9+ module system compatibility. Two independent consumers need these 
flags:
+#   1. The Hazelcast client this process embeds to talk to the Zeta engine. 
Its own
+#      serialization and networking internals reflectively touch these JDK 
APIs; nothing in
+#      this codebase calls them directly, so there is no first-party call site 
in our source
+#      to point to for these.
+#   2. This project's own reflective Kerberos configuration reload helpers 
(KuduUtil,
+#      PaimonSecurityContext) and the connector classloader injection helpers
+#      (AbstractPluginDiscovery, ConfigValidationUtils, the Flink starter 
plugin loaders),
+#      which are named per-flag below.
+# Source of truth: the launcher scripts (seatunnel.sh, seatunnel-cluster.sh) 
append the mandatory
+# flags below themselves, skipping any already present. The entries in this 
file are a
+# convenience and documentation; do not remove the launcher injection assuming 
this file is
+# sufficient, because a preserved config directory would then silently lose 
the flags.
+# Without these flags the Kerberos reload helpers log an ERROR naming the 
missing flag; other
+# consumers may not report it until the affected path is actually exercised.
+# Evidence status: only java.net has a captured failing stack trace 
(ReflectionUtilsTest).
+# The other entries are not proven necessary by a captured failure on this 
project's CI and
+# are candidates to trim later.
+# Required by Hazelcast client internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.lang=ALL-UNNAMED
+# Required by URLClassLoader#addURL reflection: AbstractPluginDiscovery,
+# ConfigValidationUtils, and the Flink starter plugin loaders inject connector 
jars this way.
+--add-opens=java.base/java.net=ALL-UNNAMED
+# Required by Hazelcast client internals (see note 1 above).
+# Evidence: also required by Apache Arrow (connector-lance unit tests fail on 
JDK 17 without it).
+--add-opens=java.base/java.nio=ALL-UNNAMED
+# Required by Hazelcast client internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.util=ALL-UNNAMED
+# Required by Hazelcast client internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
+# Required by the Kerberos configuration reload helpers KuduUtil and 
PaimonSecurityContext,
+# which reflectively call sun.security.krb5.Config#refresh() to pick
+# up a custom krb5.conf without a JVM restart.
+# Evidence: no captured failure on this project's CI; kept for the reflective 
reload.
+--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED
+
 # JVM Heap
 -Xms256m
 -Xmx512m
diff --git a/config/jvm_master_options b/config/jvm_master_options
index d435a7d275..cebd38e4b1 100644
--- a/config/jvm_master_options
+++ b/config/jvm_master_options
@@ -15,6 +15,44 @@
 # limitations under the License.
 #
 
+# JDK 9+ module system compatibility. Two independent consumers need these 
flags:
+#   1. Hazelcast, which the Zeta engine is built on. Its own serialization and 
networking
+#      internals reflectively touch these JDK APIs; nothing in this codebase 
calls them
+#      directly, so there is no first-party call site in our source to point 
to for these.
+#   2. This project's own reflective code: the Kerberos configuration reload 
helpers
+#      (KuduUtil, PaimonSecurityContext) and the connector classloader 
injection helpers
+#      (AbstractPluginDiscovery, ConfigValidationUtils, the Flink starter 
plugin loaders),
+#      which are named per-flag below.
+# Source of truth: the launcher scripts (seatunnel.sh, seatunnel-cluster.sh) 
append the mandatory
+# flags below themselves, skipping any already present. The entries in this 
file are a
+# convenience and documentation; do not remove the launcher injection assuming 
this file is
+# sufficient, because a preserved config directory would then silently lose 
the flags.
+# Without these flags the Kerberos reload helpers log an ERROR naming the 
missing flag; other
+# consumers may not report it until the affected path is actually exercised.
+# Evidence status: only java.net has a captured failing stack trace 
(ReflectionUtilsTest).
+# The other entries are not proven necessary by a captured failure on this 
project's CI and
+# are candidates to trim later.
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.lang=ALL-UNNAMED
+# Required by URLClassLoader#addURL reflection: AbstractPluginDiscovery,
+# ConfigValidationUtils, and the Flink starter plugin loaders inject connector 
jars this way.
+--add-opens=java.base/java.net=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: also required by Apache Arrow (connector-lance unit tests fail on 
JDK 17 without it).
+--add-opens=java.base/java.nio=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.util=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
+# Required by the Kerberos configuration reload helpers KuduUtil and 
PaimonSecurityContext,
+# which reflectively call sun.security.krb5.Config#refresh() to pick
+# up a custom krb5.conf without a JVM restart.
+# Evidence: no captured failure on this project's CI; kept for the reflective 
reload.
+--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED
+
 # JVM Heap
 # -Xms2g
 # -Xmx2g
diff --git a/config/jvm_options b/config/jvm_options
index 0e5d289ea0..34c44ad4b0 100644
--- a/config/jvm_options
+++ b/config/jvm_options
@@ -15,6 +15,44 @@
 # limitations under the License.
 #
 
+# JDK 9+ module system compatibility. Two independent consumers need these 
flags:
+#   1. Hazelcast, which the Zeta engine is built on. Its own serialization and 
networking
+#      internals reflectively touch these JDK APIs; nothing in this codebase 
calls them
+#      directly, so there is no first-party call site in our source to point 
to for these.
+#   2. This project's own reflective code: the Kerberos configuration reload 
helpers
+#      (KuduUtil, PaimonSecurityContext) and the connector classloader 
injection helpers
+#      (AbstractPluginDiscovery, ConfigValidationUtils, the Flink starter 
plugin loaders),
+#      which are named per-flag below.
+# Source of truth: the launcher scripts (seatunnel.sh, seatunnel-cluster.sh) 
append the mandatory
+# flags below themselves, skipping any already present. The entries in this 
file are a
+# convenience and documentation; do not remove the launcher injection assuming 
this file is
+# sufficient, because a preserved config directory would then silently lose 
the flags.
+# Without these flags the Kerberos reload helpers log an ERROR naming the 
missing flag; other
+# consumers may not report it until the affected path is actually exercised.
+# Evidence status: only java.net has a captured failing stack trace 
(ReflectionUtilsTest).
+# The other entries are not proven necessary by a captured failure on this 
project's CI and
+# are candidates to trim later.
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.lang=ALL-UNNAMED
+# Required by URLClassLoader#addURL reflection: AbstractPluginDiscovery,
+# ConfigValidationUtils, and the Flink starter plugin loaders inject connector 
jars this way.
+--add-opens=java.base/java.net=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: also required by Apache Arrow (connector-lance unit tests fail on 
JDK 17 without it).
+--add-opens=java.base/java.nio=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.util=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
+# Required by the Kerberos configuration reload helpers KuduUtil and 
PaimonSecurityContext,
+# which reflectively call sun.security.krb5.Config#refresh() to pick
+# up a custom krb5.conf without a JVM restart.
+# Evidence: no captured failure on this project's CI; kept for the reflective 
reload.
+--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED
+
 # JVM Heap
 # -Xms2g
 # -Xmx2g
diff --git a/config/jvm_worker_options b/config/jvm_worker_options
index d435a7d275..cebd38e4b1 100644
--- a/config/jvm_worker_options
+++ b/config/jvm_worker_options
@@ -15,6 +15,44 @@
 # limitations under the License.
 #
 
+# JDK 9+ module system compatibility. Two independent consumers need these 
flags:
+#   1. Hazelcast, which the Zeta engine is built on. Its own serialization and 
networking
+#      internals reflectively touch these JDK APIs; nothing in this codebase 
calls them
+#      directly, so there is no first-party call site in our source to point 
to for these.
+#   2. This project's own reflective code: the Kerberos configuration reload 
helpers
+#      (KuduUtil, PaimonSecurityContext) and the connector classloader 
injection helpers
+#      (AbstractPluginDiscovery, ConfigValidationUtils, the Flink starter 
plugin loaders),
+#      which are named per-flag below.
+# Source of truth: the launcher scripts (seatunnel.sh, seatunnel-cluster.sh) 
append the mandatory
+# flags below themselves, skipping any already present. The entries in this 
file are a
+# convenience and documentation; do not remove the launcher injection assuming 
this file is
+# sufficient, because a preserved config directory would then silently lose 
the flags.
+# Without these flags the Kerberos reload helpers log an ERROR naming the 
missing flag; other
+# consumers may not report it until the affected path is actually exercised.
+# Evidence status: only java.net has a captured failing stack trace 
(ReflectionUtilsTest).
+# The other entries are not proven necessary by a captured failure on this 
project's CI and
+# are candidates to trim later.
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.lang=ALL-UNNAMED
+# Required by URLClassLoader#addURL reflection: AbstractPluginDiscovery,
+# ConfigValidationUtils, and the Flink starter plugin loaders inject connector 
jars this way.
+--add-opens=java.base/java.net=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: also required by Apache Arrow (connector-lance unit tests fail on 
JDK 17 without it).
+--add-opens=java.base/java.nio=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/java.util=ALL-UNNAMED
+# Required by Hazelcast internals (see note 1 above).
+# Evidence: no captured failure on this project's CI; candidate to trim.
+--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
+# Required by the Kerberos configuration reload helpers KuduUtil and 
PaimonSecurityContext,
+# which reflectively call sun.security.krb5.Config#refresh() to pick
+# up a custom krb5.conf without a JVM restart.
+# Evidence: no captured failure on this project's CI; kept for the reflective 
reload.
+--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED
+
 # JVM Heap
 # -Xms2g
 # -Xmx2g
diff --git a/docs/en/developer/setup.md b/docs/en/developer/setup.md
index 720f06d987..e808f4503d 100644
--- a/docs/en/developer/setup.md
+++ b/docs/en/developer/setup.md
@@ -16,7 +16,7 @@ Before we start talking about how to set up the environment, 
we need to do some
 have installed the following software:
 
 * [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 
installed.
-* [Java](https://www.java.com/en/download/) ( JDK8/JDK11 are supported by now) 
installed and `JAVA_HOME` set.
+* [Java](https://www.java.com/en/download/) (JDK11/JDK17 are supported by now) 
installed and `JAVA_HOME` set.
 * [Scala](https://www.scala-lang.org/download/2.11.12.html) (only scala 
2.11.12 supported by now) installed.
 * [JetBrains IDEA](https://www.jetbrains.com/idea/) installed.
 
@@ -128,4 +128,3 @@ sink {
   Console {}
 }
 ```
-
diff --git a/docs/en/developer/shade-guide.md b/docs/en/developer/shade-guide.md
index a7853ffee2..c78a1c0a65 100644
--- a/docs/en/developer/shade-guide.md
+++ b/docs/en/developer/shade-guide.md
@@ -85,7 +85,7 @@ Child modules declare dependencies **without** a `<version>` 
element — the ver
 
 ### Prerequisites
 
-- Java 8+
+- Java 11+
 - Maven 3.x
 
 ### Clone and Build
diff --git a/docs/en/edge-agent/quick-start.md 
b/docs/en/edge-agent/quick-start.md
index 5379ac2e7a..0d0b895b43 100644
--- a/docs/en/edge-agent/quick-start.md
+++ b/docs/en/edge-agent/quick-start.md
@@ -31,7 +31,7 @@ The install root contains bin/, config/, and starter/.
 
 ### Prerequisites
 
-- Java 8 or 11 on the edge host, with JAVA_HOME set.
+- Java 11 or 17 on the edge host, with JAVA_HOME set.
 - No SeaTunnel Engine and no EdgeSocket connectivity required.
 - Writable install root (default WAL data/wal.db, logs, edge-agent.id).
 
@@ -182,4 +182,3 @@ Keep edge-agent.id and the data/ directory (default wal.db 
plus -wal/-shm) when
 
 Once you have completed the quick start, continue with the [Deployment 
Guide](deployment-guide.md) for production setup, or see the [Configuration 
Reference](configuration.md) for full parameters. For a complete documentation 
map, visit [About Edge Agent](about.md#recommended-reading-order).
 
-
diff --git a/docs/en/engines/zeta/download-seatunnel.md 
b/docs/en/engines/zeta/download-seatunnel.md
index 505aac6d61..7c40421f29 100644
--- a/docs/en/engines/zeta/download-seatunnel.md
+++ b/docs/en/engines/zeta/download-seatunnel.md
@@ -11,7 +11,7 @@ import TabItem from '@theme/TabItem';
 
 Before starting to download SeaTunnel, you need to ensure that you have 
installed the following software required by SeaTunnel:
 
-* Install [Java](https://www.java.com/en/download/) (Java 8 or 11, and other 
versions higher than Java 8 can theoretically work) and set `JAVA_HOME`.
+* Install [Java](https://www.java.com/en/download/) (Java 11 or Java 17) and 
set `JAVA_HOME`.
 
 ## Step 2: Download SeaTunnel
 
diff --git a/docs/en/engines/zeta/telemetry.md 
b/docs/en/engines/zeta/telemetry.md
index 71ac33a907..1d81aed91a 100644
--- a/docs/en/engines/zeta/telemetry.md
+++ b/docs/en/engines/zeta/telemetry.md
@@ -215,7 +215,7 @@ This metric is exported by the active master only. It 
reports only an aggregate
 | jvm_memory_pool_allocated_bytes_total      | Counter | **pool**,including: 
"Code Cache" "PS Eden Space" "PS Old Ge" "PS Survivor Space" "Compressed Class 
Space" "Metaspace"                                 | Total bytes allocated in a 
given JVM memory pool. Only updated after GC, not continuously              |
 | jvm_gc_collection_seconds_count            | Summary | **gc**,including: "PS 
Scavenge" "PS MarkSweep"                                                        
                                                | Time spent in a given JVM 
garbage collector in seconds                                                 |
 | jvm_gc_collection_seconds_sum              | Summary | **gc**,including: "PS 
Scavenge" "PS MarkSweep"                                                        
                                                | Time spent in a given JVM 
garbage collector in seconds                                                 |
-| jvm_info                                   | Gauge   | **runtime**, for 
example: "Java(TM) SE Runtime Environment". **vendor**, for example: "Oracle 
Corporation". **version** ,for example: "1.8.0_212-b10" | VM version info       
                                                                                
 |
+| jvm_info                                   | Gauge   | **runtime**, for 
example: "Java(TM) SE Runtime Environment". **vendor**, for example: "Oracle 
Corporation". **version** ,for example: "11.0.22+7"    | VM version info        
                                                                                
|
 | process_cpu_seconds_total                  | Counter | -                     
                                                                                
                                                | Total user and system CPU 
time spent in seconds                                                        |
 | process_start_time_seconds                 | Gauge   | -                     
                                                                                
                                                | Start time of the process 
since unix epoch in seconds                                                  |
 | process_open_fds                           | Gauge   | -                     
                                                                                
                                                | Number of open file 
descriptors                                                                     
   |
diff --git a/docs/en/getting-started/docker/docker.md 
b/docs/en/getting-started/docker/docker.md
index 9a91f9f835..5e3ac840d6 100644
--- a/docs/en/getting-started/docker/docker.md
+++ b/docs/en/getting-started/docker/docker.md
@@ -64,7 +64,7 @@ docker images | grep apache/seatunnel
 
 The Dockerfile is like this:
 ```dockerfile
-FROM seatunnelhub/openjdk:8u342
+FROM eclipse-temurin:11-jdk
 
 ARG VERSION
 # Build from Source Code And Copy it into image
diff --git a/docs/en/getting-started/kubernetes/kubernetes.mdx 
b/docs/en/getting-started/kubernetes/kubernetes.mdx
index 896f7a44bb..5431ec45b4 100644
--- a/docs/en/getting-started/kubernetes/kubernetes.mdx
+++ b/docs/en/getting-started/kubernetes/kubernetes.mdx
@@ -89,7 +89,7 @@ minikube start --kubernetes-version=v1.23.3
 For production environments, pin the SeaTunnel image tag and build commonly 
used connectors, dependencies, and base configuration into the image. This 
avoids uncertainty caused by downloading dependencies at runtime.
 
 ```Dockerfile
-FROM seatunnelhub/openjdk:8u342
+FROM eclipse-temurin:11-jdk
 
 ARG SEATUNNEL_VERSION
 ENV SEATUNNEL_HOME="/opt/seatunnel"
diff --git a/docs/en/getting-started/locally/deployment.md 
b/docs/en/getting-started/locally/deployment.md
index d640d4023b..077faded16 100644
--- a/docs/en/getting-started/locally/deployment.md
+++ b/docs/en/getting-started/locally/deployment.md
@@ -11,7 +11,7 @@ import TabItem from '@theme/TabItem';
 
 Before starting to download SeaTunnel, you need to ensure that you have 
installed the following software required by SeaTunnel:
 
-* Install [Java](https://www.java.com/en/download/) (Java 8 or 11, and other 
versions higher than Java 8 can theoretically work) and set `JAVA_HOME`.
+* Install [Java](https://www.java.com/en/download/) (Java 11 or Java 17) and 
set `JAVA_HOME`.
 
 ## Download SeaTunnel Release Package
 
@@ -92,9 +92,7 @@ If you want to install connector plugins by manually 
downloading connectors, you
 :::
 
 :::note Developer note
-
 This local deployment guide assumes that you use an official binary release 
package. If you need to validate unreleased code, debug SeaTunnel source code, 
or prepare a custom distribution, see [Set Up Develop 
Environment](../../developer/setup.md).
-
 :::
 
 # Run SeaTunnel
diff --git a/docs/en/getting-started/overview.md 
b/docs/en/getting-started/overview.md
index ceced1703b..d49561aac0 100644
--- a/docs/en/getting-started/overview.md
+++ b/docs/en/getting-started/overview.md
@@ -60,7 +60,7 @@ If you want to validate your installation in the shortest 
path:
 
 ## What You Need Before Using SeaTunnel
 
-- Java 8 or Java 11 with `JAVA_HOME` configured
+- Java 11 or Java 17 with `JAVA_HOME` configured
 - A SeaTunnel binary package from the [download 
page](https://seatunnel.apache.org/download)
 - Required connector plugins installed under `${SEATUNNEL_HOME}/connectors/`
 - Any third-party driver jars required by your chosen connectors
diff --git a/docs/en/introduction/concepts/incompatible-changes.md 
b/docs/en/introduction/concepts/incompatible-changes.md
index b89ac06de8..ac37c957a3 100644
--- a/docs/en/introduction/concepts/incompatible-changes.md
+++ b/docs/en/introduction/concepts/incompatible-changes.md
@@ -5,6 +5,23 @@ You need to check this document before you upgrade to related 
version.
 
 ## dev
 
+### Runtime Requirements
+
+- **Breaking Change: Minimum Java runtime raised from Java 8 to Java 11**
+  - **Affected component**: every module — the whole distribution, the Zeta 
engine, all connectors, and the published Docker image
+  - **Description**: The build now targets Java 11 (`maven.compiler.source` 
and `maven.compiler.target` are `11`), so every published jar contains class 
file version 55. GitHub CI compiles and tests on JDK 17 against this Java 11 
baseline, and the published Docker image moved from 
`seatunnelhub/openjdk:8u342` to `eclipse-temurin:11-jdk`, keeping a full JDK 
rather than a JRE so `jps`/`jstack`/`jmap` stay available for diagnosing a 
running node.
+  - **Impact**:
+    - A Java 8 JVM can no longer load SeaTunnel classes. Startup fails with 
`java.lang.UnsupportedClassVersionError: ... has been compiled by a more recent 
version of the Java Runtime (class file version 55.0)`. This applies to the 
client, to the Zeta master and worker nodes, and to any process that loads 
connector jars.
+    - **Flink**: the JobManager and TaskManager JVMs load SeaTunnel connector 
classes, so the whole Flink cluster must run Java 11 or later, not just the 
submitting client. Flink supports Java 11 from 1.13 onward, and the official 
Flink images publish `-java11` tags.
+    - **Spark**: the driver and executor JVMs load SeaTunnel connector 
classes, so the whole Spark cluster must run Java 11 or later. Spark only 
gained official Java 11 support in Spark 3.0 (SPARK-24417). Spark 2.4 does 
still start under Java 11, but it logs illegal reflective access warnings and 
puts an old commons-lang3 on the classpath that some connectors trip over, so 
Spark 3.x is strongly recommended.
+    - Third-party connectors that are themselves compiled for Java 8 keep 
working. A Java 11 JVM loads older class files without changes, so only the JVM 
version matters, not the bytecode level of your own jars.
+  - **Migration Guide**:
+    1. Upgrade the JVM to Java 11 or Java 17 on every node that runs SeaTunnel 
code: the client, the Zeta master and workers, and the Flink or Spark cluster 
you submit to.
+    2. If you submit to Flink, move the cluster onto an image or deployment 
that runs Java 11 or later.
+    3. If you submit to Spark 2.4, upgrade to Spark 3.x running on Java 11 or 
later. There is no Spark 2.x release that supports Java 11.
+    4. If you customized `${SEATUNNEL_HOME}/config/jvm_options` (or the 
client, master and worker variants), check your additions for flags that Java 
11 removed, such as `-XX:+UseConcMarkSweepGC` or `-XX:MaxPermSize`, because the 
JVM refuses to start on an unrecognized flag. The options shipped by default 
are already Java 11 compatible.
+    5. You do not have to copy the new JDK module flags into a preserved 
config directory. `seatunnel.sh` and `seatunnel-cluster.sh` append the 
mandatory `--add-opens`/`--add-exports` flags (`java.base/java.lang`, 
`java.net`, `java.nio`, `java.util`, `sun.nio.ch`, and 
`java.security.jgss/sun.security.krb5`) themselves and skip any your 
`jvm_*_options` already carries, so an in-place upgrade that keeps an old 
`config/` directory (a mounted Docker volume or a Kubernetes ConfigMap) still 
st [...]
+
 ### SQL TINYINT array schema
 
 The Zeta SQL ARRAY function now declares TINYINT elements as `ARRAY<TINYINT>`, 
matching the Byte values it emits. The previous `ARRAY<STRING>` declaration 
could fail in schema-dependent row consumers. Update downstream declarations 
that assumed STRING elements; cast the SQL values to STRING explicitly when 
that schema is required. Restart affected jobs with the corrected schema rather 
than restoring state that relies on the old declaration.
diff --git a/docs/zh/developer/setup.md b/docs/zh/developer/setup.md
index 8e9594dfc1..dbcaec1482 100644
--- a/docs/zh/developer/setup.md
+++ b/docs/zh/developer/setup.md
@@ -14,7 +14,7 @@
 在设置开发环境之前, 需要做一些准备工作, 确保你安装了以下软件:
 
 * 安装 [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)。
-* 安装 [Java](https://www.java.com/en/download/) (目前只支持 JDK8/JDK11) 并且设置 
`JAVA_HOME` 环境变量。
+* 安装 [Java](https://www.java.com/en/download/) (目前只支持 JDK11/JDK17) 并且设置 
`JAVA_HOME` 环境变量。
 * 安装 [Scala](https://www.scala-lang.org/download/2.11.12.html) (目前只支持 scala 
2.11.12)。
 * 安装 [JetBrains IDEA](https://www.jetbrains.com/idea/)。
 
@@ -122,4 +122,3 @@ sink {
   Console {}
 }
 ```
-
diff --git a/docs/zh/developer/shade-guide.md b/docs/zh/developer/shade-guide.md
index 9aca196d7c..98da196b06 100644
--- a/docs/zh/developer/shade-guide.md
+++ b/docs/zh/developer/shade-guide.md
@@ -85,7 +85,7 @@ ${library.version}-${seatunnel.shade.version}
 
 ### 前置条件
 
-- Java 8+
+- Java 11+
 - Maven 3.x
 
 ### 克隆并构建
diff --git a/docs/zh/edge-agent/quick-start.md 
b/docs/zh/edge-agent/quick-start.md
index dbf727535c..b4355e2e0e 100644
--- a/docs/zh/edge-agent/quick-start.md
+++ b/docs/zh/edge-agent/quick-start.md
@@ -31,7 +31,7 @@ cd "$EDGE_AGENT_HOME"
 
 ### 前提
 
-- 边缘主机已安装 Java 8 或 11,并设置 JAVA_HOME。
+- 边缘主机已安装 Java 11 或 17,并设置 JAVA_HOME。
 - 不需要 SeaTunnel Engine,也不需要 EdgeSocket 网络连通。
 - 安装根目录可写(默认持久化文件 data、日志、edge-agent.id)。
 
@@ -182,4 +182,3 @@ sh bin/seatunnel-edge-agent.sh stop
 
 快速开始完成后,建议继续阅读 [部署指南](deployment-guide.md) 进行生产部署,或查看 
[配置参数说明](configuration.md) 了解完整参数。全部文档导航见 [关于 Edge Agent](about.md#推荐阅读顺序)。
 
-
diff --git a/docs/zh/engines/zeta/download-seatunnel.md 
b/docs/zh/engines/zeta/download-seatunnel.md
index 7f2f8aca54..63dee017d2 100644
--- a/docs/zh/engines/zeta/download-seatunnel.md
+++ b/docs/zh/engines/zeta/download-seatunnel.md
@@ -11,7 +11,7 @@ import TabItem from '@theme/TabItem';
 
 在开始下载SeaTunnel之前,您需要确保您已经安装了SeaTunnel所需要的以下软件:
 
-* 安装[Java](https://www.java.com/en/download/) (Java 8 或 11, 其他高于Java 
8的版本理论上也可以工作) 以及设置 `JAVA_HOME`。
+* 安装[Java](https://www.java.com/en/download/) (Java 11 或 Java 17) 以及设置 
`JAVA_HOME`。
 
 ## 步骤 2: 下载 SeaTunnel
 
diff --git a/docs/zh/engines/zeta/telemetry.md 
b/docs/zh/engines/zeta/telemetry.md
index bd9841c424..4e2bd1d14e 100644
--- a/docs/zh/engines/zeta/telemetry.md
+++ b/docs/zh/engines/zeta/telemetry.md
@@ -207,7 +207,7 @@ worker 发送 `RequestSlotOperation` 请求以预留 slot。这些指标用于
 | jvm_memory_pool_allocated_bytes_total      | Counter | **pool**,包括:"Code 
Cache" "PS Eden Space" "PS Old Gen" "PS Survivor Space" "Compressed Class 
Space" "Metaspace" | 在给定 JVM 内存池中分配的总字节数。仅在垃圾收集后更新,而不是持续更新。 |
 | jvm_gc_collection_seconds_count            | Summary | **gc**,包括:"PS 
Scavenge" "PS MarkSweep"                                                        
                | 在给定 JVM 垃圾收集器中花费的时间(以秒为单位)             |
 | jvm_gc_collection_seconds_sum              | Summary | **gc**,包括:"PS 
Scavenge" "PS MarkSweep"                                                        
                | 在给定 JVM 垃圾收集器中花费的时间(以秒为单位)             
-| jvm_info                                   | Gauge   | 
**runtime**,例如:“Java(TM) SE Runtime Environment”。**供应商**,例如:“Oracle 
Corporation”。**版本**,例如:“1.8.0_212-b10”    | VM 版本信息                             
   |
+| jvm_info                                   | Gauge   | 
**runtime**,例如:“Java(TM) SE Runtime Environment”。**供应商**,例如:“Oracle 
Corporation”。**版本**,例如:“11.0.22+7”       | VM 版本信息                              
  |
 | process_cpu_seconds_total                  | Counter | -                     
                                                                                
        | 用户和系统 CPU 时间总计,以秒为单位                   |
 | process_start_time_seconds                 | Gauge   | -                     
                                                                                
        | 进程自 Unix 纪元以来的启动时间,以秒为单位               |
 | process_open_fds                           | Gauge   | -                     
                                                                                
        | 打开的文件描述符数量                             |
diff --git a/docs/zh/getting-started/docker/docker.md 
b/docs/zh/getting-started/docker/docker.md
index f637bf9067..85f76618e2 100644
--- a/docs/zh/getting-started/docker/docker.md
+++ b/docs/zh/getting-started/docker/docker.md
@@ -64,7 +64,7 @@ docker images | grep apache/seatunnel
 
 Dockerfile文件内容为:
 ```dockerfile
-FROM seatunnelhub/openjdk:8u342
+FROM eclipse-temurin:11-jdk
 
 ARG VERSION
 # Build from Source Code And Copy it into image
@@ -394,4 +394,4 @@ docker run --name seatunnel_client \
 更多其他命令请参考[命令行工具](../../engines/zeta/user-command.md)
 
 #### 使用RestAPI
-请参考 [提交作业](../../engines/zeta/rest-api-v2.md#提交作业)
\ No newline at end of file
+请参考 [提交作业](../../engines/zeta/rest-api-v2.md#提交作业)
diff --git a/docs/zh/getting-started/kubernetes/kubernetes.mdx 
b/docs/zh/getting-started/kubernetes/kubernetes.mdx
index cdc3e9894b..a4a69c0125 100644
--- a/docs/zh/getting-started/kubernetes/kubernetes.mdx
+++ b/docs/zh/getting-started/kubernetes/kubernetes.mdx
@@ -89,7 +89,7 @@ minikube start --kubernetes-version=v1.23.3
 生产环境建议固定 SeaTunnel 镜像 tag,并将常用连接器、依赖和基础配置构建到镜像中,避免运行时下载依赖带来的不确定性。
 
 ```Dockerfile
-FROM seatunnelhub/openjdk:8u342
+FROM eclipse-temurin:11-jdk
 
 ARG SEATUNNEL_VERSION
 ENV SEATUNNEL_HOME="/opt/seatunnel"
diff --git a/docs/zh/getting-started/locally/deployment.md 
b/docs/zh/getting-started/locally/deployment.md
index ef18f66b7b..ec18145c12 100644
--- a/docs/zh/getting-started/locally/deployment.md
+++ b/docs/zh/getting-started/locally/deployment.md
@@ -11,7 +11,7 @@ import TabItem from '@theme/TabItem';
 
 在开始本地运行前,您需要确保您已经安装了SeaTunnel所需要的以下软件:
 
-* 安装[Java](https://www.java.com/en/download/) (Java 8 或 11, 其他高于Java 
8的版本理论上也可以工作) 以及设置 `JAVA_HOME`。
+* 安装[Java](https://www.java.com/en/download/) (Java 11 或 Java 17) 以及设置 
`JAVA_HOME`。
 
 ## 下载 SeaTunnel 发行包
 
diff --git a/docs/zh/getting-started/overview.md 
b/docs/zh/getting-started/overview.md
index a3db40fa28..39a6e63bb6 100644
--- a/docs/zh/getting-started/overview.md
+++ b/docs/zh/getting-started/overview.md
@@ -60,7 +60,7 @@ SeaTunnel 是一个分布式数据集成平台,用统一的连接器模型处
 
 ## 开始之前需要准备什么
 
-- Java 8 或 Java 11,并正确设置 `JAVA_HOME`
+- Java 11 或 Java 17,并正确设置 `JAVA_HOME`
 - 从 [下载页面](https://seatunnel.apache.org/download) 获取 SeaTunnel 二进制包
 - 在 `${SEATUNNEL_HOME}/connectors/` 下安装所需插件
 - 如果所选连接器依赖第三方驱动,还需要准备对应 jar 包
diff --git a/docs/zh/introduction/concepts/incompatible-changes.md 
b/docs/zh/introduction/concepts/incompatible-changes.md
index 002cd6642e..cddfe214fe 100644
--- a/docs/zh/introduction/concepts/incompatible-changes.md
+++ b/docs/zh/introduction/concepts/incompatible-changes.md
@@ -4,6 +4,23 @@
 
 ## dev
 
+### 运行环境要求
+
+- **破坏性变更:最低 Java 运行时从 Java 8 提升到 Java 11**
+  - **影响范围**:所有模块——整个发行包、Zeta 引擎、全部连接器,以及发布的 Docker 镜像
+  - **变更说明**:构建目标改为 Java 11(`maven.compiler.source` 与 `maven.compiler.target` 
均为 `11`),因此发布的每个 jar 的 class 文件版本都是 55。GitHub CI 基于该 Java 11 基线在 JDK 17 
上编译和测试,发布的 Docker 镜像也从 `seatunnelhub/openjdk:8u342` 改为 
`eclipse-temurin:11-jdk`——仍保留完整 JDK 而非 JRE,以便 `jps`/`jstack`/`jmap` 
继续可用于诊断运行中的节点。
+  - **影响**:
+    - Java 8 JVM 无法再加载 SeaTunnel 的类,启动时会抛出 
`java.lang.UnsupportedClassVersionError: ... has been compiled by a more recent 
version of the Java Runtime (class file version 55.0)`。客户端、Zeta master 与 worker 
节点,以及任何会加载连接器 jar 的进程都受此影响。
+    - **Flink**:JobManager 和 TaskManager 的 JVM 会加载 SeaTunnel 连接器类,因此整个 Flink 
集群都必须运行 Java 11 及以上,而不只是提交作业的客户端。Flink 从 1.13 起支持 Java 11,官方 Flink 镜像提供 
`-java11` 标签。
+    - **Spark**:Driver 和 Executor 的 JVM 会加载 SeaTunnel 连接器类,因此整个 Spark 集群都必须运行 
Java 11 及以上。Spark 从 3.0 起才正式支持 Java 11(SPARK-24417)。Spark 2.4 在 Java 11 
上仍可启动,但会打印非法反射访问告警,并且会把较老的 commons-lang3 放进 classpath,部分连接器会因此初始化失败,因此强烈建议使用 
Spark 3.x。
+    - 已按 Java 8 编译的第三方连接器仍可正常使用。Java 11 JVM 可以直接加载更低版本的 class 文件,所以只有 JVM 
版本有要求,对您自己 jar 的字节码级别没有要求。
+  - **迁移指南**:
+    1. 将所有运行 SeaTunnel 代码的节点的 JVM 升级到 Java 11 或 Java 17:客户端、Zeta master 与 
worker,以及作业提交到的 Flink 或 Spark 集群。
+    2. 如果提交到 Flink,请将集群切换到运行 Java 11 及以上的镜像或部署。
+    3. 如果提交到 Spark 2.4,请升级到运行在 Java 11 及以上的 Spark 3.x。Spark 2.x 没有任何版本支持 Java 
11。
+    4. 如果您修改过 `${SEATUNNEL_HOME}/config/jvm_options`(以及 client、master、worker 
对应的变体),请检查自己添加的参数中是否包含 Java 11 已移除的选项,例如 `-XX:+UseConcMarkSweepGC` 或 
`-XX:MaxPermSize`,JVM 遇到无法识别的参数会直接拒绝启动。发行包默认提供的参数已经兼容 Java 11。
+    5. 无需把新增的 JDK 模块参数手工复制到保留下来的配置目录中。`seatunnel.sh` 和 `seatunnel-cluster.sh` 
会自行追加必需的 `--add-opens`/`--add-exports` 
参数(`java.base/java.lang`、`java.net`、`java.nio`、`java.util`、`sun.nio.ch`,以及 
`java.security.jgss/sun.security.krb5`),并跳过您的 `jvm_*_options` 
中已有的同名参数,因此原地升级并保留旧的 `config/` 目录(挂载的 Docker 卷或 Kubernetes 
ConfigMap)时,这些参数依然生效。当检测到的 JVM 版本低于 11 时,同样的脚本会直接以明确的 `SeaTunnel requires Java 
11 or newer` 提示退出,而不是让 Java 8 启动器输出原始的 `Unrecognized option` 错误。
+
 ### SQL TINYINT 数组模式
 
 Zeta SQL ARRAY 函数现在将 TINYINT 元素声明为 `ARRAY<TINYINT>`,与实际输出的 Byte 值一致。此前错误的 
`ARRAY<STRING>` 声明会导致依赖模式的行处理失败。请更新假定元素为 STRING 的下游声明;需要字符串模式时,在 SQL 中显式将值转换为 
STRING。受影响的作业应使用修正后的模式重新启动,不要恢复依赖旧声明的状态。
diff --git a/pom.xml b/pom.xml
index baf66a1ff9..831aac0e4d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,11 +77,16 @@
         
<seatunnel.shade.calcite.version>1.38.0</seatunnel.shade.calcite.version>
 
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <java.version>1.8</java.version>
+        <java.version>11</java.version>
         <scala.version>2.12.15</scala.version>
         <scala.binary.version>2.12</scala.binary.version>
         <maven.compiler.source>${java.version}</maven.compiler.source>
         <maven.compiler.target>${java.version}</maven.compiler.target>
+        <!-- Constrains javac to the API surface of java.version, not merely 
its bytecode level,
+             so compiling on a JDK newer than java.version cannot silently 
link against APIs the
+             target runtime does not have. Modules that must still output Java 
8 bytecode override
+             this property (not source/target, which the compiler plugin below 
no longer reads). -->
+        <maven.compiler.release>${java.version}</maven.compiler.release>
 
         <system-rules.version>1.2.1</system-rules.version>
         <powermock.version>2.0.9</powermock.version>
@@ -166,6 +171,19 @@
         <hugegraph.client.version>1.7.0</hugegraph.client.version>
         <!-- Option args -->
         <surefire.jvm.args>-Dfile.encoding=UTF-8</surefire.jvm.args>
+        <!--
+            JDK 9+ dropped default reflective access to several JDK internals 
that Hazelcast (the
+            Zeta engine's runtime) and this project's own reflective 
Kerberos/classloader helpers
+            depend on; see the comments in config/jvm_options for the per-flag 
rationale. Test JVMs
+            forked by Surefire/Failsafe need the same flags the launcher 
scripts inject for a real
+            cluster. They live in their own property, separate from 
surefire.jvm.args, so a CLI
+            override such as -Dsurefire.jvm.args=-Xmx3g (used by the unit-test 
CI lane) cannot
+            silently drop them, and in a plain property rather than a 
JDK-activated profile because
+            activating any profile by <jdk> deactivates the activeByDefault 
"release" profile and
+            silently removes seatunnel-dist from the default reactor. Java 11 
is the compile
+            baseline (maven.compiler.release), so the flags are always valid 
and need no JDK gate.
+        -->
+        <surefire.module.args>--add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.net=ALL-UNNAMED 
--add-opens=java.base/java.nio=ALL-UNNAMED 
--add-opens=java.base/java.util=ALL-UNNAMED 
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED 
--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED</surefire.module.args>
         <skipUT>false</skipUT>
         <skipIT>true</skipIT>
         <elasticsearch>7</elasticsearch>
@@ -768,8 +786,7 @@
                     <artifactId>maven-compiler-plugin</artifactId>
                     <version>${maven-compiler-plugin.version}</version>
                     <configuration>
-                        <source>${maven.compiler.source}</source>
-                        <target>${maven.compiler.target}</target>
+                        <release>${maven.compiler.release}</release>
                         <forceJavacCompilerUse>true</forceJavacCompilerUse>
                     </configuration>
                 </plugin>
@@ -778,7 +795,7 @@
                     <artifactId>maven-surefire-plugin</artifactId>
                     <version>${maven-surefire-plugin.version}</version>
                     <configuration>
-                        <argLine>${surefire.jvm.args}</argLine>
+                        <argLine>${surefire.jvm.args} 
${surefire.module.args}</argLine>
                         <skip>${skipUT}</skip>
                         <systemPropertyVariables>
                             
<jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile>
@@ -810,7 +827,7 @@
                     <artifactId>maven-failsafe-plugin</artifactId>
                     <version>${maven-failsafe-plugin.version}</version>
                     <configuration>
-                        <argLine>${surefire.jvm.args}</argLine>
+                        <argLine>${surefire.jvm.args} 
${surefire.module.args}</argLine>
                         <skip>${skipIT}</skip>
                     </configuration>
                     <executions>
diff --git a/seatunnel-ci-tools/pom.xml b/seatunnel-ci-tools/pom.xml
index 783d263ba7..136dc8bddc 100644
--- a/seatunnel-ci-tools/pom.xml
+++ b/seatunnel-ci-tools/pom.xml
@@ -50,8 +50,7 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <configuration>
-                    <source>8</source>
-                    <target>8</target>
+                    <release>8</release>
                 </configuration>
             </plugin>
         </plugins>
diff --git 
a/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/exception/EdgeSocketConnectorErrorCode.java
 
b/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/exception/EdgeSocketConnectorErrorCode.java
index 1861682383..5dd61b2073 100644
--- 
a/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/exception/EdgeSocketConnectorErrorCode.java
+++ 
b/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/exception/EdgeSocketConnectorErrorCode.java
@@ -30,7 +30,8 @@ public enum EdgeSocketConnectorErrorCode implements 
SeaTunnelErrorCode {
     PACKET_AES_KEY_MISSING("EDGE_SOCKET-08", "Missing secret_key for AES_GCM 
packet"),
     COLLECTOR_REJECTED(
             "EDGE_SOCKET-09",
-            "Rejected collector connection because another collector is 
already connected");
+            "Rejected collector connection because another collector is 
already connected"),
+    PACKET_DECRYPT_ERROR("EDGE_SOCKET-10", "Failed to decrypt ingress packet");
 
     private final String code;
     private final String description;
diff --git 
a/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/serialize/record/EdgeSocketPacketRecordDeserializer.java
 
b/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/serialize/record/EdgeSocketPacketRecordDeserializer.java
index 265a80464c..af6021547d 100644
--- 
a/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/serialize/record/EdgeSocketPacketRecordDeserializer.java
+++ 
b/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/serialize/record/EdgeSocketPacketRecordDeserializer.java
@@ -32,6 +32,7 @@ import javax.crypto.spec.GCMParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
 import java.security.GeneralSecurityException;
+import java.security.ProviderException;
 import java.util.Base64;
 
 public class EdgeSocketPacketRecordDeserializer implements 
EdgeSocketRecordDeserializer {
@@ -104,16 +105,24 @@ public class EdgeSocketPacketRecordDeserializer 
implements EdgeSocketRecordDeser
                     EdgeSocketConnectorErrorCode.PACKET_DECODE_ERROR,
                     "Missing iv in AES_GCM packet");
         }
+        byte[] iv;
+        try {
+            iv = Base64.getDecoder().decode(packet.getIv());
+        } catch (IllegalArgumentException invalidIvException) {
+            throw new EdgeSocketConnectorException(
+                    EdgeSocketConnectorErrorCode.PACKET_DECODE_ERROR,
+                    "Decode AES_GCM iv failed",
+                    invalidIvException);
+        }
         try {
-            byte[] iv = Base64.getDecoder().decode(packet.getIv());
             Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
             SecretKeySpec key = new SecretKeySpec(config.getSecretKeyBytes(), 
"AES");
             cipher.init(
                     Cipher.DECRYPT_MODE, key, new 
GCMParameterSpec(AES_GCM_TAG_LENGTH_BITS, iv));
             return cipher.doFinal(payloadBytes);
-        } catch (GeneralSecurityException securityException) {
+        } catch (GeneralSecurityException | ProviderException 
securityException) {
             throw new EdgeSocketConnectorException(
-                    EdgeSocketConnectorErrorCode.PACKET_DECODE_ERROR,
+                    EdgeSocketConnectorErrorCode.PACKET_DECRYPT_ERROR,
                     "AES_GCM decrypt failed",
                     securityException);
         }
diff --git 
a/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/source/EdgeSocketSourceReader.java
 
b/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/source/EdgeSocketSourceReader.java
index f914b4e96e..ec495ea6df 100644
--- 
a/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/source/EdgeSocketSourceReader.java
+++ 
b/seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/source/EdgeSocketSourceReader.java
@@ -224,7 +224,6 @@ public class EdgeSocketSourceReader extends 
AbstractSingleSplitReader<SeaTunnelR
         EdgeSocketConnectorErrorCode errorCode =
                 (EdgeSocketConnectorErrorCode) 
exception.getSeaTunnelErrorCode();
         return errorCode == EdgeSocketConnectorErrorCode.PACKET_AES_KEY_MISSING
-                || (errorCode == 
EdgeSocketConnectorErrorCode.PACKET_DECODE_ERROR
-                        && exception.getCause() instanceof 
java.security.GeneralSecurityException);
+                || errorCode == 
EdgeSocketConnectorErrorCode.PACKET_DECRYPT_ERROR;
     }
 }
diff --git a/seatunnel-connectors-v2/connector-fluss/pom.xml 
b/seatunnel-connectors-v2/connector-fluss/pom.xml
index 8db032b6f9..b66f8184bd 100644
--- a/seatunnel-connectors-v2/connector-fluss/pom.xml
+++ b/seatunnel-connectors-v2/connector-fluss/pom.xml
@@ -46,6 +46,43 @@
             <artifactId>fluss-client</artifactId>
             <version>${fluss.client.version}</version>
         </dependency>
+        <!--
+            fluss-client calls 
org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast, which
+            returns null from JavaVersion.get(...) and then throws NPE on 
runtimes the bundled
+            commons-lang3 predates. Spark 2.4 puts commons-lang3 3.5 on the 
classpath, so on
+            Java 11 the Fluss source and sink fail to initialise. Pin a 
version that knows modern
+            Java and relocate it below so the engine's own copy cannot win.
+        -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons-lang3.version}</version>
+        </dependency>
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <relocations>
+                                <relocation>
+                                    <pattern>org.apache.commons.lang3</pattern>
+                                    
<shadedPattern>${seatunnel.shade.package}.fluss.org.apache.commons.lang3</shadedPattern>
+                                </relocation>
+                            </relocations>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
 </project>
diff --git a/seatunnel-connectors-v2/connector-iceberg/pom.xml 
b/seatunnel-connectors-v2/connector-iceberg/pom.xml
index 411bc8ae60..c30bb45c70 100644
--- a/seatunnel-connectors-v2/connector-iceberg/pom.xml
+++ b/seatunnel-connectors-v2/connector-iceberg/pom.xml
@@ -110,6 +110,12 @@
             <artifactId>orc-core</artifactId>
             <version>1.7.5</version>
             <classifier>nohive</classifier>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.hadoop</groupId>
+                    <artifactId>hadoop-client-api</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.apache.iceberg</groupId>
diff --git 
a/seatunnel-connectors-v2/connector-kudu/src/main/java/org/apache/seatunnel/connectors/seatunnel/kudu/util/KuduUtil.java
 
b/seatunnel-connectors-v2/connector-kudu/src/main/java/org/apache/seatunnel/connectors/seatunnel/kudu/util/KuduUtil.java
index 4b1f4239d5..462ead3054 100644
--- 
a/seatunnel-connectors-v2/connector-kudu/src/main/java/org/apache/seatunnel/connectors/seatunnel/kudu/util/KuduUtil.java
+++ 
b/seatunnel-connectors-v2/connector-kudu/src/main/java/org/apache/seatunnel/connectors/seatunnel/kudu/util/KuduUtil.java
@@ -40,8 +40,6 @@ import org.apache.kudu.client.KuduScanToken;
 import org.apache.kudu.client.KuduTable;
 
 import lombok.extern.slf4j.Slf4j;
-import sun.security.krb5.Config;
-import sun.security.krb5.KrbException;
 
 import javax.security.auth.Subject;
 import javax.security.auth.kerberos.KerberosPrincipal;
@@ -146,12 +144,33 @@ public class KuduUtil {
 
     private static void reloadKrb5conf(String krb5conf) {
         System.setProperty(KRB5_CONF_KEY, krb5conf);
+        refreshJdkKerberosConfig();
+        KerberosName.resetDefaultRealm();
+    }
+
+    /**
+     * Refresh the JDK Kerberos configuration without a compile-time 
dependency on internal JDK
+     * packages. Directly importing sun.security.krb5.Config breaks Java 17 
compilation because the
+     * package is not exported by the java.security.jgss module.
+     */
+    private static void refreshJdkKerberosConfig() {
         try {
-            Config.refresh();
-            KerberosName.resetDefaultRealm();
-        } catch (KrbException e) {
+            
Class.forName("sun.security.krb5.Config").getMethod("refresh").invoke(null);
+        } catch (IllegalAccessException e) {
+            // Module access denied: the JVM is missing the jgss export, so 
the custom krb5.conf
+            // configured for this source cannot take effect. This is an 
actionable deployment
+            // problem, not a transient refresh failure, so report it at ERROR 
with the fix.
+            log.error(
+                    "JVM module system denied the Kerberos configuration 
reload, so the configured"
+                            + " krb5.conf will NOT take effect. Start the JVM 
with"
+                            + " 
--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED"
+                            + " (shipped in config/jvm_*_options and appended 
by the launch"
+                            + " scripts since the Java 11 baseline).",
+                    e);
+        } catch (ReflectiveOperationException | RuntimeException e) {
             log.warn(
-                    "resetting default realm failed, current default realm 
will still be used.", e);
+                    "refreshing JDK Kerberos configuration failed, current 
default realm will still be used.",
+                    e);
         }
     }
 
diff --git 
a/seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/security/PaimonSecurityContext.java
 
b/seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/security/PaimonSecurityContext.java
index 03decec17e..2b24527c3e 100644
--- 
a/seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/security/PaimonSecurityContext.java
+++ 
b/seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/security/PaimonSecurityContext.java
@@ -34,8 +34,6 @@ import org.apache.paimon.security.SecurityConfiguration;
 import org.apache.paimon.security.SecurityContext;
 
 import lombok.extern.slf4j.Slf4j;
-import sun.security.krb5.Config;
-import sun.security.krb5.KrbException;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -141,11 +139,34 @@ public class PaimonSecurityContext extends 
SecurityContext {
     private static void reloadKrb5conf(String krb5conf) {
         System.setProperty(KRB5_CONF_KEY, krb5conf);
         try {
-            Config.refresh();
+            refreshJdkKerberosConfig();
             KerberosName.resetDefaultRealm();
-        } catch (KrbException e) {
+        } catch (IllegalAccessException e) {
+            // Module access denied: the JVM is missing the jgss export, so 
the custom krb5.conf
+            // configured for this catalog cannot take effect. This is an 
actionable deployment
+            // problem, not a transient refresh failure, so report it at ERROR 
with the fix.
+            log.error(
+                    "JVM module system denied the Kerberos configuration 
reload, so the configured"
+                            + " krb5.conf will NOT take effect. Start the JVM 
with"
+                            + " 
--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED"
+                            + " (shipped in config/jvm_*_options and appended 
by the launch"
+                            + " scripts since the Java 11 baseline).",
+                    e);
+        } catch (ReflectiveOperationException e) {
             log.warn(
                     "resetting default realm failed, current default realm 
will still be used.", e);
         }
     }
+
+    /**
+     * Refreshes the JDK Kerberos configuration so that the krb5.conf just set 
takes effect.
+     *
+     * <p>Invoked reflectively because sun.security.krb5.Config lives in the 
java.security.jgss
+     * module, which does not export it to the unnamed module, so importing it 
directly fails to
+     * compile on Java 17. A failure here leaves the default realm untouched, 
which matches the
+     * previous behaviour when Config.refresh() threw.
+     */
+    private static void refreshJdkKerberosConfig() throws 
ReflectiveOperationException {
+        
Class.forName("sun.security.krb5.Config").getMethod("refresh").invoke(null);
+    }
 }
diff --git a/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-cluster.sh 
b/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-cluster.sh
index 2a91905026..a18431c518 100755
--- a/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-cluster.sh
+++ b/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-cluster.sh
@@ -154,6 +154,32 @@ do
   fi
 done
 
+# SeaTunnel requires Java 11 or newer. Fail fast with an actionable message 
instead of letting a
+# JDK 8 launcher abort on the JDK 9+ module flags below with a cryptic 
"Unrecognized option" error.
+JAVA_MAJOR_VERSION=$(java -version 2>&1 | awk -F '[".]' '/version/ {print ($2 
== "1") ? $3 : $2; exit}')
+if [[ -n "$JAVA_MAJOR_VERSION" && "$JAVA_MAJOR_VERSION" -lt 11 ]]; then
+  echo "Error: SeaTunnel requires Java 11 or newer, but Java 
${JAVA_MAJOR_VERSION} was detected. Point JAVA_HOME/PATH at a Java 11+ JDK." >&2
+  exit 1
+fi
+
+# These JDK module flags are mandatory on Java 11+: Hazelcast needs reflective 
access to JDK
+# internals and the Kerberos krb5.conf reload needs the jgss export. They are 
appended here, not
+# only shipped in the config/jvm_*_options templates, so an in-place upgrade 
that preserves an old
+# config directory (mounted Docker volume, K8s ConfigMap) cannot silently drop 
them. Appending a
+# flag twice is harmless, so config files that already carry them stay 
compatible.
+for module_flag in \
+  "--add-opens=java.base/java.lang=ALL-UNNAMED" \
+  "--add-opens=java.base/java.net=ALL-UNNAMED" \
+  "--add-opens=java.base/java.nio=ALL-UNNAMED" \
+  "--add-opens=java.base/java.util=ALL-UNNAMED" \
+  "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" \
+  "--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED"; do
+  case " ${JAVA_OPTS} " in
+    *" ${module_flag} "*) ;;
+    *) JAVA_OPTS="${JAVA_OPTS} ${module_flag}" ;;
+  esac
+done
+
 # Ensure HeapDumpPath directory exists to avoid OOM dump failures.
 
 HEAP_DUMP_PATH=""
diff --git 
a/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-connector.sh 
b/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-connector.sh
index 92dfa3d275..1b30aad5ae 100755
--- a/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-connector.sh
+++ b/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel-connector.sh
@@ -48,4 +48,18 @@ fi
 set +u
 
CLASS_PATH=${APP_DIR}/connectors/*:${APP_JAR}:${APP_DIR}/lib/seatunnel-transforms-v2.jar
 
-java -cp ${CLASS_PATH} ${LOAD_CLASS} ${args} | grep -v 
'org\.apache\.seatunnel\.plugin\.discovery\.AbstractPluginDiscovery'
+# The second pattern drops the notice log4j-api writes to stdout on every JVM 
newer than Java 8,
+# which would otherwise be parsed as extra connector identifiers by the 
connector check output.
+#
+# set -e is active from the top of the script, and grep exits 1 when it emits 
no lines at all, so
+# the pipeline has to run with errexit off or an empty connector list would 
abort the script before
+# the exit below. PIPESTATUS[0] then reports java's own status rather than 
grep's, which previously
+# let a failing java run be reported as success.
+set +e
+java -cp ${CLASS_PATH} ${LOAD_CLASS} ${args} \
+  | grep -v --line-buffered \
+         -e 
'org\.apache\.seatunnel\.plugin\.discovery\.AbstractPluginDiscovery' \
+         -e '^WARNING: sun\.reflect\.Reflection\.getCallerClass is not 
supported'
+JAVA_EXIT_CODE=${PIPESTATUS[0]}
+set -e
+exit ${JAVA_EXIT_CODE}
diff --git a/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel.sh 
b/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel.sh
index 7af0c149eb..a88704b57b 100755
--- a/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel.sh
+++ b/seatunnel-core/seatunnel-starter/src/main/bin/seatunnel.sh
@@ -109,6 +109,32 @@ do
   fi
 done
 
+# SeaTunnel requires Java 11 or newer. Fail fast with an actionable message 
instead of letting a
+# JDK 8 launcher abort on the JDK 9+ module flags below with a cryptic 
"Unrecognized option" error.
+JAVA_MAJOR_VERSION=$(java -version 2>&1 | awk -F '[".]' '/version/ {print ($2 
== "1") ? $3 : $2; exit}')
+if [[ -n "$JAVA_MAJOR_VERSION" && "$JAVA_MAJOR_VERSION" -lt 11 ]]; then
+  echo "Error: SeaTunnel requires Java 11 or newer, but Java 
${JAVA_MAJOR_VERSION} was detected. Point JAVA_HOME/PATH at a Java 11+ JDK." >&2
+  exit 1
+fi
+
+# These JDK module flags are mandatory on Java 11+: Hazelcast needs reflective 
access to JDK
+# internals and the Kerberos krb5.conf reload needs the jgss export. They are 
appended here, not
+# only shipped in the config/jvm_*_options templates, so an in-place upgrade 
that preserves an old
+# config directory (mounted Docker volume, K8s ConfigMap) cannot silently drop 
them. Appending a
+# flag twice is harmless, so config files that already carry them stay 
compatible.
+for module_flag in \
+  "--add-opens=java.base/java.lang=ALL-UNNAMED" \
+  "--add-opens=java.base/java.net=ALL-UNNAMED" \
+  "--add-opens=java.base/java.nio=ALL-UNNAMED" \
+  "--add-opens=java.base/java.util=ALL-UNNAMED" \
+  "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" \
+  "--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED"; do
+  case " ${JAVA_OPTS} " in
+    *" ${module_flag} "*) ;;
+    *) JAVA_OPTS="${JAVA_OPTS} ${module_flag}" ;;
+  esac
+done
+
 # Ensure HeapDumpPath directory exists to avoid OOM dump failures.
 HEAP_DUMP_PATH=""
 for opt in $JAVA_OPTS; do
@@ -146,4 +172,17 @@ if [[ -n "$GC_LOG_PATH" ]]; then
   fi
 fi
 
-java ${JAVA_OPTS} -cp ${CLASS_PATH} ${APP_MAIN} "${args[@]}"
+# log4j-api writes this notice to stdout on every JVM newer than Java 8, 
because
+# sun.reflect.Reflection.getCallerClass no longer exists there. It corrupts 
the machine readable
+# output of commands that emit JSON, such as `-j <jobId>`, so drop just that 
line.
+#
+# set -e is active from the top of the script, and grep exits 1 when it emits 
no lines at all, so
+# the pipeline has to run with errexit off or a command with empty stdout 
would abort the script
+# before the exit below. PIPESTATUS[0] then reports java's own status rather 
than grep's.
+# --line-buffered keeps job output streaming when stdout is redirected to a 
file.
+set +e
+java ${JAVA_OPTS} -cp ${CLASS_PATH} ${APP_MAIN} "${args[@]}" \
+  | grep -v --line-buffered '^WARNING: 
sun\.reflect\.Reflection\.getCallerClass is not supported'
+JAVA_EXIT_CODE=${PIPESTATUS[0]}
+set -e
+exit ${JAVA_EXIT_CODE}
diff --git 
a/seatunnel-core/seatunnel-starter/src/main/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommand.java
 
b/seatunnel-core/seatunnel-starter/src/main/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommand.java
index 7bf728bce0..0eceb20e56 100644
--- 
a/seatunnel-core/seatunnel-starter/src/main/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommand.java
+++ 
b/seatunnel-core/seatunnel-starter/src/main/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommand.java
@@ -40,8 +40,6 @@ import lombok.extern.slf4j.Slf4j;
 
 import java.util.Collection;
 import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /** This command is used to execute the SeaTunnel engine job by SeaTunnel API. 
*/
 @Slf4j
@@ -85,31 +83,15 @@ public class ServerExecuteCommand implements 
Command<ServerCommandArgs> {
     }
 
     private void checkEnvironment() {
-        if (isAllocatingThreadGetName()) {
+        if (isUnsupportedJavaVersion()) {
             log.warn(
-                    "The current JDK version is not recommended. Please 
upgrade to JDK 1.8.0_102 or higher. "
-                            + "The current version will affect the performance 
of log printing. "
-                            + "For details, please refer to 
https://issues.apache.org/jira/browse/LOG4J2-2052";);
+                    "The current JDK version is not supported. "
+                            + "Please use JDK 11 or JDK 17 to run SeaTunnel.");
         }
     }
 
-    static boolean isAllocatingThreadGetName() {
-        // LOG4J2-2052, LOG4J2-2635 JDK 8u102 ("1.8.0_102") removed the String 
allocation in
-        // Thread.getName()
-        if (SystemUtils.IS_JAVA_1_8) {
-            try {
-                Pattern javaVersionPattern = 
Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)_(\\d+)");
-                Matcher m = 
javaVersionPattern.matcher(System.getProperty("java.version"));
-                if (m.matches()) {
-                    return Integer.parseInt(m.group(3)) == 0 && 
Integer.parseInt(m.group(4)) < 102;
-                }
-                return true;
-            } catch (Exception e) {
-                return true;
-            }
-        } else {
-            return !SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_8);
-        }
+    static boolean isUnsupportedJavaVersion() {
+        return !SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_11);
     }
 
     @VisibleForTesting
diff --git 
a/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommandTest.java
 
b/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommandTest.java
index 78b7d06b7f..d32d942e14 100644
--- 
a/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommandTest.java
+++ 
b/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/command/ServerExecuteCommandTest.java
@@ -24,7 +24,7 @@ import 
org.apache.seatunnel.engine.server.SeaTunnelServerStarter;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.DisabledOnJre;
+import org.junit.jupiter.api.condition.EnabledOnJre;
 import org.junit.jupiter.api.condition.JRE;
 
 import com.hazelcast.cluster.Member;
@@ -37,17 +37,9 @@ import java.util.Set;
 public class ServerExecuteCommandTest {
 
     @Test
-    @DisabledOnJre(value = JRE.JAVA_11, disabledReason = "the test case only 
works on Java 8")
-    public void testJavaVersionCheck() {
-        String realVersion = System.getProperty("java.version");
-        try {
-            System.setProperty("java.version", "1.8.0_191");
-            
Assertions.assertFalse(ServerExecuteCommand.isAllocatingThreadGetName());
-            System.setProperty("java.version", "1.8.0_60");
-            
Assertions.assertTrue(ServerExecuteCommand.isAllocatingThreadGetName());
-        } finally {
-            System.setProperty("java.version", realVersion);
-        }
+    @EnabledOnJre(value = {JRE.JAVA_11, JRE.JAVA_17})
+    public void testSupportedJavaVersionCheck() {
+        
Assertions.assertFalse(ServerExecuteCommand.isUnsupportedJavaVersion());
     }
 
     @Test
diff --git a/seatunnel-dist/src/main/docker/Dockerfile 
b/seatunnel-dist/src/main/docker/Dockerfile
index aa9a7769c9..44cfdf9afc 100644
--- a/seatunnel-dist/src/main/docker/Dockerfile
+++ b/seatunnel-dist/src/main/docker/Dockerfile
@@ -1,4 +1,4 @@
-FROM seatunnelhub/openjdk:8u342 as builder
+FROM eclipse-temurin:11-jdk as builder
 
 ARG VERSION
 
@@ -12,6 +12,9 @@ RUN cd /opt && \
     sed -i 
's/rootLogger.appenderRef.file.ref/#rootLogger.appenderRef.file.ref/' 
seatunnel/config/log4j2.properties && \
     cp seatunnel/config/hazelcast-master.yaml 
seatunnel/config/hazelcast-worker.yaml
 
-FROM seatunnelhub/openjdk:8u342
+FROM eclipse-temurin:11-jdk
+RUN apt-get update \
+    && apt-get install -y --no-install-recommends python3 \
+    && rm -rf /var/lib/apt/lists/*
 COPY --from=builder /opt/seatunnel /opt/seatunnel
 WORKDIR /opt/seatunnel
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-amazondynamodb-e2e/src/test/java/org/apache/seatunnel/e2e/connector/amazondynamodb/AmazondynamodbIT.java
 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-amazondynamodb-e2e/src/test/java/org/apache/seatunnel/e2e/connector/amazondynamodb/AmazondynamodbIT.java
index da4448410e..1a2afbdca6 100644
--- 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-amazondynamodb-e2e/src/test/java/org/apache/seatunnel/e2e/connector/amazondynamodb/AmazondynamodbIT.java
+++ 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-amazondynamodb-e2e/src/test/java/org/apache/seatunnel/e2e/connector/amazondynamodb/AmazondynamodbIT.java
@@ -68,6 +68,7 @@ import java.net.ConnectException;
 import java.net.URI;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -268,7 +269,7 @@ public class AmazondynamodbIT extends TestSuiteBase 
implements TestResource {
                             BigDecimal.valueOf(11, 1),
                             "test".getBytes(),
                             LocalDate.now(),
-                            LocalDateTime.now()
+                            LocalDateTime.now().truncatedTo(ChronoUnit.MICROS)
                         });
 
         Map<String, AttributeValue> data = new 
HashMap<>(seatunnelRowType.getTotalFields());
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-tidb-e2e/pom.xml 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-tidb-e2e/pom.xml
index b0446e6701..32025682c7 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-tidb-e2e/pom.xml
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-cdc-tidb-e2e/pom.xml
@@ -28,6 +28,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
     </properties>
 
     <dependencies>
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-fluss-e2e/pom.xml 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-fluss-e2e/pom.xml
index 4105b14d24..b0c9f3ab81 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-fluss-e2e/pom.xml
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-fluss-e2e/pom.xml
@@ -72,8 +72,7 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <configuration>
-                    <source>8</source>
-                    <target>8</target>
+                    <release>8</release>
                 </configuration>
             </plugin>
         </plugins>
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/java/org/apache/seatunnel/e2e/connector/python/PythonIT.java
 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/java/org/apache/seatunnel/e2e/connector/python/PythonIT.java
index 7165ecef43..6b2d8892a1 100644
--- 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/java/org/apache/seatunnel/e2e/connector/python/PythonIT.java
+++ 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/java/org/apache/seatunnel/e2e/connector/python/PythonIT.java
@@ -37,11 +37,17 @@ import java.io.IOException;
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class PythonIT extends SeaTunnelContainer {
 
+    private static final String PYTHON_EXECUTABLE_ALLOWLIST =
+            
"/usr/bin/python3,/usr/local/bin/python3,/opt/bitnami/python/bin/python3,"
+                    + "/usr/bin/python,/usr/local/bin/python";
+
     @Override
     protected String[] buildStartCommand() {
         return new String[] {
             "env",
-            "JAVA_TOOL_OPTIONS=-Dseatunnel.source.python.enabled=true 
-Dseatunnel.source.python.allowed-executables=/usr/bin/python3",
+            "JAVA_TOOL_OPTIONS=-Dseatunnel.source.python.enabled=true"
+                    + " -Dseatunnel.source.python.allowed-executables="
+                    + PYTHON_EXECUTABLE_ALLOWLIST,
             super.buildStartCommand()[0]
         };
     }
@@ -50,6 +56,8 @@ public class PythonIT extends SeaTunnelContainer {
     @BeforeAll
     public void startUp() throws Exception {
         super.startUp();
+        Container.ExecResult execResult = installPythonIfNecessary();
+        Assertions.assertEquals(0, execResult.getExitCode(), 
execResult.getStderr());
         copyFileToContainer("/python/emit_rows.py", "/tmp/emit_rows.py");
     }
 
@@ -67,4 +75,29 @@ public class PythonIT extends SeaTunnelContainer {
         Container.ExecResult result = executeJob("/python_to_assert.conf");
         Assertions.assertEquals(0, result.getExitCode(), result.getStderr());
     }
+
+    /** Installs python3 in the shared runtime container when the base image 
does not include it. */
+    private Container.ExecResult installPythonIfNecessary()
+            throws IOException, InterruptedException {
+        return server.execInContainer(
+                "bash",
+                "-c",
+                "if command -v python3 >/dev/null 2>&1; then"
+                        + "   python3 --version;"
+                        + " elif command -v apt-get >/dev/null 2>&1; then"
+                        + "   export DEBIAN_FRONTEND=noninteractive;"
+                        + "   apt-get update;"
+                        + "   apt-get install -y --no-install-recommends 
python3;"
+                        + " elif command -v dnf >/dev/null 2>&1; then"
+                        + "   dnf install -y python3;"
+                        + " elif command -v yum >/dev/null 2>&1; then"
+                        + "   yum install -y python3;"
+                        + " elif command -v apk >/dev/null 2>&1; then"
+                        + "   apk add --no-cache python3;"
+                        + " else"
+                        + "   echo 'Unsupported package manager for installing 
python3' >&2;"
+                        + "   exit 1;"
+                        + " fi;"
+                        + " python3 --version;");
+    }
 }
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/resources/python_to_assert.conf
 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/resources/python_to_assert.conf
index 8bc7dbaa22..91cedb5589 100644
--- 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/resources/python_to_assert.conf
+++ 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-python-e2e/src/test/resources/python_to_assert.conf
@@ -23,7 +23,7 @@ env {
 source {
   Python {
     plugin_output = "python_source"
-    python.executable = "/usr/bin/python3"
+    python.executable = "python3"
     python.script.path = "/tmp/emit_rows.py"
     python.working.directory = "/tmp"
     python.script.config = {
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-rabbitmq-e2e/src/test/java/org/apache/seatunnel/e2e/connector/rabbitmq/RabbitmqIT.java
 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-rabbitmq-e2e/src/test/java/org/apache/seatunnel/e2e/connector/rabbitmq/RabbitmqIT.java
index 3444edd01d..2c3ea073ef 100644
--- 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-rabbitmq-e2e/src/test/java/org/apache/seatunnel/e2e/connector/rabbitmq/RabbitmqIT.java
+++ 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-rabbitmq-e2e/src/test/java/org/apache/seatunnel/e2e/connector/rabbitmq/RabbitmqIT.java
@@ -81,6 +81,7 @@ import java.nio.file.Path;
 import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -374,7 +375,7 @@ public class RabbitmqIT extends TestSuiteBase implements 
TestResource {
                                 BigDecimal.valueOf(11, 1),
                                 "test".getBytes(),
                                 LocalDate.now(),
-                                LocalDateTime.now()
+                                
LocalDateTime.now().truncatedTo(ChronoUnit.MICROS)
                             });
             rows.add(row);
         }
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-tdengine-e2e/pom.xml 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-tdengine-e2e/pom.xml
index 04e6744e34..3c27ff77a9 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-tdengine-e2e/pom.xml
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-tdengine-e2e/pom.xml
@@ -28,6 +28,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
     </properties>
     <dependencies>
         <!-- SeaTunnel connectors -->
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-typesense-e2e/pom.xml 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-typesense-e2e/pom.xml
index 0a7243ed6a..e544f5a66a 100644
--- a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-typesense-e2e/pom.xml
+++ b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-typesense-e2e/pom.xml
@@ -30,6 +30,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/docker/spark/Dockerfile 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/docker/spark/Dockerfile
index b7c7a13c6c..1218d5f0b5 100644
--- a/seatunnel-e2e/seatunnel-e2e-common/src/test/docker/spark/Dockerfile
+++ b/seatunnel-e2e/seatunnel-e2e-common/src/test/docker/spark/Dockerfile
@@ -14,7 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM eclipse-temurin:8-jre-jammy
+# A full JDK, not a JRE, to match the rest of this project's E2E engine 
images: ContainerUtil
+# execs jps/jstack/jmap into running containers for the post-job thread-leak 
check.
+FROM eclipse-temurin:11-jdk-jammy
 
 ARG SPARK_VERSION
 ARG HADOOP_PROFILE
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/AbstractTestFlinkContainer.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/AbstractTestFlinkContainer.java
index 88e20e6dd3..95e05d4f98 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/AbstractTestFlinkContainer.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/AbstractTestFlinkContainer.java
@@ -77,7 +77,9 @@ public abstract class AbstractTestFlinkContainer extends 
AbstractTestContainer {
                     "restart-strategy.fixed-delay.attempts: 2",
                     "restart-strategy.fixed-delay.delay: 1000");
 
-    protected static final String DEFAULT_DOCKER_IMAGE = 
"flink:1.13.6-scala_2.11";
+    // Pinned to the java11 flavour: SeaTunnel is built to Java 11 bytecode, 
so a Flink image on a
+    // Java 8 runtime cannot load its classes.
+    protected static final String DEFAULT_DOCKER_IMAGE = 
"flink:1.13.6-scala_2.11-java11";
     private static final int FLINK_REST_PORT = 8081;
 
     protected GenericContainer<?> jobManager;
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink13Container.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink13Container.java
index 27ebdc9e5e..d70c20cd14 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink13Container.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink13Container.java
@@ -19,6 +19,7 @@ package org.apache.seatunnel.e2e.common.container.flink;
 
 import org.apache.seatunnel.e2e.common.container.TestContainer;
 import org.apache.seatunnel.e2e.common.container.TestContainerId;
+import org.apache.seatunnel.e2e.common.util.EngineImageJdkUpgrader;
 
 import com.google.auto.service.AutoService;
 import lombok.NoArgsConstructor;
@@ -39,9 +40,14 @@ public class Flink13Container extends 
AbstractTestFlinkContainer {
         return TestContainerId.FLINK_1_13;
     }
 
+    /**
+     * This tag still ships a Java 8 runtime, which cannot load the Java 11 
bytecode SeaTunnel is
+     * built to, so the image is derived into a Java 11 flavour. The 1.15 to 
1.18 tags already ship
+     * Java 11 and are used as published.
+     */
     @Override
     protected String getDockerImage() {
-        return "tyrantlucifer/flink:1.13.6-scala_2.11_hadoop27";
+        return 
EngineImageJdkUpgrader.toJava11("tyrantlucifer/flink:1.13.6-scala_2.11_hadoop27");
     }
 
     @Override
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink14Container.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink14Container.java
index 9d5327740e..b88014d036 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink14Container.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink14Container.java
@@ -19,6 +19,7 @@ package org.apache.seatunnel.e2e.common.container.flink;
 
 import org.apache.seatunnel.e2e.common.container.TestContainer;
 import org.apache.seatunnel.e2e.common.container.TestContainerId;
+import org.apache.seatunnel.e2e.common.util.EngineImageJdkUpgrader;
 
 import com.google.auto.service.AutoService;
 import lombok.NoArgsConstructor;
@@ -39,9 +40,12 @@ public class Flink14Container extends 
AbstractTestFlinkContainer {
         return TestContainerId.FLINK_1_14;
     }
 
+    /**
+     * Java 8 tag, derived into a Java 11 flavour. See {@link 
Flink13Container#getDockerImage()}.
+     */
     @Override
     protected String getDockerImage() {
-        return "tyrantlucifer/flink:1.14.6-scala_2.11_hadoop27";
+        return 
EngineImageJdkUpgrader.toJava11("tyrantlucifer/flink:1.14.6-scala_2.11_hadoop27");
     }
 
     @Override
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink20Container.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink20Container.java
index 06614e52c6..0e9b814e16 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink20Container.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/flink/Flink20Container.java
@@ -19,6 +19,7 @@ package org.apache.seatunnel.e2e.common.container.flink;
 
 import org.apache.seatunnel.e2e.common.container.TestContainer;
 import org.apache.seatunnel.e2e.common.container.TestContainerId;
+import org.apache.seatunnel.e2e.common.util.EngineImageJdkUpgrader;
 
 import com.google.auto.service.AutoService;
 import lombok.NoArgsConstructor;
@@ -41,9 +42,13 @@ public class Flink20Container extends 
AbstractTestFlinkContainer {
         return TestContainerId.FLINK_1_20;
     }
 
+    /**
+     * The 1.20 tags regressed back to a Java 8 runtime, so this image is 
derived into a Java 11
+     * flavour. See {@link Flink13Container#getDockerImage()}.
+     */
     @Override
     protected String getDockerImage() {
-        return "tyrantlucifer/flink:1.20.1-scala_2.12_hadoop27";
+        return 
EngineImageJdkUpgrader.toJava11("tyrantlucifer/flink:1.20.1-scala_2.12_hadoop27");
     }
 
     @Override
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/ConnectorPackageServiceContainer.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/ConnectorPackageServiceContainer.java
index 9bfc96be5b..0fbbf8d721 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/ConnectorPackageServiceContainer.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/ConnectorPackageServiceContainer.java
@@ -53,7 +53,9 @@ import static 
org.apache.seatunnel.e2e.common.util.ContainerUtil.PROJECT_ROOT_PA
 @NoArgsConstructor
 @Slf4j
 public class ConnectorPackageServiceContainer extends AbstractTestContainer {
-    private static final String JDK_DOCKER_IMAGE = 
"seatunnelhub/openjdk:8u342";
+    // Keep a full JDK image, matching the JDK baseline this container ran on 
before, so JVM
+    // diagnostic tools stay available to the cluster tests running inside it.
+    private static final String JDK_DOCKER_IMAGE = "eclipse-temurin:11-jdk";
     private static final String CLIENT_SHELL = "seatunnel.sh";
     private static final String SERVER_SHELL = "seatunnel-cluster.sh";
     private GenericContainer<?> server1;
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/SeaTunnelContainer.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/SeaTunnelContainer.java
index b617d44c34..6a2846589e 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/SeaTunnelContainer.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/SeaTunnelContainer.java
@@ -92,7 +92,9 @@ public class SeaTunnelContainer extends AbstractTestContainer 
implements Reusabl
     private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
     private static final String REST_STOP_JOB_PATH = "/stop-job";
     private static final String REST_CHECKPOINT_OVERVIEW_PATH = 
"/jobs/checkpoints";
-    protected static final String JDK_DOCKER_IMAGE = 
"seatunnelhub/openjdk:8u342";
+    // Must stay a full JDK image: ContainerUtil inspects the running server 
with jps/jstack/jmap
+    // for the post-job thread-leak checks, and those tools are absent from 
JRE-only images.
+    protected static final String JDK_DOCKER_IMAGE = "eclipse-temurin:11-jdk";
     private static final String CLIENT_SHELL = "seatunnel.sh";
     private static final String CONNECTOR_DIRECTORY = 
"/tmp/seatunnel/connectors";
     private static final String RUNTIME_LIBRARY_DIRECTORY = 
"/tmp/seatunnel/lib";
@@ -707,7 +709,14 @@ public class SeaTunnelContainer extends 
AbstractTestContainer implements Reusabl
                 || s.startsWith("seatunnel-error-sink-")
                 // Jetty QueuedThreadPool NIO selector thread from the 
embedded REST server;
                 // it may outlive the job and cause the E2E thread-leak check 
to fail.
-                || s.startsWith("qtp");
+                || s.startsWith("qtp")
+                // java.lang.ref.Cleaner's worker thread (JDK 9+ replacement 
for the old
+                // sun.misc.Cleaner/finalizer based native resource cleanup). 
Some JDBC drivers
+                // call Cleaner.create() to manage native buffers, and the 
resulting thread runs
+                // for the life of the JVM by design, so it only shows up as a 
false leak on the
+                // first job that lazily triggers it. Now that the e2e engine 
container runs on a
+                // Java 11 JDK image instead of Java 8, this thread is a 
normal presence.
+                || s.startsWith("Cleaner-");
     }
 
     private void classLoaderObjectCheck(Integer maxSize) throws IOException, 
InterruptedException {
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark2Container.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark2Container.java
index 595b6b220a..5ab3dea937 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark2Container.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark2Container.java
@@ -19,6 +19,7 @@ package org.apache.seatunnel.e2e.common.container.spark;
 
 import org.apache.seatunnel.e2e.common.container.TestContainer;
 import org.apache.seatunnel.e2e.common.container.TestContainerId;
+import org.apache.seatunnel.e2e.common.util.EngineImageJdkUpgrader;
 
 import com.google.auto.service.AutoService;
 import lombok.NoArgsConstructor;
@@ -44,9 +45,15 @@ public class Spark2Container extends 
AbstractTestSparkContainer {
         return "seatunnel-spark-starter" + File.separator + 
"seatunnel-spark-2-starter";
     }
 
+    /**
+     * The published image bundles a Java 8 runtime, which cannot load the 
Java 11 bytecode
+     * SeaTunnel is built to, so it is derived into a Java 11 flavour. Note 
that Spark 2.4 predates
+     * Spark's own Java 11 support (SPARK-24417, released in Spark 3.0), so 
this lane is expected to
+     * stay the weakest signal of the matrix.
+     */
     @Override
     protected String getDockerImage() {
-        return "tyrantlucifer/spark:2.4.6";
+        return EngineImageJdkUpgrader.toJava11("tyrantlucifer/spark:2.4.6");
     }
 
     @Override
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark3Container.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark3Container.java
index fd8b3c5e47..545fd62e8f 100644
--- 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark3Container.java
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/spark/Spark3Container.java
@@ -19,6 +19,7 @@ package org.apache.seatunnel.e2e.common.container.spark;
 
 import org.apache.seatunnel.e2e.common.container.TestContainer;
 import org.apache.seatunnel.e2e.common.container.TestContainerId;
+import org.apache.seatunnel.e2e.common.util.EngineImageJdkUpgrader;
 
 import com.google.auto.service.AutoService;
 import lombok.NoArgsConstructor;
@@ -44,9 +45,14 @@ public class Spark3Container extends 
AbstractTestSparkContainer {
         return "seatunnel-spark-starter" + File.separator + 
"seatunnel-spark-3-starter";
     }
 
+    /**
+     * The published image bundles a Java 8 runtime, which cannot load the 
Java 11 bytecode
+     * SeaTunnel is built to, so it is derived into a Java 11 flavour. Spark 
3.3 itself supports
+     * Java 11.
+     */
     @Override
     protected String getDockerImage() {
-        return "tyrantlucifer/spark:3.3.0";
+        return EngineImageJdkUpgrader.toJava11("tyrantlucifer/spark:3.3.0");
     }
 
     @Override
diff --git 
a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/util/EngineImageJdkUpgrader.java
 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/util/EngineImageJdkUpgrader.java
new file mode 100644
index 0000000000..9a92861711
--- /dev/null
+++ 
b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/util/EngineImageJdkUpgrader.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+package org.apache.seatunnel.e2e.common.util;
+
+import org.testcontainers.images.builder.ImageFromDockerfile;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Derives Java 11 flavours of the published engine images the e2e suite pins.
+ *
+ * <p>SeaTunnel jars are compiled to Java 11 bytecode, but several of the 
Flink and Spark images
+ * still ship a Java 8 runtime, so loading any SeaTunnel class inside them 
fails with {@code
+ * UnsupportedClassVersionError: class file version 55.0}. No Java 11 tags are 
published for those
+ * images, and falling back to the vanilla upstream images is not an option 
either: the {@code
+ * *_hadoop27} Flink images carry the shaded Hadoop jars the file based 
connectors need on the Flink
+ * classpath, which is exactly why they were adopted in the first place (see 
issue #2291).
+ *
+ * <p>So the original image is kept byte for byte and only its JVM is 
replaced: a Java 11 JDK is
+ * copied in and the image's own {@code JAVA_HOME} is re-pointed at it through 
a symlink. Because
+ * the swap happens at the path the image already advertises, every hardcoded 
{@code JAVA_HOME}
+ * reference and every {@code PATH} entry baked into the image keeps 
resolving, which matters for
+ * the bitnami based Spark images whose startup scripts export {@code 
JAVA_HOME} themselves.
+ *
+ * <p>A full JDK rather than a JRE is required because {@link ContainerUtil} 
inspects running
+ * servers with {@code jps}, {@code jstack} and {@code jmap}.
+ *
+ * <p>Images that already ship Java 11 must not be routed through this class: 
deriving them would
+ * cost a docker build for no benefit.
+ */
+public final class EngineImageJdkUpgrader {
+
+    /** Source of the Java 11 runtime that replaces the JVM of the derived 
images. */
+    private static final String JDK_IMAGE = "eclipse-temurin:11-jdk";
+
+    /** Path {@link #JDK_IMAGE} unpacks its JDK to, and the path it is copied 
from. */
+    private static final String JDK_IMAGE_JAVA_HOME = "/opt/java/openjdk";
+
+    /** Where the Java 11 JDK is installed before the image's own JAVA_HOME is 
linked to it. */
+    private static final String JDK_INSTALL_PATH = "/opt/seatunnel-e2e-jdk11";
+
+    /** Prefix of the derived image names, kept stable so repeated runs reuse 
the same build. */
+    private static final String DERIVED_IMAGE_PREFIX = "seatunnel-e2e-jdk11-";
+
+    /**
+     * Derived image name per source image. A docker build is expensive, so 
each source image is
+     * derived at most once per JVM and the daemon keeps the result for the 
rest of the job.
+     */
+    private static final Map<String, String> DERIVED_IMAGES = new 
ConcurrentHashMap<>();
+
+    private EngineImageJdkUpgrader() {}
+
+    /**
+     * Returns a Java 11 flavour of {@code sourceImage}, building it on first 
use.
+     *
+     * @param sourceImage published engine image that still ships a Java 8 
runtime
+     * @return name of the derived image, usable anywhere the source image 
name was used
+     */
+    public static String toJava11(String sourceImage) {
+        return DERIVED_IMAGES.computeIfAbsent(sourceImage, 
EngineImageJdkUpgrader::build);
+    }
+
+    private static String build(String sourceImage) {
+        String dockerfile =
+                "FROM "
+                        + JDK_IMAGE
+                        + " AS jdk\n"
+                        + "FROM "
+                        + sourceImage
+                        + "\n"
+                        // bitnami based images build as an unprivileged user, 
so take root before
+                        // replacing the JDK. The e2e containers already run 
as root at runtime.
+                        + "USER root\n"
+                        + "COPY --from=jdk "
+                        + JDK_IMAGE_JAVA_HOME
+                        + " "
+                        + JDK_INSTALL_PATH
+                        + "\n"
+                        // Fail the build loudly rather than silently keeping 
Java 8 if the source
+                        // image does not declare JAVA_HOME. The trailing java 
-version check closes
+                        // a gap the JAVA_HOME test alone does not: some base 
images resolve the
+                        // bare
+                        // `java` on PATH through /usr/bin/java -> 
/etc/alternatives/java rather
+                        // than
+                        // through $JAVA_HOME/bin, so the symlink swap above 
can succeed while the
+                        // java a caller actually invokes is still the 
original Java 8 one.
+                        + "RUN test -n \"$JAVA_HOME\" && rm -rf \"$JAVA_HOME\" 
&& ln -s "
+                        + JDK_INSTALL_PATH
+                        + " \"$JAVA_HOME\""
+                        + " && java -version 2>&1 | grep -q 'version \"11'\n";
+        return new ImageFromDockerfile(derivedImageName(sourceImage), false)
+                .withFileFromString("Dockerfile", dockerfile)
+                .get();
+    }
+
+    /** Turns an image reference into a deterministic, docker compatible 
derived image name. */
+    private static String derivedImageName(String sourceImage) {
+        return DERIVED_IMAGE_PREFIX
+                + 
sourceImage.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9._-]", "-")
+                + ":latest";
+    }
+}
diff --git 
a/seatunnel-e2e/seatunnel-edge-agent-e2e/src/test/java/org/apache/seatunnel/edge/agent/e2e/EdgeAgentContainer.java
 
b/seatunnel-e2e/seatunnel-edge-agent-e2e/src/test/java/org/apache/seatunnel/edge/agent/e2e/EdgeAgentContainer.java
index 8958df7295..d5792e4dd1 100644
--- 
a/seatunnel-e2e/seatunnel-edge-agent-e2e/src/test/java/org/apache/seatunnel/edge/agent/e2e/EdgeAgentContainer.java
+++ 
b/seatunnel-e2e/seatunnel-edge-agent-e2e/src/test/java/org/apache/seatunnel/edge/agent/e2e/EdgeAgentContainer.java
@@ -34,7 +34,7 @@ import java.util.stream.Stream;
 public class EdgeAgentContainer extends GenericContainer<EdgeAgentContainer> {
 
     private static final String AGENT_LOGGER_NAME = "edge-agent-e2e";
-    private static final String JDK_IMAGE = "seatunnelhub/openjdk:8u342";
+    private static final String JDK_IMAGE = "eclipse-temurin:11-jre";
     private static final String AGENT_HOME = "/opt/edge-agent";
     private static final String APP_LOG_FILE = AGENT_HOME + 
"/log/edge-agent.log";
     private static final String STARTUP_LOG_FILE = AGENT_HOME + 
"/edge-agent.out";
diff --git 
a/seatunnel-e2e/seatunnel-engine-e2e/seatunnel-engine-k8s-e2e/src/test/resources/seatunnel_dockerfile
 
b/seatunnel-e2e/seatunnel-engine-e2e/seatunnel-engine-k8s-e2e/src/test/resources/seatunnel_dockerfile
index 4acbb9a821..976331f5e9 100644
--- 
a/seatunnel-e2e/seatunnel-engine-e2e/seatunnel-engine-k8s-e2e/src/test/resources/seatunnel_dockerfile
+++ 
b/seatunnel-e2e/seatunnel-engine-e2e/seatunnel-engine-k8s-e2e/src/test/resources/seatunnel_dockerfile
@@ -15,7 +15,9 @@
 # limitations under the License.
 #
 
-FROM openjdk:8u162-jdk
+# The build now targets Java 11 bytecode, so the pod JVM must be at least Java 
11.
+# A full JDK is kept because the engine e2e helpers inspect the running server 
with jps/jstack.
+FROM eclipse-temurin:11-jdk
 ENV SEATUNNEL_HOME="/opt/seatunnel"
 COPY /jars/seatunnel-shade-hadoop3-uber.jar 
${SEATUNNEL_HOME}/lib/seatunnel-shade-hadoop3-uber.jar
 COPY /jars/seatunnel-transforms-v2.jar 
${SEATUNNEL_HOME}/lib/seatunnel-transforms-v2.jar
diff --git a/seatunnel-examples/seatunnel-flink-examples/pom.xml 
b/seatunnel-examples/seatunnel-flink-examples/pom.xml
index a39d6d1437..79098ddb40 100644
--- a/seatunnel-examples/seatunnel-flink-examples/pom.xml
+++ b/seatunnel-examples/seatunnel-flink-examples/pom.xml
@@ -36,6 +36,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 
diff --git 
a/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-13-example/pom.xml
 
b/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-13-example/pom.xml
index ca17fd3ea3..b56ff337f2 100644
--- 
a/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-13-example/pom.xml
+++ 
b/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-13-example/pom.xml
@@ -31,6 +31,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 
diff --git 
a/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-15-example/pom.xml
 
b/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-15-example/pom.xml
index e861d6fc99..8cfdce8a03 100644
--- 
a/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-15-example/pom.xml
+++ 
b/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-15-example/pom.xml
@@ -30,6 +30,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 
diff --git 
a/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-20-example/pom.xml
 
b/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-20-example/pom.xml
index 82c53c05a6..5fc166f3a6 100644
--- 
a/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-20-example/pom.xml
+++ 
b/seatunnel-examples/seatunnel-flink-examples/seatunnel-flink-20-example/pom.xml
@@ -30,6 +30,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 
diff --git a/seatunnel-formats/seatunnel-format-protobuf/pom.xml 
b/seatunnel-formats/seatunnel-format-protobuf/pom.xml
index 8f8f7030f6..d36e9d3a4b 100644
--- a/seatunnel-formats/seatunnel-format-protobuf/pom.xml
+++ b/seatunnel-formats/seatunnel-format-protobuf/pom.xml
@@ -28,6 +28,7 @@
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
+        <maven.compiler.release>8</maven.compiler.release>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <protobuf.version>3.25.3</protobuf.version>
         <protoc.jar.version>3.11.4</protoc.jar.version>
diff --git a/tools/update_modules_check/test_ci_scope.py 
b/tools/update_modules_check/test_ci_scope.py
index 437bc194a9..42c6a0a0d8 100644
--- a/tools/update_modules_check/test_ci_scope.py
+++ b/tools/update_modules_check/test_ci_scope.py
@@ -81,7 +81,6 @@ class CiScopeTest(unittest.TestCase):
                 ["tools/benchmarks/save_jmh_result.py"],
             )
         )
-
     def test_skip_full_api_check_for_dist_only_fork_change(self) -> None:
         self.assertFalse(
             should_run_full_api_check(

Reply via email to