为了确保用户请求被路由到每个 Keycloak 站点,我们需要使用负载均衡器。为了防止客户端 DNS 缓存问题,该实现应使用静态 IP 地址,该地址在将客户端路由到两个可用区时保持不变。
在本指南中,我们描述如何通过 AWS Global Accelerator 负载均衡器路由所有 Keycloak 客户端请求。如果 Keycloak 站点发生故障,Accelerator 可确保所有客户端请求都路由到剩余的健康站点。如果两个站点都被标记为不健康,则 Accelerator 将“故障打开”并将请求转发到随机选择的站点。
在两个 ROSA 集群上都创建了一个 AWS 网络负载均衡器 (NLB),以便使 Keycloak Pod 可以作为终端节点用于 AWS Global Accelerator 实例。每个集群终端节点都分配了 128 的权重(最大权重 255 的一半),以确保当两个集群都健康时,加速器流量可以平均路由到两个可用区。
创建网络负载均衡器
在每个 Keycloak 集群上执行以下操作
登录到 ROSA 集群
创建一个 Kubernetes 负载均衡器服务
cat <<EOF | kubectl apply -n $NAMESPACE -f - (1)
apiVersion: v1
kind: Service
metadata:
name: accelerator-loadbalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: accelerator=${ACCELERATOR_NAME},site=${CLUSTER_NAME},namespace=${NAMESPACE} (2)
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-healthcheck-path: "/lb-check"
service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol: "https"
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "10" (3)
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: "3" (4)
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3" (5)
spec:
ports:
- name: https
port: 443
protocol: TCP
targetPort: 8443
selector:
app: keycloak
app.kubernetes.io/instance: keycloak
app.kubernetes.io/managed-by: keycloak-operator
sessionAffinity: None
type: LoadBalancer
EOF
1 | $NAMESPACE 应替换为您的 Keycloak 部署的命名空间 |
2 | 向 AWS 创建的资源添加额外的标签,以便我们稍后可以检索它们。ACCELERATOR_NAME 应该是后续步骤中创建的 Global Accelerator 的名称,CLUSTER_NAME 应该是当前站点的名称。 |
3 | 健康检查探针的执行频率(秒) |
4 | 必须通过多少次健康检查才能将 NLB 视为健康 |
5 | 必须失败多少次健康检查才能将 NLB 视为不健康 |
记下 DNS 主机名,稍后将需要它
kubectl -n $NAMESPACE get svc accelerator-loadbalancer --template="{{range .status.loadBalancer.ingress}}{{.hostname}}{{end}}"
abab80a363ce8479ea9c4349d116bce2-6b65e8b4272fa4b5.elb.eu-west-1.amazonaws.com
创建 Global Accelerator 实例
aws globalaccelerator create-accelerator \
--name example-accelerator \ (1)
--ip-address-type DUAL_STACK \ (2)
--region us-west-2 (3)
1 | 要创建的加速器的名称,根据需要更新 |
2 | 可以是 'DUAL_STACK' 或 'IPV4' |
3 | 所有 globalaccelerator 命令都必须使用 'us-west-2' 区域 |
{
"Accelerator": {
"AcceleratorArn": "arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71", (1)
"Name": "example-accelerator",
"IpAddressType": "DUAL_STACK",
"Enabled": true,
"IpSets": [
{
"IpFamily": "IPv4",
"IpAddresses": [
"75.2.42.125",
"99.83.132.135"
],
"IpAddressFamily": "IPv4"
},
{
"IpFamily": "IPv6",
"IpAddresses": [
"2600:9000:a400:4092:88f3:82e2:e5b2:e686",
"2600:9000:a516:b4ef:157e:4cbd:7b48:20f1"
],
"IpAddressFamily": "IPv6"
}
],
"DnsName": "a099f799900e5b10d.awsglobalaccelerator.com", (2)
"Status": "IN_PROGRESS",
"CreatedTime": "2023-11-13T15:46:40+00:00",
"LastModifiedTime": "2023-11-13T15:46:42+00:00",
"DualStackDnsName": "ac86191ca5121e885.dualstack.awsglobalaccelerator.com" (3)
}
}
1 | 与创建的 Accelerator 实例关联的 ARN,这将在后续命令中使用 |
2 | IPv4 Keycloak 客户端应连接到的 DNS 名称 |
3 | IPv6 Keycloak 客户端应连接到的 DNS 名称 |
为加速器创建侦听器
aws globalaccelerator create-listener \
--accelerator-arn 'arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71' \
--port-ranges '[{"FromPort":443,"ToPort":443}]' \
--protocol TCP \
--region us-west-2
{
"Listener": {
"ListenerArn": "arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71/listener/1f396d40",
"PortRanges": [
{
"FromPort": 443,
"ToPort": 443
}
],
"Protocol": "TCP",
"ClientAffinity": "NONE"
}
}
为侦听器创建终端节点组
CLUSTER_1_ENDPOINT_ARN=$(aws elbv2 describe-load-balancers \
--query "LoadBalancers[?DNSName=='abab80a363ce8479ea9c4349d116bce2-6b65e8b4272fa4b5.elb.eu-west-1.amazonaws.com'].LoadBalancerArn" \ (1)
--region eu-west-1 \ (2)
--output text
)
CLUSTER_2_ENDPOINT_ARN=$(aws elbv2 describe-load-balancers \
--query "LoadBalancers[?DNSName=='a1c76566e3c334e4ab7b762d9f8dcbcf-985941f9c8d108d4.elb.eu-west-1.amazonaws.com'].LoadBalancerArn" \ (1)
--region eu-west-1 \ (2)
--output text
)
ENDPOINTS='[
{
"EndpointId": "'${CLUSTER_1_ENDPOINT_ARN}'",
"Weight": 128,
"ClientIPPreservationEnabled": false
},
{
"EndpointId": "'${CLUSTER_2_ENDPOINT_ARN}'",
"Weight": 128,
"ClientIPPreservationEnabled": false
}
]'
aws globalaccelerator create-endpoint-group \
--listener-arn 'arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71/listener/1f396d40' \ (2)
--traffic-dial-percentage 100 \
--endpoint-configurations ${ENDPOINTS} \
--endpoint-group-region eu-west-1 \ (3)
--region us-west-2
1 | 集群 NLB 的 DNS 主机名 |
2 | 上一步创建的侦听器的 ARN |
3 | 这应该是托管集群的 AWS 区域 |
{
"EndpointGroup": {
"EndpointGroupArn": "arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71/listener/1f396d40/endpoint-group/2581af0dc700",
"EndpointGroupRegion": "eu-west-1",
"EndpointDescriptions": [
{
"EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/abab80a363ce8479ea9c4349d116bce2/6b65e8b4272fa4b5",
"Weight": 128,
"HealthState": "HEALTHY",
"ClientIPPreservationEnabled": false
},
{
"EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a1c76566e3c334e4ab7b762d9f8dcbcf/985941f9c8d108d4",
"Weight": 128,
"HealthState": "HEALTHY",
"ClientIPPreservationEnabled": false
}
],
"TrafficDialPercentage": 100.0,
"HealthCheckPort": 443,
"HealthCheckProtocol": "TCP",
"HealthCheckPath": "undefined",
"HealthCheckIntervalSeconds": 30,
"ThresholdCount": 3
}
}
可选:配置您的自定义域名
如果您正在使用自定义域名,请通过在您的自定义域名中配置别名或 CNAME 将您的自定义域名指向 AWS Global Load Balancer。
创建或更新 Keycloak 部署
在每个 Keycloak 集群上执行以下操作
登录到 ROSA 集群
确保 Keycloak CR 具有以下配置
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
name: keycloak
spec:
hostname:
hostname: $HOSTNAME (1)
ingress:
enabled: false (2)
1 | 客户端用于连接到 Keycloak 的主机名 |
2 | 禁用默认入口,因为所有 Keycloak 访问都应通过预配置的 NLB |
为了确保请求转发按预期工作,Keycloak CR 必须指定客户端将通过其访问 Keycloak 实例的主机名。这可以是与 Global Accelerator 关联的 DualStackDnsName
或 DnsName
主机名。如果您正在使用自定义域名,请将您的自定义域名指向 AWS Global Accelerator,并在此处使用您的自定义域名。