From b2a422338322bc523c7466c602dc86dbb5515864 Mon Sep 17 00:00:00 2001 From: Tungle Duy Date: Tue, 8 Sep 2026 15:31:44 +0700 Subject: [PATCH 1/2] Bump Tomcat to 11.0.x and base Docker image to JDK 21 Arises from the killbill-admin-ui-standalone JRuby 10 upgrade: jruby-rack 2.0.0 (the release that targets JRuby 10/JDK21) is compiled against jakarta.servlet, which requires a Jakarta EE servlet container (Tomcat 10+) and a JDK 21+ JVM to run it. Targets Tomcat 11.0.x rather than 10.1.x: both major lines are currently supported by the Tomcat project (which keeps 3 concurrent supported major versions), but 11.0.x implements the newest specs (Servlet 6.1 vs 10.1's 6.0) and will have a longer support runway before the next EOL rotation. Since we already require JDK 21 for jruby-rack 2.0 regardless, there's no downside to going straight to 11.0.x (it only requires JDK 17+, same as 10.1's JDK 11+ floor is irrelevant here). - ansible/roles/tomcat/tasks/install.yml: bump the maven-metadata.xml version regex and download URL from tomcat-10 (10.1.x) to tomcat-11 (11.0.x). Validated the regex against the live repo1.maven.org/maven2/org/apache/tomcat/tomcat/maven-metadata.xml (resolves to 11.0.25, matching the current official download page). - ansible/templates/tomcat/conf/web.xml.j2: update the schema from jakarta.ee/web-app_6_0.xsd to jakarta.ee/web-app_6_1.xsd, matching Tomcat 11's actual bundled default web.xml (verified against a real local Tomcat 11.0.25 install). server.xml.j2/context.xml.j2 needed no changes (pure org.apache.catalina.* internal classes, unaffected by the servlet spec version). - docker/templates/base/latest/Dockerfile: openjdk-11-jdk-headless -> openjdk-21-jdk-headless, and the java-11-openjdk -> java-21-openjdk JAVA_HOME symlink. Validated end to end: built the killbill-admin-ui-standalone WAR (rack 2.2.24 + jruby-rack 2.0.0 + json 2.21.2 + csv fix) and deployed it to a real local Tomcat 11.0.25 instance under JDK21 - it booted successfully with no errors, served an HTTP 302 redirect to /users/sign_in with correct session cookie handling and Transfer-Encoding: chunked, and correctly established a JDBC connection. jruby-rack 2.0.0 (built against Servlet 6.0) works unmodified against Tomcat 11's Servlet 6.1 API, as expected since 6.1 is backward compatible with 6.0. IMPORTANT: this base Docker image is shared with the killbill/killbill core server image. The core server team should validate their own deployment is compatible with Tomcat 11 (javax vs jakarta.servlet) and JDK 21 before this rolls out to production; core server source is out of scope for this repo. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ansible/roles/tomcat/tasks/install.yml | 4 ++-- ansible/templates/tomcat/conf/web.xml.j2 | 8 ++++---- docker/templates/base/latest/Dockerfile | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ansible/roles/tomcat/tasks/install.yml b/ansible/roles/tomcat/tasks/install.yml index dd617ec1..f9a71bf8 100644 --- a/ansible/roles/tomcat/tasks/install.yml +++ b/ansible/roles/tomcat/tasks/install.yml @@ -38,14 +38,14 @@ # We don't use the xml module to avoid a dependency on lxml - name: Set tomcat_version ansible.builtin.set_fact: - tomcat_version: "{{ tomcat_metadata.content | regex_findall('(9.0.*)', '\\1') | last }}" + tomcat_version: "{{ tomcat_metadata.content | regex_findall('(11.0.*)', '\\1') | last }}" when: tomcat_version is undefined tags: install - name: Install Tomcat become: true ansible.builtin.unarchive: - src: "http://archive.apache.org/dist/tomcat/tomcat-9/v{{ tomcat_version }}/bin/apache-tomcat-{{ tomcat_version }}.tar.gz" + src: "http://archive.apache.org/dist/tomcat/tomcat-11/v{{ tomcat_version }}/bin/apache-tomcat-{{ tomcat_version }}.tar.gz" remote_src: true dest: "{{ tomcat_install_dir }}" owner: "{{ tomcat_owner }}" diff --git a/ansible/templates/tomcat/conf/web.xml.j2 b/ansible/templates/tomcat/conf/web.xml.j2 index c851684d..ea6bc6d0 100644 --- a/ansible/templates/tomcat/conf/web.xml.j2 +++ b/ansible/templates/tomcat/conf/web.xml.j2 @@ -1,9 +1,9 @@ - + xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee + https://jakarta.ee/xml/ns/jakartaee/web-app_6_1.xsd" + version="6.1"> default diff --git a/docker/templates/base/latest/Dockerfile b/docker/templates/base/latest/Dockerfile index ed14a32e..4d230a3f 100644 --- a/docker/templates/base/latest/Dockerfile +++ b/docker/templates/base/latest/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get update && \ libapr1 \ mysql-client \ net-tools \ - openjdk-11-jdk-headless \ + openjdk-21-jdk-headless \ python3-lxml \ sudo \ unzip \ @@ -33,7 +33,7 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* # Configure default JAVA_HOME path -RUN ln -s java-11-openjdk-$(dpkg --print-architecture) /usr/lib/jvm/default-java +RUN ln -s java-21-openjdk-$(dpkg --print-architecture) /usr/lib/jvm/default-java ENV JAVA_HOME=/usr/lib/jvm/default-java ENV JSSE_HOME=$JAVA_HOME/jre/ From fc77a4931d8e6985e8cb11f0dec69f33fbf8695c Mon Sep 17 00:00:00 2001 From: Tungle Duy Date: Wed, 9 Sep 2026 12:33:46 +0700 Subject: [PATCH 2/2] Fix CI failure: drop --with-ssl=yes (incompatible with Tomcat Native 2.x) CI on this PR was failing: "Build killbill/base:latest" step, in the "Configure native libraries" ansible task: configure: error: yes is not a directory Root-caused by extracting and diffing the tomcat-native.tar.gz bundled in each Tomcat distribution: - Tomcat 9.0.x (the pre-PR baseline) bundles Tomcat Native 1.3.8, whose configure script special-cases the literal value "yes" for --with-ssl (falls back to auto-detecting OpenSSL from standard system paths). - Tomcat 10.1.x AND 11.0.x both bundle Tomcat Native 2.0.x (2.0.9 and 2.0.15 respectively), whose configure script dropped that special case: it now only accepts "no" or an actual directory path, otherwise erroring with " is not a directory". This means the bug was latent in the jump from Tomcat 9.0.x to EITHER 10.1.x or 11.0.x - not specific to the choice of 11.0.x made in this PR. Fix: drop the --with-ssl=yes argument entirely. Confirmed by reading both configure scripts that omitting --with-ssl produces the exact same auto-detect-from-system-paths behavior as passing "yes" did on tcnative 1.x, and is also the documented tcnative 2.x default (skips the explicit value check, falls through to the same "guess it" search over /usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw). Validated by fully reproducing the native build in a fresh ubuntu:24.04 container (same toolchain packages the "Install toolchain" task installs: dpkg-dev, gcc, libapr1-dev, libssl-dev, make; same JDK: openjdk-21-jdk-headless) using Tomcat 11.0.25's actual bundled tomcat-native.tar.gz: checking for OpenSSL location... using openssl from /usr/lib and /usr/include checking OpenSSL library version >= 3.0.0... ok configure: creating ./config.status (exit 0) Then ran `make all` (produced libtcnative-2.so.0.0.15) and `make install` (landed correctly in the configured libdir) - both exit 0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ansible/roles/tomcat/tasks/native.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/ansible/roles/tomcat/tasks/native.yml b/ansible/roles/tomcat/tasks/native.yml index 48639f0b..340684e5 100644 --- a/ansible/roles/tomcat/tasks/native.yml +++ b/ansible/roles/tomcat/tasks/native.yml @@ -93,7 +93,6 @@ - --prefix={{ catalina_home }} - --with-apr={{ tomcat_apr_config_path }} - --with-java-home={{ java_home }} - - --with-ssl=yes chdir: "{{ tomcat_workspace.path }}/native" changed_when: false tags: native