본문 바로가기
공부/AWS

[AWS] AWS lambda + event bridge 매일 크롤링해서 private RDS에 저장

by 웅대 2023. 6. 17.
728x90
반응형

프로젝트를 진행하던 중 매일 크롤링을 해서 데이터베이스에 데이터를 갱신해야 하는 작업이 있었다.

 

처음에는 EC2에 배포한 스프링부트에서 직접 자바로 크롤링을 하도록 구성을 했었는데 보안을 위해 private subnet에 EC2 인스턴스를 두면서 어려워졌다.

 

NAT gateway를 통해 크롤링을 하는 방법도 있었지만 비용 문제로 다른 방법을 사용하기로 했다.

 

그 다른 방법은 AWS lambda와 AWS event bridge를 사용하여 매일 자정에 자동으로 크롤링을 해서 private RDS에 저장하는 방법이다.

 

<아키텍처>

  1. AWS Event Bridge의 Cron Rule을 사용하여 매일 자정에 이벤트를 발생시켜 Lambda를 호출한다.
  2. Lambda는 원하는 사이트를 크롤링 하여 원하는 데이터를 RDS에 저장한다.

 

아래 링크는 이전에 작성했던 lambda 기초 사용법 포스팅이다.

 

lambda 함수 사용

https://growth-coder.tistory.com/147

api 배포

https://growth-coder.tistory.com/148

lambda rds 연동

https://growth-coder.tistory.com/149

lambda rds 연동

https://growth-coder.tistory.com/150

 

private subnet에 RDS가 이미 존재한다는 가정하에 포스팅을 작성한다.

 

(없다면 다음 포스팅 참고)

https://growth-coder.tistory.com/170

 

[AWS] public subnet에 EC2, private subnet에 RDS 인스턴스 생성하기 (2)

https://growth-coder.tistory.com/169 이전 포스팅에서 public subnet에 EC2 인스턴스를 생성해보았다. 이번 시간에는 private subnet에 RDS 인스턴스를 생성해서 EC2에서만 접근할 수 있도록 해 볼 예정이다. RDS를

growth-coder.tistory.com

NAT gateway 생성

lambda를 private subnet에 둘 예정이므로 NAT gateway를 생성한다.

 

처음에는 lambda를 public subnet에 두었는데 실패하여 private subnet에 두고 NAT gateway를 사용하기로 했다.

 

public subnet에 두는 방법도 있는 것 같긴 한데 매우 복잡한 것 같아서 NAT gateway를 사용한다.

 

VPC -> NAT gateway -> NAT gateway 생성에 들어간다.

 

서브넷은 퍼블릭 서브넷, 연결 유형은 퍼블릭, 탄력적 IP도 할당한다.

 

서브넷이 없으면 Internet gateway와 연결한 public subnet을 생성한다.

 

(public subnet 생성 방법이 궁금하면 다음 포스팅 참고)

https://growth-coder.tistory.com/169

 

[AWS] public subnet에 EC2, private subnet에 RDS 인스턴스 생성하기 (1)

이번 포스팅에서는 public subnet에 EC2 인스턴스를 생성하고 privatet tsubnet에 RDS 인스턴스를 생성해서 통신할 예정이다. 다음 다이어그램은 우리가 만들 aws 아키텍처이다. EC2는 인터넷 게이트웨이와

growth-coder.tistory.com

참고로 NAT gateway는 프리티어에 해당되지 않아 비용이 발생한다.

private subnet 생성

서로 다른 가용 영역에 존재하는 private subnet 두 개를 생성한다.

 

lambda를 VPC 내부에 둘 경우 가용 영역이 다른 private subnet 두 개를 설정해야하기 때문이다.

 

이제 두 서브넷 모두 NAT gateway를 향하도록 라우팅 테이블을 수정해야 한다.

 

VPC -> 라우팅 테이블 -> 라우팅 테이블 생성에 들어간다.

 

생성한 라우팅 테이블의 라우팅 테이블 편집에 들어간다.

0.0.0.0/0과 NAT gateway를 선택하고 변경 사항을 저장한다.

 

그리고 이전에 생성한 private subnet에 들어가서 라우팅 테이블 -> 라우팅 테이블 연결 편집에 들어간다.

 

만든 라우팅 테이블을 선택하기만 하면 된다. 다른 private subnet에 대해서도 똑같은 설정을 한다.

 

보안 그룹 생성

lambda에게 할당할 보안 그룹을 생성한다.

 

그리고 private RDS의 보안 그룹의 인바운드 규칙에서 lamdba의 보안 그룹을 등록해주면 된다.

 

(다음 포스팅의 3번 참고)

https://growth-coder.tistory.com/170

 

[AWS] public subnet에 EC2, private subnet에 RDS 인스턴스 생성하기 (2)

https://growth-coder.tistory.com/169 이전 포스팅에서 public subnet에 EC2 인스턴스를 생성해보았다. 이번 시간에는 private subnet에 RDS 인스턴스를 생성해서 EC2에서만 접근할 수 있도록 해 볼 예정이다. RDS를

growth-coder.tistory.com

lambda 함수에 VPC 및 권한 설정

이제 lambda 함수가 VPC 외부가 아닌 VPC 내부에 넣을 차례이다.

생성한 람다 함수의 구성 -> VPC -> 편집에 들어가서 RDS의 VPC, private subnet 두 개, 보안 그룹을 선택하고 저장한다.

그리고 RDS에 접속할 수 있도록 권한을 설정해야한다.

 

IAM -> 역할 -> 역할 생성에 들어간다.

AWSLambdaVPCAccessExecutionRole을 추가해준다.

이 다음 이름과 설정 정보를 검토하고 생성한다.

 

다시 lambda 함수에 들어가서 구성 -> 권한 -> 편집에 들어간다.

역할 부분에 생성한 역할을 선택하고 저장하면 된다.

파이썬 함수 작성 및 환경 세팅

우선 크롤링을 해서 rds에 저장하는 "lambda_function.py" 파이썬 코드를 작성한다.

 

크롤링 코드는 네이버 지식인에 "파이썬"을 검색해서 나오는 첫 번째 글의 제목을 가져오는 코드로 아래 링크에서 가져왔다.

 

https://wikidocs.net/85739

 

2.6 사이트 정보 추출하기 - beautifulsoup 사용법 (1)

# BeautifulSoup가 필요한 이유 request.text를 이용해 가져온 데이터는 **텍스트형태의 html **입니다. 텍스트형태의 데이터에서 원하는 html 태그…

wikidocs.net

난 다음 코드를 C 드라이브 -> python-crawling 폴더 안에 작성하였다.

 

<lambda_function.py>

import requests
import logging
import pymysql
import sys
from bs4 import BeautifulSoup
rds_host  = "rds 엔드포인트"
user_name = "마스터 사용자 이름"
password = "password"
db_name = "초기 데이터베이스 이름"

logger = logging.getLogger()
logger.setLevel(logging.INFO)


logger = logging.getLogger()
logger.setLevel(logging.INFO)

try:
    conn = pymysql.connect(host=rds_host, user=user_name, passwd=password, db=db_name, connect_timeout=5)
except pymysql.MySQLError as e:
    logger.error("연결 실패!")
    logger.error(e)
    sys.exit()

logger.info("연결 성공!")

def lambda_handler(event, context):
    url = 'https://kin.naver.com/search/list.nhn?query=%ED%8C%8C%EC%9D%B4%EC%8D%AC'
    response = requests.get(url)
    if response.status_code == 200:
        html = response.text
        soup = BeautifulSoup(html, 'html.parser')
        title = soup.select_one('#s_content > div.section > ul > li:nth-child(1) > dl > dt > a')
    else : 
        print(response.status_code)



    item_count = 0
    sql_string = f"insert into CRAWLING (text) values('{title.get_text()}')"
    
    with conn.cursor() as cur:
        cur.execute("create table if not exists CRAWLING ( id INT AUTO_INCREMENT PRIMARY KEY, text varchar(50) NOT NULL)")
        cur.execute(sql_string)
        conn.commit()

    

    return "크롤링 성공!"

즉 우리는 매일 자정마다 네이버 지식인에 "파이썬"을 검색해서 나오는 첫 번째 글의 제목을 mysql 데이터베이스에 추가하려고 한다.

 

위 파이썬 코드를 작성하는 것만으로는 안된다.

 

lambda에는 라이브러리가 설치되어있지 않기 때문에 라이브러리도 설치를 하고 zip 파일로 압축을 해서 업로드 해야 한다.

 

우리가 설치해야 할 라이브러리는 requests(http 요청), pymysql(데이터베이스), bs4(크롤링)이다.

 

이제 C 드라이브에서 (내 기준) bash 창을 열었다.

 

python-crawling 폴더를 타겟으로 라이브러리를 설치한다.

 

다음 명령어를 입력하면 된다.

pip install --target python-crawling requests --no-user
pip install --target python-crawling pymysql --no-user
pip install --target python-crawling bs4 --no-user

아마 다음과 같은 폴더들이 생성되었을 것이다.

파이썬 코드 포함 모든 폴더들을 함께 압축한다.

 

이제 Lambda -> 함수 생성에 들어가서 이름과 Python 3.10을 선택하고 함수를 생성한다.

생성한 함수에 들어가서 "에서 업로드" -> .zip 파일을 선택한다.

업로드를 하면 된다.

 

이제 테스트 이벤트를 만들고 테스트를 해보자. 우리는 받는 인자가 없기 때문에 입력 값은 아무거나 넣어도 상관이 없다.

크롤링 성공! 이라는 메시지가 반환되면 성공이다.

요청을 5번하고 RDS에서도 확인하면 잘 반영된 모습을 확인할 수 있다. (나는 EC2 session manager를 통해 접속했다.)

 

Event Bridge를 통해 매일 자정마다 크롤링 요청

이제 Event Bridge를 통해서 매일 자정마다 크롤링 요청을 보내면 된다.

 

Amazon Event Bridge -> 일정 -> 일정 생성에 들어간다.

 

핵심은 일정 패턴이다. 반복 일정, Cron 기반 일정, 유효한 Cron 표현식을 선택한다.

 

자정이면 0시 0분에 실행되어야 하고 나머지는 상관이 없기 때문에 *을 입력해준다. (요일은 물음표)

 

유효한 Cron 표현식이 입력되면 다음 10개 트리거 날짜를 알려준다. 매일 자정에 실행하는 모습을 볼 수 있다.

 

테스트는 해야하기 때문에 나는 우선 1시간 간격으로 실행하도록 임시 설정을 했다.

 

유연한 기간은  끈다.

 

다음으로 넘어가면 대상을 선택할 수 있다. AWS Lambda를 선택해준다.

이 아래에 입력 값 또한 설정할 수 있는데 우리는 입력 값이 없어도 되기 때문에 설정하지 않고 다음으로 넘어간다.

 

그 다음 추가적인 설정을 할 수 있는데 별도로 설정하지 않고 일정을 생성했다.

 

이제 정해둔 시간마다 데이터베이스에 반영되는지 확인만 하면 된다.

 

참고

https://try-it.tistory.com/67

https://blog.naver.com/PostView.nhn?blogId=saga111&logNo=221822387800&parentCategoryNo=71&categoryNo=75&viewDate=&isShowPopularPosts=false&from=postView 

 

728x90
반응형

댓글