AWS

ECS + ALB로 띄운 사이드 프로젝트, Lambda Container Image로 옮겨도 될까?

드럼치던코딩노예 2026. 5. 6. 17:16

 

 

안녕하세요.

오늘은 사이드 프로젝트를 운영하다 보면 한 번쯤 마주치는 AWS 비용 이야기를 해보려고 합니다.

저는 백엔드 배포를 EC2에서 시작했습니다. 서버에 직접 접속해서 앱 올리고, Nginx 붙이고, 로그 보고, 문제가 생기면 SSH로 들어가서 확인하는 방식이요.

그러다 컨테이너를 쓰기 시작하면서 배포가 꽤 편해졌습니다.

Dockerfile로 빌드하고, 이미지를 ECR에 올리고, ECS Service로 띄우고, ALB 붙이고, Target Group으로 헬스체크하고, GitHub Actions로 배포 자동화하고.

회사에서라면 이 구성이 충분히 좋습니다. 서비스는 항상 떠 있어야 하고, 트래픽도 있고, 운영 안정성도 중요합니다. 무엇보다 비용을 개인이 직접 내는 게 아니니까요.

그런데 사이드 프로젝트로 오면 이야기가 달라집니다.

ECS + ALB는 좋은데, 아무도 안 와도 돈이 나갑니다

사이드 프로젝트를 하나 띄워놓고 보면 처음에는 기분이 좋습니다.

"오, 이거 진짜 서비스처럼 배포됐다."

프런트엔드는 S3 + CloudFront, 백엔드는 ECS Fargate, 앞에는 ALB, Route 53으로 도메인 연결, HTTPS까지 붙이면 꽤 그럴듯합니다.

문제는 그 다음입니다.

사람이 안 들어와도 비용이 나갑니다.

ALB는 요청이 없다고 0원이 되는 구조가 아닙니다. ECS Fargate task도 마찬가지입니다. CPU를 10%만 쓰고 있어도, 거의 놀고 있어도, 잡아둔 vCPU와 메모리 기준으로 계속 과금됩니다.

그래서 자연스럽게 이런 생각이 들었습니다.

이거 Lambda로 옮기면 안 되나?

서버리스가 좋은 건 알지만, 막상 옮기려면 애매합니다

서버리스가 좋은 건 다들 알고 있습니다.

요청이 없으면 거의 비용이 안 나오고, 서버 관리도 줄고, 오토스케일링도 알아서 됩니다. 포트폴리오 사이트나 공부용 서비스처럼 트래픽이 많지 않은 프로젝트라면 이 장점이 꽤 크게 느껴집니다.

저도 실제로 serverless 방식으로 사이트를 만들면서 느낀 게 있습니다.

"아, 진짜 사람이 안 들어오면 거의 돈이 안 나오는구나."

물론 완전 무료는 아닙니다. Route 53, CloudWatch Logs, 도메인, 데이터베이스, NAT Gateway 같은 걸 어떻게 쓰느냐에 따라 비용은 나옵니다. 그래도 ECS + ALB로 항상 뭔가를 띄워두는 방식과는 확실히 다릅니다.

문제는 기존 백엔드입니다.

기존에 Express 같은 서버를 컨테이너로 잘 만들어뒀다면, 그걸 Lambda로 옮기는 게 처음에는 좀 어색합니다.

기존 컨테이너 앱:
Express app -> app.listen(3000) -> Dockerfile -> ECR -> ECS Service -> ALB

Lambda:
event -> handler -> response

 

서버가 포트를 열고 계속 떠 있는 구조가 아니라, 요청이 들어올 때 함수가 실행되는 구조입니다.

그래서 당연히 고민이 생깁니다.

  • 기존 Express 코드를 얼마나 바꿔야 하지?
  • API Gateway랑 ALB는 뭐가 다르지?
  • cold start는 괜찮을까?
  • DB connection은?
  • 배포와 롤백은 어떻게 하지?
  • 문제가 생기면 다시 ECS로 돌아갈 수 있을까?

요즘은 AI가 코드 변환을 정말 잘 도와주긴 합니다. 하지만 AI가 바꿔준 구조가 내 프로젝트에 맞는지는 별개의 문제입니다.

Lambda Container Image가 중간 다리 역할을 합니다

여기서 흥미로운 선택지가 Lambda container image입니다.

Lambda는 zip 패키지뿐 아니라 ECR에 올라간 container image도 실행할 수 있습니다. 즉 Dockerfile 기반으로 이미지를 만들고, 그 이미지를 Lambda 함수로 실행할 수 있습니다.

ECS에 익숙한 개발자에게는 이게 꽤 반갑습니다.

완전히 새로운 방식으로 모든 걸 다시 배워야 하는 느낌이 아니라, 기존 Dockerfile과 ECR 중심의 흐름을 어느 정도 유지할 수 있기 때문입니다.

예를 들면 Express 앱을 이렇게 나눌 수 있습니다.

app.ts     -> Express app 생성
server.ts  -> 로컬/ECS용 app.listen()
lambda.ts  -> Lambda handler

 

ECS에서는 server.ts를 실행하고, Lambda에서는 lambda.ts에서 @codegenie/serverless-express 같은 어댑터로 Express 앱을 handler에 연결합니다.

모든 앱에 맞는 방식은 아니지만, 일반적인 request/response API라면 꽤 현실적인 마이그레이션 경로입니다.

Lambda로 옮기면 관리할 게 없어질까요?

Lambda로 옮긴다고 관리할 게 완전히 사라지는 건 아닙니다.

EC2나 ECS처럼 서버와 task를 계속 관리하지 않아도 되는 건 맞습니다. 대신 Lambda container image에는 다른 관리 포인트가 있습니다.

구분 ECS + ALB Lambda container image
실행 단위 ECS Service, Task, Target Group Lambda function, version, alias
배포 단위 Task definition revision ECR image, Lambda version
트래픽 진입점 ALB listener/rule API Gateway HTTP API 또는 Lambda Function URL
스케일링 desired count, service autoscaling concurrency, throttle, reserved concurrency
비용 task 실행 시간, ALB, LCU request, duration, API Gateway, logs
롤백 이전 task definition으로 service update 이전 Lambda version으로 alias 이동
런타임 상태 컨테이너 프로세스가 계속 살아 있음 실행 환경 재사용은 가능하지만 보장되지 않음

 

개인적으로 가장 중요하게 보는 건 배포와 롤백입니다.

Lambda container image는 ECR에 이미지를 push 했다고 자동으로 함수가 바뀌지 않습니다. Lambda 함수에 새 image URI를 반영해야 합니다. 운영에서는 그 뒤에 version을 publish 하고 alias를 옮기는 흐름이 좋습니다.

ECR image push
-> Lambda update-function-code
-> Lambda publish-version
-> alias live 이동

이렇게 해야 문제가 생겼을 때 이전 version으로 alias를 되돌릴 수 있습니다.

ECS + ALB와 Lambda Container Image를 비교하면

조금 더 단순하게 비교하면 이렇게 볼 수 있습니다.

항목 ECS + ALB Lambda container image
비용 구조 항상 떠 있는 task와 ALB 비용이 기본 발생 요청이 없으면 compute 비용이 거의 없음
개발자 친숙도 일반적인 서버/포트 모델이라 익숙함 handler/event 모델을 이해해야 함
컨테이너 활용 Dockerfile, ECR, task definition Dockerfile, ECR, Lambda image
긴 연결 WebSocket, SSE에 유리 기본적으로 부적합하거나 별도 설계 필요
긴 작업 컨테이너가 계속 실행 가능 최대 15분 제한
cold start 일반적으로 없음 있음. 이미지 크기와 런타임에 영향
로컬 개발 docker compose, npm run dev가 자연스러움 sam local, Lambda adapter 등 필요
사이드 프로젝트 적합성 트래픽이 적어도 고정비가 있음 낮거나 불규칙한 트래픽에 유리

 

Lambda는 비용 구조가 매력적이지만, 실행 모델이 다릅니다. 반대로 ECS는 비용이 더 나올 수 있지만, 기존 서버 애플리케이션의 동작 방식과 훨씬 잘 맞습니다.

결국 "어떤 게 더 최신인가"가 아니라 "내 서비스가 어떤 실행 모델에 가까운가"의 문제입니다.

그런데 AWS SAM CLI BuildKit 지원이 나왔습니다

그러던 중 AWS에서 이런 공지를 냈습니다.

AWS SAM CLI adds BuildKit support for AWS Lambda functions packaged as container images

 

AWS SAM CLI adds BuildKit support for AWS Lambda functions packaged as container images - AWS

AWS Serverless Application Model Command Line Interface (SAM CLI) now supports BuildKit for building container images from Dockerfiles, enabling faster, more efficient container image builds for Lambda functions packaged as container images. SAM CLI is a c

aws.amazon.com

 

AWS SAM CLI 1.159.0부터 Lambda container image를 빌드할 때 BuildKit을 사용할 수 있다고 합니다.

sam build --use-buildkit

BuildKit을 사용하면 Dockerfile 기반 빌드에서 이런 장점을 기대할 수 있습니다.

  • multi-stage build
  • build cache
  • parallel build
  • x86_64 / arm64 cross-architecture build
  • build secret

여기서 중요한 건 이 기능이 Lambda 비용을 직접 줄여주는 기능은 아니라는 점입니다.

ECS + ALB 비용을 줄이는 핵심은 Lambda의 실행 모델입니다. SAM CLI BuildKit은 그다음 문제를 건드립니다.

Lambda container image로 가기로 했을 때, 빌드하고 테스트하고 배포하는 경험이 얼마나 편한가?

실제 배포 흐름은 어떻게 바뀔까요?

제가 진행하던 aws_exam 백엔드도 비슷한 방향으로 작업하고 있었습니다.

기존에는 ECS Service + ALB에 가까운 구조였고, 지금은 Lambda container image로 옮기는 형태를 보고 있습니다.

GitHub Actions에서 직접 관리하는 흐름은 대략 이런 모양입니다.

-> npm ci
-> npm run build
-> docker buildx build -f Dockerfile.lambda
-> ECR push
-> aws lambda update-function-code
-> aws lambda publish-version
-> aws lambda update-alias live
-> smoke test

명확하지만, Lambda container image 배포에 필요한 세부 명령을 전부 직접 들고 갑니다.

SAM CLI를 제대로 끼우면 목표는 이런 식의 축약입니다.

-> sam build --use-buildkit
-> sam deploy
-> smoke test

조금 더 구체적으로 보면 이렇게 바뀝니다.

기존 직접 스크립트 SAM CLI로 옮겼을 때
npm ci Dockerfile 안의 RUN npm ci 또는 SAM build 과정으로 이동
npm run build Dockerfile 안의 RUN npm run build 또는 SAM build 과정으로 이동
docker buildx build -f Dockerfile.lambda sam build --use-buildkit
ECR login / push sam deploy가 이미지 패키징/업로드 과정에서 처리
aws lambda update-function-code sam deploy가 CloudFormation stack update로 처리
aws lambda publish-version SAM template의 AutoPublishAlias 설정으로 처리 가능
aws lambda update-alias live AutoPublishAlias: live로 처리 가능
smoke test 여전히 별도 실행 권장

예를 들면 SAM template에는 이런 식의 설정이 들어갑니다.

Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      PackageType: Image
      AutoPublishAlias: live
      Events:
        Api:
          Type: HttpApi
          Properties:
            Path: /{proxy+}
            Method: ANY
    Metadata:
      Dockerfile: Dockerfile.lambda
      DockerContext: ./backend
      DockerTag: lambda-latest

GitHub Actions는 대략 이렇게 줄어듭니다.

- name: Build with SAM BuildKit
  run: sam build --use-buildkit

- name: Deploy with SAM
  run: sam deploy --no-confirm-changeset --no-fail-on-empty-changeset

- name: Smoke test
  run: curl --fail --silent --show-error "$API_BASE_URL/debug-sentry"

 

 

보기에는 확실히 간단합니다.

다만 조건이 있습니다. SAM이 Lambda, API Gateway, ECR packaging, alias 같은 배포 흐름을 소유할 때 가장 깔끔합니다. 반대로 Terraform이 Lambda/API Gateway/IAM/Route 53을 이미 관리하고 있다면 sam deploy를 그대로 넣는 순간 CloudFormation과 Terraform의 책임이 섞일 수 있습니다.

그래서 저는 이렇게 봅니다.

상황 추천
새 서버리스 프로젝트 SAM CLI + BuildKit으로 단순하게 시작
기존 Terraform 프로젝트 Docker Buildx + AWS CLI 유지가 더 명확할 수 있음
빌드만 개선하고 싶음 기존 workflow에 BuildKit/cache 최적화만 반영
로컬 Lambda/API Gateway 테스트가 중요함 SAM local 도입 검토
배포 ownership을 SAM으로 옮길 수 있음 sam build --use-buildkit + sam deploy 가치가 커짐

새 기능이 나왔다고 해서 항상 기존 파이프라인을 갈아엎을 필요는 없습니다.

비용은 어느 정도 차이가 날까요?

간단하게 계산해 보면 차이가 꽤 보입니다.

서울 리전 기준으로 아주 작은 ECS/Fargate 구성을 잡아보겠습니다.

  • Fargate 1 task
  • 0.25 vCPU
  • 0.5GB memory
  • ALB 1개
  • LCU 1개 정도로 단순 가정
  • 30일 계속 실행

이렇게 잡으면 대략 월 $32 정도가 나옵니다.

중요한 건 요청이 0건이어도 이 정도 baseline 비용은 나간다는 점입니다.

AWS에도 비용 최적화를 도와주는 도구들이 있습니다. AWS Compute Optimizer는 ECS on Fargate 서비스의 task CPU와 memory 권장값을 제안할 수 있고, Lambda memory size 추천도 제공합니다. AWS Trusted Advisor나 Cost Optimization Hub도 비용 절감 기회를 보여줍니다.

다만 이런 도구들은 right-sizing에 가깝습니다.

ECS task memory를 줄이세요는 말해줄 수 있지만, 이 사이드 프로젝트는 요청이 거의 없으니 ECS + ALB보다 Lambda container image가 맞습니다 같은 아키텍처 판단은 결국 개발자가 해야 합니다.

Lambda + API Gateway HTTP API는 요청량과 실행 시간에 따라 비용이 늘어납니다.

512MB Lambda 기준으로 단순 계산하면 대략 이런 느낌입니다.

하루 요청량 월 요청량 200ms 500ms 1s
1,000 30,000 $0.09 $0.17 $0.29
10,000 300,000 $0.93 $1.68 $2.93
100,000 3,000,000 $9.29 $16.79 $29.28
500,000 15,000,000 $46.46 $83.95 $146.40

 

사이드 프로젝트에서는 왜 Lambda가 매력적인지 바로 보입니다.

하루에 1,000명도 안 들어오는 서비스라면 ECS + ALB를 계속 켜두는 것보다 Lambda가 훨씬 가볍습니다.

그렇다고 Lambda가 무조건 정답은 아닙니다

Lambda container image를 쓴다고 Lambda의 제약이 사라지는 건 아닙니다.

컨테이너 이미지는 패키징 방식입니다. 실행 모델은 여전히 Lambda입니다.

특히 이런 경우는 조심해야 합니다.

  • 최대 실행 시간 15분을 넘을 수 있음
  • cold start가 사용자 경험에 크게 영향을 줌
  • WebSocket, SSE, streaming 같은 장기 연결이 중요함
  • 메모리에 상태를 들고 있어야 함
  • 백그라운드 worker가 계속 돌아야 함
  • DB connection 관리가 민감함
  • VPC Lambda로 인해 NAT Gateway나 VPC endpoint 비용이 커질 수 있음

참고로 Lambda 쪽에도 긴 흐름을 다루기 위한 선택지가 늘고 있습니다. 예를 들어 AWS Lambda durable functions는 checkpoint/replay, wait, callback을 이용해 다단계 워크플로를 일시 중단하고 재개할 수 있습니다. 다만 이건 HTTP 서버를 그대로 오래 실행하는 방식이라기보다, 장기 워크플로를 Lambda 식으로 모델링하는 기능에 가깝습니다.

API Gateway timeout도 같이 봐야 합니다. 예전에는 API Gateway의 29초 제한을 많이 이야기했는데, 2024년부터 Regional REST API와 private REST API는 integration timeout을 29초 이상으로 늘릴 수 있습니다. 다만 이 경우 account-level throttle quota가 줄어들 수 있고, HTTP API 등 API 타입별 제한은 따로 확인해야 합니다. 결국 긴 요청을 동기 HTTP 응답으로 오래 붙잡는 구조가 맞는지부터 봐야 합니다.

이런 경우 ECS/Fargate가 여전히 더 솔직한 선택입니다.

컨테이너를 더 본격적으로 운영하고 싶다면 EKS/Kubernetes도 선택지입니다. 포트폴리오 관점에서는 Kubernetes, Ingress, HPA, Helm, GitOps 같은 키워드가 매력적이기도 합니다.

다만 이 글의 관심사는 컨테이너 플랫폼을 더 크게 가져가는 것이 아닙니다. 사이드 프로젝트에서 ECS + ALB의 고정 비용을 줄일 수 있느냐입니다.

제 기준의 선택은 이렇습니다

사이드 프로젝트를 새로 만든다면 저는 이렇게 볼 것 같습니다.

요청/응답형 API이고, 트래픽이 낮거나 예측이 어렵다면 Lambda container image를 먼저 봅니다. 이미 Dockerfile이 있고 Express나 FastAPI 같은 백엔드라면 Lambda handler로 감싸서 옮길 수 있는지 확인할 것 같습니다.

반대로 이런 경우라면 ECS/Fargate를 유지합니다.

  • 서비스가 항상 warm 상태여야 함
  • WebSocket/SSE가 중요함
  • 요청 시간이 길거나 백그라운드 작업이 많음
  • 컨테이너 프로세스가 계속 떠 있는 구조가 핵심임
  • 이미 ECS 운영 파이프라인이 안정적이고 비용도 감당 가능함

SAM CLI는 새 서버리스 프로젝트라면 적극적으로 써볼 만합니다.

template.yaml에 Lambda/API Gateway 구성을 넣고, sam build --use-buildkit, sam local start-api, sam deploy 흐름으로 가면 꽤 깔끔합니다.

하지만 이미 Terraform으로 인프라를 관리하고 있고, GitHub Actions에서 Docker Buildx로 이미지 빌드와 Lambda 배포를 잘하고 있다면 굳이 SAM을 억지로 끼우지는 않을 것 같습니다.

이 경우에는 BuildKit의 장점만 기존 Docker Buildx 파이프라인에 잘 녹이는 게 더 현실적입니다.

정리하면

이번 AWS SAM CLI BuildKit 발표는 "이제 Lambda가 ECS를 대체합니다" 같은 이야기는 아닙니다.

비용을 줄이는 건 Lambda의 pay-per-use 모델입니다.

SAM CLI BuildKit은 Lambda container image를 빌드하고 배포하는 경험을 조금 더 자연스럽게 만들어주는 업데이트에 가깝습니다.

그래도 이 업데이트가 반가운 이유는 있습니다.

EC2에서 시작해서 ECS + ALB에 익숙해진 개발자에게 서버리스는 처음엔 꽤 어색합니다. 하지만 사이드 프로젝트처럼 "사람이 안 들어오면 돈도 거의 안 나가야 하는" 서비스라면 한 번쯤 진지하게 계산해 볼 만합니다.

그리고 그때 중요한 질문은 이겁니다.

이 서비스를 꼭 항상 띄워둬야 할까?

 

만약 답이 아니라면, Lambda container image는 생각보다 괜찮은 선택지가 될 수 있습니다.