[AWS] Playwright를 Lambda에서 실행하기

Woonil·2일 전
0

AWS

목록 보기
4/4

AWS Lambda는 AWS가 제공하는 Serverless 서비스로, 이것을 활용하면 사용자는 짧은 시간 동안 진행되는 프로그래밍 작업을 별도의 서버 구축 없이 수행할 수 있다. 주기적으로 수행되고 실행시간이 그리 길지 않은 공지사항 크롤링이 이러한 서버리스의 이점을 최대로 활용하기에 좋은 주제라고 생각했다. 따라서 기존에는 서버를 직접 구성하여 진행했던 교내 공지사항 통합 프로젝트 MoaBoa를 개선해보고자 했다. 이때, 크롤링을 Lambda에서 수행하기 위해 설정해야 하는 작업에서 많은 시행착오가 있었고 해결 과정을 정리해 보고자 한다.

😎해결 과정

지금부터 설명할 해결 과정을 이해하기 위해서는 우선 Lambda의 Layer 개념을 알아야 한다. 간략히 설명하자면 Layer(이하 레이어)는 여러 Lambda 함수가 공통으로 사용하는 코드(라이브러리, 설정, 데이터) 를
한 번만 업로드해 공유하는 기능이다.

레이어에 등록할 zip 파일 생성

Python

    python/
    └── lib/
        └── python3.12/
           └── site-packages/
                └── test/   ← 여기 라이브러리 코드
mkdir -p layer/python
cd layer/python

pip install 필요한 패키지

cd ..
zip -r test_layer.zip python

Nodejs

nodejs/
 └── node_modules/
     └── test/
         ├── index.js
         └── package.json
mkdir -p layer/nodejs
cd layer/nodejs

npm init -y
npm install 필요한 패키지

cd ..
zip -r test_layer.zip nodejs

Python 3.11에서 Node.js 20.x로 변경

초반에는 람다 핸들러 런타임을 Python 3.11으로 작성하고 Playwright 관련 패키지를 레이어에 등록하고 실행했지만, 아래와 같은 라이브러리 관련 이슈를 해결하지 못하였다.

No module named 'greenlet._greenlet’

동일한 이슈를 겪은 분의 블로그를 찾긴 했지만, 마땅한 해결책을 찾지 못하여 런타임은 Node.js 20.x, 코드도 JavaScript로 교체하기로 결정했다.

⚠️layers consume more than the available size of 262144000 bytes

Playwright 관련 레이어를 추가하려고 했지만, 해당 에러와 함께 레이어 추가되지 않았다. Lambda에는 등록할 수 있는 레이어 총 용량 제한이 존재하는 것을 알게 되었다. 해당 핸들러에는 googlesheet과의 연동을 위한 googleapis, googleauth 레이어도 있었는데, 이미 그 패키지들의 용량이 몇 백 메가 단위였다. 스택오버플로우 질문을 참고하여 레이어에 등록할 파일 생성 시 불필요한 패키지들은 제외하여 용량을 줄일 수 있었다.

제거 전

제거 후

❌playwright-aws-lambda

같은 이유로 Playwright를 통째로 Layer에 올려서는 안됐으며, 경량화된 패키지를 사용해야 했다. playwright-core 라는 패키지가 존재했고, 여기에는 브라우저 바이너리는 포함되어 있지 않아서 별도로 관련 패키지를 설치해야 했다. 구글링 결과, playwright-aws-lambda 라이브러리를 사용한 사례가 많았고, 아래 명령어를 수행하여 설치할 수 있었다.

https://blog.pages.kr/3046
https://www.browsercat.com/post/running-playwright-on-aws-lambda

npm install playwright-core playwright-aws-lambda --save

하지만 레이어에 라이브러리 추가 후 실행 시 아래와 같은 에러를 만날 수 있었다.

[pid=13][err] /tmp/chromium: error while loading shared libraries: libnspr4.so: cannot open shared object file: No such file or directory

챗지피티와 많은 대화를 해봤지만 해결하지 못했고, 나중에서야 해당 라이브러리 저장소의 최근 issue에서 나와 같은 상황인 사람들이 있는 것을 알게 되었다.

해당 이슈

이슈를 내리다보면 sparticruz/chromium를 사용하여 해결했다는 답변이 있다. 처음에는 ESM을 사용하지도 않았고 낚시용 답변인줄 알았지만, 며칠동안 삽질만 했기에 반신반의하며 검색해 보았다. 크롬 브라우저의 바이너리를 패키지화 해놓은 프로젝트였으며, 최근 업데이트도 불과 며칠 전이었고 스타가 꽤나 많았다.

✅playwright-core + sparticruz/chromium

리드미에도 친절하게 설명되어 있지만, zip 파일도 제공하고 있었다. 최신 zip 파일을 레이어에 생성 및 등록하고, 아래와 같이 내 포트폴리오 웹사이트 경로의 제목을 가져오는 테스트를 작성해보았다. 이때, 아래 두가지를 유의한다.

  1. playwright-corechromium 과 변수명이 동일하므로 둘 중 하나는 별칭을 사용해야 함.
  2. 인스턴스에 최소 512MB의 RAM을 할당해야 하지만 1600MB(또는 그 이상)가 권장됨.

메모리 조정의 경우, 함수의 '구성' 탭에서 수정할 수 있다.

import { chromium as pw } from 'playwright-core';
import chromium from '@sparticuz/chromium';

export const handler = async () => {
  const browser = await pw.launch({
    args: chromium.args,
    executablePath: await chromium.executablePath(),
    headless: true,
  });

  const page = await browser.newPage();
  await page.goto('https://woonil.com');
  const title = await page.title();
  await browser.close();

  return {
    statusCode: 200,
    body: JSON.stringify({ title }),
  };
};

결과는 성공적!!

이로써 기반 작업이 끝나 이후 세부적인 크롤링 코드 수정 등 핵심 작업에 더욱 집중할 수 있게 되었다. 역시나 뭐든 세팅에서 가장 많은 시간이 소요되는 것 같다. 하지만 이번 삽질을 통해 Lambda와 좀 더 가까워진 기분이 든다.

profile
프론트 개발과 클라우드 환경에 관심이 많습니다:)

0개의 댓글