KC database env configurations are ignored

Hi,

I created Dockerfile based on Keycloak documentation:

FROM quay.io/keycloak/keycloak:20.0.2 as builder
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
ENV KC_DB=postgres
ENV KC_DB_URL=jdbc:postgres://auth-keycloak-db:15434/keycloak
ENV KC_DB_USERNAME=keycloak
ENV KC_DB_PASSWORD=keycloak
WORKDIR /opt/keycloak
COPY <provider>.jar providers/
RUN keytool -genkeypair -storepass password -storetype PKCS12 -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore conf/server.keystore
RUN bin/kc.sh build
#
FROM quay.io/keycloak/keycloak:20.0.2
COPY --from=builder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

Created this docker-compose file, regarding usage of postgres-db:

version: "3.8"

services:

  auth-keycloak:
    build:
      context: ..
      dockerfile: deploy/Dockerfile
    environment:
      - KEYCLOAK_ADMIN=admin
      - KEYCLOAK_ADMIN_PASSWORD=admin
      - KC_HOSTNAME=auth-keycloak
    ports:
      - "9990:8443"
    depends_on:
      - "auth-keycloak-db"
    command: ["start"]

  auth-keycloak-db:
    image: postgres:13.3
    volumes:
      - ./data/keycloak/db:/var/lib/postgresql/data
    ports:
      - "15434:5432"
    environment:
      - POSTGRES_DB=keycloak
      - POSTGRES_USER=keycloak
      - POSTGRES_PASSWORD=keycloak

It works this way. The problem is, regarding database configuration, it only works THIS way (and only for 20.0.2, in 20.0.3 I had no success at all), i.e. by setting env in build stage.

I need to specify db connection info in docker-compose as environment variables, for example, but then Keycloak doesn’t recognize any KC env config. Besides docker-compose envs, tried also: as start argument (cli), with --optimized option (as mentioned in v19 doc), setting in Dockerfile after build stage and so on, also I’ve read many other discussions, but none of these seems to work for me.

I’ll give some error examples, like when I set as docker-compose env variables, including:

      - KC_DB_URL=jdbc:postgres://auth-keycloak-db:15434/keycloak
      - KC_DB_USERNAME=keycloak
      - KC_DB_PASSWORD=keycloak

Gives error below (as expecting h2 db):

2023-02-03 16:24:30,883 WARN  [io.agroal.pool] (agroal-11) Datasource '<default>': URL format error; must be "jdbc:h2:{ {.|mem:}[name] | [file:]fileName | {tcp|ssl}:[//]server[:port][,server2[:port]]/name }[;key=value...]" but is "jdbc:postgres://auth-keycloak-db:15434/keycloak" [90046-214]
2023-02-03 16:24:30,885 WARN  [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator] (JPA Startup Thread: keycloak-default) HHH000342: Could not obtain connection to query metadata: org.h2.jdbc.JdbcSQLNonTransientConnectionException: URL format error; must be "jdbc:h2:{ {.|mem:}[name] | [file:]fileName | {tcp|ssl}:[//]server[:port][,server2[:port]]/name }[;key=value...]" but is "jdbc:postgres://auth-keycloak-db:15434/keycloak" [90046-214]
  at org.h2.message.DbException.getJdbcSQLException(DbException.java:678)
  at org.h2.message.DbException.getJdbcSQLException(DbException.java:477)
  at org.h2.message.DbException.get(DbException.java:223)
  at org.h2.engine.ConnectionInfo.getFormatException(ConnectionInfo.java:687)
  at org.h2.engine.ConnectionInfo.<init>(ConnectionInfo.java:86)
  at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:113)
  at org.h2.jdbcx.JdbcDataSource.getXAConnection(JdbcDataSource.java:322)
  at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:232)
  at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:535)
  at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:516)
  at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
  at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
  at java.base/java.lang.Thread.run(Thread.java:829)
auth-keycloak       |

If I add - KC_DB=postgres to it (regarding explicitly not h2 db), it gives have another error, like pointing to a default db:

2023-02-03 16:47:59,873 WARN  [io.agroal.pool] (main) Datasource '<default>': Ignoring property 'URL': null
2023-02-03 16:47:59,874 WARN  [io.agroal.pool] (main) Datasource '<default>': Ignoring property 'URL': null
2023-02-03 16:48:00,156 WARN  [io.agroal.pool] (agroal-11) Datasource '<default>': Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
2023-02-03 16:48:00,160 WARN  [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator] (JPA Startup Thread: keycloak-default) HHH000342: Could not obtain connection to query metadata: org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
  at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:319)
  at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)
  at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:247)
  at org.postgresql.Driver.makeConnection(Driver.java:434)
  at org.postgresql.Driver.connect(Driver.java:291)
  at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:677)
  at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:228)
  at org.postgresql.ds.common.BaseDataSource.getConnection(BaseDataSource.java:103)
  at org.postgresql.xa.PGXADataSource.getXAConnection(PGXADataSource.java:49)
  at org.postgresql.xa.PGXADataSource.getXAConnection(PGXADataSource.java:35)
  at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:232)
  at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:535)
  at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:516)
  at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
  at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
  at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.net.ConnectException: Connection refused (Connection refused)
  at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
  at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:412)
  at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:255)
  at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:237)
  at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
  at java.base/java.net.Socket.connect(Socket.java:609)
  at org.postgresql.core.PGStream.createSocket(PGStream.java:241)
  at org.postgresql.core.PGStream.<init>(PGStream.java:98)
  at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:109)
  at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:235)
  ... 17 more

If I replace start command to show-config in compose, I can see all env set properly:

Current Configuration:
  kc.cache =  ispn (PersistedConfigSource)
  kc.config.built =  true (SysPropConfigSource)
  kc.db =  postgres (KcEnvVarConfigSource)
  kc.db-password =  ******* (KcEnvVarConfigSource)
  kc.db-url =  jdbc:postgres://auth-keycloak-db:15434/keycloak (KcEnvVarConfigSource)
  kc.db-username =  keycloak (KcEnvVarConfigSource)
  kc.db.password =  keycloak (KcEnvVarConfigSource)
  kc.db.url =  jdbc:postgres://auth-keycloak-db:15434/keycloak (KcEnvVarConfigSource)
  kc.db.username =  keycloak (KcEnvVarConfigSource)
  kc.health-enabled =  true (PersistedConfigSource)
  kc.hostname =  auth-keycloak (KcEnvVarConfigSource)
...

But when I start keycloak, it doesn’t see any of those. In addition to that, if I keep these env in build stage and then try to set again (any other further stage in Dockerfile or docker-compose), it seems to override the same env variables, but then Keycloak just ignore all of them. I mean: any other combination than keeping these KC_DB env ONLY in Dockerfile build stage does not work, at least on my experience, and it’s not making much sense to me, so if anyone went thru that or maybe helping understanding, I would really appreciate.

1 Like

hey @bzani

I looked over your logs. Couple questions concerning the database.
Was the database already configure with username “admin” and password “admin”? if so have you tried to alter the database used by keycloak?

example:

ALTER USER postgres PASSWORD '<new-password>';

I seen this… Connection to localhost:5432 refused.

What I dont see in your Docker-compose is netwrok configurations, is this correct?
Can I ask where you got this keycloak docker-compose.yaml file?

Hi @gsmith thanks for replying!

Was the database already configure with username “admin” and password “admin”? if so have you tried to alter the database used by keycloak?

Here is just to create initial keycloak user, I don´t see error in this point.

What I dont see in your Docker-compose is netwrok configurations, is this correct?

I´m using default network, here works the same if I set custom as bridge for example.

–

Update: in latest tests, using start --optimized flag Keycloak is overriding Dockerfile envs by docker-compose envs (success), though I tried this before and can´t explain why didn´t work. I also changed a little my config files, and will post below. However, I could only connect to db by exposing default port 5432, any other port didn´t work and I´m still investigating this (probably, not Kc related).

# Dockerfile
FROM quay.io/keycloak/keycloak:20.0.2 as builder
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
ENV KC_DB=postgres
WORKDIR /opt/keycloak
COPY <provider> providers/
RUN keytool -genkeypair ...
RUN bin/kc.sh build

FROM quay.io/keycloak/keycloak:20.0.2
COPY --from=builder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

# docker-compose.yml
version: "3.8"
services:
  auth-keycloak:
    hostname: auth-keycloak
    container_name: auth-keycloak
    build:
      context: ..
      dockerfile: deploy/Dockerfile
    env_file:
      - kc-vars.env
    ports:
      - "8080:8080"
      - "8443:8443"
    depends_on:
      - "auth-keycloak-db"
    command: ["start --optimized"]
  auth-keycloak-db:
    hostname: "auth-keycloak-db"
    image: postgres:13.3
    container_name: auth-keycloak-db
    volumes:
      - auth-keycloak-volume:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=keycloak
      - POSTGRES_USER=keycloak
      - POSTGRES_PASSWORD=keycloak
volumes:
  auth-keycloak-volume:

# kc-vars.env
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=admin
KC_HOSTNAME=localhost
KC_DB=postgres
KC_DB_USERNAME=keycloak
KC_DB_PASSWORD=keycloak
KC_DB_SCHEMA=public
KC_DB_URL_DATABASE=keycloak
KC_DB_URL_HOST=auth-keycloak-db
KC_DB_URL_PORT=5432
KC_HTTP_ENABLED=true
KC_PROXY=edge

ps: I also noticed that when I set env only in my build stage it seemed to work, because Keycloak is up, thought I didn´t find no info in logs about what db it was using and no tables created in local db (possibly using default local db), which go against my first statement.