Keycloak provides a documentation on how is to configure Keycloak the proper way in Kubernetes. I wouldn't repeat the documentation so please make sure you go through it.
The most important part when said:
We recommend optimizing Keycloak to provide faster startup and better memory consumption before deploying Keycloak in a production environment. This section describes how to apply Keycloak optimizations for the best performance and runtime behavior - Optimize the startup
For that to happen, let us write our Dockerfile
The Dockerfile
Let us have a look to the entire Dockerfile before we go into each Dockefile layer.
ARG KC_VERSION
FROM quay.io/keycloak/keycloak:${KC_VERSION} AS builder
ARG KC_HEALTH_ENABLED=true
ARG KC_METRICS_ENABLED=true
ARG KC_DB=postgres
ARG KC_FEATURES
ARG KC_METRICS_SPI_VERSION
ARG KC_HOSTNAME_PATH=keycloak
ARG KC_HTTP_RELATIVE_PATH=/keycloak
ENV KC_VERSION=${KC_VERSION}
ENV KC_HEALTH_ENABLED=${KC_HEALTH_ENABLED}
ENV KC_DB=${KC_DB}
ENV KC_HOSTNAME_PATH=${KC_HOSTNAME_PATH}
ENV KC_HTTP_RELATIVE_PATH=${KC_HTTP_RELATIVE_PATH}
ENV KC_FEATURES=${KC_FEATURES}
ADD --chown=keycloak:keycloak https://github.com/aerogear/keycloak-metrics-spi/releases/download/${KC_METRICS_SPI_VERSION}/keycloak-metrics-spi-${KC_METRICS_SPI_VERSION}.jar /opt/keycloak/providers/keycloak-metrics-spi-${KC_METRICS_SPI_VERSION}.jar
RUN /opt/keycloak/bin/kc.sh build --cache-stack=kubernetes
# Installing additional RPM packages https://www.keycloak.org/server/containers
FROM registry.access.redhat.com/ubi9:9.3 AS ubi-micro-build
RUN mkdir -p /mnt/rootfs
RUN dnf install -y curl-7.76.1 --installroot /mnt/rootfs --releasever 9 --setopt install_weak_deps=false --nodocs && \
dnf --installroot /mnt/rootfs clean all && \
rpm --root /mnt/rootfs -e --nodeps setup
FROM quay.io/keycloak/keycloak:${KC_VERSION}
COPY --from=builder /opt/keycloak/ /opt/keycloak/
COPY --from=ubi-micro-build /mnt/rootfs /
COPY ./entrypoint.sh /deployments/entrypoint.sh
ENTRYPOINT ["/deployments/entrypoint.sh"]
Build Keycloak
For maintainability, parameterize the Keycloak version so it is easier from the build tool (CI/CD) to upgrade Keycloak without touching the Dockerfile. Below is the first stage in our multi-stage Dockerfile defined as builder
ARG KC_VERSION
FROM quay.io/keycloak/keycloak:${KC_VERSION} AS builder
Arguments
Here is the Dockerfile arguments.
ARG KC_HEALTH_ENABLED=true
ARG KC_METRICS_ENABLED=true
ARG KC_DB=postgres
ARG KC_FEATURES
ARG KC_METRICS_SPI_VERSION
ARG KC_HOSTNAME_PATH=keycloak
ARG KC_HTTP_RELATIVE_PATH=/keycloak
-
KC_HEALTH_ENABLED
andKC_METRICS_ENABLED
: Both are important for monitoring Keycloak. I enabled them by default. -
KC_DB
: For the target database provider. I considerpostgres
database. -
KC_FEATURES
: To control the enabling features in Keycloak from CI/CD. -
KC_METRICS_SPI_VERSION
: IfKC_METRICS_ENABLED
is true, the target version of the Keycloak Metrics SPI. Keycloak Metrics SPI is not an official metrics from Keycloak but a well known SPI. It worth to check and decide about it. -
KC_HOSTNAME_PATH
andKC_HTTP_RELATIVE_PATH
are required to be added by the same name if you choose different context path for Keycloak than the default/
. In my case, I choose/keycloak
as context path.
Prepare the environment variables
ENV KC_VERSION=${KC_VERSION}
ENV KC_HEALTH_ENABLED=${KC_HEALTH_ENABLED}
ENV KC_DB=${KC_DB}
ENV KC_HOSTNAME_PATH=${KC_HOSTNAME_PATH}
ENV KC_HTTP_RELATIVE_PATH=${KC_HTTP_RELATIVE_PATH}
ENV KC_FEATURES=${KC_FEATURES}
Keycloak uses the environment variables during the build to read from and act based on it. In the above snippet, the required environment variables for our build added.
Prepare the SPIs
ADD --chown=keycloak:keycloak https://github.com/aerogear/keycloak-metrics-spi/releases/download/${KC_METRICS_SPI_VERSION}/keycloak-metrics-spi-${KC_METRICS_SPI_VERSION}.jar /opt/keycloak/providers/keycloak-metrics-spi-${KC_METRICS_SPI_VERSION}.jar
A example build step that downloads a JAR file from a URL and adds it to the providers directory
Build Keycloak
RUN /opt/keycloak/bin/kc.sh build --cache-stack=kubernetes
This is the most important step where we build Keycloak based on the environment variables we provided in the build step and cache stack as kubernetes
.
Install additional RPM packages
# Installing additional RPM packages https://www.keycloak.org/server/containers
FROM registry.access.redhat.com/ubi9:9.3 AS ubi-micro-build
RUN mkdir -p /mnt/rootfs
RUN dnf install -y curl-7.76.1 --installroot /mnt/rootfs --releasever 9 --setopt install_weak_deps=false --nodocs && \
dnf --installroot /mnt/rootfs clean all && \
rpm --root /mnt/rootfs -e --nodeps setup
This step is not necessary, although if you need to have additional RPM packages in the container, you can install it as shown in the above example for installing curl
.
Final image.
FROM quay.io/keycloak/keycloak:${KC_VERSION}
COPY --from=builder /opt/keycloak/ /opt/keycloak/
COPY --from=ubi-micro-build /mnt/rootfs /
COPY ./entrypoint.sh /deployments/entrypoint.sh
The final stage is our image where Keycloak build files are pre-installed and ready to start up.
- From the
builder
stage, we copy the Keycloak build - From the
ubi-micro-build
stage, we copy the installed packages -
entrypoint.sh
is our custom entrypoint file to start Keycloak. In its basic form can be as simple as below:
exec /opt/keycloak/bin/kc.sh start --optimized
I prefer to have the entrypoint in separate file so later I have the flexibility to customize it without modifying the Dockerfile. Indeed I use additional scripts in the entrypoint. For instance, integrate Datadog with Keycloak. I can write a separate article to describe it ;)
Keycloak is an identity provider which provides the front-end for the users same as admins. Someone would think to narrow the exposed part of Keycloak to only what necessary public and keep everything else to be accessed only through VPN / Internal network.
In the next blog post, I describe how you can separate Keycloak public and private APIs/URLs for an enhanced security.
I hope you find it useful.
Top comments (0)