인생은 고통의 연속

수제 FinOps - NAT편 본문

개발스터디&모임/커뮤니티

수제 FinOps - NAT편

gnidoc 2023. 7. 14. 18:34
    반응형

    2023.07.14 - [개발스터디&모임/커뮤니티] - 수제 FinOps - Lambda편

     

    수제 FinOps - Lambda편

    https://www.meetup.com/ko-KR/awskrug/events/294199401/ Login to Meetup | Meetup Not a Meetup member yet? Log in and find groups that host online or in person events and meet people in your local community who share your interests. www.meetup.com 본 내용

    gnidoc.tistory.com

    위 글에서 이어지는 글입니다


    NAT란?

    https://docs.aws.amazon.com/ko_kr/vpc/latest/userguide/nat-gateway-scenarios.html

    NAT는 일반적으로 Private Subnet에 있는 리소스가
    인터넷, 다른 VPC, On-Premise 등 다른 네트워크에 연결되도록 허용할 수 있게 제공해주는 기능입니다

    NAT가 있으므로써 Private Subnet에 있는 리소스는 외부 서비스와 통신할 수 있지만
    원치 않는 요청은 받을 수 있게 되는거죠

    그래서 일반적으로 보안을 위해서
    EC2, RDS와 같은 리소스는 보안상 안전하게 Private Subnet에 위치시키고
    ELB나 NAT 같은 리소스는 Public Subnet에 위치시켜서
    Public/Private Subnet 간의 통신이 되게끔 구성하죠

    그리고 NAT의 가장 주요한 역할 중 하나는
    여러 개의 인스턴스가 같은 Public IP를 쓰게끔도 해줍니다
    쉽게 생각하면 집에서 쓰는 IP공유기(ex - ipTIME) 같은 역할을 해준다라고 보시면 됩니다

    요즘은 공유기 성능이 너무 좋아서 저가형 제품들도
    일반적인 NAT에서 제공해주는 기능(DNS, port forwarding 등)도 어느정도는 제공 해주고 있죠

     

    근데 NAT를 꼭 써야하나?

    NAT가 없으면 통신이 안되고
    어쩔 수 없이 NAT를 쓰게 되면 추가 요금이 발생하게 되는 좀 슬픈 상황이죠

    물론 NAT를 안쓰고 서비스는 가능합니다
    모든 리소스를 Public Subnet에 두는거죠

    하지만 그랬다간 누군가 몰래 EC2에 접속해서 코인을 채굴하게 되는 그런 슬픈 상황이 올 수 있습니다
    (일반적인 암호방식은 brute force로는 언젠가는 뚫리는 구조니깐 통신만 된다면 언젠가는 뚫립니다)
    단순히 구글링만해도 엑세스키나 보안그룹 잘못관리해서 억대 요금이 발생했다는 얘기가 심심지 않게 나오죠

    매우 흔한(?) 일

     

    NAT 얼마면 돼?

    NAT의 요금제 구성은 정말 간단하지만 한번 생성되면 끌 수 없는 리소스라서 참 애매한 친구입니다
    무조건 365일 24시간 매일 살아있어야 통신이 되니깐요
    비용은 아래와 같습니다

    https://aws.amazon.com/ko/vpc/pricing/

    보시는것처럼 NAT가 숨만 쉬어도 시간당 $0.059 비용이 발생하고
    한달(30일 * 24시간)에 1개를 쓰면 고정적으로 $42.48가 발생합니다
    그리고 NAT를 통해서 통신이 이뤄진다면 처리된 데이터의 GB당 요금은 $0.059가 발생하게 됩니다

     

    그럼 FinOps랑 NAT랑 무슨 상관이죠?

    네 저도 그렇게 생각하고 있었죠
    이제까지 모든 EC2, RDS는 Private Subnet에 넣고 NAT를 통해서만 통신하게끔 썼으니깐요
    (아 물론 공식적으로 ㅎㅎ...)

    그런데 말입니다?
    연말이니 예산도 확인할겸 작년에 발생했던 요금을 billing - 청구서에서 내역을 월별로 쭉 봤습니다
    근데 전체 사용량 중 유독 EC2의 비용이 많이 발생하더라구요?
    심지어 EC2 비용이 TOP 1이었습니다

    22년 9월 청구서 TOP 3

    근데 이전 포스팅에서 언급한것처럼
    모든 서비스는 서버리스 형태로 사용하고 있었기 때문에
    EC2의 비용이 저렇게 나올 수가 없었습니다

    한달 동안 EC2로 $400 이상의 비용을 쓰려면
    단일 인스턴스로 m6g.4xlarge (한달에 약 $540)정도는 거의 상시 실행하고 있어야하는데
    저만한 사이즈를 사용하고 있진 않았거든요

    https://aws.amazon.com/ko/ec2/pricing/on-demand/?refid=4c74fd91-5632-4f18-ac76-a6c66c92e185

    물론 개발/분석용으로 작은거 하나 띄워서 쓰고 있는게 있었습니다
    안 믿으실것 같아서 사용 중인 인스턴스를 까봤습니다

    r5.xlarge 단 하나!

    근데 분명 저거 쓰시는분이 작은거라 했는데 왜 저거지? 이름부터 large 잖아요

    r시리즈가 비싸긴 해도 m시리즈보다 4배나 비싸진 않거든요
    실제로 요금표로 봐도 시간당 $0.304 정도입니다

    https://aws.amazon.com/ko/ec2/pricing/on-demand/?refid=4c74fd91-5632-4f18-ac76-a6c66c92e185

    순수하게 항상 실행해놓고 쓰고 있었다면 $218.88(=$0.304 * 30일 * 24시간) 정도는 쓰고 있었네요
    하지만 실제 비용은 $438.13을 쓰고 있었죠

    그럼 귀신이 나머지 $219.25을 노잣돈으로 쓰고 있었을까요...?

     

    형이 거기서 왜 나와?

    22년 9월 EC2에 대한 상세 내역을 한번 다시 보죠

    형이 왜 거기서 나와...?

    짜잔~!
    사실 EC2 안에는 NAT를 통해서 사용한 트래픽 비용과 NAT 시간당 비용이 들어있었습니다 ㅎㅎㅎㅎㅎ
    심지어 EC2 자체는 IR가 적용되서 더 저렴하게 쓰고 있었고
    순수하게 NAT 사용에 대한 비용이 $241.60를 쓰고 있었습니다

    여러분 NAT가 이렇게 위험합니다

    일단 NAT 실행시간에 대한 비용은 AZ A/C 2개로 이중화를 했기 때문에 $82.60에 대해서는 타당했습니다
    하지만 트래픽 비용이 저렇게 많이 나온건 좀 이상했죠

    그럼 Lambda때처럼 역산을 해보면
    EC2가 한달간 NAT를 통해서 사용한 트래픽 용량은 아래와 같습니다

    $159 / $0.059 = 약 2695GB(2.7TB)

    한달에 2.7TB면
    대충 하루에 100GB 이상 NAT를 통해서 어떤 통신을 했다는거죠

    아무리 생각해도 이해가 되지 않아서
    일단 이게 나가는 트래픽인지 들어오는 트래픽인지 구별할 필요가 있었습니다

    다행히 CloudWatch에서 특정 인스턴스의 NetworkIn/Out에 대한 Metric을 볼 수가 있어서
    월별로 확인해보니 아래와 같았습니다

    그치... 써봤자 얼마나 썼겠어....

    확인해보니 NetworkIn/Out 모두 합쳐봤자 한달에 200GB 내외로 사용하고 있었습니다
    그럼 EC2가 범인은 아닌데 남은 2.5TB는 누가 쓴거지...?

     

    EC2는 죄가 없었다!

    EC2와 VPC구조

    일단 개발용 EC2도 생각보다 많이 쓰고 있긴했었는데
    NAT를 통하는 경우는 대부분 RDS에서 데이터를 가져와서 분석을 위한 batch 작업을 하는 경우였습니다
    그래서 개발용치고는 생각보다 트래픽이 많았던것이었죠

    아무튼 해당 EC2는 NAT를 통해서 2.5TB나 쓰고 있진 않았습니다

     

    그럼 범인은 누구지?

    EC2가 범인에서 제외되면서 오리무중에 빠졌습니다
    요금서가 거짓말을 할리는 없는데 이게 왜 EC2 요금으로 잡혔을까요?

    그럼 일단 NAT를 통하려면 라우팅 테이블에 정의된대로 통신할테니
    해당 VPC에서 쓰는 라우팅 테이블을 모두 검사해봤습니다

    우측 위는 Public Subnet / 우측 아래는 Private Subnet에 대한 라우팅 테이블

    Public Subnet에는 EC2외에는 존재하지 않기 때문에 NAT를 통할일이 없었고
    유일하게 의심이 가능 부분은 NAT가 타겟으로 정의된 Private Subnet뿐이었죠

     

    범인은 바로 너!

    전 포스팅에서 언급했던것처럼 API서버와 모델용 Lambda들이 Private Subnet에 있었습니다

    Lambda가 왜 Private Subnet에 있었냐면
    방화벽 등록하기 좋게 NAT의 역할 중 하나인 Public IP를 함께 쓰려고 모두 Private Subnet에 할당해놨죠

    물론 단순히 방화벽 등록을 위해서 한건 아니고
    Lambda에서 slack 이나 JIRA API 같이 인터넷 영역에 있는 다른 서비스의 API에 접근하려면
    Lambda도 Public IP가 있어야지 통신이 가능했거든요

    하지만 기본적으로 VPC에 할당된 Lambda는 Public Subnet에 있어도 Private IP만 가지고 있고
    Private IP만 가지고는 인터넷 통신을 할 순 없기 때문에
    NAT를 통해서 Public IP를 받아 인터넷 통신을 하고 있었습니다

    물론 Lambda에 붙어서 생성된 ENI에 EIP를 할당해도 되지만
    언제 ENI가 생성될줄 알고 그걸 하나하나 하겠습니까...

     

    사실은 이랬습니다

    매일/매주/매달마다 정기적으로 실행되는 배치용 Lambda가 있었습니다

    

    이 친구의 역할은 On-Premise에서 업로드한 S3 데이터를 가지고
    기존에 RDS에 만든 테이블에 정규화해서 이쁘게 넣는 작업을 하고 있었죠

    물론 이 또한 pandas를 통해서 아래와 같이 작업하고 있었습니다

    1줄이면 s3를 dataframe으로 바꿀 수 있다구욧!

     

    근데 이게 비용이 나올만한건가?

    위 그림만 보면 모두 AWS 서비스를 쓴거니깐 AWS 내부에서 통신을 했으니 당연히 비용이 안나올거라 생각했습니다
    왜냐면 저는 아래의 이 문구만 기억하고 있었거든요

    이제까지 내가 알고 있던 내용

    그래서 당연하게 AWS 내에서 통신이 발생했으니 트래픽 비용이 발생하지 않았겠지?라는 생각으로 구축했었는데
    한국말은 끝까지 들어야죠?
    외국 문서도 한국어로 번역해서 그런가 끝까지 봐야되더라구요

    아니 외국문서도 끝까지 읽어야되는거였냐...

    Lambda의 경우 VPC에 할당되서 NAT를 통해서 S3로 통신하고 있기 때문에 비용이 발생하고 있던 것이었습니다
    쉽게 그림으로 보자면 아래와 같은 상황이었던 것이죠

    Private Subnet에 있는 Lambda는
    NAT를 통해서 Internet Gateway(=IGW)를 거쳐 인터넷망에 있는 S3와 통신하고 있었습니다

    그러니깐 저는 이제까지 인터넷망으로 S3을 접근해서 쓰고 있던것이었습니다
    AWS는 죄가 없고 안내문을 제대로 안읽은 제 잘못이었던 것이죠
    물론 이것도 S3의 데이터를 많이 쓰니깐 알았던 것이지 영원히 모를뻔했네요

    그냥 사용자가 늘어서 트래픽도 늘어나니깐 비용이 늘었겠지하고 행복사할뻔했습니다
    그리고 사실은 비용이 늘었지만 사용자는 그대로였거든요(아아... 눙물...)

     

    그래서 해결은 어떻게 하죠?

    사실 AWS에서 기본으로 제시하는 VPC 가이드라인은 아래와 같습니다

    https://docs.aws.amazon.com/ko_kr/vpc/latest/userguide/vpc-example-private-subnets-nat.html

    왼쪽에 보시면 S3 Gateway가 있죠?
    NAT 외에 S3 Gateway를 둬서 NAT 트래픽 비용을 절감할 수 있습니다

     

    S3 Interface Endpoint도 있잖아요?

    공식 가이드가 그렇다는데 그냥 좀 Gateway 씁시다

    S3 Interface Endpoint를 쓰면 Gateway Endpoint와 위 그림과 동일하게
    VPC내에서 NAT를 통하지 않고 Private Endpoint를 통해서 S3에 접근할 수 있습니다

    그래서 사실 S3 Endpoint로 검색하면 Interface 방식이 제일 먼저 뜨긴하죠
    하지만 이 친구의 특징을 보면 이렇습니다

    • private link(=private endpoint)로 제공되기 때문에 이중화를 위해선 사용 중인 AZ마다 생성 필요

    AZ마다 1개씩은 생성해줘야 특정 AZ가 죽어도 다른 AZ에 있는 Private Endpoint를 통해서 S3에 접근할 수 있습니다
    일단 아래 요금표를 보면서 AZ A/C 2개에 설정한다고 치고 1달 예상 요금을 계산해봅시다

    https://aws.amazon.com/ko/privatelink/pricing/

    1달 예상 요금
    = 시간당 비용 * AZ 2개 + 트래픽 비용
    = ($0.013 * 30일 * 24시간) * 2 + ($0.01 * 2500GB)
    = $9.36 * 2 + $25
    = $43.72

    EC2에서 발생한 트래픽을 200GB 제외하고 대충 2.5TB로 계산했지만
    S3 Interface Endpoint를 사용했을때 한달에 대충 $45가 발생하겠네요

    원래 NAT를 통해서 S3에 접근하고 있었더라면 $200~$250 정도 썼을텐데
    S3 Interface Endpoint로 이중화해서 구성해도 $150 정도 절감할 수 있게 생겼습니다

    "그럼 이거 쓰면 되겠네요??"
    라는 생각은 이제 아래 내용을 보면 싹 정리되실겁니다

     

    • 생성된 endpoint를 사용하려면 코드 레벨에서 해당 endpoint를 명시해서 사용해야된다

    문제는 실제 코드레벨에서 적용이 필요한 부분이 있습니다
    즉, 아래와 같이 써야된다라는 겁니다

    근데 문제는 분석가분들은 이렇게 쓰고 있죠??

    자 그럼 이제 분석가분들에게 이렇게 설명해주시면 됩니다

    본인의 EC2나 Lambda의 AZ에 따라서 endpoint가 다르게 설정하셔야되고
    pandas.read_csv하실때 endpoint에 따라서 S3 endpoint에 접근되게 고치셔야됩니다!
    아 물론 안하셔도 NAT를 통해서 통신이 되긴하지만 
    비용이 많이나오고 어쩌구저쩌구...
    근데 저는 pandas를 잘 몰라서 어쩌구저쩌구...

    분석가분들은 보통 비개발자 출신분들이 많으실텐데
    이걸 이해시키고 설득하려면 딱봐도 매우 귀찮겠죠?

    운좋게(?) 분석가분들이 찰떡 같이 알아들어도 S3를 어떻게 써야할지도 가이드를 줘야합니다
    문제는 설정이 제대로 안되면 또 NAT를 통해서 통신이 될테고
    이걸 구별하기는 쉽지 않죠 ㅠ
    (그리고 인수인계가 잘안되면 또 endpoint를 안쓰겠죠)

    그리고 NAT로 트래픽이 나가는지, S3 Endpoint로 나가는지 구별하려면
    vpc flow logs 옵션을 켜서 로그를 다 찍어보고 그래야되는데
    vpc flow logs를 키면 아마 지금 낭비하는 요금보다 더 많은 비용이 발생할겁니다

    https://aws.amazon.com/ko/cloudwatch/pricing/

    일단 vpc 에서 발생하는 트래픽을 CloudWatch or S3로 전송해야되는데
    전송 요금과 전송된 로그를 보관하는 비용이 따로 부가됩니다
    로그의 크기는 실제 켜봐야 알겠지만 대충 100GB라고 쳐도 $80정도 나올겁니다

    CloudWatch logs 예상 요금
    = 전송 요금 + 저장된 데이터 요금
    = ($0.76 * 100GB) + ($0.0314 * 100GB)
    = $76 + $3.14
    = $79.14

    어쨋든 로그를 저장하면 수많은 로그를 다 하나하나보면서 분석해야되는데
    CloudWatch는 검색이 불편하고
    S3는 athena 같은걸로 조회는 가능하지만 어쨋든 어려운 일입니다

    왜냐구요? 내가 생성했던 ENI는 Lambda에 붙어있었기 때문에
    이 친구는 생겼다 사라졌다하거든요
    어떤 Lambda가 어떤 Private IP를 가지고 통신했었는지까지 찾으려고 한다면 진짜 눈물납니다

    그리고 대충 보고 S3가 싼데? 싶어서 S3로 보내면
    athena로 쿼리하면서 발생하는 비용이 또 발생할거라 결국 어느걸 선택하든 비슷할겁니다

    그리고 로그가 너무 많거나해서 cloudwatch나 athena로 조회하기 불편한 상황이라면
    더 큰 규모의 서비스인 EMR, redshift를 써야겠죠
    돈 10만원 아끼려고 배보다 배꼽이 큰 상황이 발생할 수 있다는겁니다

     

    그래서 S3 Gateway Endpoint 쓰면 해결되나?

    네 Interface Endpoint로도 잘되는데 안될게 뭐가 있겠습니까?

    사실 Interface Endpoint는 On-Premise 서버에서 AWS Private DNS에 접근을 못하는 상황에서
    On-Premise 서버에서 S3로 접근할때 주로 사용하는데
    이것만 가지고도 하루종일 얘기해야되서 그냥 아래 이미지와 링크로 설명을 대체합니다

    https://docs.aws.amazon.com/ko_kr/vpc/latest/privatelink/vpc-endpoints-s3.html#private-dns-s3

    아무튼 S3 Gateway Endpoint는 Interface 방식과 가장 큰 차이점이 뭐냐면
    Gateway 방식은 라우팅을 할때
    코드레벨에서 명시적으로 사용할 필요없이 네트워크단에서 알아서 처리가 된다는 점이죠
    즉, 개발자/분석가가 인프라를 신경쓰지 않아도 된다는 점입니다

    https://docs.aws.amazon.com/ko_kr/vpc/latest/privatelink/vpc-endpoints-s3.html#private-dns-s3

    그래서 보통 위와 같이 AWS 내에선 Gateway Endpoint를 통해서 S3에 접근하고
    On-Premise 서버에서는 Interface Endpoint를 통해서 S3에 접근하여 비용을 절감합니다

    물론 On-Premise 서버에서 AWS Private DNS에 접근 가능하게
    Route 53 Resolver 같은걸 잘 세팅하면 쓸 수는 있을텐데
    저도 네트워크 전문가는 아닌 일개 개발자라 잘모르겠네요 ㅎㅎ;

    그리고 사실 눈치가 빠르신분은 앞에 제가 첨부한 라우팅 테이블에 이미 설정이 되어있는걸 보셨을겁니다

    이미 조치까지 다하고 글을 쓰는거라 설정이 이미 되있었죠 ㅎ

    Private Subnet의 라우팅 테이블에서 이렇게 설정해준다면
    라우팅 테이블에서 알아서 S3 트래픽이라면 S3 Gateway Endpoint로 라우팅 시켜줄테고
    인터넷이 필요하다면 NAT로 라우팅할겁니다
    더이상 개발자/분석가가 Endpoint 설정때문에 고통스럽지 않아도 된다는것이죠!

    심지어 Gateway Endpoint는 AZ가 아닌 VPC에 위치하기 때문에
    Interface 방식과 다르게 굳이 이중화할 필요가 없습니다

    그럼 Gateway Endpoint의 비용을 계산해볼까요?

    https://aws.amazon.com/ko/privatelink/pricing/

    1달 예상 요금
    = 시간당 비용 + 트래픽 비용
    = ($0.013 * 30일 * 24시간) + ($0.0035 * 2500GB)
    = $9.36 + $8.75
    = $18.11

    위에서 S3 Interface Endpoint는 이중화까지 고려했을때 $45가 나왔는데
    S3 Gateway Endpoint는 약 $20로 더 비용을 더 줄일 수 있었습니다

     

    그래서 실제론 얼마나 아꼈는데?

    좀 늦게 발견해서 조치가 늦었는데
    문제를 발견했던 9월과 조치가 완료된 상태인 11월의 요금을 비교해보면 이렇게 변했습니다

    위가 22년 9월 / 아래가 22년 11월

    결론적으로 코드나 다른 인프라 수정 없이
    S3 Gateway Endpoint만 추가하여 트래픽 비용을 매달 약 $150 정도 절약할 수 있었습니다

     

    결론

    전에 포스팅한 Lambda편과 합치면 거의 매달 $500달러를 절감했습니다

    열심히 절감했는데 월급에 꽂아주면 좋겠네요

    반응형
    Comments