Keycloak單機部署很是的簡單,前面的關於Keycloak應用相關的文章中也都是使用的單機部署。可是在真正的生產環境中,Keycloak做爲基礎的身份認證服務,勢必要部署多個實例組成集羣以保證高可用性。本文講述如何使用Docker在生產環境快速部署Keycloak高可用集羣。java
默認狀況下,多個Keycloak實例的用戶、角色等數據信息以及Session是不一樣步的,因此部署集羣重點是要解決如下2個問題:nginx
Keycloak默認使用內嵌的H2數據庫做爲數據存儲,因此爲了實現數據共享,咱們只須要將H2替換成外置的共享數據庫便可。Keycloak官方支持MySQL、PostgreSQL、Oracel、SQL Server等數據庫。git
要想讓Keycloak多個實例之間的Session進行同步,須要對Keycloak的實例進行配置以實現自動發現。參考Keycloak官方博客:Keycloak Cluster Setup ,有多種方式能夠實現。從實際的表現來看,最推薦使用JDBC_PING
實現自動發現。github
Keycloak官方的Docker鏡像有對外置共享數據庫的支持,可是並無集成自動發現機制,因此須要咱們基於官方的鏡像進行構建以集成自動發現功能。sql
FROM jboss/keycloak:latest
ADD cli/TCPPING.cli /opt/jboss/tools/cli/jgroups/discovery/ ADD cli/JDBC_PING.cli /opt/jboss/tools/cli/jgroups/discovery/ 複製代碼
這裏重點講一下JDBC_PING.cli,官方博客中提供的只是針對MySQL的版本docker
embed-server --server-config=standalone-ha.xml --std-out=echo
batch
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:write-attribute(name=owners, value=${env.CACHE_OWNERS:2})
/subsystem=jgroups/stack=tcp:remove()
/subsystem=jgroups/stack=tcp:add()
/subsystem=jgroups/stack=tcp/transport=TCP:add(socket-binding="jgroups-tcp")
/subsystem=jgroups/stack=tcp/protocol=JDBC_PING:add()
/subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=datasource_jndi_name:add(value=java:jboss/datasources/KeycloakDS)
/subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=initialize_sql:add(value="CREATE TABLE IF NOT EXISTS JGROUPSPING (own_addr varchar(200) NOT NULL, cluster_name varchar(200) NOT NULL, updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, ping_data varbinary(5000) DEFAULT NULL, PRIMARY KEY (own_addr, cluster_name)) ENGINE=InnoDB DEFAULT CHARSET=utf8")
/subsystem=jgroups/stack=tcp/protocol=MERGE3:add()
/subsystem=jgroups/stack=tcp/protocol=FD_SOCK:add(socket-binding="jgroups-tcp-fd")
/subsystem=jgroups/stack=tcp/protocol=FD:add()
/subsystem=jgroups/stack=tcp/protocol=VERIFY_SUSPECT:add()
/subsystem=jgroups/stack=tcp/protocol=pbcast.NAKACK2:add()
/subsystem=jgroups/stack=tcp/protocol=UNICAST3:add()
/subsystem=jgroups/stack=tcp/protocol=pbcast.STABLE:add()
/subsystem=jgroups/stack=tcp/protocol=pbcast.GMS:add()
/subsystem=jgroups/stack=tcp/protocol=pbcast.GMS/property=max_join_attempts:add(value=5)
/subsystem=jgroups/stack=tcp/protocol=MFC:add()
/subsystem=jgroups/stack=tcp/protocol=FRAG3:add()
/subsystem=jgroups/stack=udp:remove()
/subsystem=jgroups/channel=ee:write-attribute(name=stack, value=tcp)
/socket-binding-group=standard-sockets/socket-binding=jgroups-mping:remove()
run-batch
try
:resolve-expression(expression=${env.JGROUPS_DISCOVERY_EXTERNAL_IP})
/subsystem=jgroups/stack=tcp/transport=TCP/property=external_addr/:add(value=${env.JGROUPS_DISCOVERY_EXTERNAL_IP})
catch
echo "JGROUPS_DISCOVERY_EXTERNAL_IP maybe not set."
end-try
stop-embedded-server
複製代碼
若是要使用其餘的數據庫,需將initialize_sql
部分進行替換,例如使用PostgreSQL,則對應的initialize_sql
以下數據庫
/subsystem=jgroups/stack=tcp/protocol=JDBC_PING/property=initialize_sql:add(value="CREATE TABLE IF NOT EXISTS JGROUPSPING (own_addr varchar(200) NOT NULL, cluster_name varchar(200) NOT NULL, updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ping_data bytea DEFAULT NULL, PRIMARY KEY(own_addr, cluster_name))")
複製代碼
我這邊已經構建好了支持集羣部署的Keycloak鏡像,若是不想本身構建的話,能夠直接使用vigoz/keycloak-ha這個鏡像,支持MySQL和PostgreSQLexpress
根據實際須要,部署給Keycloak存儲數據的數據庫,如MySQL、PostgreSQL等等,這部份內容非本文重點,參考資料也不少,此處直接略過bash
以使用PostgreSQL數據庫爲例,此處運行2個實例session
docker run -d --name keycloak1 --restart=always \
-p 8080:8080 \
-p 8443:8443 \
-p 8009:8009 \
-p 9990:9990 \
-p 7600:7600 \
-p 57600:57600 \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=admin \
-e DB_VENDOR=postgres \
-e DB_ADDR=localhost \
-e DB_PORT=5432 \
-e DB_DATABASE=keycloak \
-e DB_SCHEMA=public \
-e DB_USER=keycloak \
-e DB_PASSWORD=password \
-e JGROUPS_DISCOVERY_PROTOCOL=JDBC_PING \
-e JGROUPS_DISCOVERY_EXTERNAL_IP=172.31.72.101 \
-e PROXY_ADDRESS_FORWARDING=true \
-e KEYCLOAK_FRONTEND_URL=https://your-domain/auth \
vigoz/keycloak-ha:10.0.0-postgres
複製代碼
docker run -d --name keycloak2 --restart=always \
-p 8080:8080 \
-p 8443:8443 \
-p 8009:8009 \
-p 9990:9990 \
-p 7600:7600 \
-p 57600:57600 \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=admin \
-e DB_VENDOR=postgres \
-e DB_ADDR=localhost \
-e DB_PORT=5432 \
-e DB_DATABASE=keycloak \
-e DB_SCHEMA=public \
-e DB_USER=keycloak \
-e DB_PASSWORD=password \
-e JGROUPS_DISCOVERY_PROTOCOL=JDBC_PING \
-e JGROUPS_DISCOVERY_EXTERNAL_IP=172.31.72.102 \
-e PROXY_ADDRESS_FORWARDING=true \
-e KEYCLOAK_FRONTEND_URL=https://your-domain/auth \
vigoz/keycloak:10.0.0-postgres
複製代碼
KEYCLOAK_USER
:Keycloak管理員用戶名
KEYCLOAK_PASSWORD
:Keycloak管理員密碼
DB_VENDOR
:使用的數據庫類型
DB_ADDR
:數據庫地址
DB_PORT
:數據庫端口
DB_DATABASE
:數據庫庫名
DB_SCHEMA
:數據庫Schema
DB_USER
:數據庫用戶名
DB_PASSWORD
:數據庫密碼
JGROUPS_DISCOVERY_PROTOCOL
:自動發現協議,建議使用JDBC_PING
JGROUPS_DISCOVERY_EXTERNAL_IP
:外部IP,此IP需設置爲Docker實例所在機器的IP,確保多個實例間能夠通訊
PROXY_ADDRESS_FORWARDING
:代理地址轉發,Keycloak前有負載均衡時需設爲true
KEYCLOAK_FRONTEND_URL
:Keycloak外部訪問的基礎地址
通過以上的步驟,就運行了一個由2個實例組成的Keycloak集羣。
最後一步,咱們還須要在Keycloak前面配置一個負載均衡,提供統一的外部訪問入口,將流量轉發到多臺Keycloak實例上
使用nginx配置參考以下:
upstream keycloak {
server 172.31.72.101:8080;
server 172.31.72.102:8080;
}
server {
server_name your-domain;
location / {
proxy_pass http://keycloak;
}
listen 443 ssl;
ssl_certificate /path/to/your-domain.cer;
ssl_certificate_key /path/to/your-domain.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
}
server {
if ($host = your-domain) {
return 301 https://$host$request_uri;
}
server_name your-domain;
listen 80;
return 404;
}
複製代碼
使用Docker部署Keycloak高可用集羣很是的簡單高效,配置好數據庫及負載均衡後便可在生產環境使用,很是的方便。
Dockerfile地址:keycloak-ha
Docker鏡像地址:keycloak-ha