Migrate Keycloak H2 database to Postgres on Kubernetes

keycloak
Reading Time: 4 minutes

In this blog. We will discuss how we can migrate the Keycloak H2 database to Postgres on production or for the new server. Follow stepwise instructions to migrate the Keycloak H2 database to Postgres.

Introduction – Migrate Keycloak

  1. Keycloak: is open source identity & access management software. It provides many services for authentication and security.
  2. H2 database: H2 database in-memory java-based relational database for keycloak.
  3. Postgresql: is open-source relational database management system.
  4. Kubernetes: Orchestration for managing container based microservices.

Scope – Migrate Keycloak

We are migrating from the H2 database of an already deployed Keycloak server to the Postgres database for Keycloak to persist Keycloak data with no downtime & rolling update strategy. Our database is small so we will use migration provider singleFile which imports data into a single JSON file. We will require some basic knowledge of the above tools and corresponding CLIs must be installed.

migrate keycloak data to postgres

Prerequisites

  1. Keycloak: Deployed on kubernetes
  2. Postgres knowledge

Let’s start migration from H2 to postgres

1. Export JSON form Keycloak server

1 Exec into master keycloak server

kubectl exec <-keycloak-pod-name> -it -- bash

2 Go to keycloak directory

cd /opt/jboss/keycloak

3 Run exporting script

bin/standalone.sh \
    -Dkeycloak.migration.action=export\
    -Djboss.socket.binding.port-offset=1\
    -Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.file=data-keycloak.json

wait for a minute then the output will look like this

export keycloak data for postgres

When this output appears wait a couple of seconds and stop the script by aborting signal ctrl+c. A JSON file named data-keycloak.json is created at /opt/jboss/keycloak or at the present working directory.

4 Copy the JSON file to the local system

kubectl cp <namespace>/keycloak-0:opt/bitnami/data-keycloak.json data-keycloak.json

Now, the JSON file is exported successfully & stored in your local system.

2. Create configMap

Now we will create configMap to insert the JSON data into our keycloak pod

1 Make compact of the exported JSON file

For this, you will require jq tool

cat <path-to-json>/data-keycloak.json |jq -c >> keycloak.json

2 Create configMap of JSON

Paste the compact JSON (keycloak.json) in the data section of configMap

configmap.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: keycloak-data
data:
  keycloak.json: |
    {"id":"c74c7c08-dfed-4028-8307-7d3888bcb7ac","name":"query-groups","description":"${role_query-groups}","composite":false,"clientRole":true,"containerId":"c9a05bc2-3e0f-4e74-971e-73d93e0fcb45","attributes":{}},{"id":"c7040aad-76a6-422d-819e-65eab9803755","name":"manage-clients","description":"${role_manage-clients}","composite":false,"clientRole":true,"containerId":"c9a05bc2-3e0f-4e74-971e-73d93e0fcb45","attributes":{}},{"id":"0d147ea7-a449-4330-9ce5-e1ae67df267e","name":"query-clients","description":"${role_query-clients}","composite":false,"clientRole":true,"containerId":"c9a05bc2-3e0f-4e74-971e-73d93e0fcb45","attributes":{}},{"id":"a8f67dc9-2c16-4523-978c-06b4341fd385","name":"view-events","description":"${role_view-events}","composite":false,"clientRole":true,"containerId":"c9a05bc2-3e0f-4e74-971e-73d93e0fcb45","attribut

3 Deploy configMap

kubectl create -f configmap.yml

3. Deploy Postgres Database

1 Create deployment file for Postgres

Environment Variables

KeyValue
POSTGRES_PASSWORDsecret
PGDATA/data/pgdata
POSTGRES_USERkeycloak
POSTGRES_DBkeycloak

postrgres-sfs.yml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql-db
spec:
  serviceName: postgresql-db-service
  selector:
    matchLabels:
      app: postgresql-db
  replicas: 1
  template:
    metadata:
      labels:
        app: postgresql-db
    spec:
      containers:
      - name: postgresql-db
        image: postgres:latest
        volumeMounts:
        - name: postgresql-db-disk
          mountPath: /data
        env:
        - name: POSTGRES_PASSWORD
          value: password
        - name: PGDATA
          value: /data/pgdata
        - name: POSTGRES_USER
          value: keycloak
        - name: POSTGRES_DB
          value: keycloak
# Volume Claim
  volumeClaimTemplates:
  - metadata:
      name: postgresql-db-disk
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
         storage: 1Gi
---
# PostgreSQL StatefulSet Service
apiVersion: v1
kind: Service
metadata:
  name: postgres-db-lb
spec:
  selector:
    app: postgresql-db
  type: LoadBalancer
  ports:
  - port: 5432
    targetPort: 5432

2 Deploy Postgres on Kubernetes

kubectl apply -f postgres-sfs.yml

4. Create a Job

1 Create a YAML file for the job to import data

importkeycloak.yml

apiVersion: batch/v1
kind: Job
metadata:
  name: migrate
spec:
  ttlSecondsAfterFinished: 100
  template:
    spec:
      containers:
      - name: keycloak-migrate
        image: quay.io/keycloak/keycloak:16.1.1
        volumeMounts:
          - mountPath: "/app/data"
            name: data-kc
            readOnly: true
        env:
        - name: KEYCLOAK_USER
          value: "secret-user"
        - name: KEYCLOAK_PASSWORD
          value: "secret-password"
        - name: DB_VENDOR
          value: "postgres"
        - name: DB_ADDR
          value: "postgres-db-lb"
        - name: DB_DATABASE
          value: "keycloak"
        - name: DB_USER
          value: "keycloak"
        - name: DB_SCHEMA
          value: "public"
        - name: DB_PASSWORD
          value: db-password
        ports:
        - name: http
          containerPort: 8080
        - name: https
          containerPort: 8443
        command:
          - "/opt/jboss/tools/docker-entrypoint.sh"
        args:
          - "-Dkeycloak.migration.action=import"
          - "-Dkeycloak.migration.strategy=OVERWRITE_EXISTING"
          - "-Djboss.socket.binding.port-offset=0"
          - "-Dkeycloak.migration.provider=singleFile"
          - "-Dkeycloak.migration.file=/app/data/keycloak.json"
          - "-b"
          - "0.0.0.0"
      restartPolicy: Never
      volumes:
        - name: data-kc
          configMap:
            name: keycloak-data
            items:
              - key: "keycloak.json"
                path: "keycloak.json"

2 Run the job

kubectl apply -f importkeycloak.yml

3 Check logs of job

kubectl logs job/migrate
import keycloak migrate to postgres

This means importing is done. Now you can suspend the job.

4 Suspend the job

kubectl edit job/migrate

Change suspend: false to suspend: true

5. Deploy Keycloak

1 Update existing YAML or create a new deployment for Keycloak

keycloak-deploy.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  namespace: default
  labels:
    app: keycloak
spec:
  replicas: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      containers:
      - name: keycloak
        resources: {}
        image: quay.io/keycloak/keycloak:16.1.1
        env:
        - name: KEYCLOAK_USER
          value: "admin"
        - name: KEYCLOAK_PASSWORD
          value: "admin"
        - name: DB_VENDOR
          value: "postgres"
        - name: DB_ADDR
          value: "postgres-db-lb"
        - name: DB_DATABASE
          value: "keycloak"
        - name: DB_USER
          value: "keycloak"
        - name: DB_SCHEMA
          value: "public"
        - name: DB_PASSWORD
          value: password
        ports:
        - name: http
          containerPort: 8080
        - name: https
          containerPort: 8443
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: keycloak
spec:
  tls:
    - hosts:
      - keycloak.192.168.49.2.nip.io
  rules:
  - host: keycloak.192.168.49.2.nip.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: keycloak
            port:
              number: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: keycloak
  labels:
    app: keycloak
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  selector:
    app: keycloak
  type: LoadBalancer

2 Roll out the deployment or create Keycloak deployment

kubectl apply -f keycloak-deploy.yml

Congrats

You have successfully migrated the H2 database to Postgres for Keycloak.

References

Server Administration Guide – Keycloak – Import/export

Written by 

Rahul Soni is a Software Consultant at Knoldus Software. He is always charged up for new things & learnings. He is dedicated to his work and believes in quality output. He loves to take deep dives into cloud technologies & different tools.

1 thought on “Migrate Keycloak H2 database to Postgres on Kubernetes6 min read

Comments are closed.