아래의 지난 글에서도 언급했듯이, 쿠버네티스에서 카나리아 배포를 사용할 경우 로드 밸런싱 때문에 문제가 생길 수 있다. 신 버전에서 구 버전 서버로 로드 밸런싱이 되어 UI/UX가 변경되는 등의 혼돈이 생기는 것이다. (자세한 글은 아래 참조!)
그렇다면 이러한 종류의 문제는 어떻게 해결할 수 있을까? 어떻게 카나리아 배포가 있는 서버에 접속한 유저는 계속 카나리아 배포를 보도록 하고, 구 버전 서버에 접속한 유저는 구 버전을 계속 보게 만들 수 있을까? 이를 알기 위해서는 먼저 세션(Session)의 역할을 알아야 한다.
세션(Session)이란?
우리가 어떤 웹 페이지를 만들었다고 가정해보자. 사용자의 상태가 필요없는 서비스도 있지만(예를 들어, 내 이력서를 보여주기만 한다면 정적 웹 호스팅을 사용하면 되므로, 웹 페이지를 보고 있는 사용자의 상태가 어떤지는 상관없다) 사용자가 어떤 상태인지 알아야 하는 서비스가 대부분이다. 사용자가 로그인을 했는가? 그렇다면 서비스를 사용할 수 있어야 한다. 사용자가 로그아웃을 한 상황인가? 이 경우에는 서비스를 이용할 수 있는 권한이 없다. 이렇게 사용자의 상태(state)가 필요한 어플리케이션을 상태 유지(stateful) 어플리케이션이라고 한다.
세션(Session)은 웹 애플리케이션에서 사용자의 상태 유지를 위해 사용되는 개념이다. 세션을 통해 서버는 클라이언트 간에 지속적인 상태를 유지하고, 클라이언트의 요청과 응답을 추적할 수 있다. 클라이언트와 서버가 세션을 통해 상태 유지하는 방법을 간략하게 설명하자면 다음과 같다.
- 클라이언트가 서버에 최초로 접속하면, 서버는 클라이언트에게 고유한 세션 식별자(Session ID)를 할당한다. 이 식별자는 일반적으로 쿠키(Cookie)라는 HTTP 헤더를 통해 클라이언트에게 전달된다.
- 클라이언트는 이후 요청을 보낼 때, 쿠키를 함께 전송하여 자신의 세션 식별자를 서버에게 알려준다.
- 서버는 세션 식별자를 사용하여 세션 저장소에서 세션을 찾고, 이를 통해 클라이언트의 상태를 가져온다.
- 서버는 클라이언트의 요청을 처리하면서 세션 저장소에서 필요한 상태와 데이터를 읽거나 쓰면서 클라이언트에 대한 상태 정보를 유지하고, 개별 요청 간에 정보를 공유한다.
- 클라이언트가 세션을 종료하거나 만료되면, 서버는 해당 세션에 대한 정보를 삭제하고 저장소에서 정리한다.
가끔 어떤 서비스를 사용할 때 로그인한 후 오랫동안 창을 켜놓고 아무것도 하지 않으면 자동으로 로그아웃되는 것을 볼 수 있다. 이는 개발자 측에서 일정 시간 내에 사용자 요청이 없을 경우 자동으로 세션이 만료되도록 설정한 것이다. 이처럼 세션이 만료되거나 삭제되면 유저에 대한 식별 정보 및 상태 정보가 없어지게 되므로, 서비스를 사용하다가도 로그아웃되는 등의 상황이 일어난다.
로드 밸런싱과 세션을 같이 사용할 경우
위에서는 하나의 서버만 있었으므로 자연스럽게 모든 사용자의 모든 세션이 하나의 세션 저장소에서 관리된다. 그런데 서버가 여러 대 있어서 로드 밸런싱으로 트레픽을 관리하는 상황이라고 가정해보자. 로드 밸런서는 트레픽 분산을 위해서 자동으로 각 요청당 서버를 할당해준다. 따라서 새로고침을 하거나 다른 요청을 서버에게 하는 순간 내 세션을 가지고 있지 않은 다른 서버로 변경될 수 있다. 예를 들어, 내가 특정 서비스에 로그인을 했는데 새로고침을 하자마자 로그인이 풀리는 상황이 생길 수 있다!
위의 그림에서 볼 수 있듯이, 사용자가 처음 접속한 서버와 로드 밸런싱으로 인해 다시 접속하게 된 서버가 달라질 수 있다(굉장히 높은 확률로 일어나는 일이다). 따라서 세션 정보를 사용할 수 있게 하기 위해 처음 접속한 서버로 고정해줄 필요가 있다. 이때 사용하는 것이 바로 스티키 세션, 다른 말로는 Session Affinity이다.
Session Affinity(Sticky Session)의 필요성
스티키 세션은 처음 접속했던 서버에 계속 접속할 수 있도록 하는 방식이다. 위의 그림에서 볼 수 있듯이, 같은 사용자일 경우 계속 새로 고침을 해도 같은 서버에만 접속하게 되는 것을 알 수 있다. 물론, 이 방식은 서버 과부화를 일으킬 수 있다. 로드 밸런싱이란 트레픽을 원활하게 여러 서버에 분산하기 위한 방식인데, 이를 스티키 세션을 써서 유저:서버를 1대 1로 고정하기 때문이다. 이 때문에 각 서버에 세션 저장소를 만드는 방식이 아닌, 세션 서버를 따로 구축해서 세션 클러스터링을 하는 방식을 많이 사용한다. (이번 글의 핵심은 쿠버네티스에서 스티키 세션을 사용하는 것이므로, 세션 클러스터링에 대한 내용은 다른 글 참고)
쿠버네티스에서 Sticky Session 사용하기
이것 저것 언급이 많았지만, 쿠버네티스에서 스티키 세션을 사용하는 방식은 굉장히 간단하다. 아래와 같이 Service
의 yaml 파일을 생성할 때 spec
아래에 sessionAffinity: ClientIP
를 작성해주기만 하면 된다.
kind: Service
apiVersion: v1
metadata:
name: "test"
spec:
type: LoadBalancer
sessionAffinity: ClientIP
selector:
app: "hello"
ports:
- protocol: "TCP"
port: 80
targetPort: 80
스티키 세션이 잘 잘동하는지 알아보는 방식은, 세션 ID를 출력해주는 간단한(!) 코드를 작성한 후 이를 빌드하여 이미지로 만들고, 쿠버네티스 파드에 띄운 다음 type: LoadBalancer
로 서비스, sessionAffinity: ClientIP
로 설정해주고, kubectl get svc
명령어를 치면 나오는 EXTERNAL-IP
로 접근한 후 여러 번 새로고침하면 세션이 계속 고정되어 있다는 것을 확인할 수 있다.
'👷♂️DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] 쿠버네티스 배포 전략: 롤링(rolling) vs Blue/Green vs Canary 업데이트 (0) | 2023.05.15 |
---|