[AWS] Image Resizing 파이프라인 구축

아키텍처 개요

S3, SQS, Lambda 서비스를 활용하여 자동화된 이미지 처리 파이프라인을 구성하였다.

사용자는 S3 버킷에 원본 이미지를 업로드하며, 이때 발생하는 이벤트가 SQS를 통해 메시지 형태로 전달된다. SQS는 Lambda 함수를 트리거하고, 해당 Lambda는 S3에서 원본 이미지를 가져와 리사이징 작업을 수행한 뒤, 결과 이미지를 별도의 S3 버킷에 저장한다.

구성 배경 및 목적

서버리스 아키텍처의 활용

이러한 구성은 AWS Lambda를 중심으로 한 서버리스 아키텍처에 기반한다. Lambda 함수는 요청이 있을 때만 실행되며, 별도의 서버 인프라 관리가 필요 없다. 또한, 트래픽 증가에 따라 자동 확장되므로 대량의 이미지 처리도 안정적으로 수행할 수 있다.

비용 효율성과 유연성

Lambda와 S3는 사용한 만큼만 비용을 지불하는 구조(Pay-per-use)이기 때문에, 고정된 인프라를 유지할 필요 없이 비용 최적화가 가능하다. 이는 트래픽 변동이 큰 서비스에서 특히 유리하다.

SQS를 통한 안정성과 확장성 확보

SQS는 이벤트 메시지를 비동기적으로 안전하게 저장하고, Lambda와의 연동을 통해 안정적인 메시지 처리를 가능하게 한다. 큐를 통해 처리량이 일시적으로 폭주하더라도 메시지가 유실되지 않으며, 순차적으로 안정적인 처리가 가능하다.

실습 순서 

  • S3 버킷 X 2 생성(오리진 전용, 리사이징 전용)
  • Lambda 함수 생성
  • SQS 큐 생성
  • S3 이벤트 설정(SQS)
  • Lambda IAM 역할 설정 & Lambda와 SQS 트리거
  • 테스트

S3 버킷 X 2 생성(오리진 전용, 리사이징 전용)

오리진 전용 버킷과 리사이징 전용 버킷을 각각 하나씩 생성하겠다. 테스트를 진행할 것이기 때문에 퍼블릭 액세스 차단은 해제하겠다.

Lambda 함수 생성

런타임으로 python을 이용할 것이기 때문에 python3.12버전을 선택해주고, 실행역할을 하나 생성해준다.

 

이미지 리사이징을 위해 AWS Python SDK인 boto3와 이미지 처리 라이브러리 Pillow 모듈을 사용하겠다.
boto3는 Lambda의 기본 Python 런타임 환경에서 이미 제공되므로 추가 설치는 필요 없다.
하지만 Pillow 모듈은 별도로 Lambda 함수에 추가해야 한다. 이를 위해 아래 두 가지 방법 중 하나를 선택할 수 있다.

 

1. Pillow 모듈을 ZIP 파일로 패키징하여 Lambda Layer에 적용하기

  • 로컬 환경에서 Pillow 모듈을 설치한 후 이를 ZIP 파일로 패키징한다.
  • AWS Lambda 콘솔에서 새로운 Layer를 생성하고, 패키징한 ZIP 파일을 업로드하여 적용한다.

2. AWS Lambda Layer의 ARN 주소를 지정하여 적용하기

  • AWS에서 제공하는 미리 패키징된 Lambda Layer의 ARN 주소를 Lambda 함수 설정에 추가한다.
  • 이 방법은 간단하고 빠르게 Pillow 모듈을 Lambda 함수에서 사용할 수 있게 해준다.

이번 테스트에서는 두 번째 방법인 AWS Lambda Layer의 ARN 주소를 지정해 Pillow 모듈을 사용하는 방법을 다루겠다.

Lambda 함수 코드 작성

이미지 리사이징 코드 lambda_funtion.py

import json
import os
import boto3
from io import BytesIO
from PIL import Image
import urllib.parse

s3 = boto3.client('s3')

def lambda_handler(event, context):
    try:
        # SQS 이벤트 파싱
        records = event['Records']
        for record in records:
            # SQS 메시지 본문 파싱
            body = json.loads(record['body'])
            s3_event = body['Records'][0]['s3']
            aws_region = body['Records'][0]['awsRegion']
            bucket = s3_event['bucket']['name']
            key = urllib.parse.unquote_plus(s3_event['object']['key'])
    
            # 환경 변수에서 대상 S3 버킷 설정
            resized_bucket = os.environ['RESIZED_BUCKET']
    
            # 소스 S3 버킷에서 이미지 읽기
            response = s3.get_object(Bucket=bucket, Key=key)
            image_data = response['Body'].read()
    
            # PIL (Pillow)를 사용하여 이미지 열기
            image = Image.open(BytesIO(image_data))
    
            # 이미지를 RGB로 변환 (PNG, GIF, TIFF 등 처리)
            if image.mode != 'RGB':
                image = image.convert('RGB')
    
            # 이미지 크기 조정
            image = image.resize((200, 200))
    
            # 모든 이미지를 JPEG로 변환
            buffer = BytesIO()
            image.save(buffer, format='JPEG')
            buffer.seek(0)
            resized_data = buffer.read()
    
            # 원본 키에서 파일 이름과 확장자 분리
            base_name = os.path.splitext(key)[0]
            new_key = f"{base_name}.jpg"
    
            # 조정된 이미지를 대상 S3 버킷에 업로드
            s3.put_object(Bucket=resized_bucket, Key=new_key, Body=resized_data, ContentType='image/jpeg')
    
        return {
            'statusCode': 200,
            'body': json.dumps('Image resized and uploaded successfully')
        }
    except Exception as e:
        print(f"Error processing image: {e}")
        return {
            'statusCode': 500,
            'body': json.dumps('Error processing image')
        }

환경변수 설정

리사이징된 이미지를 저장할 버킷명을 환경변수에 추가해준다. 

Lambda Layer 설정

아래 URL를 통해 Python 버전에 맞는 Pillow모듈을 찾아 ARN을 입력해준다. 
https://github.com/keithrozario/Klayers/tree/master/deployments/python3.12

Lambda Layer에 주소를 복사하여 추가해준다. 

SQS 큐 생성

표준모드와 FIFO유형중 표준모드로 테스트를 진행하겠다. 

SQS를 생성하고 S3에서 이벤트 알람을 받아야하니 액세스 정책편집에서 다음과 같이 정책을 수정해준다. 

액세스 정책 JSON

{
"Version": "2012-10-17",
 "Id": "example-ID",
 "Statement": [
   {
    "Sid": "example-statement-ID",
    "Effect": "Allow",
    "Principal": {"Service": "s3.amazonaws.com"},
    "Action": "SQS:SendMessage",
    "Resource": "arn:aws:sqs:ap-northeast-2:880076045111:Image-resizing-SQS",
    "Condition": {
      "ArnLike": {
        "aws:SourceArn": "arn:aws:s3:::origin-s3-bucket"
      }
    }
  }
 ]
}

S3 이벤트 설정(SQS)

S3 오리진 버킷의 속성탭에서 SQS에 대한 이벤트 알림을 생성해준다. 

접두사 접미사로 S3에 대한 경로를 설정해주고 파일유형을 지정해줄 수 있다. 현재 테스트에서는 생략하도록 하겠다. 

Lambda IAM 역할 설정 & Lambda와 SQS 트리거

AWS Lambda 함수가 CloudWatch Logs, S3 버킷, SQS와 상호 작용하는 데 필요한 최소한의 권한에 대한 역할을 추가해주겠다. 

다음 Json 코드로 정책을 변경시켜준 후 SQS를 트리거 해준다. 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogGroup",
                "logs:CreateLogStream"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Sid": "OriginS3Access",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::origin-s3-bucket",
                "arn:aws:s3:::origin-s3-bucket/*"
            ]
        },
        {
            "Sid": "ResizingS3Access",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::resizing-s3-bucket",
                "arn:aws:s3:::resizing-s3-bucket/*"
            ]
        },
        {
            "Sid": "SQSAccess",
            "Effect": "Allow",
            "Action": [
                "sqs:SendMessage",
                "sqs:ReceiveMessage",
                "sqs:DeleteMessage",
                "sqs:GetQueueAttributes"
            ],
            "Resource": "arn:aws:sqs:ap-northeast-2:880076045111:Image-resizing-SQS"
        }
    ]
}

테스트

설정을 다 끝냈으니 오리진 버킷에 이미지를 업로드하여 이미지 리사이징이 되는지 한번 테스트해보겠다. 

오리진 버킷에 카멜레온.png 이미지 업로드를 해준다. 

리사이징 버킷 확인

리사이징 버킷을 확인해 보면, 이미지가 정상적으로 리사이징되어 저장된 걸 볼 수 있다.
Lambda 함수의 Python 코드에서는 모든 유형의 이미지 파일을 JPEG 형식으로 변환하도록 설정했기 때문에,
PNG 이미지 또한 JPEG 형식으로 변환되어 저장된다.
이렇게 하면 다양한 이미지 형식을 일관된 JPEG 형식으로 관리할 수 있다.

S3 주소로 접속해보니 이미지가 리사이징 되었다. 

이걸로 AWS의 S3, SQS, Lambda를 활용한 자동 이미지 리사이징 파이프라인 구축이 끝났다. 이제 개발자나 클라이언트는 원본 이미지만 업로드하면, 별도 작업 없이 자동으로 리사이징된 이미지를 얻을 수 있다.