쿠버네티스의 파드로 통하는 트래픽의 클라이언트 IP를 확인하고 싶은 개발자 파트로부터의 요구사항이 발생했습니다. 현재 Istio access log에는 요청의 X-Forwarded-For 헤더가 로깅되도록 설정되어있는데 실제로 확인해보면 172로 시작하는 알 수 없는 IP가 담겨져 있습니다.
istio access log 확인 방법
이것은 pod가 띄워져있는 노드의 calico ip로 원하는 값이 아닙니다.
클라이언트의 ip를 얻는 방법은 무엇일까요?
쿠버네티스는 externalTrafficPolicy를 통해 client IP를 확인하는 방법을 지원합니다. externalTrafficPolicy가 기존값은 Cluster인데 Local로 수정하는 것이죠. 하지만 이 방법에는 큰 문제점이 있습니다.
externalTrafficPolicy를 Local로 설정한다면 클러스터 내에서 다른 노드로 트래픽이 이동할 수 없습니다. 예를 들어, 원래 NodePort 타입으로 서비스를 배포한다면 기존에는 클러스터의 아무 노드의 지정 포트번호로 접속하면 정상적으로 접근할 수 있었습니다. 하지만 externalTrafficPolicy를 Local로 설정하면 해당 pod가 떠있는 노드의 IP로만 서비스로 접근 가능합니다.
만약 Cloud의 로드밸런서를 사용한다면 알아서 노드를 찾아가므로 문제가 없겠지만 저처럼 온프레미스의 MetalLB L2 모드를 사용하는 경우에는 문제가 됩니다.
(출처: https://velog.io/@youwins/MetalLB)
위의 그림처럼 MetalLB는 여러 speaker pod 중 하나의 leader pod를 선정해 leader pod가 존재하는 노드로 external IP의 모든 트래픽이 들어오게 되므로 다른 노드로 트래픽이 이동하지 못하면 서비스가 작동하지 않는 참사가 발생합니다.
따라서 다른 방법을 찾아야 했습니다.
저는 클러스터에 들어오는 요청이 모두 HAProxy를 통과하므로 HAProxy를 활용할 수 있는 방안을 생각했습니다. 그러다가 재밌는 글을 발견했습니다. HAProxy와 Istio ingress gateway에서 프록시 프로토콜을 적용하는 글입니다.
프록시 프로토콜은 클라이언트의 TCP 연결이 프록시를 통과할 때 클라이언트의 IP 주소를 보존하기 위한 네트워크 프로토콜입니다.
(출처: https://docs.hivemq.com/hivemq/latest/user-guide/proxy-protocol.html)
중요한 점은 프록시 프로토콜 헤더를 보내면 받는 컴포넌트가 프록시 프로토콜을 지원하는 서비스여야 한다는 것입니다.
프록시 프로토콜의 지원 서비스는 다음과 같습니다.
적용 방법도 굉장히 간단합니다.
HAProxy
Envoy Proxy
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: proxy-protocol
namespace: testbed
spec:
workloadSelector:
labels:
app: test-ingressgateway
configPatches:
- applyTo: LISTENER
patch:
operation: MERGE
value:
listener_filters:
- name: envoy.filters.listener.proxy_protocol
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol
- name: envoy.filters.listener.tls_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
HAProxy와 Istio ingress gateway에 프록시 프로토콜을 적용하고 트래픽을 발생시켜 보았습니다.
istio gateway access log
pod istio-proxy access log
정상적으로 접속한 IP를 로깅하는 것을 알 수 있습니다.
HAProxy를 활용한 해결책을 찾는 과정에서, 기존에 당연하게 여겼던 인프라 구성요소들을 새로운 시각으로 바라보게 되었습니다. 이를 통해 기존 인프라의 수정없이 요구사항을 충족할 수 있었습니다. 이는 다른 문제에 직면했을 때도 현재 가지고 있는 자원들을 창의적으로 활용할 순 없는지를 바라보는 시각을 얻었습니다.
프록시 프로토콜에 대해 학습하면서, 네트워크 통신의 복잡성과 각 계층에서 일어나는 일들에 대해 더 깊이 이해하게 되었습니다. 이는 앞으로 네트워크 관련 문제를 해결할 때 큰 자산이 될 것 같습니다.
개발자분들이 요구사항이 해결된 인프라를 신기해하고 이에 대해 커뮤니케이션을 하는 것이 즐거웠습니다. 예전부터 속을 썩이던 문제여서 해결한 것에 대해 뿌듯함을 많이 느꼈습니다.