Article

Serverless로 AWS 이미지 최적화 시스템 구축하기

서버리스로 이미지 처리 자동화하기

이미지 최적화는 웹 서비스의 성능과 사용자 경험에 직접적인 영향을 미칩니다. 하지만 대량의 이미지를 처리하는 것은 서버 리소스를 많이 소모합니다.

이 글에서는 AWS 서버리스 아키텍처를 이용해 이미지를 자동으로 최적화하는 시스템을 구축하는 방법을 소개합니다.

프로젝트 목표

이 프로젝트를 통해 배울 수 있는 것들입니다:

  1. AWS 서버리스 아키텍처 이해: Lambda, S3, API Gateway 등의 서비스 활용
  2. Serverless Framework 숙달: 인프라를 코드로 관리 (IaC)
  3. TypeScript 실전 활용: 타입 안정성과 함께 백엔드 개발
  4. 이미지 처리 파이프라인: 온디멘드 방식의 자동화 시스템

이미지 최적화 아키텍처

3가지 구현 방식

1. 온디멘드 방식 (권장)

사용자 요청 → API Gateway → Lambda → 이미지 처리 → S3 저장 → URL 반환

장점:

  • 필요할 때만 처리 (비용 효율)
  • 최신 이미지만 처리
  • 응답 시간 단축

2. 이벤트 직접 호출

S3 업로드 이벤트가 발생하면 Lambda를 직접 호출합니다.

3. 이벤트 구독 방식

SNS나 SQS를 통해 비동기 처리합니다.

필수 설치 사항

1단계: AWS CLI 설치

# macOS
brew install awscli

# 또는 pip 사용
pip install awscli

2단계: AWS 인증 설정

aws configure

대화형 프롬프트에 다음 정보를 입력합니다:

AWS Access Key ID: [AWS Console IAM에서 발급받은 Key ID]
AWS Secret Access Key: [AWS Console IAM에서 발급받은 Secret Access Key]
Default region name: ap-northeast-2  # 서울 리전
Default output format: json

3단계: Serverless Framework 설치

# 전역 설치
npm install -g serverless

# 또는 프로젝트 로컬 설치
npm install --save-dev serverless

환경 변수 관리 (Optional)

direnv를 사용하면 환경 변수를 편하게 관리할 수 있습니다.

.envrc 파일 생성

export BUCKET_NAME="my-image-bucket"
export ROOT_DOMAIN="example.com"
export SUB_DOMAIN="cdn"
export INFRA_DOMAIN="production"
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
export AWS_DEFAULT_REGION="ap-northeast-2"
export ACM_CERTIFICATE_ARN="arn:aws:acm:..."

direnv 활성화:

direnv allow

이제 이 디렉토리에 들어오면 자동으로 환경 변수가 로드됩니다.

프로젝트 구조

serverless-image-optimizer/
├── src/
│   └── handlers/
│       ├── uploadImage.ts
│       ├── optimizeImage.ts
│       └── getImage.ts
├── serverless.yml
├── tsconfig.json
├── package.json
└── .envrc

Serverless Framework 설정

serverless.yml 예제

service: image-optimizer

provider:
  name: aws
  runtime: nodejs18.x
  region: ${env:AWS_DEFAULT_REGION, 'ap-northeast-2'}
  environment:
    BUCKET_NAME: ${env:BUCKET_NAME}

functions:
  uploadImage:
    handler: src/handlers/uploadImage.handler
    events:
      - http:
          path: upload
          method: post

  optimizeImage:
    handler: src/handlers/optimizeImage.handler
    events:
      - s3:
          bucket: ${env:BUCKET_NAME}
          event: s3:ObjectCreated:*
          rules:
            - prefix: uploads/

resources:
  Resources:
    ImageBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${env:BUCKET_NAME}

주요 명령어

패키징

# 배포 전 의존성과 코드를 압축
serverless package
# 또는
npm run package

배포

# AWS에 배포
serverless deploy
# 또는
npm run deploy

배포 완료 후 출력되는 정보:

Service Information
service: image-optimizer
stage: dev
region: ap-northeast-2
endpoints:
  POST - https://xxxxx.execute-api.ap-northeast-2.amazonaws.com/dev/upload

functions:
  uploadImage: image-optimizer-dev-uploadImage

함수 테스트

serverless invoke local -f uploadImage -d '{"file": "test.jpg"}'

제거

# AWS에서 배포된 리소스 모두 삭제
serverless remove
# 또는
npm run remove

주의사항: sls remove가 안될 때

문제: S3 버킷에 파일이 남아있으면 삭제 실패

해결 방법:

# 1. S3 버킷 비우기
aws s3 rm s3://bucket-name --recursive

# 2. 다시 삭제 시도
serverless remove

실전 예제: 이미지 최적화 Lambda 함수

uploadImage.ts (이미지 업로드 핸들러)

import { APIGatewayProxyHandler } from 'aws-lambda';
import AWS from 'aws-sdk';
import sharp from 'sharp';

const s3 = new AWS.S3();

export const handler: APIGatewayProxyHandler = async (event) => {
  try {
    const body = JSON.parse(event.body || '{}');
    const { filename, base64Data } = body;

    // Base64 디코딩
    const buffer = Buffer.from(base64Data, 'base64');

    // 이미지 최적화 (JPEG로 변환, 품질 80%)
    const optimized = await sharp(buffer)
      .jpeg({ quality: 80 })
      .toBuffer();

    // S3에 업로드
    const key = `optimized/${Date.now()}-${filename}`;
    await s3.putObject({
      Bucket: process.env.BUCKET_NAME!,
      Key: key,
      Body: optimized,
      ContentType: 'image/jpeg',
    }).promise();

    return {
      statusCode: 200,
      body: JSON.stringify({
        success: true,
        key,
        url: `https://${process.env.BUCKET_NAME}.s3.ap-northeast-2.amazonaws.com/${key}`,
      }),
    };
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Upload failed' }),
    };
  }
};

비용 최적화

Serverless를 사용하면:

  • 비용: 요청 수와 실행 시간에만 과금
  • 스케일링: 자동으로 수평 확장
  • 유휴 비용 제로: 실행하지 않으면 비용 없음

비용 예측

  • Lambda: 100만 요청당 약 $0.20
  • S3: GB당 $0.023 (저장료)
  • 데이터 전송: GB당 $0.05

프로젝트 저장소

완전한 예제는 다음 저장소에서 확인할 수 있습니다:

GitHub - serverless-study-image-optimizer

다음 단계

이 기초 위에서 다음과 같이 확장할 수 있습니다:

  1. 여러 포맷 지원: WebP, AVIF 등 현대적 이미지 포맷
  2. 이미지 크기별 생성: 썸네일, 중간 크기, 원본 자동 생성
  3. CDN 통합: CloudFront로 글로벌 캐싱
  4. 모니터링: CloudWatch 로그와 알람 설정
  5. 비용 추적: 월별 Lambda 실행 비용 모니터링

마치며

서버리스 아키텍처는 이미지 처리 같은 배치 작업에 최적입니다. 인프라 관리 걱정 없이 비즈니스 로직에만 집중할 수 있습니다.

Serverless Framework를 배우면 AWS의 여러 서비스를 효율적으로 조합할 수 있고, 이는 클라우드 네이티브 개발의 기초가 됩니다.

지금 바로 시작하세요!

댓글