Cluster Keycloak with MariaDB and LDAP using Docker Standalone - amsalama/dcm4chee-arc-light GitHub Wiki
Keycloak with MariaDB and LDAP using Docker Standalone
Clusters.o.:
- Cluster Keycloak with MariaDB and LDAP using Docker Swarm
- Keycloak - Blog - Keycloak Cluster Setup
- Master to Master Replication between two MariaDB Servers
Note : The whole setup entitles starting two types of Databases. MariaDB shall be the database used for Keycloak backend, whereas Postgres shall be the database used for Archive backend. The LDAP containers of both clusters are also synced which shall be used by archive containers for its configurations and by the Keycloak containers for accessing their User Federation.
-
Create
docker-compose.env
for first and second clusters as follows :STORAGE_DIR=/storage/fs1 POSTGRES_DB=pacsdb POSTGRES_USER=pacs POSTGRES_PASSWORD=pacs AUTH_SERVER_URL=http://keycloak:8880/auth
Note the
AUTH_SERVER_URL
here useskeycloak
in its hostname. On the first node, map this hostkeycloak
to the IP Address of the first node in its/etc/hosts
file. This is done in order to simulate a loadbalancer for two clusters. -
Specify services for first node in a configuration file
docker-compose.yml
(e.g.) :version: "3" services: host1-ldap: image: dcm4che/slapd-dcm4chee:2.4.48-22.2 ports: - "389:389" env_file: docker-compose.env environment: LDAP_URLS: "ldap://host1-ldap/" LDAP_REPLICATION_HOSTS: "ldap://host1-ldap/ ldap://host2-ldap/" extra_hosts: - "host2-ldap:host2-IP-addr" volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc/ldap1:/var/lib/openldap/openldap-data - /var/local/dcm4chee-arc/slapd1.d:/etc/openldap/slapd.d mariadb: image: mariadb:10.7.3 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: verys3cret MYSQL_DATABASE: keycloak MYSQL_USER: keycloak MYSQL_PASSWORD: keycloak command: - "--log-bin" - "--log-basename=host1" - "--server-id=1" - "--replicate-do-db=keycloak" - "--auto_increment_increment=2" - "--auto_increment_offset=1" volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc/mysql:/var/lib/mysql keycloak: image: dcm4che/keycloak:10.0.1 ports: - "8880:8880" - "8843:8843" - "8990:8990" - "8993:8993" - "7600:7600" environment: DB_VENDOR: mysql KEYCLOAK_DB_CONNECTION_URL: jdbc:mysql://mariadb:3306/keycloak?serverTimezone=Europe/Vienna JGROUPS_DISCOVERY_EXTERNAL_IP: host1 JGROUPS_DISCOVERY_PROTOCOL: TCPPING JGROUPS_DISCOVERY_INITIAL_HOSTS: "host2[7600],host1[7600]" HTTP_PORT: 8880 HTTPS_PORT: 8843 MANAGEMENT_HTTP_PORT: 8990 MANAGEMENT_HTTPS_PORT: 8993 KEYCLOAK_WAIT_FOR: host1-ldap:389 mariadb:3306 JAVA_OPTS: -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -agentlib:jdwp=transport=dt_socket,address=*:8887,server=y,suspend=n depends_on: - host1-ldap - mariadb extra_hosts: - "ldap:host1-IP-addr" - "host1:host1-IP-addr" - "host2:host2-IP-addr" volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc/keycloak:/opt/keycloak/standalone db: image: dcm4che/postgres-dcm4chee:12.2-22 logging: driver: json-file options: max-size: "10m" ports: - "5432:5432" env_file: docker-compose.env volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc/db:/var/lib/postgresql/data arc: image: dcm4che/dcm4chee-arc-psql:5.22.2-secure logging: driver: json-file options: max-size: "10m" ports: - "8080:8080" - "8443:8443" - "9990:9990" - "9993:9993" - "11112:11112" - "2575:2575" env_file: docker-compose.env extra_hosts: - "ldap:host1-IP-addr" - "host1:host1-IP-addr" environment: WILDFLY_CHOWN: /opt/wildfly/standalone /storage WILDFLY_WAIT_FOR: host1-ldap:389 db:5432 JAVA_OPTS: -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -agentlib:jdwp=transport=dt_socket,address=*:8787,server=y,suspend=n depends_on: - host1-ldap - keycloak - db volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc/wildfly:/opt/wildfly/standalone - /var/local/dcm4chee-arc/storage:/storage
replace host1-IP-addr and host2-IP-addr by the IP Addresses of the docker hosts where each of the two clusters are running, which must be resolvable by your DNS server.
-
Specify services for second node in a configuration file
docker-compose.yml
(e.g.) :version: "3" services: host2-ldap: image: dcm4che/slapd-dcm4chee:2.4.48-22.2 ports: - "389:389" env_file: docker-compose.env environment: LDAP_URLS: "ldap://host2-ldap/" LDAP_REPLICATION_HOSTS: "ldap://host1-ldap/ ldap://host2-ldap/" SKIP_INIT_CONFIG: "true" extra_hosts: - "host1-ldap:host1-IP-addr" volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc2/ldap2:/var/lib/openldap/openldap-data - /var/local/dcm4chee-arc2/slapd2.d:/etc/openldap/slapd.d mariadb: image: mariadb:10.7.3 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: verys3cret MYSQL_DATABASE: keycloak MYSQL_USER: keycloak MYSQL_PASSWORD: keycloak command: - "--log-bin" - "--log-basename=host2" - "--server-id=2" - "--replicate-do-db=keycloak" - "--auto_increment_increment=2" - "--auto_increment_offset=2" volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc2/mysql:/var/lib/mysql keycloak: image: dcm4che/keycloak:10.0.1 ports: - "8880:8880" - "8843:8843" - "8990:8990" - "8993:8993" env_file: docker-compose.env environment: DB_VENDOR: mysql KEYCLOAK_DB_CONNECTION_URL: jdbc:mysql://mariadb:3306/keycloak?serverTimezone=Europe/Vienna JGROUPS_DISCOVERY_EXTERNAL_IP: host2 JGROUPS_DISCOVERY_PROTOCOL: TCPPING JGROUPS_DISCOVERY_INITIAL_HOSTS: "host1[7600],host2[7600]" HTTP_PORT: 8880 HTTPS_PORT: 8843 MANAGEMENT_HTTP_PORT: 8990 MANAGEMENT_HTTPS_PORT: 8993 VALIDATE_PASSWORD_POLICY: "true" KEYCLOAK_WAIT_FOR: host2-ldap:389 mariadb:3306 JAVA_OPTS: -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -agentlib:jdwp=transport=dt_socket,address=*:8887,server=y,suspend=n depends_on: - host2-ldap - mariadb extra_hosts: - "ldap:host2-IP-addr" - "host2:host2-IP-addr" - "host1:host1-IP-addr" volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc2/keycloak:/opt/keycloak/standalone db: image: dcm4che/postgres-dcm4chee:12.2-22 ports: - "5432:5432" env_file: docker-compose.env volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc2/db:/var/lib/postgresql/data arc: image: dcm4che/dcm4chee-arc-psql:5.22.2-secure ports: - "8080:8080" - "8443:8443" - "9990:9990" - "9993:9993" - "8787:8787" - "11112:11112" - "2575:2575" extra_hosts: - "ldap:host2-IP-addr" - "host2:host2-IP-addr" env_file: docker-compose.env environment: WILDFLY_CHOWN: /opt/wildfly/standalone /storage WILDFLY_WAIT_FOR: host2-ldap:389 db:5432 JAVA_OPTS: -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -agentlib:jdwp=transport=dt_socket,address=*:8787,server=y,suspend=n depends_on: - host2-ldap - keycloak - db volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /var/local/dcm4chee-arc2/wildfly:/opt/wildfly/standalone - /var/local/dcm4chee-arc2/storage:/storage
replace host1-IP-addr and host2-IP-addr by the IP Addresses of the docker hosts where each of the two clusters are running, which must be resolvable by your DNS server. Note: In LDAP container configuration, we have used
SKIP_INIT_CONFIG: "true"
. This is to start LDAP without any configuration on second host; on enabling replication as explained in following steps, it shall pull the configuration from first LDAP. -
Start
host1-ldap
andmariadb
containers on first clusterdocker-compose up -d host1-ldap mariadb
-
Start
host2-ldap
andmariadb
containers on second clusterdocker-compose up -d host2-ldap mariadb
-
You may verify on second cluster, by logging in to its LDAP using Apache Directory Studio, that it is started without any configuration in it, whereas on the LDAP of first cluster, it is initialized with default configuration of archive.
-
Prepare replication for ldap on host 1 as follows :
docker exec <host1-ldap-container-name> prepare-replication
replace with the ldap container name on host1
-
Prepare replication for ldap on host 2 as follows :
docker exec <host2-ldap-container-name> prepare-replication
replace with the ldap container name on host2
-
Enable replication first for ldap on host 2, since we have used
SKIP_INIT_CONFIG: "true"
, as follows :docker exec <host2-ldap-container-name> enable-replication
replace with the ldap container name on host2
-
Enable replication for ldap on host 1 as follows :
docker exec <host1-ldap-container-name> enable-replication
replace with the ldap container name on host1
-
You may test replication of LDAP was successful or not, by logging in to LDAP of second cluster using Apache Directory Studio and verify that it has pulled the configuration from LDAP of first cluster. Alternatively, also change value of some attribute on LDAP of first cluster and verify it gets reflected in LDAP of second cluster.
-
Enable Master to Master Replication between two MariaDB Servers. You may skip points 1 and 4 as we have already started the mariadb containers on the two clusters.
-
Once replications of LDAP and MariaDB are successful, start the
keycloak
,db
(postgres) andarc
containers on first cluster
docker-compose up -d keycloak db arc
- Verify that Keycloak on first cluster is completely started and is up and running by verifying in the server logs as :
2019-11-25 16:49:29,459 INFO [org.jboss.as.server] (ServerService Thread Pool -- 60) WFLYSRV0010: Deployed "keycloak-server.war" (runtime-name : "keycloak-server.war")
2019-11-25 16:49:29,553 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
2019-11-25 16:49:29,558 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0062: Http management interface listening on http://172.22.0.4:8990/management and https://172.22.0.4:8993/management
2019-11-25 16:49:29,558 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0053: Admin console listening on http://172.22.0.4:8990 and https://172.22.0.4:8993
2019-11-25 16:49:29,559 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 10.0.1 (WildFly Core 11.1.1.Final) started in 49640ms - Started 686 of 974 services (682 services are lazy, passive or on-demand)
This is done so that, when Keycloak is started on second cluster, it shall find the dcm4che
realm in the clustered
MariaDB database and shall not override the settings of the same.
- Start the
keycloak
,db
(postgres) andarc
containers on second cluster.
docker-compose up -d keycloak db arc
Verify the logs of Keycloak on second cluster as explained in previous point.
- In the server logs of Keycloak on both sides, one shall also eventually see that the Keycloaks of the two clusters have discovered each other, as follows :
2019-11-25 16:51:09,920 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,923 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN100000: Node cd93fdec978e joined the cluster
2019-11-25 16:51:09,924 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,925 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN100000: Node cd93fdec978e joined the cluster
2019-11-25 16:51:09,925 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,926 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN100000: Node cd93fdec978e joined the cluster
2019-11-25 16:51:09,926 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,926 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN100000: Node cd93fdec978e joined the cluster
2019-11-25 16:51:09,931 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,932 INFO [org.infinispan.CLUSTER] (thread-11,ejb,3ff29e403864) ISPN100000: Node cd93fdec978e joined the cluster
and
2019-11-25 16:51:09,963 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,964 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN100000: Node 3ff29e403864 joined the cluster
2019-11-25 16:51:09,965 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,965 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN100000: Node 3ff29e403864 joined the cluster
2019-11-25 16:51:09,966 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,966 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN100000: Node 3ff29e403864 joined the cluster
2019-11-25 16:51:09,966 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,966 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN100000: Node 3ff29e403864 joined the cluster
2019-11-25 16:51:09,967 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN000093: Received new, MERGED cluster view for channel ejb: MergeView::[cd93fdec978e|1] (2) [cd93fdec978e, 3ff29e403864], 2 subgroups: [3ff29e403864|0] (1) [3ff29e403864], [cd93fdec978e|0] (1) [cd93fdec978e]
2019-11-25 16:51:09,967 INFO [org.infinispan.CLUSTER] (thread-13,ejb,cd93fdec978e) ISPN100000: Node 3ff29e403864 joined the cluster
- Once clustering of Keycloaks has been verified, proceed to Register Archive UI as OIDC Client in Keycloak
on Keycloak of first cluster.
Note that the
Valid Redirect URIs
andWeb Origins
it shall contain URLs of both sides, (e.g.) :
Root URL : https://host1:8443/dcm4chee-arc/ui2
Admin URL : https://host1:8443/dcm4chee-arc/ui2
Valid Redirect URI : http://host1:8080/dcm4chee-arc/ui2/*
https://host1:8443/dcm4chee-arc/ui2/*
http://host2:8080/dcm4chee-arc/ui2/*
https://host2:8443/dcm4chee-arc/ui2/*
Web Origins : http://host1:8080
https://host1:8443
http://host2:8080
https://host2:8443
- Login to Archive UI of first cluster and verify that one is able to login. Logout and verify one is able to login on Archive UI of second cluster as well.