
TL;DR: Ceci est une description de Keycloak, un systÚme de contrÎle d'accÚs open source, une analyse de son fonctionnement interne et des détails de configuration.
Introduction et concepts clés
Dans cet article, nous allons examiner les idées principales à garder à l'esprit lors du déploiement d'un cluster Keycloak sur Kubernetes.
Si vous souhaitez en savoir plus sur Keycloak, consultez les liens Ă la fin de l'article. Pour vous immerger davantage dans la pratique, vous pouvez Ă©tudier avec un module qui met en Ćuvre les concepts clĂ©s de cet article (un guide de dĂ©marrage est Ă©galement disponible, cet article prĂ©sentera un aperçu de la structure et des configurations, note du traducteur).
Keycloak est un systÚme complexe écrit en Java et construit sur le serveur d'applications . En bref, c'est un framework pour l'autorisation, offrant aux utilisateurs des applications la fédération et la possibilité de SSO (authentification unique).
Nous vous invitons à consulter la ou pour une compréhension détaillée.
Démarrage de Keycloak
Keycloak nécessite deux sources de données persistantes pour fonctionner :
- Une base de données utilisée pour stocker les données stables, telles que les informations sur les utilisateurs.
- Un cache Datagrid, qui est utilisĂ© pour mettre en cache les donnĂ©es de la base de donnĂ©es et pour stocker certaines mĂ©tadonnĂ©es Ă©phĂ©mĂšres et souvent changeantes, telles que les sessions utilisateurs. RĂ©lisĂ© par , qui est gĂ©nĂ©ralement beaucoup plus rapide qu'une base de donnĂ©es. Cependant, dans tous les cas, les donnĂ©es stockĂ©es dans Infinispan sont Ă©phĂ©mĂšres - elles ne doivent pas ĂȘtre sauvegardĂ©es lors du redĂ©marrage du cluster.
Keycloak fonctionne en quatre modes différents :
- Standard â un seul processus, configurĂ© via le fichier standalone.xml
- Cluster standard (version haute disponibilitĂ©) â tous les processus doivent utiliser la mĂȘme configuration, qui doit ĂȘtre synchronisĂ©e manuellement. Les paramĂštres sont stockĂ©s dans le fichier standalone-ha.xml, un accĂšs commun Ă la base de donnĂ©es et un rĂ©partiteur de charge doivent Ă©galement ĂȘtre configurĂ©s.
- Cluster de domaine â le lancement d'un cluster en mode standard devient rapidement une tĂąche routiniĂšre et ennuyeuse Ă mesure que le cluster se dĂ©veloppe, car Ă chaque modification de la configuration, il faut apporter ces modifications sur chaque nĆud du cluster. Le mode domaine rĂ©sout ce problĂšme en configurant un espace de stockage commun et en publiant la configuration. Ces paramĂštres sont stockĂ©s dans le fichier domain.xml
- RĂ©plication entre centres de donnĂ©es â si vous souhaitez exĂ©cuter Keycloak dans un cluster composĂ© de plusieurs centres de donnĂ©es, souvent situĂ©s Ă des endroits gĂ©ographiquement Ă©loignĂ©s. Dans cette configuration, chaque centre de donnĂ©es disposera de son propre cluster de serveurs Keycloak.
Dans cet article, nous allons examiner en détail la deuxiÚme option, à savoir un cluster standard, et nous aborderons également briÚvement le sujet de la réplication entre les centres de données, car ces deux options ont du sens à exécuter dans Kubernetes. Heureusement, Kubernetes n'a pas de problÚmes de synchronisation des paramÚtres de plusieurs pods (nodes Keycloak), donc un cluster de domaine ne sera pas trop difficile à mettre en place.
Veuillez également noter que le terme un cluster sera utilisé dans cet article uniquement en référence à un groupe de nodes Keycloak fonctionnant ensemble, sans qu'il soit nécessaire de faire référence au cluster Kubernetes.
Cluster standard de Keycloak
Pour exécuter Keycloak en mode standard, il est nécessaire de :
- configurer une base de données externe partagée
- installer un répartiteur de charge
- avoir un réseau interne prenant en charge le multicast IP
Nous ne discuterons pas de la configuration de la base de données externe, car ce n'est pas l'objectif de cet article. Supposons donc qu'il existe quelque part une base de données fonctionnelle à laquelle nous avons un point de connexion. Nous allons simplement ajouter ces données dans les variables d'environnement.
Pour mieux comprendre comment Keycloak fonctionne dans un cluster à haute disponibilité (HA), il est essentiel de savoir à quel point cela dépend des capacités de clusterisation de Wildfly.
Wildfly utilise plusieurs sous-systĂšmes, certains d'entre eux Ă©tant utilisĂ©s comme rĂ©partiteurs de charge, d'autres pour la haute disponibilitĂ©. Le rĂ©partiteur de charge assure la disponibilitĂ© de l'application en cas de surcharge d'un nĆud du cluster, tandis que la haute disponibilitĂ© garantit l'accĂšs Ă l'application mĂȘme en cas de dĂ©faillance d'une partie des nĆuds du cluster. Parmi ces sous-systĂšmes, on trouve :
mod_cluster: fonctionne en collaboration avec Apache comme rĂ©partiteur de charge HTTP, dĂ©pend de TCP multicast pour la dĂ©couverte des nĆuds par dĂ©faut. Peut ĂȘtre remplacĂ© par un rĂ©partiteur de charge externe.infinispan: cache distribuĂ© utilisant les canaux JGroups comme couche de transport. Peut Ă©galement utiliser le protocole HotRod pour communiquer avec un cluster externe Infinispan afin de synchroniser le contenu du cache.jgroups: fournit une prise en charge de la communication de groupe pour des services hautement disponibles basĂ©s sur des canaux JGroups. Les canaux nommĂ©s permettent aux instances d'application dans le cluster de se connecter en groupes, de sorte que la communication possĂšde des propriĂ©tĂ©s telles que la fiabilitĂ©, l'ordre et la sensibilitĂ© aux pannes.
Ăquilibreur de charge
Lors de l'installation d'un équilibreur de charge en tant que contrÎleur d'entrée dans un cluster Kubernetes, il est important de prendre en compte les éléments suivants :
Le fonctionnement de Keycloak implique que l'adresse distante du client se connectant par HTTP au serveur d'authentification soit la vĂ©ritable adresse IP de l'ordinateur client. Les paramĂštres de l'Ă©quilibreur de charge et de l'entrĂ©e doivent correctement Ă©tablir les en-tĂȘtes HTTP X-Forwarded-For et X-Forwarded-Proto, ainsi que de conserver l'en-tĂȘte original HĂTE. La derniĂšre version ingress-nginx (> 0.22.0)
L'activation du drapeau proxy-address-forwarding en définissant la variable d'environnement PROXY_ADDRESS_FORWARDING dans true donne à Keycloak la compréhension qu'il fonctionne derriÚre un proxy.
Il faut Ă©galement activer les sessions persistantes dans l'entrĂ©e. Keycloak utilise un cache distribuĂ© Infinispan pour conserver les donnĂ©es liĂ©es Ă la session d'authentification actuelle et Ă la session utilisateur. Les caches fonctionnent avec un seul propriĂ©taire par dĂ©faut, en d'autres termes, cette session particuliĂšre est conservĂ©e sur un certain nĆud du cluster, et d'autres nĆuds doivent y accĂ©der Ă distance s'ils ont besoin d'accĂ©der Ă cette session.
En particulier, chez nous, contrairement Ă la documentation, l'attachement de session avec le nom de cookie
AUTH_SESSION_ID. Keycloak a provoqué une boucle de redirection, donc nous recommandons de choisir un autre nom de cookie pour la session persistante.
De plus, Keycloak attache le nom du nĆud ayant rĂ©pondu en premier Ă AUTH_SESSION_ID, et comme chaque nĆud dans une configuration hautement disponible utilise la mĂȘme base de donnĂ©es, chacun d'eux un identifiant de nĆud distinct et unique pour gĂ©rer les transactions. Il est recommandĂ© de dĂ©finir dans JAVA_OPTS les paramĂštres jboss.node.name et jboss.tx.node.id comme uniques pour chaque nĆud â par exemple, on peut utiliser le nom du pod. Si vous utilisez le nom du pod, n'oubliez pas la limite de 23 caractĂšres pour les variables jboss, donc il est prĂ©fĂ©rable d'utiliser un StatefulSet plutĂŽt qu'un Deployment.
Un autre piĂšge â si le pod est supprimĂ© ou redĂ©marrĂ©, son cache est perdu. Ătant donnĂ© cela, il convient de dĂ©finir le nombre de propriĂ©taires de cache pour tous les caches Ă au moins deux, afin qu'une copie du cache reste. La solution consiste Ă dĂ©ployer lors du lancement du pod, en le plaçant dans le rĂ©pertoire /opt/jboss/startup-scripts dans le conteneur :
Contenu du script
embed-server --server-config=standalone-ha.xml --std-out=echo
batch
echo * Définir CACHE_OWNERS sur "${env.CACHE_OWNERS}" dans tous les cache-containers
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
run-batch
stop-embedded-serveraprÚs quoi définir la valeur de la variable d'environnement CACHE_OWNERS au besoin.
Réseau privé avec prise en charge de l'ip multicast
Si vous utilisez Weavenet comme CNI, le multicast fonctionnera immĂ©diatement â et vos nĆuds Keycloak pourront se voir dĂšs leur dĂ©marrage.
Si vous n'avez pas de prise en charge de l'ip multicast dans le cluster Kubernetes, vous pouvez configurer JGroups pour fonctionner avec d'autres protocoles de dĂ©couverte de nĆuds.
La premiĂšre option est d'utiliser KUBE_DNS, qui utilise un service sans tĂȘte pour dĂ©couvrir les nĆuds Keycloak, vous passez simplement Ă JGroups le nom du service qui sera utilisĂ© pour la dĂ©couverte des nĆuds.
Une autre option est d'appliquer la mĂ©thode KUBE_PING, qui fonctionne avec l'API pour dĂ©couvrir les nĆuds (vous devez configurer serviceAccount avec les droits list et obtenir, puis configurer les pods pour utiliser cette serviceAccount).
Le moyen de dĂ©couvrir des nĆuds pour JGroups est configurĂ© en dĂ©finissant des variables d'environnement JGROUPS_DISCOVERY_PROTOCOL et JGROUPS_DISCOVERY_PROPERTIES. Pour KUBE_PING vous devez choisir les pods en spĂ©cifiant namespace et labels.
ïž Si vous utilisez multicast et que vous lancez deux clusters Keycloak ou plus dans le mĂȘme cluster Kubernetes (par exemple, l'un dans le namespace
production, l'autre âstaging) â les nĆuds d'un cluster Keycloak peuvent rejoindre un autre cluster. Assurez-vous d'utiliser une adresse multicast unique pour chaque cluster en dĂ©finissant les variablesjboss.default.multicast.addressetjboss.modcluster.multicast.addressdansJAVA_OPTS.
Réplication entre centres de données

Connexion
Keycloak utilise plusieurs clusters de caches Infinispan sĂ©parĂ©s pour chaque centre de donnĂ©es, oĂč se trouvent les clusters Keycloak, composĂ©s de nĆuds Keycloak. Mais il n'y a pas de diffĂ©rence entre les nĆuds Keycloak dans diffĂ©rents centres de donnĂ©es.
Les nĆuds Keycloak utilisent une grille de donnĂ©es Java externe (serveurs Infinispan) pour la communication entre les centres de donnĂ©es. La communication se fait via le protocole .
Les caches Infinispan doivent ĂȘtre configurĂ©s avec l'attribut remoteStore, afin que les donnĂ©es puissent ĂȘtre stockĂ©es dans des caches distants (dans un autre centre de donnĂ©es, note du traducteur) . Il existe des clusters Infinispan distincts parmi les serveurs JDG, donc les donnĂ©es stockĂ©es sur JDG1 sur le site site1 seront rĂ©pliquĂ©es sur JDG2 sur le site site2.
Enfin, le serveur JDG rĂ©cipiendaire informe les serveurs Keycloak de son cluster via des connexions client, ce qui est une caractĂ©ristique du protocole HotRod. Les nĆuds Keycloak sur site2 mettent Ă jour leurs caches Infinispan, et une session utilisateur spĂ©cifique devient Ă©galement accessible sur les nĆuds Keycloak sur site2.
Pour certains caches, il est Ă©galement possible de ne pas faire de sauvegardes et de renoncer complĂštement Ă l'Ă©criture de donnĂ©es via le serveur Infinispan. Pour cela, il faut retirer la configuration remote-store pour le cache Infinispan spĂ©cifique (dans le fichier standalone-ha.xml), aprĂšs quoi un certain replicated-cache cessera Ă©galement d'ĂȘtre nĂ©cessaire du cĂŽtĂ© du serveur Infinispan.
Configuration des caches
Il existe deux types de caches dans Keycloak :
Local. Il est situĂ© Ă proximitĂ© de la base de donnĂ©es, sert Ă rĂ©duire la charge sur la base de donnĂ©es et Ă diminuer la latence de rĂ©ponse. Dans ce type de cache, on stocke le realm, les clients, les rĂŽles et les mĂ©tadonnĂ©es utilisateur. Ce type de cache n'est pas rĂ©pliquĂ©, mĂȘme si ce cache fait partie d'un cluster Keycloak. Si une entrĂ©e dans le cache change, un message de changement est envoyĂ© aux autres serveurs du cluster, aprĂšs quoi l'entrĂ©e est exclue du cache. Voir la description
workci-aprĂšs, pour une description plus dĂ©taillĂ©e de la procĂ©dure.RĂ©pliquĂ©. GĂšre les sessions utilisateur, les tokens offline, et surveille Ă©galement les erreurs de connexion pour dĂ©tecter les tentatives de phishing de mots de passe et d'autres attaques. Les donnĂ©es stockĂ©es dans ces caches sont temporaires, ne sont stockĂ©es qu'en mĂ©moire vive, mais peuvent ĂȘtre rĂ©pliquĂ©es Ă travers le cluster.
Caches Infinispan
Sessions â un concept dans Keycloak, des caches distinctsappelĂ©s authenticationSessions, sont utilisĂ©s pour stocker les donnĂ©es des utilisateurs spĂ©cifiques. Les requĂȘtes provenant de ces caches sont gĂ©nĂ©ralement nĂ©cessaires pour les navigateurs et les serveurs Keycloak, pas pour les applications. C'est ici qu'apparaĂźt la dĂ©pendance aux sessions persistantes, et de tels caches n'ont pas besoin d'ĂȘtre rĂ©pliquĂ©s, mĂȘme en mode Active-Active.
Token d'action. Une nouvelle conception, gĂ©nĂ©ralement utilisĂ©e pour divers scĂ©narios, lorsque, par exemple, un utilisateur doit faire quelque chose de maniĂšre asynchrone par email. Par exemple, pendant la procĂ©dure oubli de mot de passe cache actionTokens est utilisĂ© pour suivre les mĂ©tadonnĂ©es des tokens associĂ©s â par exemple, un token dĂ©jĂ utilisĂ©, et qui ne peut pas ĂȘtre activĂ© Ă nouveau. Ce type de cache doit gĂ©nĂ©ralement ĂȘtre rĂ©pliquĂ© entre les centres de donnĂ©es.
Mise en cache et expiration des donnĂ©es stockĂ©es fonctionne pour allĂ©ger la charge sur la base de donnĂ©es. Ce type de mise en cache amĂ©liore les performances, mais prĂ©sente un problĂšme Ă©vident. Si un serveur Keycloak met Ă jour des donnĂ©es, les autres serveurs doivent ĂȘtre informĂ©s de cela, afin qu'ils puissent mettre Ă jour les donnĂ©es dans leurs caches. Keycloak utilise des caches locaux realms, users et autorisation pour mettre en cache les donnĂ©es de la base.
Il existe Ă©galement un cache distinct work, qui est rĂ©pliquĂ© dans tous les centres de donnĂ©es. Celui-ci ne stocke aucune donnĂ©e de la base, mais sert Ă envoyer des messages sur l'expiration des donnĂ©es aux nĆuds du cluster entre les centres de donnĂ©es. En d'autres termes, dĂšs que les donnĂ©es sont mises Ă jour, un nĆud Keycloak envoie un message aux autres nĆuds dans son centre de donnĂ©es, ainsi qu'aux nĆuds d'autres centres de donnĂ©es. AprĂšs avoir reçu un tel message, chaque nĆud procĂšde Ă un nettoyage des donnĂ©es correspondantes dans ses caches locaux.
Sessions utilisateur. Les caches avec les noms sessions, clientSessions, offlineSessions et offlineClientSessions, sont gĂ©nĂ©ralement rĂ©pliquĂ©s entre les centres de donnĂ©es et servent Ă stocker des donnĂ©es sur les sessions utilisateur, qui sont actives pendant l'activitĂ© de l'utilisateur dans le navigateur. Ces caches fonctionnent avec l'application traitant les requĂȘtes HTTP des utilisateurs finaux, de sorte qu'elles sont liĂ©es aux sessions persistantes et doivent ĂȘtre rĂ©pliquĂ©es entre les centres de donnĂ©es.
Protection contre les attaques par force brute. Le cache loginFailures sert Ă suivre les donnĂ©es des Ă©checs de connexion, par exemple, le nombre de fois qu'un utilisateur a entrĂ© un mot de passe incorrect. La rĂ©plication de ce cache est une affaire d'administrateur. Mais pour un comptage prĂ©cis, il est conseillĂ© d'activer la rĂ©plication entre les centres de donnĂ©es. En revanche, si ces donnĂ©es ne sont pas rĂ©pliquĂ©es, cela peut amĂ©liorer les performances, et si la question se pose â la rĂ©plication peut ĂȘtre dĂ©sactivĂ©e.
Lors du déploiement du cluster Infinispan, il est nécessaire d'ajouter des définitions de caches dans le fichier de configuration :
Il est nécessaire de configurer et de démarrer le cluster Infinispan avant de lancer le cluster Keycloak
Ensuite, il faut configurer remoteStore pour les caches Keycloak. Pour cela, un script suffira, qui se fait de maniÚre similaire à celui utilisé pour configurer la variable CACHE_OWNERS, il faut le sauvegarder dans un fichier et le placer dans le répertoire /opt/jboss/startup-scripts:
Contenu du script
embed-server --server-config=standalone-ha.xml --std-out=echo
batch
echo *** Mise Ă jour du sous-systĂšme infinispan ***
/subsystem=infinispan/cache-container=keycloak:write-attribute(name=module, value=org.keycloak.keycloak-model-infinispan)
echo ** Ajout de la liaison de socket distante au serveur infinispan **
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-cache:add(host=${remote.cache.host:localhost}, port=${remote.cache.port:11222})
echo ** Mise à jour de l'élément de travail cache répliqué **
/subsystem=infinispan/cache-container=keycloak/replicated-cache=work/store=remote:add(
passivation=false,
fetch-state=false,
purge=false,
preload=false,
shared=true,
remote-servers=["remote-cache"],
cache=work,
properties={
rawValues=true,
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory,
protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion}
}
)
/subsystem=infinispan/cache-container=keycloak/replicated-cache=work:write-attribute(name=statistics-enabled,value=true)
echo ** Mise à jour de l'élément des sessions cache distribuées **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions/store=remote:add(
passivation=false,
fetch-state=false,
purge=false,
preload=false,
shared=true,
remote-servers=["remote-cache"],
cache=sessions,
properties={
rawValues=true,
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory,
protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion}
}
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:write-attribute(name=statistics-enabled,value=true)
echo ** Mise à jour de l'élément offlineSessions cache distribuée **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions/store=remote:add(
passivation=false,
fetch-state=false,
purge=false,
preload=false,
shared=true,
remote-servers=["remote-cache"],
cache=offlineSessions,
properties={
rawValues=true,
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory,
protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion}
}
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:write-attribute(name=statistics-enabled,value=true)
echo ** Mise à jour de l'élément clientSessions cache distribuée **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions/store=remote:add(
passivation=false,
fetch-state=false,
purge=false,
preload=false,
shared=true,
remote-servers=["remote-cache"],
cache=clientSessions,
properties={
rawValues=true,
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory,
protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion}
}
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions:write-attribute(name=statistics-enabled,value=true)
echo ** Mise à jour de l'élément offlineClientSessions cache distribuée **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions/store=remote:add(
passivation=false,
fetch-state=false,
purge=false,
preload=false,
shared=true,
remote-servers=["remote-cache"],
cache=offlineClientSessions,
properties={
rawValues=true,
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory,
protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion}
}
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions:write-attribute(name=statistics-enabled,value=true)
echo ** Mise à jour de l'élément loginFailures cache distribuée **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures/store=remote:add(
passivation=false,
fetch-state=false,
purge=false,
preload=false,
shared=true,
remote-servers=["remote-cache"],
cache=loginFailures,
properties={
rawValues=true,
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory,
protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion}
}
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:write-attribute(name=statistics-enabled,value=true)
echo ** Mise à jour de l'élément actionTokens cache distribuée **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens/store=remote:add(
passivation=false,
fetch-state=false,
purge=false,
preload=false,
shared=true,
cache=actionTokens,
remote-servers=["remote-cache"],
properties={
rawValues=true,
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory,
protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion}
}
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:write-attribute(name=statistics-enabled,value=true)
echo ** Mise à jour de l'élément authenticationSessions cache distribuée **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:write-attribute(name=statistics-enabled,value=true)
echo *** Mise Ă jour du sous-systĂšme undertow ***
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)
run-batch
stop-embedded-serverN'oubliez pas de configurer JAVA_OPTS pour les nĆuds Keycloak afin de faire fonctionner HotRod : remote.cache.host, remote.cache.port et le nom du service jboss.site.name.
Liens et documentation supplémentaire
L'article a Ă©tĂ© traduit et prĂ©parĂ© pour Habr par ses employĂ©s â intensifs, cours vidĂ©o et formation en entreprise dispensĂ©s par des professionnels (Kubernetes, DevOps, Docker, Ansible, Ceph, SRE)
Source : habr.com
