From dbe23f3b3598dc66376c732b12ba9d43aa472120 Mon Sep 17 00:00:00 2001 From: xsalefter Date: Sat, 8 Aug 2026 07:35:01 +0700 Subject: [PATCH 1/5] update ansible/java.yml to use Java 21 --- ansible/java.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ansible/java.yml b/ansible/java.yml index 79746525..75fa3642 100644 --- a/ansible/java.yml +++ b/ansible/java.yml @@ -2,8 +2,8 @@ - name: Install Java hosts: all vars: - java_package: openjdk-11-jdk - default_java_home: /usr/lib/jvm/java-11-openjdk-amd64 + java_package: openjdk-21-jdk + default_java_home: /usr/lib/jvm/java-21-openjdk-amd64 java_home: /usr/lib/jvm/default-java tasks: - name: Install Java From 5358590531ba429faff03f8339c5a08f3f85f26b Mon Sep 17 00:00:00 2001 From: xsalefter Date: Sat, 8 Aug 2026 07:36:02 +0700 Subject: [PATCH 2/5] Update base/latest/Dockerfile to use openjdk-21 This is actually optional changes. But since this is a candidate for future release, lets start to change this. --- docker/templates/base/latest/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/templates/base/latest/Dockerfile b/docker/templates/base/latest/Dockerfile index f7061da9..1c0737af 100644 --- a/docker/templates/base/latest/Dockerfile +++ b/docker/templates/base/latest/Dockerfile @@ -23,7 +23,7 @@ RUN apt-get update && \ libapr1 \ mysql-client \ net-tools \ - openjdk-11-jdk-headless \ + openjdk-21-jdk-headless \ python3-lxml \ sudo \ unzip \ @@ -32,7 +32,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 413b02202e767116c75f5db936621edd76a0931a Mon Sep 17 00:00:00 2001 From: xsalefter Date: Sat, 8 Aug 2026 07:36:17 +0700 Subject: [PATCH 3/5] ignore beta Dockerfile --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 444d1d65..44ab4354 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ docker/templates/kaui/tagged/Dockerfile docker/templates/killbill/latest/Dockerfile docker/templates/killbill/tagged/Dockerfile docker/templates/killbill/tagged/kpm.yml +docker/templates/killbill/beta/Dockerfile From 02a30d1c98990ce8fb26f15b231016403c0af6cb Mon Sep 17 00:00:00 2001 From: xsalefter Date: Sat, 8 Aug 2026 07:36:32 +0700 Subject: [PATCH 4/5] add beta Dockerfile.template: killbill only, and ignore touching "latest" tag --- .../killbill/beta/Dockerfile.template | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 docker/templates/killbill/beta/Dockerfile.template diff --git a/docker/templates/killbill/beta/Dockerfile.template b/docker/templates/killbill/beta/Dockerfile.template new file mode 100644 index 00000000..cbef09b9 --- /dev/null +++ b/docker/templates/killbill/beta/Dockerfile.template @@ -0,0 +1,191 @@ +# Dedicated, self-contained multi-stage Dockerfile for beta/RC killbill releases. +# +# Why this exists? +# - Beta/RC versions may need base-image-level changes (e.g. a newer Tomcat/JDK) that are not yet part of the publicly +# published killbill/base:latest or killbill/killbill:latest images. Building FROM those would silently ignore any +# such branch-local change. +# - Avoid to use separate, intermediate `killbill/base:beta-*` tag to Docker Hub just to have another "base" image. +# - Using docker buildx's multi-stage build (FROM ... AS ) to keeps all of that intermediate state private. +# And then do single `docker buildx build` invocation. This way, nothing but the final image is ever pushed. +# +# This intentionally duplicates the *Dockerfile instructions* normally split across: +# docker/templates/base/latest/Dockerfile (stage: base) +# docker/templates/killbill/latest/Dockerfile (stage: shell) +# docker/templates/killbill/tagged/Dockerfile.template (stage: final) + +# --------------------------------------------------------------------------- +# Stage: base (mirrors docker/templates/base/latest/Dockerfile) +# --------------------------------------------------------------------------- +FROM ubuntu:24.04 AS builder-base +LABEL maintainer="killbilling-users@googlegroups.com" + +USER root + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 +ENV PYTHONIOENCODING=utf8 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get install --no-install-recommends -y \ + ansible \ + apt-utils \ + curl \ + gettext-base \ + git \ + less \ + libapr1 \ + mysql-client \ + net-tools \ + openjdk-21-jdk-headless \ + python3-lxml \ + sudo \ + unzip \ + vim && \ + rm -rf /var/lib/apt/lists/* + +# Configure default JAVA_HOME path +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/ + +ENV TOMCAT_OWNER=tomcat +ENV TOMCAT_GROUP=tomcat +ENV TOMCAT_HOME=/var/lib/tomcat +RUN adduser $TOMCAT_OWNER \ + --home $TOMCAT_HOME \ + --disabled-password \ + --gecos '' && \ + usermod -aG sudo $TOMCAT_GROUP && \ + echo "$TOMCAT_OWNER:$TOMCAT_OWNER" | chpasswd && \ + echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +USER $TOMCAT_OWNER +WORKDIR $TOMCAT_HOME + +# Install ansible roles dependencies. +# KILLBILL_CLOUD_REF is a git ref (branch/tag/SHA) of the killbill-cloud repository, used by +# ansible-galaxy below to fetch the ansible roles that install Tomcat/Java/KPM. This Dockerfile +# has no opinion on which ref that should be - the caller (see kb_beta_release.yml) decides that. +ARG KILLBILL_CLOUD_REF +RUN ansible-galaxy collection install community.general && \ + ansible-galaxy install git+https://git@github.com/killbill/killbill-cloud.git,$KILLBILL_CLOUD_REF +ENV KILLBILL_CLOUD_ANSIBLE_ROLES=$TOMCAT_HOME/.ansible/roles/killbill-cloud/ansible +ENV ENV_HOST_IP=localhost +ENV ANSIBLE_OPTS="-i localhost, \ + -e ansible_connection=local \ + -e ansible_python_interpreter=/usr/bin/python3 \ + -e java_home=$JAVA_HOME \ + -vv" + +# Install KPM +ENV NEXUS_URL=https://repo1.maven.org +ARG NEXUS_REPOSITORY +ENV NEXUS_REPOSITORY=${NEXUS_REPOSITORY:-maven2} +ENV KPM_INSTALL_DIR=/opt +RUN ansible-playbook $ANSIBLE_OPTS \ + -e kpm_install_dir=$KPM_INSTALL_DIR \ + -e kpm_path=$KPM_INSTALL_DIR/kpm-latest \ + -e kpm_owner=$TOMCAT_OWNER \ + -e kpm_group=$TOMCAT_GROUP \ + -e nexus_url=$NEXUS_URL \ + -e nexus_repository=$NEXUS_REPOSITORY \ + $KILLBILL_CLOUD_ANSIBLE_ROLES/kpm.yml +ENV PATH="/opt/kpm-latest:${PATH}" + +# Install Tomcat (without native libraries) +ENV CATALINA_BASE=$TOMCAT_HOME +ENV CATALINA_HOME=/usr/share/tomcat +ENV CATALINA_PID=$CATALINA_BASE/tomcat.pid +ENV CATALINA_TMPDIR=/var/tmp +ENV TOMCAT_INSTALL_DIR=/opt +ENV TOMCAT_NATIVE_LIBDIR=$CATALINA_HOME/native-jni-lib +ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR +RUN ansible-playbook $ANSIBLE_OPTS \ + -e tomcat_install_dir=$TOMCAT_INSTALL_DIR \ + -e tomcat_native_libdir=$TOMCAT_NATIVE_LIBDIR \ + -e tomcat_owner=$TOMCAT_OWNER \ + -e tomcat_group=$TOMCAT_GROUP \ + -e tomcat_home=$TOMCAT_HOME \ + -e catalina_home=$CATALINA_HOME \ + -e catalina_base=$CATALINA_BASE \ + --skip-tags native \ + $KILLBILL_CLOUD_ANSIBLE_ROLES/tomcat.yml + +# Build Tomcat native libraries +FROM builder-base AS builder-tomcat +USER $TOMCAT_OWNER +RUN ansible-playbook $ANSIBLE_OPTS \ + -e tomcat_install_dir=$TOMCAT_INSTALL_DIR \ + -e tomcat_native_libdir=$TOMCAT_NATIVE_LIBDIR \ + -e tomcat_owner=$TOMCAT_OWNER \ + -e tomcat_group=$TOMCAT_GROUP \ + -e tomcat_home=$TOMCAT_HOME \ + -e catalina_home=$CATALINA_HOME \ + -e catalina_base=$CATALINA_BASE \ + -t native \ + $KILLBILL_CLOUD_ANSIBLE_ROLES/tomcat.yml + +FROM builder-base AS base +COPY --from=builder-tomcat /usr/share/tomcat/native-jni-lib /usr/share/tomcat/native-jni-lib + +# --------------------------------------------------------------------------- +# Stage: shell (mirrors docker/templates/killbill/latest/Dockerfile) +# --------------------------------------------------------------------------- +FROM base AS shell +LABEL maintainer="killbilling-users@googlegroups.com" + +ENV KILLBILL_INSTALL_DIR=/var/lib/killbill + +RUN sudo mkdir -p $KILLBILL_INSTALL_DIR $KILLBILL_INSTALL_DIR/bundles $KILLBILL_INSTALL_DIR/config +RUN sudo chown -R $TOMCAT_OWNER:$TOMCAT_GROUP $KILLBILL_INSTALL_DIR + +ENV KB_org_killbill_osgi_bundle_install_dir=$KILLBILL_INSTALL_DIR/bundles +ENV KB_org_killbill_billing_osgi_bundles_jruby_conf_dir=$KILLBILL_INSTALL_DIR/config +ENV KB_org_killbill_server_baseUrl=http://$ENV_HOST_IP:8080 +ENV KB_org_killbill_billing_plugin_kpm_kpmPath=$KPM_INSTALL_DIR/kpm-latest/kpm +ENV KB_org_killbill_billing_plugin_kpm_bundlesPath=$KILLBILL_INSTALL_DIR/bundles +ENV KB_org_killbill_security_shiroResourcePath=$KILLBILL_INSTALL_DIR/config/shiro.ini +ENV KB_org_killbill_notificationq_main_queue_mode=POLLING +ENV KB_org_killbill_notificationq_analytics_queue_mode=POLLING +ENV KB_ADMIN_PASSWORD=password + +COPY ./latest/setenv2.sh $CATALINA_BASE/bin +COPY ./latest/shiro.ini.template $KILLBILL_INSTALL_DIR/config + +ENV KPM_INSTALL_CMD="ansible-playbook $ANSIBLE_OPTS \ + -e kpm_install_dir=$KPM_INSTALL_DIR \ + -e kpm_path=$KPM_INSTALL_DIR/kpm-latest \ + -e kpm_yml=$KILLBILL_INSTALL_DIR/kpm.yml \ + -e killbill_kpm_yml=$KILLBILL_INSTALL_DIR/kpm.yml \ + -e kb_config_dir=$KILLBILL_INSTALL_DIR \ + -e kb_plugins_dir=$KILLBILL_INSTALL_DIR/bundles \ + -e tomcat_owner=$TOMCAT_OWNER \ + -e tomcat_group=$TOMCAT_GROUP \ + -e catalina_base=$CATALINA_BASE \ + $KILLBILL_CLOUD_ANSIBLE_ROLES/killbill.yml" + +# Install Logstash dependencies +ENV LOGSTASH_ENABLED=true +RUN ansible-playbook $ANSIBLE_OPTS $KILLBILL_CLOUD_ANSIBLE_ROLES/killbill_json_logging.yml --tags download + +# --------------------------------------------------------------------------- +# Stage: final (mirrors docker/templates/killbill/tagged/Dockerfile.template) +# --------------------------------------------------------------------------- +FROM shell AS final +LABEL maintainer="killbilling-users@googlegroups.com" + +ENV KILLBILL_VERSION=__VERSION__ + +# Pinned kpm.yml (version baked in, not resolved at runtime like the "latest" shell image). Reuses +# templates/killbill/tagged/kpm.yml as-is (build context is templates/killbill/, and __VERSION__ substitution is done +# by the workflow before build, same as docker/dockerTemplate.sh does for the tagged/ template). +COPY ./tagged/kpm.yml $KILLBILL_INSTALL_DIR + +# Install Kill Bill + the default OSGi bundles (kpm, logger, metrics) at build time +RUN $KPM_INSTALL_CMD $KILLBILL_CLOUD_ANSIBLE_ROLES/killbill_json_logging.yml + +COPY ./tagged/killbill.sh $KILLBILL_INSTALL_DIR + +EXPOSE 8080 +CMD ["/var/lib/killbill/killbill.sh"] From 2d034f02d4bd39a318a49a2cd94bb0d78306158a Mon Sep 17 00:00:00 2001 From: xsalefter Date: Sat, 8 Aug 2026 07:38:52 +0700 Subject: [PATCH 5/5] add workflow file that will execute beta Dockerfile --- .github/workflows/kb_beta_release.yml | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/kb_beta_release.yml diff --git a/.github/workflows/kb_beta_release.yml b/.github/workflows/kb_beta_release.yml new file mode 100644 index 00000000..6a2650b3 --- /dev/null +++ b/.github/workflows/kb_beta_release.yml @@ -0,0 +1,70 @@ +name: kb_beta_release + +# Publishes a single, explicitly-pinned killbill/killbill: docker image for beta / release-candidate versions +# (e.g. 0.25.1), without touching KAUI and `latest` tag (hence named "beta" release: it only ever publishes an +# explicit, pinned version tag and never promotes/updates `latest`). +# +# Unlike release.yml, this workflow does not reuse the already-published killbill/base:latest or +# killbill/killbill:latest images as parents, and it does not publish any intermediate killbill/base:beta-* image to +# Docker Hub either. Instead, it uses a single dedicated, self-contained multi-stage Dockerfile +# (docker/templates/killbill/beta/Dockerfile.template, stages: base -> shell -> final) so that: +# - branch-local changes (e.g. a Tomcat/JDK bump on a branch such as java2x) are actually baked into the resulting +# image, instead of silently falling back to whatever is currently published under :latest on Docker Hub, and +# - no intermediate image is ever published publicly - only the final killbill/killbill: tag is pushed. +# +# Ansible/ansible-galaxy note: the base stage still installs Tomcat/Java/KPM via this repo's own ansible roles +# (same as release.yml), to keep user/group/permissions/ACL setup identical to a normal release image rather than +# hand-rolling it differently here. +# +# IMPORTANT - killbill-cloud git ref used for the ansible roles: the base stage fetches the ansible roles fresh from +# GitHub via `ansible-galaxy install git+...,` - it does NOT use this workflow run's own checkout for that. Rather +# than a separate input, this workflow uses ${{ github.ref_name }}, i.e. whatever branch you pick in the +# "Use workflow from" selector above. +# +# Concretely: if you pick "java2x" there, make sure your ansible/Dockerfile changes on java2x are already committed +# AND pushed to origin/java2x before running this. Uncommitted or unpushed local changes will NOT be picked up, since +# the clone happens fresh from GitHub. +on: + workflow_dispatch: + inputs: + killbill_version: + description: 'Kill Bill version to release (must already be published to Maven Central, e.g. 0.25.1)' + required: true + nexus_repository: + description: 'Nexus repository for KPM' + required: true + default: 'maven2' + +jobs: + docker: + name: Publish killbill/killbill beta/RC image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v7 + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + - name: Login to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # Bake the pinned Kill Bill version into the Dockerfile (same __VERSION__ substitution dockerTemplate.sh does for + # docker/templates/killbill/tagged/Dockerfile.template), then build+push the final stage only. + # The `base` and `shell` (See "stage" in the template) intermediate stages are never pushed. They exist purely + # inside this one buildx invocation's build graph. + - name: Build and push killbill beta/RC image + run: | + cd docker/templates/killbill + sed -e "s/__VERSION__/${{ github.event.inputs.killbill_version }}/" beta/Dockerfile.template > beta/Dockerfile + sed -e "s/__VERSION__/${{ github.event.inputs.killbill_version }}/" tagged/kpm.yml.template > tagged/kpm.yml + docker buildx build --push --platform=linux/arm64,linux/amd64 --no-cache \ + --target final \ + -t killbill/killbill:${{ github.event.inputs.killbill_version }} \ + -f beta/Dockerfile \ + --build-arg KILLBILL_CLOUD_REF=${{ github.ref_name }} \ + --build-arg NEXUS_REPOSITORY=${{ github.event.inputs.nexus_repository }} \ + .