반응형

[성능 개선 이야기] Scouter 클라이언트가 안 붙을 때 — 유동 IP와 방화벽, 그리고 터널링

안녕하세요, 가야태자 @talkit 입니다.

지난 글에서 Scouter 수집기를 띄우고 톰캣에 자바 에이전트까지 붙였습니다.

에이전트는 데이터를 잘 보내고 있습니다. 이제 제 PC에서 클라이언트로 접속해서 보기만 하면 되는데요.

여기서 막혔습니다 T.T


증상

방화벽에 제 접속 IP를 열어 달라고 요청해서 등록까지 마쳤습니다.

그런데 클라이언트가 수집기에 안 붙습니다.

분명히 어제는 됐는데 오늘은 안 되고, 다시 열어 달라고 하면 또 며칠 되다가 안 되고요.


원인은 유동 IP였습니다

고객사 쪽 인터넷 회선의 공인 IP가 유동이었습니다.

방화벽에 등록해 둔 건 그때 그 시점의 IP입니다. 회선이 재접속되거나 임대 시간이 지나면 IP가 바뀝니다. 그러면 등록해 둔 IP는 이제 저와 아무 상관이 없는 주소가 되어 버립니다.

접속이 되다가 안 되다가 하는 게 그래서였습니다.


그런데 이건 Scouter의 구조와도 관련이 있습니다

이 문제가 왜 하필 여기서 생겼는지 생각해 볼 필요가 있습니다.

Scouter의 클라이언트는 Eclipse RCP 기반의 데스크톱 프로그램입니다. 그리고 이 클라이언트는 수집기의 TCP 6100 포트에 직접 붙습니다.

내 PC가 서버 쪽으로 직접 들어가는 구조입니다. 그러니 내 PC의 IP를 방화벽에서 허용해 줘야 하죠.

만약 웹 기반이었다면 어땠을까요? 웹 서비스는 보통 앞단에 프록시나 로드밸런서를 두고 443으로 받습니다. 접속자 IP를 하나하나 등록하는 방식으로 운영하지 않습니다. 애초에 이런 고민을 할 일이 없습니다.

Scouter가 데스크톱 클라이언트를 쓰는 건 이유가 있습니다. 공식 문서에 따르면 웹 뷰어보다 더 많은 성능 데이터를 다루기 위한 선택이라고 합니다. 실제로 데이터를 깊게 파고들 때는 확실히 편하구요.

다만 그 선택의 대가를 배포 환경에서 치르게 됩니다. 사내망에 서버가 있고 자리에 앉아서 보는 환경이라면 아무 문제가 없는데, 클라우드에 있는 서버를 외부에서 봐야 하는 상황이 되면 이야기가 달라집니다.


생각해 본 방법들

① IP 대역을 넓게 열기

가능은 합니다. 그런데 보안 부서에서 좋아할 리가 없습니다. 그리고 유동이면 대역 자체가 바뀔 수도 있어서 근본 해결이 아닙니다.

② 바뀔 때마다 방화벽 신청

며칠에 한 번씩 신청서를 쓰게 됩니다. 현실적으로 불가능합니다.

③ VPN

있으면 좋습니다. 그런데 없으면 그것부터 구축해야 하는데, APM 하나 보자고 하기에는 일이 너무 커집니다.


해결: SSM 세션 포트포워딩

결국 AWS Systems Manager의 세션 포트포워딩으로 풀었습니다.

원리는 이렇습니다. 인스턴스에 설치된 SSM 에이전트가 아웃바운드로 AWS와 연결을 맺어 둡니다. 그 연결을 통로 삼아 내 PC의 로컬 포트를 인스턴스의 포트로 이어 줍니다.

내 PC의 localhost:6100
      ↓  (SSM 터널)
AWS 인스턴스의 수집기 6100

방화벽에 인바운드를 열 필요가 없습니다. 배스천 호스트도 필요 없구요. 그리고 무엇보다 내 IP가 무엇이든 상관이 없습니다. 유동이든 고정이든, 카페에서 접속하든 집에서 접속하든 똑같이 됩니다.

명령은 이런 형태입니다.

aws ssm start-session \
  --target i-0xxxxxxxxxxxxxxxx \
  --document-name AWS-StartPortForwardingSession \
  --parameters '{"portNumber":["6100"],"localPortNumber":["6100"]}'

터널이 열리면 Scouter 클라이언트에서 접속 주소를 localhost:6100으로 잡아 주면 됩니다. 실제 트래픽은 터널을 타고 넘어갑니다.

참고로 로컬에 AWS CLI와 Session Manager 플러그인이 설치되어 있어야 합니다.

문서(document)가 두 가지인데, 기준은 간단합니다

SSM 포트포워딩에는 문서가 두 가지 있습니다. 처음엔 헷갈리는데 기준은 하나입니다.

목적지가 SSM으로 관리되는 그 인스턴스 자신이냐, 아니냐.

  • AWS-StartPortForwardingSession — 인스턴스 자신의 포트로 연결할 때
  • AWS-StartPortForwardingSessionToRemoteHost — 그 인스턴스를 발판 삼아 뒤에 있는 다른 호스트로 연결할 때

저는 이렇게 나눠 쓰고 있습니다.

  • Scouter 수집기, SCP → 인스턴스에 직접 설치되어 있으니 AWS-StartPortForwardingSession
  • RDS → 인스턴스가 아니라 별도 서비스라 AWS-StartPortForwardingSessionToRemoteHost

RDS 쪽은 이런 형태가 됩니다.

aws ssm start-session \
  --target i-0xxxxxxxxxxxxxxxx \
  --document-name AWS-StartPortForwardingSessionToRemoteHost \
  --parameters '{"host":["RDS엔드포인트"],"portNumber":["1521"],"localPortNumber":["11521"]}'

원격 호스트 방식은 SSM 에이전트가 어느 정도 최신이어야 동작합니다.


서버가 여러 대라면 로컬 포트에 규칙을 정하세요

이게 실무에서 생각보다 중요합니다.

저는 지금 세 대의 서버를 모니터링하고 있습니다. 서버마다 수집기가 따로 있으니 터널도 세 개를 열어야 합니다.

그런데 서버 쪽 포트는 셋 다 6100입니다. 로컬 포트를 아무렇게나 잡으면 어느 창이 어느 서버인지 금방 헷갈립니다.

그래서 규칙을 정했습니다.

용도 서버 포트 로컬 포트
Scouter 수집기 6100 16100 / 16200 / 16300
SCP (SSH) 22 7771 / 7772 / 7773

Scouter는 원래 포트 6100이 그대로 보이게 두고 앞뒤로 서버 번호를 붙였습니다. SCP는 777 뒤에 서버 번호를 붙였구요.

이렇게 해두면 포트 번호만 보고 "아, 2번 서버구나" 하고 바로 압니다.

지난 글에서 obj_name을 규칙 있게 지어야 한다고 말씀드렸는데, 같은 이야기입니다. 나중에 찾을 수 있게 이름 짓는 일은 어디서나 똑같이 중요합니다. 그때는 화면에 뜨는 이름이었고, 지금은 포트 번호일 뿐이죠.

파일을 올릴 때도 같은 방법을 썼습니다. 22번 포트를 로컬 777N으로 포워딩해 두고 SCP로 올리면 됩니다.


여기서 중요한 것 하나

이 방법이 통했던 건 클라이언트가 TCP만 쓰기 때문입니다.

지난 글에서 Scouter가 6100번을 TCP와 UDP 둘 다 쓴다고 말씀드렸습니다. 그래서 이 부분을 정리하고 갈 필요가 있습니다.

  • 에이전트 → 수집기: 성능 데이터는 UDP, 제어는 TCP
  • 클라이언트 → 수집기: TCP만

에이전트와 수집기는 같은 VPC 안에 있으니 UDP든 TCP든 문제가 되지 않습니다. 서버 쪽 방화벽에는 둘 다 열려 있으면 됩니다.

그리고 밖에서 들어가야 하는 건 클라이언트뿐인데, 이건 TCP만 필요합니다. SSM 포트포워딩은 TCP 기반이라 정확히 맞아떨어졌습니다.

만약 클라이언트도 UDP를 써야 하는 구조였다면 이 방법으로는 못 풀었을 겁니다. 어떤 구간이 어떤 프로토콜을 쓰는지 알아야 해결 방법이 보입니다.


정리하면

증상은 "클라이언트가 안 붙는다"였지만, 실제로 확인해야 했던 건 세 가지였습니다.

  1. 왜 접속이 되다 안 되나 → 유동 IP
  2. 왜 IP를 등록해야 하나 → 클라이언트가 TCP로 직접 붙는 구조
  3. 터널로 우회할 수 있나 → 클라이언트 구간은 TCP뿐이라 가능

그리고 터널을 여러 개 쓰게 되면서 로컬 포트에도 규칙이 필요하다는 걸 알게 됐습니다.

도구를 고를 때 기능만 보게 되는데, 그 도구가 어떤 환경을 전제로 설계되었는지도 봐야 한다는 걸 다시 느꼈습니다. 사내망에 서버를 두고 자리에서 보던 시절의 전제가, 클라우드와 원격 근무 환경에서는 그대로 통하지 않으니까요.

비슷한 상황에 계신 분들께 도움이 되었으면 좋겠습니다.

즐거운 하루 되십시오.

반응형

+ Recent posts