RicoCheesethe studio log · v2.0
Live · KRRead posts
목록으로
뉴스PUBLISHED · 2026년 5월 20일·11 MIN READ

Lambda에 파일 시스템이 생겼다. AI 에이전트를 올려봤다.

AWS S3 Files가 Lambda에 파일 시스템 마운트 기능을 추가했다. S3 버킷을 로컬 파일 시스템처럼 사용하는 신규 기능과, 이를 활용해 AI 코드 리뷰 에이전트를 구축한 사례를 소개한다.

#serverless#aws#lambda#ai
Lambda Just Got a File System. I Put AI Agents on It.

Lambda에서 S3 데이터를 다루는 코드는 늘 같은 패턴이었다. S3 이벤트가 발생하면 Lambda가 깨어나 /tmp에 파일을 내려받고, 처리하고, 결과를 다시 업로드하고, /tmp를 정리한다. 모든 파일, 모든 호출, 모든 함수에서 반복되는 작업이다.

S3 Files가 이 패턴을 바꾼다. S3 버킷을 로컬 파일 시스템으로 마운트하면 Lambda 코드에서 그냥 open()을 쓸 수 있다. 여러 Lambda 함수가 마운트된 S3 버킷을 공유 워크스페이스로 사용하는 AI 코드 리뷰 에이전트를 구축했고, 파일 접근 코드가 프로젝트에서 가장 단순한 부분이 됐다. 그게 핵심이다.

/tmp 세금 #

Lambda에서 S3 데이터를 다뤄봤다면 이 패턴을 알 것이다. 파일이 필요하지만 S3는 파일이 아니라 오브젝트를 제공한다. 그래서 오브젝트를 /tmp에 내려받고, 작업하고, 결과를 다시 업로드한다.

untitled
python
# 기존 방식: 모든 Lambda 개발자가 한 번쯤 작성해본 코드
import boto3

s3 = boto3.client("s3")

def lambda_handler(event, context):
    bucket = event["bucket"]
    key = event["key"]

    # /tmp에 다운로드
    local_path = f"/tmp/{key.split('/')[-1]}"
    s3.download_file(bucket, key, local_path)

    # 실제 작업
    with open(local_path) as f:
        content = f.read()
    result = process(content)

    # 결과 업로드
    s3.put_object(Bucket=bucket, Key=f"output/{key}", Body=result)

    # /tmp 정리
    os.remove(local_path)

"파일 읽고 쓰기"치고는 의식이 너무 많다. 여러 함수가 같은 데이터를 다뤄야 할 때는 더 복잡해진다. 각 함수가 자체 /tmp 복사본을 관리해야 한다. 큰 저장소나 데이터셋을 처리하다 보면 10GB /tmp 한도를 금방 소진한다.

s3fssmart_open 같은 라이브러리가 이 문제를 어느 정도 완화해주지만, 이들도 내부적으로는 API 호출을 한다. 코드는 여전히 SDK를 통해 S3와 통신하는 것이지, 파일 시스템을 쓰는 게 아니다.

Lambda용 S3 Files #

S3 Files는 S3 버킷을 Lambda 함수의 로컬 파일 시스템으로 마운트하는 신규 기능이다. 코드는 /mnt/workspace 같은 마운트 경로에서 파일을 읽고 쓰고, S3 Files가 버킷과 동기화를 처리한다. 쓴 변경사항은 수 분 내에 S3에 반영되고, S3 오브젝트의 변경사항은 수 초 내에 파일 시스템에 나타난다.

untitled
python
# 새로운 방식: 그냥 파일 경로
from pathlib import Path

WORKSPACE = Path("/mnt/workspace")

def lambda_handler(event, context):
    # 마운트에서 직접 읽기
    content = (WORKSPACE / "source" / "app.py").read_text()
    result = process(content)

    # 마운트에 직접 쓰기
    (WORKSPACE / "output" / "result.json").write_text(result)

파일 접근에 boto3가 필요 없다. /tmp 관리도, 업로드 단계도 없다. 파일 시스템 자체가 인터페이스다.

내부적으로 S3 Files는 Amazon EFS 기반이다. 활성 데이터는 고성능 스토리지에 캐시해 서브밀리초 레이턴시를 제공하고, 대용량 순차 읽기는 S3에서 직접 스트리밍한다. S3의 내구성과 경제성을 갖춘 파일 시스템 시맨틱을 얻을 수 있다.

단, S3 Files는 VPC가 필요하다. Lambda 함수가 마운트 타겟과 같은 VPC에 있어야 하고, 외부 인터넷 접근을 위한 NAT 게이트웨이도 필요하다. VPC 연결 Lambda 함수의 콜드 스타트 페널티는 예전부터 해결됐고, 네트워크 설정은 한 번만 작성하면 되는 보일러플레이트다.

구축한 것 #

S3 Files를 "CSV 읽기"보다 흥미로운 용도로 테스트하기 위해 서버리스 코드 리뷰 시스템을 만들었다. 공개 GitHub 저장소를 가리키면 세 가지 일이 벌어진다:

  1. 내구성 있는 오케스트레이터 함수가 공유 S3 Files 워크스페이스에 저장소를 클론
  2. 보안 리뷰 에이전트와 스타일 리뷰 에이전트가 병렬로 코드 분석
  3. 결과가 동일한 워크스페이스에 JSON 파일로 저장되어 S3에 동기화

세 Lambda 함수 모두 같은 S3 버킷을 마운트한다. 오케스트레이터가 파일을 쓰고, 에이전트가 읽는다. 함수 간에 S3 키를 전달하지 않고, /tmp에 내려받지도 않는다. 파일 시스템이 곧 협력 레이어다.

에이전트는 Amazon Bedrock과 Strands Agents SDK를 사용한다. 각 에이전트는 마운트 경로에서 동작하는 커스텀 파일 도구를 받고, Claude가 어떤 파일을 읽고 분석하고 쓸지 결정한다. 오케스트레이터는 Lambda 내구성 함수로 자동 체크포인팅과 함께 워크플로우를 조율한다.

전체 소스: singledigit/lambda-s3-files-example

SAM 템플릿 #

IaC 부분이 가장 많은 시행착오를 거쳤다. S3 Files는 완전히 새로운 기능이라 CloudFormation 리소스 타입이 아직 린터에 없다.

리소스 체인

S3 Files를 Lambda와 연동하려면 다섯 가지 리소스가 필요하다:

  1. 버전 관리가 활성화된 S3 버킷 (필수)
  2. S3 Files가 버킷에 접근하기 위한 IAM 역할
  3. 버킷과 NFS를 연결하는 S3 Files FileSystem
  4. 각 AZ의 마운트 타겟 (네트워크 엔드포인트)
  5. Lambda의 POSIX 아이덴티티를 제어하는 액세스 포인트

리소스 타입은 AWS::S3Files::FileSystem, AWS::S3Files::MountTarget, AWS::S3Files::AccessPoint다. IDE의 CloudFormation 린터가 아직 이를 인식하지 못하지만 무시해도 된다.

IAM 역할 주의사항

S3 Files IAM 역할은 s3files.amazonaws.com이 아닌 elasticfilesystem.amazonaws.com을 신뢰한다. S3 Files가 EFS 기반이라 신뢰 관계가 EFS 서비스 주체를 통해 연결된다.

untitled
yaml
S3FilesRole:
  Type: AWS::IAM::Role
  Properties:
    Path: /service-role/
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Sid: AllowS3FilesAssumeRole
          Effect: Allow
          Principal:
            Service: elasticfilesystem.amazonaws.com
          Action: sts:AssumeRole
          Condition:
            StringEquals:
              aws:SourceAccount: !Ref AWS::AccountId
            ArnLike:
              aws:SourceArn: !Sub 'arn:aws:s3files:${AWS::Region}:${AWS::AccountId}:file-system/*'

액세스 포인트

Lambda에서 중요한 부분이다. 액세스 포인트는 함수가 실행되는 POSIX 아이덴티티를 제어하고 쓰기 가능한 루트 디렉터리를 생성한다. 없으면 Lambda가 파일 시스템을 마운트할 수는 있지만 쓸 수 없다.

untitled
yaml
S3FilesAccessPoint:
  Type: AWS::S3Files::AccessPoint
  Properties:
    FileSystemId: !GetAtt S3FileSystem.FileSystemId
    PosixUser:
      Uid: '1000'
      Gid: '1000'
    RootDirectory:
      Path: /lambda
      CreationPermissions:
        OwnerUid: '1000'
        OwnerGid: '1000'
        Permissions: '755'

CreationPermissions 속성이 핵심이다. 클라이언트가 처음 연결할 때 올바른 소유권으로 /lambda 디렉터리를 자동 생성한다. 없으면 루트 디렉터리가 root(UID 0) 소유가 되고, 액세스 포인트를 통해 UID 1000으로 실행되는 Lambda가 서브디렉터리를 만들 수 없다.

Lambda 설정

Lambda 쪽에서 FileSystemConfigs는 파일 시스템 ARN이 아닌 액세스 포인트 ARN과 로컬 마운트 경로를 받는다:

untitled
yaml
OrchestratorFunction:
  Type: AWS::Serverless::Function
  DependsOn:
    - MountTargetA
    - MountTargetB
  Properties:
    FileSystemConfigs:
      - Arn: !GetAtt S3FilesAccessPoint.AccessPointArn
        LocalMountPath: /mnt/workspace
    VpcConfig:
      SecurityGroupIds:
        - !GetAtt NetworkingStack.Outputs.LambdaSGId
      SubnetIds:
        - !GetAtt NetworkingStack.Outputs.PrivateSubnetAId
        - !GetAtt NetworkingStack.Outputs.PrivateSubnetBId

마운트 타겟의 DependsOn이 중요하다. 마운트 타겟이 준비되기 전까지 Lambda가 파일 시스템을 마운트할 수 없으며, 마운트 타겟 생성에는 약 5분이 걸린다.

참고할 점 #

일관성 모델이 중요하다. S3 Files는 close-to-open 일관성을 제공한다. 함수 A가 파일을 쓰고 함수 B가 바로 읽으면 최신 버전이 보이지 않을 수 있다. 오케스트레이터가 먼저 쓰고 에이전트가 다음에 실행되므로 순서가 자연스럽지만, 동시 쓰기 간 실시간 협력이 필요하다면 다른 패턴이 필요하다.

VPC가 복잡도를 더한다. 크진 않지만 서브넷, 보안 그룹, 인터넷 접근용 NAT 게이트웨이가 필요하다. 한 번 템플릿을 만들어 재사용하면 된다.

콜드 스타트는 괜찮다. VPC 연결 Lambda 함수는 예전에 10초 이상의 콜드 스타트 시간이 있었지만 몇 년 전에 해결됐다. 파일 시스템 마운트 상태에서도 2초 이내로 콜드 스타트된다.

전체 코드: github.com/singledigit/lambda-s3-files-example


이 글은 위 출처의 내용을 바탕으로 작성된 초안입니다. 원문의 의견과 정보를 그대로 전달하며, 별도의 견해를 포함하지 않습니다.