Tutorial 7 - Keycloak deployment in Kubernetes

What are we doing?

We create a local Kubernetes cluster using minikube to run a custom Keycloak container image.

We show how Helm charts can be used to deploy a container image of Keycloak in a local minikube Kubernetes cluster.

There are similar projects and guides available on the internet:

Why are we doing this?

“2029, more than 95% of global organizations will run containerized applications in production — a significant increase from fewer than 50% in 2023.” - Report from Gartner as quoted by Aqua Security

“[…]if you look on the open side, what Google is doing with Kubernetes[…]. Pretty soon, anybody will be able to use the same deployment tools that Google is using to manage their workloads. That’s where innovation is moving.” -Jim Whitehurst, former CEO of Red Hat and president of IBM in an interview with The Motley Fool.

As an IAM solution, Keycloak must always be online. Kubernetes’s native features like self-healing and pod distribution ensure that if one Keycloak instance fails, another takes its place, preventing authentication outages.

It also allows Keycloak to automatically scale using the Horizontal Pod Autoscaler (HPA), adding more instances to handle high login volumes and scaling back down to save costs. Finally, using Helm charts automates the complex setup, configuration, and upgrades of a clustered Keycloak deployment.

Requirements

You need to install the following components to follow the tutorial:

Steps

This tutorial is based on our public Keycloak-Custom repo on GitHub.

Keycloak-Custom Repo

Now please create your own new custom Keycloak project by either cloning, forking or using the template feature Use this template of the Keycloak-Custom GitHub repo.

Then open the new repository with your favourite Java IDE. For the IntelliJ IDE, we provide ready to use run configurations, which are explained in the usage section.

Ideally you familiarise yourself with Keycloak-Custom with our Custom Keycloak tutorial.

In this tutorial, we will focus on the helm module.

Step 1: getting started with minikube

Let’s create a profile for minikube where we’ll install the keycloak. This updates the central kubeconfig to set keycloak-custom as the current context for following kubectl calls.

minikube -p keycloak-custom start

We’ll observe the pods in the minikube cluster by keeping a terminal open with the following command.

 kubectl get pods --all-namespaces --watch

Let’s add the required chart repositories.

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add codecentric https://codecentric.github.io/helm-charts

Now we’ll install a Postgres database for the Keycloak. Navigate into the helm directory, as following path references will be relative to the helm directory.

helm install postgresql bitnami/postgresql --values ./src/test/resources/postgresql/values.minikube.yaml

Step 2: placing the custom Keycloak image on minikube

We can now observe in the terminal with the kubectl... --watch command the progress of the Postgres installation. The last line printed after a few seconds should indicate that the database pod is running.

As a next step we want to register the keycloak custom image in the minikube registry. We can point the current shell to the minikube Docker daemon. Let’s see what configuration is required

minikube -p keycloak-custom docker-env

This prints the required export statements. As instructed in the output, we can call the following to run these export statements in the current shell.

eval $(minikube -p keycloak-custom docker-env)

Now, when we run the Maven install phase, the Keycloak custom container will be registered in the minikube’s Docker daemon.

mvn clean install -f ../pom.xml -DskipTests

Verify the image is installed in the minikube’s Docker registry with either of the calls.

docker images
minikube -p keycloak-custom ssh -- docker images

The direct docker images call will only work, provided Docker is installed locally. Given we set DOCKER_HOST in this terminal, the result should be equivalent.

The resulting in output should look similar to the following. Notably we recognize that these are images in the minikube and we find our custom container.

REPOSITORY                                                                  TAG              IMAGE ID       CREATED              SIZE
ghcr.io/inventage/keycloak-custom/com.inventage.keycloak.custom.container   1.0.0-SNAPSHOT   3902d8e3462c   About a minute ago   982MB
ghcr.io/inventage/keycloak-custom/com.inventage.keycloak.custom.container   latest           3902d8e3462c   About a minute ago   982MB
<none>                                                                      <none>           8d012399a42f   2 minutes ago        250MB
registry.access.redhat.com/ubi9                                             latest           b6d42355e74e   46 hours ago         228MB
registry-1.docker.io/bitnami/postgresql                                     latest           0ff7ffbd212e   6 days ago           407MB
quay.io/keycloak/keycloak                                                   26.4.2           9e9dc7357d40   3 weeks ago          459MB
registry.k8s.io/kube-apiserver                                              v1.34.0          d291939e9940   2 months ago         83.7MB
registry.k8s.io/kube-controller-manager                                     v1.34.0          996be7e86d9b   2 months ago         71.5MB
registry.k8s.io/kube-scheduler                                              v1.34.0          a25f5ef9c34c   2 months ago         50.5MB
registry.k8s.io/kube-proxy                                                  v1.34.0          6fc32d66c141   2 months ago         74.7MB
registry.k8s.io/etcd                                                        3.6.4-0          a1894772a478   3 months ago         205MB
registry.k8s.io/pause                                                       3.10.1           d7b100cd9a77   4 months ago         514kB
registry.k8s.io/coredns/coredns                                             v1.12.1          138784d87c9c   7 months ago         72.1MB
busybox                                                                     1.32             2a3d4686b403   4 years ago          1.4MB
gcr.io/k8s-minikube/storage-provisioner                                     v5               ba04bb24b957   4 years ago          29MB

In case the custom keycloak image is missing, you can try run the mvn clean install again and explicitly set the Docker host using -Ddocker.host=$DOCKER_HOST, to override any settings in your settings.xml for example.

Step 3: installing Keycloak on minikube

We use a ConfigMap and a Secret for providing the environment specific values. The following commands will create these resources using the provided Kubernetes manifest files.

kubectl apply -f ./src/test/resources/local/keycloak-custom-config-vars.local.yaml
kubectl apply -f ./src/test/resources/local/keycloak-custom-secret-vars.local.yaml

We are now ready to deploy the Keycloak.

helm install keycloak codecentric/keycloakx --values ./src/generated/keycloak-custom-chart/values.yaml

Confirm the keycloak is started up in the terminal with where the kubectl ... --watch is still running.

Let’s forward the port to access the keycloak locally

kubectl port-forward service/keycloak-keycloakx-http "8080:80"

You can access now the Keycloak Admin Console http://localhost:8080/ with user temp-admin and password admin. The password is defined by our secret, while the values.yaml defines the initial, temporary username.

Step 4: uninstalling on minikube

Let’s uninstall Keycloak and Postgres.

helm uninstall keycloak
helm uninstall postgresql

Our terminal with the watch should show the updated state of the pods accordingly.

To delete the keycloak-custom minikube cluster and confirm the list of profiles afterwards, we can call:

minikube -p keycloak-custom delete
minikube profile list

This will also terminate our watch, as the API server of the cluster is also terminated.