Skip to content

Instantly share code, notes, and snippets.

@thomasdarimont
Last active August 25, 2026 18:36
Show Gist options
  • Select an option

  • Save thomasdarimont/573fdc471a7b87116ae344d1fe3a1354 to your computer and use it in GitHub Desktop.

Select an option

Save thomasdarimont/573fdc471a7b87116ae344d1fe3a1354 to your computer and use it in GitHub Desktop.
./build-dockerized.sh 26.6.6 acme/keycloak
#!/usr/bin/env bash
# Dockerized variant of build.sh: the only host dependency is docker.
#
# The Keycloak source build (git clone + maven + node/pnpm for the
# admin/account UI) runs inside a builder container built from ./Dockerfile.
# The resulting server distribution archive is then fed to the regular
# Keycloak container build as part of the local build context, so no
# temporary HTTP server is needed and the final image is placed in the
# local docker image store.
# Enable exit on error
set -e
print_usage() {
echo "Usage: ./build-dockerized.sh VERSION_TAG TARGET_IMAGE_NAME"
echo "Example: ./build-dockerized.sh 26.6.6 acme/keycloak"
}
if [ -z "$1" ]; then
echo "Warning: First argument must be Keycloak version tag."
print_usage
exit 1
fi
KC_VERSION="$1"
if [ -z "$2" ]; then
echo "Warning: Second argument must be target docker image name."
print_usage
exit 1
fi
TARGET_IMAGE_NAME="$2"
# Java / Node / pnpm versions used inside the builder container.
# Node and pnpm should match node.version / pnpm.version in the Keycloak js/pom.xml.
JAVA_VERSION="${JAVA_VERSION:-21}"
NODE_VERSION="${NODE_VERSION:-24.9.0}"
PNPM_VERSION="${PNPM_VERSION:-10.14.0}"
echo "### Building custom Keycloak base image for $KC_VERSION with target image name $TARGET_IMAGE_NAME"
SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd)
cd "${SCRIPT_DIR}"
# Temp dir for Keycloak checkout, shared with the builder container
mkdir -p "$SCRIPT_DIR/tmp"
BUILDER_IMAGE="keycloak-release-builder:jdk$JAVA_VERSION-node$NODE_VERSION-pnpm$PNPM_VERSION"
echo "### Ensuring builder image $BUILDER_IMAGE is available"
docker build \
--build-arg="JAVA_VERSION=$JAVA_VERSION" \
--build-arg="NODE_VERSION=$NODE_VERSION" \
--build-arg="PNPM_VERSION=$PNPM_VERSION" \
-t "$BUILDER_IMAGE" .
DIST_FILE="$SCRIPT_DIR/tmp/keycloak-$KC_VERSION/quarkus/dist/target/keycloak-$KC_VERSION.tar.gz"
if [ ! -f "$DIST_FILE" ]; then
echo "### Building Keycloak $KC_VERSION distribution inside builder container"
# A named volume caches the maven repository across builds.
# The chown at the end keeps the checkout owned by the host user on Linux.
docker run --rm \
-v "$SCRIPT_DIR/tmp:/build" \
-v keycloak-release-m2:/root/.m2 \
-e KC_VERSION="$KC_VERSION" \
-e HOST_UID="$(id -u)" \
-e HOST_GID="$(id -g)" \
"$BUILDER_IMAGE" \
bash -c '
set -e
cd /build
if [ ! -d "keycloak-$KC_VERSION" ]; then
echo "### Checking out Keycloak Repository with Tag $KC_VERSION"
git clone https://github.com/keycloak/keycloak.git --depth=1 --branch "$KC_VERSION" "keycloak-$KC_VERSION"
fi
echo "### Building local Keycloak version with Tag $KC_VERSION"
echo "### Using java version"
java -version
cd "keycloak-$KC_VERSION"
./mvnw clean install -DskipTests -am
chown -R "$HOST_UID:$HOST_GID" "/build/keycloak-$KC_VERSION"
'
echo "### Keycloak build completed."
else
echo "### Keycloak distribution for $KC_VERSION already built, skipping build."
fi
CONTAINER_DIR="$SCRIPT_DIR/tmp/keycloak-$KC_VERSION/quarkus/container"
echo "### Docker image build start..."
# Copy the distribution into the build context so the Dockerfile ADD
# can pick it up as a local file instead of downloading it via HTTP.
cp "$DIST_FILE" "$CONTAINER_DIR/"
docker build \
--build-arg="KEYCLOAK_DIST=keycloak-$KC_VERSION.tar.gz" \
--build-arg="KEYCLOAK_VERSION=$KC_VERSION" \
-t "$TARGET_IMAGE_NAME:$KC_VERSION" \
"$CONTAINER_DIR"
rm "$CONTAINER_DIR/keycloak-$KC_VERSION.tar.gz"
echo "### Docker image build completed"
#!/usr/bin/env bash
# Plain bash custom keycloak image build.
# Note that this Keycloak build requires the following components to be installed:
# git
# java
# docker
# nodejs (e.g. 18.20.2)
# pnpm https://pnpm.io/
# python3
# Enable printing commands and exit on error
set -e
print_usage() {
echo "Usage: ./build.sh VERSION_TAG TARGET_IMAGE_NAME"
echo "Example: ./build.sh 26.6.6 acme/keycloak"
}
if [ -z "$1" ]; then
echo "Warning: First argument must be Keycloak version tag."
print_usage
exit 1
fi
KC_VERSION="$1"
if [ -z "$2" ]; then
echo "Warning: Second argument must be target docker image name."
print_usage
exit 1
fi
TARGET_IMAGE_NAME="$2"
echo "### Building custom Keycloak base image for $KC_VERSION with target image name $TARGET_IMAGE_NAME"
SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd)
cd "${SCRIPT_DIR}"
# Temp dir for Keycloak checkout
mkdir -p "$SCRIPT_DIR/tmp"
echo "### Using Building Keycloak Version $KC_VERSION"
# Check if directory exists, if not, run a command
if [ ! -d "tmp/keycloak-$KC_VERSION" ]; then
echo "### Checking out Keycloak Repository with Tag $KC_VERSION"
git clone https://github.com/keycloak/keycloak.git --depth=1 --branch "$KC_VERSION" "tmp/keycloak-$KC_VERSION"
echo "### Building local Keycloak version with Tag $KC_VERSION"
echo "### Using java version"
java -version
cd "$SCRIPT_DIR/tmp/keycloak-$KC_VERSION"
./mvnw clean install -DskipTests -am
echo "### Keycloak build completed."
else
cd "$SCRIPT_DIR/tmp/keycloak-$KC_VERSION"
echo "### Keycloak tag is already downloaded, skipping build."
fi
cd quarkus
echo "### Start temporary local HTTP server to serve Keycloak server distribution archive"
python3 -m http.server --directory dist/target &
PID="$!"
# Give python http server some time to start
sleep 2
DOCKER_HOSTNAME=host.docker.internal
echo "Using DOCKER_HOSTNAME=$DOCKER_HOSTNAME"
echo "### Docker image build start..."
cd container
docker build \
--build-arg="KEYCLOAK_DIST=http://$DOCKER_HOSTNAME:8000/keycloak-$KC_VERSION.tar.gz" \
--build-arg="KEYCLOAK_VERSION=$KC_VERSION" \
-t "$TARGET_IMAGE_NAME:$KC_VERSION" .
echo "### Stop temporary local HTTP server"
kill -9 "$PID"
echo "### Docker image build completed"
# Builder image for compiling Keycloak from source, see build-dockerized.sh
ARG JAVA_VERSION=21
FROM eclipse-temurin:${JAVA_VERSION}-jdk
# Node / pnpm versions should match the ones declared in the Keycloak js/pom.xml
# (node.version / pnpm.version) of the version being built.
ARG NODE_VERSION=24.9.0
ARG PNPM_VERSION=10.14.0
RUN apt-get update && \
apt-get install -y --no-install-recommends git ca-certificates curl xz-utils libicu-dev && \
rm -rf /var/lib/apt/lists/*
# Install node from the official binary distribution (amd64 / arm64) and pnpm via npm
RUN set -eux; \
ARCH="$(dpkg --print-architecture)"; \
case "$ARCH" in \
amd64) NODE_ARCH="x64" ;; \
arm64) NODE_ARCH="arm64" ;; \
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; \
esac; \
curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz" \
| tar -xJ -C /usr/local --strip-components=1 --no-same-owner; \
npm install -g "pnpm@${PNPM_VERSION}"; \
node --version; \
pnpm --version
WORKDIR /build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment