23년 8월 글인데, 벌써 keycloak에서는 이런 점들을 업데이트하고 k8s 환경에서 실행할 수 있도록 가이드를 바꿔놨다. 아래 글들은 k8s를 keycloak을 통해서 공부하는데에만 참고하고, 실제 keycloak의 k8s에서의 실행은 아래 문서를 참고하도록 한다.
https://www.keycloak.org/getting-started/getting-started-kube
1. 이론
keycloak의 cache 작동 원리에 대해 기술해놓는다. built-in으로 infinispan을 사용하므로 주로 infinispan에 대한 내용을 다룰 것이다.
1.1 Cache의 distributed cache 작동
1.1.1 cache 작동 방식
cache는 일반적으로 2가지 모드로 작동한다.
- Distributed Cache
- Replicated Cache
Distributed cache 방식은 여러 노드에 캐시 정보들을 분산해서 저장해놓는다. Replicated Cache 방식은 모든 노드에 캐시 정보를 똑같이 복제해놓는 방식을 의미한다. Replicated Cache 방식은 용량적으로 한계가 있다.
다시 말해 infinispan의 세션 정보를 캐시에 저장하는 제한이 10,000개라면 10,000개 이상의 세션을 저장할 때는 여러 개의 노드에 분산해서 저장한다는 것이다.
1.1.2 원격 캐시 조회(Remote Cache Lookup): GPT로 검색한 내용이고, 다른 refrence에서는 잘 못찾겠어서 용어 자체는 맞는 내용인지 의문이 듦
Distributed cache 방식으로 설정하는 경우, 유저 A에 대한 세션은 노드 A에 있는데, 유저 A의 요청이 노드 B로 간다면 세션 정보를 찾을 수 없을 것이다. 이 때 infinispan은 해당 세션이 다른 노드에 있는지 탐색해보게 되는데 이를 remote cache lookup이라고 한다. 용어 자체는 신뢰성이 떨어지나, 실제로 distributed cache 방식이 작동하는 방식이며, 아래 링크의 그림인 1.4절 Figure 4 부분을 보면 작동 방식을 어느 정도 이해할 수 있다.
각 세션 ID가 어느 노드에 저장되어있는 지에 대한 매핑 정보를 들고 있기 때문에, 특정 노드를 찾아서 들어가게 된다. 만약 세션 정보가 없다면 다른 노드에 remote cache lookup을 요청하고, 그래도 없다면 DB(persistence storage)를 참조하게 된다.
1.1.3 데이터 접근과 고가용성
위 그림처럼 복제된 데이터를 갖고 있는 node의 개수를 replication factor(복제 인덱스)를 지정하여 설정한다. 위 그림의 예제대로라면 2개의 노드에 같은 데이터를 복제 해놓으므로 replication factor = 2 인 것이다. 이럴 경우 1개 node가 down 되더라도 나머지 노드에 캐시 정보가 저장되어 있으므로 고가용성을 확보할 수 있다.
2. 실제 k8s에 배포하는 내용
Ref.) https://engineering.vendavo.com/keycloak-deployment-with-distributed-cache-43f72995674d
캐시에 유저 정보를 저장하여 데이터 복제, migration이 일어날 때나 instance를 재시작하더라도 user들은 영향을 받지 않음
JGroups라는 라이브러리를 사용해서 다른 노드에 있는 instance들을 찾아내서 연동한다. 다만 상세 설정을 위해서는 XML 파일을 수정해야한다. Keycloak의 기본 docker image는 k8s용 JGroup provider를 포함하고 있지 않기 때문에 아래처럼 custom image를 생성해야한다.
FROM quay.io/keycloak/keycloak:21.1.2 as builder
ENV JGROUPS_KUBERNETES_VERSION 2.0.1.Final
COPY jgroups-kubernetes-$JGROUPS_KUBERNETES_VERSION.jar /opt/keycloak/providers/
COPY cache-ispn.xml /opt/keycloak/conf/cache-ispn.xml
RUN /opt/keycloak/bin/kc.sh build
FROM quay.io/keycloak/keycloak:21.1.2
COPY --from=builder /opt/keycloak/ /opt/keycloak/
WORKDIR /opt/keycloak
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
cache-ispn.xml 파일을 COPY하는 것을 볼 수 있다. 공식 문서에 나오는 것처럼 이 파일을 수정해야한다.
아래 코드처럼 수정하면, k8s의 label이 labels에 설정된 항목들을 찾아내어 연결시켜준다.
<jgroups xmlns="http://jgroups.org/schema/jgroups-4.2.xsd">
<stack name="tcp-k8s" extends="tcp">
<org.jgroups.protocols.kubernetes.KUBE_PING
port_range="1"
namespace="${kubeping_namespace:default}"
labels="${kubeping_label:app.kubernetes.io/name=keycloak}"
stack.position="MPING"
stack.combine="REPLACE"
/>
</stack>
</jgroups>
2개의 replica를 생성하여 연결하고, pod을 실행하면 아래와 같이 ISPN으로 클러스터 내에 연결되었다는 로그를 확인할 수 있다고 한다.
실제 k8s로 테스트 해보는 내용은 다음 글에 정리해두었다.
https://whitepro.tistory.com/manage/newpost/1013?type=post&returnURL=ENTRY
ISPN000078: Starting JGroups channel `ISPN` with stack `tcp-k8s`
ISPN000094: Received new cluster view for channel ISPN: [keycloak-1-8854|71] (2) [keycloak-1-8854, keycloak-0-34554]
ISPN000079: Channel `ISPN` local address is `keycloak-0-34554`, physical addresses are `[172.18.94.81:7800]`
다른 좋은 글들의 링크 및 주요 내용을 기록해놓는다.
1)https://qiita.com/uturned0/items/37d2ce64d04a3f3a5dd2
- 일본어라 번역으로 봐야함
- infinispan은 기본적으로 UDP로 작동하는데, k8s에서 사용하기 위해서는 k8s의 기본 방식인 TCP로 작동하도록 설정해주어야함
- k8s의 특수 리소스인 headless-service의 FQDN을 자바 옵션으로 추가해줘야함
- load balancer에서 stickey session을 설정해주는 것도 하나의 방법일 수 있음. 이 때는 붙어있던 pod이 down되는 경우 세션 cache hit이 실패할 수 있음
'Programming-[Backend] > Keycloak' 카테고리의 다른 글
Keycloak ID(username) 찾기 기능 구현하기 (2) | 2024.10.21 |
---|---|
keycloak 2차 인증(문자, 이메일) 구현하기 w/ AWS SNS (3) | 2024.10.21 |
[공식 문서] Keycloak DB 설정 (1) | 2024.09.20 |
Keycloak Email 서버 테스트 with Mailtrap (0) | 2024.09.20 |
Keycloak <-> Okta SAML 연동, Attribute to Role (0) | 2024.09.19 |