How to Cluster a Keycloak Server

In this post I am going to explain, how cluster a Keycloak server in detail.

These are the topic I am covering.

  1. Clustering Methods
  2. Keycloak cluster architecture
  3. Infinispan clustering
  4. Setting up and running a Keycloak cluster

1. Keycloak Clustering Methods

There are two Keycloak clustering architectures.

  • Single cluster deployment
  • Multi cluster deployment

Single Cluster Deployment

Deploy Keycloak in a single cluster, optionally across multiple availability-zones or data centers. This setup can withstand Keycloak app(pod) failures.

Multi Cluster Deployment

Connect two Keycloak clusters deployed, for example in different Kubernetes clusters in two availability zones or data centers. This setup can withstand cluster failures or regional outages.

This post focuses on the single cluster deployment method.

2. Let’s dive through the Keycloak Single Cluster Architecture

Cluster of three Keycloak servers

Major Aspects to Focus on this Architecture.

i. Load Balancing

It is mandatory to setup the cluster behind a load balancer because load balancer routes the request to each Keycloak instance. Load balancer’s request routing algorithm can be configured as necessary. Few of them are

  • Round robin
  • Weighted round robin
  • IP hash

You can use any routing algorithm as you prefer.

ii. Database

Each Keycloak instance is backed by the same database. Database is used for keycloak instance discovery (explained below).

PostgreSQL is the default and widely used database to store Keycloak data (users, clients, realms, identity providers, offline sessions, etc.)

iii. Cache (Infinispan)

Keycloak has an internal data cache. In development mode it is a local cache and it does not support clustering and intended for development purpose only.

In the production mode, Keycloak uses Infinispan open-source in-memory database to store its frequently used data.

Infinispan supports both caching and clustering. It stores frequently accessed data such as user sessions, authentication sessions, realms, users, and tokens in memory to reduce database load and improve performance.

In clustered deployments, Infinispan enables session replication and synchronization across multiple Keycloak nodes, ensuring high availability and consistent user login state even if one node fails.

Infinispan becomes the most important component in Keycloak when it comes to clustering.

I would say if you can setup the Infinispan cluster properly, then you are more than 80% done in Keycloak clustering.

3. Infinispan clustering

Let’s further discuss about Infinispan clustering.

When it comes to Infinispan clustering there are two phases.

  1. Neighbor discovery
  2. Cluster creation (communicating with neighbors)

In Infinispan, the neighbor discovery phase is the process where a new node finds the other members of the cluster so it can join and form a shared cluster view.

Earlier Keycloak supported multiple discovery mechanisms (Multicast, UPD, EC2, AZURE, JDBC-PING-UDP), but many of these are unreliable in modern cloud and Kubernetes environments due to blocked multicast, changing pod IPs, DNS quirks, and permission constraints.

Because of that, Keycloak has standardized on JDBC_PING, where each node registers its own address in a shared database table and reads the addresses of other live nodes from the same table; the database acts only as a discovery “phonebook,” and once nodes find each other, they connect directly and communicate normally over the network.

Neighbor Discover Flow

JDBC_PING method uses a table named jgroups_ping to store the details of each Keycloak instance.

Using the jgroups_ping table, it is possible for each node to identify it’s neighbors.

4. Running Keycloak Cluster

If you are interested in running a keycloak cluster locallly, you can use the below docker compose file and the nginx.conf file. what you have to do is;

copy below two files to the same folder and run the command:

docker compose up

As prerequisites you should have docker installed on your environment. This command will spin up four docker containers.

  • One PostgreSQL docker
  • One Nginx docker
  • Two Keycloak dockers
version: '3.8'

services:

  postgres:
    image: postgres:15
    container_name: kc-postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - kc-network

  keycloak-1:
    image: quay.io/keycloak/keycloak:26.5.3
    container_name: keycloak-1
    command:
      - start
      - --cache=ispn
      - --cache-stack=jdbc-ping
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: password

      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: admin

      KC_HOSTNAME: http://localhost:8080
      KC_HTTP_ENABLED: "true"

      KC_CACHE: ispn
      KC_CACHE_STACK: jdbc-ping
    depends_on:
      - postgres
    networks:
      - kc-network

  keycloak-2:
    image: quay.io/keycloak/keycloak:26.5.3
    container_name: keycloak-2
    command:
      - start
      - --cache=ispn
      - --cache-stack=jdbc-ping
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: password

      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: admin

      KC_HOSTNAME: http://localhost:8080
      KC_HTTP_ENABLED: "true"

      KC_CACHE: ispn
      KC_CACHE_STACK: jdbc-ping
    depends_on:
      - postgres
    networks:
      - kc-network

  nginx:
    image: nginx:1.25
    container_name: kc-nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - keycloak-1
      - keycloak-2
    networks:
      - kc-network

volumes:
  postgres_data:

networks:
  kc-network:
events {}

http {

    upstream keycloak_cluster {
        server keycloak-1:8080;
        server keycloak-2:8080;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://keycloak_cluster;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Once the cluster is up and running. You can simply visit the url http://localhost:8080 and you will be able to access Keycloak using the admin credentials (admin / admin in this case).

This is how to find whether the cluster is actually created

You can make sure the cluster is working properly by inspecting the server logs and jgroups_ping table.

jgroups_ping table should show two entries for the above setup if the cluster is properly created.

select * from jgroups_ping jp ;

Also you can inspect docker compose logs and it will show logs related to forming an Infinispan cluster.

docker compose logs

With that we come to the end of this post. I hope you got a good understanding about Keycloak clustering. If you have any question please comment and I will make sure to answer them as time permits.

Thank you !!!

References

https://www.keycloak.org/high-availability/single-cluster/introduction

Similar Posts