AWS 모듈 3: Go와 Lambda

발행: (2025년 12월 15일 오전 07:21 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

Mac을 떠나지 않고 Linux용으로 컴파일 (비용 $0.06)

시리즈: AWS Zero to Architect - 모듈 3
읽는 시간: 20 분
구현 시간: 120 분

이전 모듈들에서 AWS, Terraform, IAM을 설정했습니다. 이제 재미있는 단계가 왔습니다: Go로 첫 Lambda 함수를 만들고, 비용은 센트 수준이며 Python보다 3배 빠릅니다.

🤔 우리 모두가 겪는 문제

일반적인 시나리오

“간단한 API가 있어요. 하루에 100 request만 받아도 매달 $50짜리 24/7 서버를 운영해야 할까요?”

답변: 아니오. Lambda를 사용하세요.

⚡ Lambda 설명: 푸드 트럭 vs 레스토랑

🏢 레스토랑 (EC2 – 전통 서버)

- Rentas local completo: $500/mes
- Pagas luz/agua/gas 24/7
- Staff de tiempo completo
- Si hay 3 clientes o 300, pagas lo mismo
- Si hay demanda, el local se satura

Costo fijo: $500/mes

🚚 푸드 트럭 (Lambda – 서버리스)

- Solo pagas cuando sirves un plato
- $0.20 por cada 1 millón de platos
- Sin staff fijo (AWS lo maneja)
- Escala automáticamente
- 3 clientes = $0.0006
- 300 clientes = $0.06

Costo variable: $0‑$100/mes

간헐적인 트래픽을 받는 API에 어느 것이 더 합리적일까요?

💰 실제 가격 (마케팅 과장 없이)

내 현재 Lambda

100,000 requests/mes
128 MB RAM
200 ms promedio de duración

Cálculo:
Requests: 100,000 ÷ 1,000,000 × $0.20 = $0.02
Compute:  0.128 GB × 0.2 s × 100,000 × $0.0000166667 = $0.04

Total: $0.06/mes

무료 티어

  • 1 millón de requests/mes
  • 400,000 GB‑segundos

번역: 개발 및 작은 앱에 무료.

🐹 왜 Go이고 Python/Node.js가 아닌가?

정직한 벤치마크 (내 직접 측정)

LanguageCold Start (콜드 스타트)Memory Used (사용 메모리)Warm Invoke (웜 인보크)
Go156 ms48 MB45 ms
Node.js342 ms89 MB89 ms
Python478 ms127 MB134 ms
Java1,240 ms186 MB203 ms

결과: Go는 콜드 스타트에서 3배 더 빠릅니다.

콜드 스타트란 무엇인가?

Primera invocación del día:
1. AWS crea un container → 100 ms
2. Carga tu runtime (Node.js/Python) → 200 ms
3. Carga tu código → 100 ms
Total: ~400 ms

Con Go:
1. AWS crea container → 100 ms
2. Ejecuta binario → 50 ms
Total: ~150 ms

최종 사용자에게: Go는 약 150 ms, Python은 약 400 ms에 응답합니다.

비용 장점

Python (512 MB): $0.0000083 por 100 ms
Go (128 MB):     $0.0000021 por 100 ms
Ahorro: 75 %

월 100만 요청 기준

  • Python: $83/월
  • Go: $21/월

차이: $62/월 × 12개월 = $744/년

🏗️ 아키텍처: 서버리스 헥사고날

헥사고날 아키텍처란?

간단한 아이디어: 비즈니스 로직 AWS에 의존하면 안 된다.

// ❌ MAL (Acoplado a AWS)
func CreateSession(userID string) {
    dynamodb.PutItem(...)  // Directo a AWS
}

// ✅ BIEN (Desacoplado)
// Domain (puro Go, sin AWS)
type Session struct {
    ID     string
    UserID string
}

func NewSession(userID string) *Session { ... }

// Adapter (traduce a AWS)
type DynamoDBRepo struct { ... }
func (r *DynamoDBRepo) Save(session *Session) { ... }

장점

  • ✅ DynamoDB를 Postgres로 교체해도 도메인 코드는 건드릴 필요 없음
  • ✅ AWS 없이 테스트 가능
  • ✅ 비즈니스 로직이 명확함

내 구조

go-hexagonal-auth/
├── cmd/lambda/main.go           # Lambda handler
├── internal/
│   ├── core/domain/
│   │   └── session.go           # 비즈니스 로직
│   └── adapters/repository/
│       └── dynamodb_session.go  # AWS 어댑터
└── terraform/
    └── lambda.tf                # 인프라

💻 중요한 코드

도메인 모델 (AWS 없음)

package domain

import (
    "time"
    "github.com/google/uuid"
)

type Session struct {
    SessionID string
    UserID    string
    ExpiresAt time.Time
    CreatedAt time.Time
}

func NewSession(userID string, ttl time.Duration) *Session {
    now := time.Now()
    return &Session{
        SessionID: uuid.New().String(),
        UserID:    userID,
        CreatedAt: now,
        ExpiresAt: now.Add(ttl),
    }
}

func (s *Session) IsValid() bool {
    return s.SessionID != "" && s.UserID != ""
}

주의: AWS import가 전혀 없습니다. 순수 로직.

DynamoDB 어댑터

package repository

import (
    "context"
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb"
    "go-hexagonal-auth/internal/core/domain"
)

type DynamoDBRepo struct {
    client    *dynamodb.Client
    tableName string
}

func (r *DynamoDBRepo) Save(ctx context.Context, session *domain.Session) error {
    item := map[string]interface{}{
        "session_id": session.SessionID,
        "user_id":    session.UserID,
        "expires_at": session.ExpiresAt.Unix(),
    }

    _, err := r.client.PutItem(ctx, &dynamodb.PutItemInput{
        TableName: aws.String(r.tableName),
        Item:      marshalMap(item),
    })
    return err
}

Lambda 핸들러

package main

import (
    "context"
    "encoding/json"
    "time"

    "github.com/aws/aws-lambda-go/lambda"
    "go-hexagonal-auth/internal/core/domain"
    "go-hexagonal-auth/internal/adapters/repository"
)

type APIGatewayRequest struct {
    Body string `json:"body"`
}

type CreateSessionRequest struct {
    UserID string `json:"user_id"`
}

type Response struct {
    StatusCode int    `json:"statusCode"`
    Body       string `json:"body"`
}

func handler(ctx context.Context, request APIGatewayRequest) (Response, error) {
    // 1. Parse input
    var req CreateSessionRequest
    if err := json.Unmarshal([]byte(request.Body), &req); err != nil {
        return Response{StatusCode: 400, Body: err.Error()}, err
    }

    // 2. Create session (domain logic)
    session := domain.NewSession(req.UserID, 24*time.Hour)

    // 3. Save (adapter)
    repo := repository.NewDynamoDBRepo(ctx)
    if err := repo.Save(ctx, session); err != nil {
        return Response{StatusCode: 500, Body: err.Error()}, err
    }

    // 4. Response
    body, _ := json.Marshal(session)
    return Response{
        StatusCode: 201,
        Body:       string(body),
    }, nil
}

func main() {
    lambda.Start(handler)
}

흐름: JSON 파싱 → 비즈니스 로직 (도메인) → 영속성 (어댑터) → 응답.

🔨 크로스 플랫폼 컴파일 (Go의 마법)

문제

Desarrollo en: macOS ARM64 (M1/M2/M3)
Lambda ejecuta: Linux ARM64

¿Cómo compilo para Linux sin salir de macOS?

Go의 해결책

# Un solo comando
GOOS=linux GOARCH=arm64 go build -o bootstrap ./cmd/lambda

그게 전부입니다. Docker, 가상 머신, CI/CD 빌드가 필요 없습니다; Go는 다른 플랫폼용으로 네이티브 컴파일합니다.

Makefile (자동화)

build:
	GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
		go build -ldflags="-s -w" \
		-o build/bootstrap ./cmd/lambda

zip: build
	cd build && zip lambda.zip bootstrap

명령어

make build   # Compila para Lambda
make zip     # Crea lambda.zip

크기

build/bootstrap: 7.2 MB (sin comprimir)
build/lambda.zip: 2.8 MB (comprimido)

중요한 플래그

-ldflags="-s -w"  # Reduce tamaño 30‑40 %
CGO_ENABLED=0     # Binario estático (sin dependencias C)

🚀 Terraform으로 배포

Lambda Configuration

resource "aws_lambda_function" "create_session" {
  filename      = "../build/lambda.zip"
  function_name = "go-hexagonal-auth-dev-create-session"
  role          = aws_iam_role.lambda_exec.arn
  handler       = "bootstrap"
  runtime       = "provided.al2"
  memory_size
Back to Blog

관련 글

더 보기 »

AWS Terraform IAM 사용자 관리

소개: AWS에서 IAM 사용자를 수동으로 관리하면 복잡해지고 오류가 발생하기 쉬우며 확장이 어려워집니다. 팀이 성장함에 따라 반복 가능하고 감사 가능한…

Day 16. IAM 사용자 생성

!Day 16 커버 이미지. IAM 사용자 생성 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads...