[쿠버네티스 패턴 18장] ambassador 패턴

bocopile·2025년 12월 13일

쿠버네티스 패턴

목록 보기
17/28
post-thumbnail

컨테이너 환경에서 애플리케이션을 개발하다 보면 외부 서비스와의 통신이 복잡해지는 경우가 많습니다. 주소가 동적으로 변하거나, 프로토콜이 불안정하거나, 환경(Dev/Prod)에 따라 연결 대상이 달라져야 할 때가 있죠.

이번 포스팅에서는 메인 컨테이너가 외부 세상과 소통하는 복잡함을 대신 처리해 주는 Ambassador 패턴에 대해 알아보겠습니다.

1. Ambassador 패턴이란?

Ambassador 패턴은 외부의 복잡성을 숨기고 파드(Pod) 외부의 서비스에 접근할 수 있는 통일된 인터페이스를 제공하는 특수한 형태의 사이드카(Sidecar)입니다.

쉽게 말해, 메인 컨테이너 대신 외부 의존성에 접근하는 '프록시(Proxy)' 역할을 수행하여 메인 컨테이너와 외부 연결 로직을 분리(Decouple)하는 패턴입니다.

2. 해결하려는 문제 (Problem)

컨테이너화된 서비스는 고립되어 존재하지 않으며, 종종 안정적으로 접근하기 어려운 타 서비스들과 통신해야 합니다. 이 과정에서 다음과 같은 어려움이 발생합니다.

  • 접근의 어려움: 대상 서비스의 주소가 동적으로 변하거나, 로드 밸런싱이 필요하거나, 프로토콜이 불안정하거나, 데이터 포맷이 까다로울 수 있습니다.
  • 단일 책임 원칙 위배: 컨테이너는 하나의 목적만 가져야 합니다. 만약 비즈니스 로직을 수행하는 컨테이너가 복잡한 외부 서비스 연결 로직(예: 서비스 디스커버리 라이브러리 포함)까지 담당하게 되면 책임이 과도해집니다.
  • 환경 간 이식성 저하: 개발 환경(Dev)과 운영 환경(Prod)에서 서로 다른 종류의 서비스(예: 로컬 캐시 vs 분산 캐시)를 사용해야 할 때, 컨테이너 내부 로직을 수정해야 한다면 재사용성이 떨어집니다.

3. 해결책 (Solution)

Ambassador 패턴의 핵심은 외부 서비스에 접근하는 로직을 추상화하고 격리하는 것입니다.

  • 메인 컨테이너: 외부 서비스의 복잡한 위치나 프로토콜을 알 필요 없이, 단순히 localhost로 요청을 보냅니다.
  • Ambassador 컨테이너: localhost의 특정 포트에서 대기하다가 요청을 받아, 실제 외부 서비스(복잡한 로직 처리)로 전달합니다.

적용 예시

1) 다양한 환경 지원 (캐시 서버 연결)
개발 환경에서는 로컬 인메모리 캐시(memcached)를 사용하고, 운영 환경에서는 분산 캐시(etcd 등)를 사용해야 할 수 있습니다.

  • 운영 환경 (Figure 18-1): 앱 -> localhost -> Ambassador(etcd client) -> 원격 etcd 클러스터.
  • 개발 환경 (Figure 18-2): 앱 -> localhost -> Ambassador(memcached) -> 로컬 memcached.
    메인 애플리케이션 코드는 수정할 필요 없이 Ambassador 컨테이너만 교체하면 됩니다.

2) 서비스 디스커버리 및 서킷 브레이커
HTTP와 같이 신뢰할 수 없는 프로토콜을 사용할 때, Ambassador가 대신 서킷 브레이커, 타임아웃, 재시도(Retry) 로직을 수행하거나 레지스트리에서 서비스를 찾는 역할을 맡을 수 있습니다.

4. 실전 예제 (Example)

다음은 REST 서비스의 로그 데이터를 처리하는 Ambassador 패턴의 예제입니다.
메인 애플리케이션은 로그를 어떻게 처리할지 고민할 필요 없이, 그저 localhost:9009로 전송하기만 하면 됩니다.

apiVersion: v1
kind: Pod
metadata:
  name: random-generator
spec:
  containers:
  # 1. 메인 컨테이너 (애플리케이션)
  - image: k8spatterns/random-generator:1.0
    name: main
    env:
    - name: LOG_URL
      value: http://localhost:9009  # localhost로 전송
    ports:
    - containerPort: 8080
      protocol: TCP
      
  # 2. Ambassador 컨테이너
  - image: k8spatterns/random-generator-log-ambassador
    name: ambassador
    # 9009 포트에서 리스닝하며 로그를 받아 처리 (외부 노출 X)

5. 최신 쿠버네티스와의 연관성 (Native Sidecar Support)

기존 Ambassador 패턴의 가장 큰 골칫거리는 '컨테이너 시작 순서(Startup Order)' 였습니다. 쿠버네티스 초기 버전에서는 파드 내 컨테이너들의 시작 순서를 보장하지 않았기 때문에, Ambassador 컨테이너가 준비되기도 전에 메인 애플리케이션이 연결을 시도하여 에러가 발생하는 문제가 종종 있었습니다.

하지만 최신 쿠버네티스(v1.28 알파, v1.29 베타 도입 후 v1.33+ Stable)에서는 SidecarContainers 기능이 기본적으로 활성화되어 이 문제가 깔끔하게 해결되었습니다.

Native Sidecar를 적용한 Ambassador 패턴

이제 Ambassador 컨테이너를 일반 containers가 아닌, initContainers 항목에 restartPolicy: Always를 추가하여 정의할 수 있습니다. 이를 통해 다음과 같은 이점을 얻을 수 있습니다.

  1. 시작 순서 보장: Ambassador(Init 컨테이너)가 먼저 완전히 시작(Ready)된 후에야 메인 애플리케이션 컨테이너가 시작됩니다. 따라서 메인 앱이 켜지자마자 localhost로 요청을 보내도 안전합니다.
  2. 종료 순서 보장: 메인 애플리케이션이 종료될 때까지 Ambassador는 계속 살아있으며, 메인 앱이 완전히 종료된 후에야 Ambassador가 종료됩니다. (로그 유실 방지 등에 탁월)

변경된 YAML 예시 (Native Sidecar 적용):

apiVersion: v1
kind: Pod
metadata:
  name: random-generator-native
spec:
  # Ambassador를 initContainers로 정의하되, 항상 재시작하도록 설정
  initContainers:
  - name: ambassador
    image: k8spatterns/random-generator-log-ambassador
    restartPolicy: Always # 핵심: 이 설정으로 인해 사이드카로 동작함
    
  containers:
  - name: main
    image: k8spatterns/random-generator:1.0
    env:
    - name: LOG_URL
      value: http://localhost:9009

최신 버전의 쿠버네티스를 사용 중이라면, Ambassador 패턴 구현 시 반드시 이 Native Sidecar 방식을 사용하는 것이 권장됩니다.

6. 논의 및 요약 (Discussion)

Ambassador 패턴 vs Sidecar 패턴

  • Ambassador는 큰 범주에서 Sidecar 패턴의 일종입니다.
  • 차이점: 일반적인 사이드카가 메인 애플리케이션의 기능을 확장(enhance)하는 데 초점을 맞춘다면, Ambassador는 외부 세계로 나가는 똑똑한 프록시(Smart Proxy) 역할에 집중합니다.

장점

  • 단일 책임 & 재사용성: 메인 컨테이너는 비즈니스 로직에만 집중하고, 외부 연동의 구체적인 책임은 Ambassador에게 위임합니다.
  • 레거시 애플리케이션 지원: 수정하기 어려운 레거시 앱에 모니터링, 로깅, 라우팅 같은 최신 네트워크 기능을 붙일 때 유용합니다.
  • 모듈화: 특수 목적의 Ambassador 컨테이너(예: MySQL 연결용, 로깅용)를 만들어 여러 애플리케이션에서 재사용할 수 있습니다.

7. 참조 문헌

  • Kubernetes Patterns Chapter 18 (Ambassador)
  • Kubernetes Official Docs (Sidecar Containers)
profile
DevOps Engineer

0개의 댓글