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:
- Java JDK 21
- minikube
- Helm
- kubectl (Note, you can also replace all
kubectl <kubectl commands>commands in the tutorial withminikube kubectl -- <kubectl commands>) - jq
Steps
This tutorial is based on our public Keycloak-Custom repo on GitHub.

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 startWe’ll observe the pods in the minikube cluster by keeping a terminal open with the following command.
kubectl get pods --all-namespaces --watchLet’s add the required chart repositories.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add codecentric https://codecentric.github.io/helm-chartsNow 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.yamlStep 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-envThis 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 -DskipTestsVerify the image is installed in the minikube’s Docker registry with either of the calls.
docker images
minikube -p keycloak-custom ssh -- docker imagesThe 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.yamlWe are now ready to deploy the Keycloak.
helm install keycloak codecentric/keycloakx --values ./src/generated/keycloak-custom-chart/values.yamlConfirm 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 postgresqlOur 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 listThis will also terminate our watch, as the API server of the cluster is also terminated.