[AWS] EC2 IP 변경시마다 자동으로 DNS 매핑되도록 Lambda 구성

NewNewDaddy·2023년 10월 24일
0

AWS

목록 보기
8/13
post-thumbnail

0. INTRO

  • EC2의 경우 Elastic IP 연결이 되어있지 않다면 Stop/Start 할 때 마다 Public IP가 허용된 CIDR 값 안에서 랜덤으로 변경되게 된다.

  • 만약 해당 EC2 IP가 특정 DNS와 연결되어 웹서비스를 하고 있는 상황에서 스케쥴링 작업이 되어야 한다면? 서버가 시작될때마다 변경되는 IP를 Route53의 DNS쪽에서 수동으로 바꿔주는건 정말 번거롭고 서버의 다운타임도 길어지게되는 문제가 있다.

  • 이번 실습에서는 서버의 시작을 감지하여 특정 Lambda 함수를 작동시켜 변경된 Public IP를 이미 지정된 DNS에서 자동으로 매핑시키는 작업을 해 볼 것이다.

  • 전체적인 아키텍쳐와 작동순서는 아래와 같다.

    image

    1. EC2의 RUNNING Event를 Eventbridge가 감지
    2. Eventbridge에 반응이 잡히면 해당 소스를 Trigger로 잡아놓은 Lambda 함수를 호출
    3. Lambda 함수내에서 Python SDK를 통해 EC2의 Public IP 조회 및 저장
    4. 변경된 IP를 미리 지정된 DNS와 매핑
  • 이렇게 되면 서버의 Stop/Start 액션이 일어나도 웹서비스되는 DNS 주소는 새로 변경된 IP 주소를 가리키게 되므로 Front 단에서 주소의 변경 및 다운타임 없이 서비스가 될 수 있다.

  • 사전 요구사항

    • 미리 구매된 DNS 주소 (ex> example.com)
    • 특정 이름으로 생성된 A Record 주소 (ex> ryan.example.com)

1. Eventbridge Rule 생성

  • Amazon EventBridge > Rules > Create rule 탭으로 들어가 Event의 이름 설정 및 아래와 같이 특정 EC2가 RUNNING 상태일 때 Event가 생성되도록 규칙을 정한다.

    image

  • 이후 탭에서 Skip to Review and update 버튼을 눌러 Event에 대해서만 생성을 완료한다.

2. Lambda 함수 구성

  • 함수의 역할은 크게 두 가지이다.

    1. Running EC2에서 Public IP 주소 조회

    2. 조회한 Public IP 주소를 기존 매핑되어 있는 DNS 주소와 연결

      import time
      import boto3
      
      # EC2 상태 조회 후 Running 상태라면 해당 EC2의 IP 받아오는 함수
      def get_instance_status(instance_id, IP:bool=False):
          ec2 = boto3.client("ec2")
          describeInstance = ec2.describe_instances(InstanceIds=[instance_id])
          status = describeInstance['Reservations'][0]['Instances'][0]['State']['Name']
          if IP == True:
              public_ip = describeInstance['Reservations'][0]['Instances'][0]['PublicIpAddress']
              return status, public_ip
          return status
      
      # EC2의 IP를 받아 A record 주소와 매핑시켜주는 함수
      def change_A_record(public_ip):
          hosted_zone_id = '구매한 DNS의 zone ID'
          record_name = 'DNS 주소 이름'
          route53_client = boto3.client('route53')
          response = route53_client.change_resource_record_sets(
              HostedZoneId=hosted_zone_id,
              ChangeBatch={
                  'Changes': [
                      {
                          'Action': 'UPSERT',
                          'ResourceRecordSet': {
                              'Name': record_name,
                              'Type': 'A',
                              'TTL': 300,
                              'ResourceRecords': [{'Value': public_ip}]
                          }
                      }
                  ]
              }
          )
      
          return {
              'statusCode': 200,
              'body': f'A record updated successfully to {public_ip}'
          }
      
      def lambda_handler(event, context):
          INSTANCE_ID = 'EC2 Instance ID'
          status = get_instance_status(INSTANCE_ID)
              
          while True:
              time.sleep(5)
              current_status = get_instance_status(INSTANCE_ID)
              print(current_status)
              if current_status == 'running':
                  current_status, public_ip = get_instance_status(INSTANCE_ID, True)
                  record_cng = change_A_record(public_ip)
                  break
              else: pass
          return record_cng

3. Lambda 함수의 Trigger 설정

  • Lambda > Add Trigger 섹션에서 위에서 만든 Eventbridge의 Rule을 Lambda 함수의 Trigger로 설정한다.

    image

  • EC2의 Start Event가 감지되면 Lambda가 Trigger 되며 이와 관련된 Log는 Lambda와 연결된 Cloudwatch Log Group에서 볼 수 있다.

    image


4. OUTRO

  • DNS 주소를 통해 웹서비스를 하는 경우 보통은 서버가 항상 Running 중이거나 Elastic IP를 통해 Public IP를 고정시켜 이 IP를 DNS 주소와 연결시키는 경우가 많다.
  • 서버에 SSH로 접속하여 작업해야할 상황에서는 조금 번거로울 수 있겠지만 Elastic IP 비용 절감을 할 수 있으며 EC2가 많아지더라도 Elastic IP 할당량에 대한 고민 없이 A Record와 즉각적인 1:1 대응이 가능해진다.
profile
데이터 엔지니어의 작업공간 / #PYTHON #CLOUD #SPARK #AWS #GCP #NCLOUD

0개의 댓글