Skip to content

Instantly share code, notes, and snippets.

@sarath-soman
Last active November 6, 2025 00:16
Show Gist options
  • Select an option

  • Save sarath-soman/5d9aec06953bbd0990c648605d4dba07 to your computer and use it in GitHub Desktop.

Select an option

Save sarath-soman/5d9aec06953bbd0990c648605d4dba07 to your computer and use it in GitHub Desktop.
Keycloak docker compose with health checks
# Keycloak containers doesn't come with curl or wget in it, this forces the users to use alternative mechanisms to realise
# health check for the keycloak standard containers. This example leverages the capability of modern Java to dynamically
# compile a *.java source file and execute it on the fly using the `java` command. The HealthCheck class uses
# java.net.URL to open a connection to the `health/live` endpoint of keycloak and exits the process with a non-zero status
# if the http status is not `Ok`
version: '3'
services:
############################
# Keycloak service
############################
keycloak:
image: quay.io/keycloak/keycloak:22.0.5
command:
- start-dev
- --import-realm
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
DB_VENDOR: h2
KC_HEALTH_ENABLED: true
ports:
- '8080:8080'
volumes:
- ./keycloak:/opt/keycloak/data/import
healthcheck:
test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)new java.net.URL(args[0]).openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:8080/health/live']
interval: 5s
timeout: 5s
retries: 30
@felipementel
Copy link

Verify the "Installing additional RPM packages" subject at https://www.keycloak.org/server/containers

but, always exists others ways....

  keycloak-service:
    container_name: keycloak-container
    image: quay.io/keycloak/keycloak:26.0.7
    environment:
      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
      KC_HOSTNAME: localhost
      KC_HOSTNAME_PORT: 8080
      KC_HOSTNAME_STRICT_BACKCHANNEL: 'true'
      KC_HOSTNAME_STRICT_FRONTCHANNEL: 'true'
      KC_HTTP_ENABLED: 'true' #PRD false
      KC_HEALTH_ENABLED: 'true'
      KC_METRICS_ENABLED: 'true'
      KC_HTTP_METRICS_HISTOGRAMS_ENABLED: 'true'
      KC_CACHE_METRICS_HISTOGRAMS_ENABLED: 'true'
      KC_LOG_LEVEL: INFO # DEBUG
      # DB Configuration
      KC_DB: postgres
      KC_DB_VENDOR: postgres
      KC_DB_SCHEMA: public
      KC_DB_HOST: postgresHost
      KC_DB_PORT: 5432
      KC_DB_NAME: keycloakDB
      KC_DB_URL: jdbc:postgresql://postgres-container:5432/keycloakDB
      KC_DB_USERNAME: userKeyCloak
      KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
    depends_on:
      postgres-service:
        condition: service_healthy
    healthcheck:
      test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)new java.net.URL(args[0]).openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:9000/health/live']
      interval: 5s
      timeout: 5s
      retries: 30
    command: ['start-dev', '--http-port', '8080']
    ports:
      - 8087:8080
      - 7447:7443
      - 9007:9000
    networks:
      - local_network
    labels:
      - maintainer="Felipe Augusto, Canal DEPLOY, https://linktr.ee/felipementel"
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 256M
        reservations:
          cpus: '0.25'
          memory: 128M
    cpuset: '1'

@col-panic
Copy link

sry, on my side it's working now... the good version was in github actions because my docker image cache was not clean.

This one working good locally and in githubaction with keycloak 26.0

    healthcheck:
      test: ["CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000;echo -e 'GET /health/ready HTTP/1.1\r\nhost: http://localhost\r\nConnection: close\r\n\r\n' >&3;if [ $? -eq 0 ]; then echo 'Healthcheck Successful';exit 0;else echo 'Healthcheck Failed';exit 1;fi;"]
      start_period: 10s
      interval: 30s
      retries: 3
      timeout: 5s

Starting with 26.0.8 for me this leads to the following log entries:

keycloak-1  | 2025-01-16T11:42:36.127925007Z 2025-01-16 11:42:36,127 ERROR [io.vertx.ext.web.RoutingContext] (vert.x-eventloop-thread-3) Unhandled exception in router

@felipementel
Copy link

healthcheck:
test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)new java.net.URL(args[0]).openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:9000/health/live']
interval: 5s
timeout: 5s
retries: 30

try to use your healthcheck like this

    healthcheck:
      test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)new java.net.URL(args[0]).openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:9000/health/live']
      interval: 5s
      timeout: 5s
      retries: 30

@codespearhead
Copy link

For what it’s worth, I’ve updated my previous answer [1] to bump the Keycloak version to v26.1.0-0 (released on 2025-01-15), and I confirm that no changes to the health check logic were necessary.

[1] https://gist.github.com/sarath-soman/5d9aec06953bbd0990c648605d4dba07?permalink_comment_id=5376088#gistcomment-5376088

@AlecKotovichSAM
Copy link

To avoid Java warning [deprecation] URL(String) in URL has been deprecated, I rewrote it like that:

    healthcheck:
      test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { java.net.URI uri = java.net.URI.create(args[0]); System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)uri.toURL().openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:9000/health/live']
      interval: 5s
      timeout: 5s
      retries: 5

Worked for me.

@HungNguyenThac
Copy link

To avoid Java warning [deprecation] URL(String) in URL has been deprecated, I rewrote it like that:

    healthcheck:
      test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { java.net.URI uri = java.net.URI.create(args[0]); System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)uri.toURL().openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:9000/health/live']
      interval: 5s
      timeout: 5s
      retries: 5

Worked for me.

Worked for me too

@SimonVonXCVII
Copy link

To avoid Java warning [deprecation] URL(String) in URL has been deprecated, I rewrote it like that:

    healthcheck:
      test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { java.net.URI uri = java.net.URI.create(args[0]); System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)uri.toURL().openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:9000/health/live']
      interval: 5s
      timeout: 5s
      retries: 5

Worked for me.

Worse for me too. But I found a brief introduction at https://www.keycloak.org/observability/health and shared it with you, hoping it can help others in need.

@brammitch
Copy link

brammitch commented Oct 23, 2025

    healthcheck:
      test: [
        "CMD-SHELL",
        "exec 3<>/dev/tcp/localhost/${ENV_KC_HTTP_MANAGEMENT_PORT:?}; \
        echo -en 'GET /health/ready' >&3; \
        # Give the server a moment to respond, then search for 'UP'
        if timeout 3 cat <&3 | grep -m 1 'UP'; then \
          exec 3<&-; exec 3>&-; exit 0; \
        else \
          exec 3<&-; exec 3>&-; exit 1; \
        fi"
      ]

Thanks @codespearhead! This worked for me using Keycloak 26.3.4.

@vit-zikmund
Copy link

Hi folks! You can now see the official docs for a little more concise healthcheck command.
It's a variant on the bash tcp socket redirect I independently figured out and described in a PR that got eventually merged 🙏.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment