근묵자흑
Kubernetes Pattern: Ambassador 본문
Ambassador 패턴은 Kubernetes의 구조적 패턴(Structural Patterns) 중 하나로, 외부 서비스에 대한 접근을 프록시하고 복잡성을 숨기는 특수한 사이드카 컨테이너입니다. 이 패턴을 통해 메인 애플리케이션 컨테이너는 외부 의존성에 직접 접근하지 않고도 localhost를 통해 단순화된 인터페이스로 외부 서비스를 사용할 수 있습니다.
flowchart LR
subgraph Pod["Pod"]
direction LR
Main["메인 애플리케이션<br/>컨테이너"]
Ambassador["Ambassador<br/>컨테이너"]
Main -->|"localhost:port"| Ambassador
end
Ambassador -->|"프록시"| External1["외부 서비스 A"]
Ambassador -->|"프록시"| External2["외부 서비스 B"]
Ambassador -->|"프록시"| External3["외부 서비스 C"]
style Main fill:#4a90d9,stroke:#333,color:#fff
style Ambassador fill:#e67e22,stroke:#333,color:#fff
style External1 fill:#95a5a6,stroke:#333,color:#fff
style External2 fill:#95a5a6,stroke:#333,color:#fff
style External3 fill:#95a5a6,stroke:#333,color:#fff
Problem: 왜 Ambassador 패턴이 필요한가?
컨테이너화된 서비스는 고립되어 존재하지 않으며, 외부 서비스에 접근해야 하는 경우가 많습니다. 하지만 외부 서비스에 접근하는 것은 다음과 같은 어려움을 수반합니다.
외부 서비스 접근의 복잡성
flowchart TB
subgraph Challenges["외부 서비스 접근 시 직면하는 문제들"]
C1["동적으로 변하는 주소"]
C2["클러스터 인스턴스의<br/>로드 밸런싱 필요"]
C3["불안정한 프로토콜"]
C4["복잡한 데이터 포맷"]
C5["서비스 디스커버리<br/>라이브러리 필요"]
end
App["비즈니스 로직<br/>+<br/>외부 서비스 접근 로직"]
C1 --> App
C2 --> App
C3 --> App
C4 --> App
C5 --> App
App --> Problem["단일 책임 원칙 위반<br/>재사용성 저하<br/>환경별 설정 복잡"]
style Problem fill:#e74c3c,stroke:#333,color:#fff
style Challenges fill:#f8f9fa,stroke:#333
구체적인 문제 시나리오
시나리오 1: 환경별 캐시 서버 접근
개발 환경에서는 로컬 Redis를 사용하고, 프로덕션에서는 분산된 Redis 클러스터를 사용해야 합니다. 애플리케이션 코드가 이 복잡성을 직접 처리한다면, 환경마다 다른 클라이언트 설정과 연결 로직이 필요합니다.
flowchart LR
subgraph Traditional["기존 방식의 문제"]
AppCode["애플리케이션 코드"]
AppCode --> DevConfig["개발 설정"]
AppCode --> ProdConfig["프로덕션 설정"]
DevConfig --> LocalRedis["로컬 Redis"]
ProdConfig --> Cluster["Redis 클러스터"]
end
Problem["환경마다 다른 코드<br/>복잡한 조건문<br/>유지보수 어려움"]
Traditional --> Problem
style Problem fill:#e74c3c,stroke:#333,color:#fff
시나리오 2: 서비스 디스커버리
외부 서비스를 사용하려면 레지스트리에서 서비스를 조회하고 클라이언트 사이드 서비스 디스커버리를 수행해야 합니다. 이러한 라이브러리를 애플리케이션에 포함시키면 컨테이너가 무거워지고 종속성이 증가합니다.
시나리오 3: 불안정한 프로토콜 처리
HTTP와 같은 불안정한 프로토콜로 서비스를 소비할 때, 서킷 브레이커 로직, 타임아웃 설정, 재시도 로직 등이 필요합니다. 이 모든 것을 애플리케이션에 구현하면 비즈니스 로직이 인프라 관심사와 뒤섞입니다.
핵심 문제: 관심사의 분리 실패
이상적으로 컨테이너는 단일 목적을 가지고 다른 컨텍스트에서 재사용 가능해야 합니다. 하지만 비즈니스 기능을 제공하면서 동시에 외부 서비스를 특수한 방식으로 소비하는 컨테이너는 두 가지 이상의 책임을 갖게 됩니다.
Ambassador 패턴의 해결 방식
Ambassador 패턴은 외부 서비스 접근의 복잡성을 숨기고, 메인 애플리케이션 컨테이너에게 localhost를 통한 단순화된 뷰를 제공합니다.
아키텍처 개요
flowchart LR
subgraph DevEnv["개발 환경"]
subgraph DevPod["Pod"]
DevApp["애플리케이션"] -->|"localhost:6379"| DevAmb["Ambassador<br/>(Local Proxy)"]
end
DevAmb --> LocalRedis["로컬 Redis"]
end
subgraph ProdEnv["프로덕션 환경"]
subgraph ProdPod["Pod"]
ProdApp["애플리케이션"] -->|"localhost:6379"| ProdAmb["Ambassador<br/>(Cluster Proxy)"]
end
ProdAmb --> Redis1["Redis Shard 1"]
ProdAmb --> Redis2["Redis Shard 2"]
ProdAmb --> Redis3["Redis Shard 3"]
end
style DevAmb fill:#e67e22,stroke:#333,color:#fff
style ProdAmb fill:#e67e22,stroke:#333,color:#fff
style DevApp fill:#4a90d9,stroke:#333,color:#fff
style ProdApp fill:#4a90d9,stroke:#333,color:#fff
위 다이어그램에서 볼 수 있듯이, 애플리케이션은 항상 localhost:6379로 연결하면 됩니다. Ambassador 컨테이너가 환경에 따라 적절한 백엔드로 프록시합니다.
로그 처리 Ambassador
가장 기본적인 Ambassador 패턴 예제를 살펴보겠습니다. REST 서비스가 생성한 데이터를 로깅할 때, Ambassador가 로그 데이터를 처리합니다.
# ambassador-log-example.yaml
apiVersion: v1
kind: Pod
metadata:
name: random-generator
labels:
app: random-generator
spec:
containers:
# 메인 애플리케이션 컨테이너: 랜덤 숫자를 생성하는 REST 서비스
- name: main
image: k8spatterns/random-generator:1.0
env:
# Ambassador와 통신하기 위한 URL - localhost 사용
- name: LOG_URL
value: http://localhost:9009
ports:
- containerPort: 8080
protocol: TCP
# Ambassador 컨테이너: 로그 데이터를 받아 처리
- name: ambassador
image: k8spatterns/random-generator-log-ambassador
이 예제의 핵심 포인트는 다음과 같습니다:
1. localhost를 통한 통신: 메인 컨테이너는 http://localhost:9009로 로그 데이터를 전송합니다. 같은 Pod 내의 컨테이너들은 네트워크 네임스페이스를 공유하므로 localhost로 서로 통신할 수 있습니다.
2. 관심사의 분리: 메인 컨테이너는 로그 데이터가 어떻게 처리되는지 알 필요가 없습니다. Ambassador가 단순히 콘솔에 출력할 수도 있고, 전체 로깅 인프라로 전달할 수도 있습니다.
3. 컨테이너 교체 용이성: Ambassador 컨테이너를 교체해도 메인 컨테이너는 수정할 필요가 없습니다. Pod 정의만 재구성하면 됩니다.
사이드카 패턴 패밀리 비교
Ambassador 패턴을 이해하기 전에, 사이드카 패턴 패밀리를 비교해보면 각 패턴의 역할이 명확해집니다.
flowchart TB
subgraph Sidecar["Sidecar 패턴"]
direction LR
S_Main["메인 컨테이너"] <-->|"기능 확장"| S_Side["사이드카 컨테이너"]
end
subgraph Adapter["Adapter 패턴"]
direction RL
A_External["외부 시스템<br/>(Prometheus 등)"] -->|"표준 형식 요청"| A_Adapter["Adapter<br/>컨테이너"]
A_Adapter -->|"변환된 데이터"| A_Main["메인 컨테이너"]
end
subgraph Ambassador["Ambassador 패턴"]
direction LR
Amb_Main["메인 컨테이너"] -->|"localhost"| Amb_Proxy["Ambassador<br/>컨테이너"]
Amb_Proxy -->|"프록시"| Amb_External["외부 서비스"]
end
style S_Side fill:#27ae60,stroke:#333,color:#fff
style A_Adapter fill:#9b59b6,stroke:#333,color:#fff
style Amb_Proxy fill:#e67e22,stroke:#333,color:#fff
| 패턴 | 역할 | 프록시 방향 | 주요 사용 사례 |
|---|---|---|---|
| Sidecar | 메인 컨테이너 기능 확장 | 양방향 협력 | 로그 수집, 설정 동기화 |
| Adapter | 이기종 시스템 출력 표준화 | 외부 → 내부 (Reverse Proxy) | 메트릭 변환, 로그 포맷 변환 |
| Ambassador | 외부 서비스 접근 단순화 | 내부 → 외부 (Client Proxy) | 서비스 디스커버리, 캐시 접근 |
Native Sidecar 컨테이너
Kubernetes 1.28에서 알파로 도입되고 1.29에서 베타로 기본 활성화된 Native Sidecar 컨테이너는 Ambassador 패턴의 구현을 개선합니다.
기존 방식의 문제점
기존에는 사이드카 컨테이너를 일반 컨테이너(spec.containers)로 정의했습니다. 이 방식에는 몇 가지 문제가 있었습니다.
sequenceDiagram
participant IC as Init Container
participant Main as 메인 컨테이너
participant Sidecar as 사이드카<br/>(기존 방식)
Note over IC,Sidecar: 기존 방식의 문제점
IC->>IC: 완료될 때까지 실행
IC-->>Main: Init 완료 후 시작
Main->>Main: 시작
Sidecar->>Sidecar: 동시 시작
Note over Main,Sidecar: 문제 1: 사이드카가 준비되기 전에<br/>메인이 시작될 수 있음
Main->>Main: 완료
Sidecar->>Sidecar: 계속 실행 중...
Note over Main,Sidecar: 문제 2: 메인이 종료되어도<br/>사이드카가 Pod 종료를 막음
Native Sidecar의 해결책
Native Sidecar는 initContainers에 restartPolicy: Always를 설정하여 정의합니다.
# native-sidecar-ambassador.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-with-ambassador
spec:
# Native Sidecar는 initContainers에 정의
initContainers:
# Ambassador 컨테이너를 Native Sidecar로 정의
- name: ambassador-proxy
image: envoyproxy/envoy:v1.28-latest
restartPolicy: Always # 이것이 Native Sidecar의 핵심
ports:
- containerPort: 10000
name: proxy
# startupProbe로 메인 컨테이너 시작 전 준비 완료 보장
startupProbe:
httpGet:
path: /ready
port: 9901
initialDelaySeconds: 2
periodSeconds: 5
failureThreshold: 10
# 메인 애플리케이션 컨테이너
containers:
- name: main-app
image: my-application:1.0
env:
- name: EXTERNAL_SERVICE_URL
value: http://localhost:10000
Native Sidecar의 라이프사이클
sequenceDiagram
participant Init as 일반 Init Container
participant Sidecar as Native Sidecar<br/>(Ambassador)
participant Main as 메인 컨테이너
Note over Init,Main: Native Sidecar 라이프사이클
Init->>Init: 실행 및 완료
Init-->>Sidecar: Init 완료 후 시작
Sidecar->>Sidecar: 시작
Note over Sidecar: startupProbe 통과 대기
Sidecar-->>Main: Sidecar 준비 완료 후 시작
Main->>Main: 실행
Note over Sidecar,Main: 메인과 사이드카 동시 실행
Main->>Main: 완료 (종료)
Note over Sidecar: 메인 종료 후<br/>SIGTERM 수신
Sidecar->>Sidecar: 정리 후 종료
Note over Init,Main: Pod 종료 완료
Native Sidecar의 주요 이점
시작 순서 보장: Native Sidecar는 항상 메인 컨테이너보다 먼저 시작됩니다. startupProbe를 사용하면 사이드카가 준비된 후에만 메인 컨테이너가 시작됩니다.
종료 순서 보장: Kubernetes 1.29부터 메인 컨테이너가 모두 종료된 후에야 사이드카가 SIGTERM을 받습니다. 사이드카는 정의된 역순으로 종료됩니다.
Job 워크로드 지원: 기존 방식에서는 Job의 메인 컨테이너가 완료되어도 사이드카가 계속 실행되어 Job이 완료되지 않는 문제가 있었습니다. Native Sidecar는 이 문제를 해결합니다.
리소스 계산 개선: Native Sidecar의 리소스 요청은 메인 컨테이너의 리소스 요청과 합산되어 더 정확한 스케줄링이 가능합니다.
실습: Ambassador 패턴 구현
실습 1: 기본 Ambassador 패턴 - 로그 프록시
가장 기본적인 Ambassador 패턴입니다. 메인 애플리케이션이 생성한 로그를 Ambassador가 처리합니다.
# manifests/test1-basic-log-proxy.yaml
apiVersion: v1
kind: Pod
metadata:
name: random-generator
labels:
app: random-generator
spec:
containers:
- name: main
image: k8spatterns/random-generator:1.0
env:
- name: LOG_URL
value: http://localhost:9009 # Ambassador로 로그 전송
ports:
- containerPort: 8080
- name: ambassador
image: k8spatterns/random-generator-log-ambassador
# 포트 9009는 Pod 외부로 노출되지 않음
flowchart LR
subgraph Pod["random-generator Pod"]
Main["main container<br/>(랜덤 숫자 생성)"]
Ambassador["ambassador container<br/>(로그 수집)"]
Main -->|"localhost:9009<br/>(로그 데이터)"| Ambassador
end
Client["외부 클라이언트"] -->|"http://:8080<br/>(API 호출)"| Main
Ambassador -->|"로그 전송"| LogSystem["로깅 시스템"]
style Main fill:#4a90d9,stroke:#333,color:#fff
style Ambassador fill:#e67e22,stroke:#333,color:#fff
실습 2: HTTP 프록시 Ambassador
Nginx를 사용하여 외부 HTTP 서비스를 프록시하는 Ambassador입니다.
# ConfigMap으로 Nginx 설정 외부화
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ambassador-config
data:
nginx.conf: |
http {
upstream external_service {
server httpbin.org:80;
}
server {
listen 8080;
location /health {
return 200 "Ambassador is healthy\n";
}
location / {
proxy_pass http://external_service;
proxy_connect_timeout 5s;
proxy_read_timeout 10s;
# 재시도 정책
proxy_next_upstream error timeout http_502;
proxy_next_upstream_tries 3;
}
}
}
---
apiVersion: v1
kind: Pod
metadata:
name: http-proxy-ambassador
spec:
containers:
- name: main
image: curlimages/curl:8.5.0
command:
- sh
- -c
- |
while true; do
# Ambassador를 통해 외부 API 호출
curl http://localhost:8080/get
sleep 15
done
- name: ambassador
image: nginx:1.25-alpine
ports:
- containerPort: 8080
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: nginx-ambassador-config
flowchart LR
subgraph Pod["http-proxy-ambassador Pod"]
Main["main container"]
Nginx["nginx ambassador"]
Main -->|"localhost:8080"| Nginx
end
Nginx -->|"프록시"| External["httpbin.org"]
Note["타임아웃: 5s<br/>재시도: 3회<br/>서킷브레이커"]
style Main fill:#4a90d9,stroke:#333,color:#fff
style Nginx fill:#e67e22,stroke:#333,color:#fff
style Note fill:#fff3cd,stroke:#333
동일한 애플리케이션 코드로 개발/프로덕션 환경에서 다른 백엔드를 사용합니다.
개발 환경: 로컬 Redis
# manifests/test4-env-backend-dev.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-dev-env
labels:
env: development
spec:
containers:
- name: main
image: redis:7-alpine
command:
- sh
- -c
- |
# 애플리케이션 코드 (환경 무관)
while true; do
redis-cli -h localhost -p 6379 SET "key" "value"
redis-cli -h localhost -p 6379 GET "key"
sleep 10
done
- name: ambassador
image: redis:7-alpine
command: ["redis-server", "--port", "6379"]
프로덕션 환경: HAProxy + Redis 클러스터
# manifests/test4-env-backend-prod.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: haproxy-ambassador-config
data:
haproxy.cfg: |
frontend redis_frontend
bind *:6379
default_backend redis_backend
backend redis_backend
balance roundrobin
server redis1 redis-backend-1:6379 check
server redis2 redis-backend-2:6379 check
---
apiVersion: v1
kind: Pod
metadata:
name: app-prod-env
labels:
env: production
spec:
containers:
- name: main
image: redis:7-alpine
command:
- sh
- -c
- |
# 동일한 애플리케이션 코드
while true; do
redis-cli -h localhost -p 6379 SET "key" "value"
redis-cli -h localhost -p 6379 GET "key"
sleep 10
done
- name: ambassador
image: haproxy:2.9-alpine
volumeMounts:
- name: haproxy-config
mountPath: /usr/local/etc/haproxy/haproxy.cfg
subPath: haproxy.cfg
volumes:
- name: haproxy-config
configMap:
name: haproxy-ambassador-config
flowchart TB
subgraph Dev["개발 환경"]
DevApp["main<br/>(애플리케이션)"]
DevAmb["ambassador<br/>(로컬 Redis)"]
DevApp -->|"localhost:6379"| DevAmb
end
subgraph Prod["프로덕션 환경"]
ProdApp["main<br/>(동일한 코드)"]
ProdAmb["ambassador<br/>(HAProxy)"]
ProdApp -->|"localhost:6379"| ProdAmb
ProdAmb --> Redis1["Redis 1"]
ProdAmb --> Redis2["Redis 2"]
end
Code["동일한 애플리케이션 코드<br/>환경 차이 없음"]
Code -.->|"개발"| DevApp
Code -.->|"프로덕션"| ProdApp
style DevAmb fill:#e67e22,stroke:#333,color:#fff
style ProdAmb fill:#e67e22,stroke:#333,color:#fff
style Code fill:#2ecc71,stroke:#333,color:#fff
핵심 포인트:
- 메인 컨테이너 코드가 두 환경에서 동일
- Ambassador만 교체하여 환경별 백엔드 전환
- 관심사의 분리 달성
실습 4: Native Sidecar를 사용한 시작 순서 보장
Kubernetes 1.28+ 에서 Native Sidecar 기능을 사용합니다.
# manifests/test6-native-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
name: native-sidecar-test
spec:
initContainers:
# 1. 일반 init container
- name: init-setup
image: busybox:1.36
command:
- sh
- -c
- |
echo "[INIT] Running one-time initialization..."
sleep 2
echo "[INIT] Initialization complete!"
# 2. Native Sidecar (restartPolicy: Always)
- name: ambassador-sidecar
image: hashicorp/http-echo:1.0
restartPolicy: Always # 핵심
args:
- "-listen=:8080"
- "-text=Native Sidecar Ambassador is running"
ports:
- containerPort: 8080
# startupProbe: 메인은 이것이 성공할 때까지 시작 안 됨
startupProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 2
periodSeconds: 2
failureThreshold: 5
containers:
- name: main-app
image: curlimages/curl:8.5.0
command:
- sh
- -c
- |
echo "[MAIN] Main application starting..."
echo "[MAIN] Native Sidecar should already be running!"
# Ambassador가 이미 준비되어 있어야 함
if curl -s http://localhost:8080; then
echo "[MAIN] SUCCESS: Ambassador was ready before main started!"
fi
# 계속 실행
for i in $(seq 1 10); do
echo "[MAIN] Request #$i to Ambassador..."
curl -s http://localhost:8080
sleep 5
done
echo "[MAIN] Exiting..."
sequenceDiagram
participant K8s as Kubernetes
participant Init as init-setup
participant Amb as ambassador-sidecar<br/>(Native Sidecar)
participant Main as main-app
Note over K8s,Main: Native Sidecar 시작 순서
K8s->>Init: 1. Init container 시작
Init->>Init: 초기화 작업 수행
Init-->>K8s: 완료
K8s->>Amb: 2. Native Sidecar 시작
Amb->>Amb: 시작 중...
Amb->>Amb: startupProbe 실행
Note over Amb: Probe 실패... 재시도
Note over Amb: Probe 성공
Amb-->>K8s: 준비 완료
K8s->>Main: 3. 메인 컨테이너 시작
Main->>Amb: 즉시 요청 가능
Amb-->>Main: 응답
Note over Main: 작업 완료
Main-->>K8s: 종료
K8s->>Amb: SIGTERM
Amb->>Amb: 정리
Amb-->>K8s: 종료
실무적인 관점에서 활용 방안
1. Service Mesh와의 관계
Ambassador 패턴은 Service Mesh의 기초가 됩니다. Istio의 Envoy sidecar가 대표적인 예입니다.
flowchart TB
subgraph ServiceMesh["Service Mesh Architecture"]
subgraph PodA["Pod A"]
AppA["Application A"]
EnvoyA["Envoy Sidecar<br/>(Ambassador)"]
AppA <--> EnvoyA
end
subgraph PodB["Pod B"]
AppB["Application B"]
EnvoyB["Envoy Sidecar<br/>(Ambassador)"]
AppB <--> EnvoyB
end
EnvoyA <-->|"mTLS<br/>로드밸런싱<br/>재시도"| EnvoyB
ControlPlane["Control Plane<br/>(Istiod)"]
ControlPlane -.->|"설정<br/>정책"| EnvoyA
ControlPlane -.->|"설정<br/>정책"| EnvoyB
end
style EnvoyA fill:#e67e22,stroke:#333,color:#fff
style EnvoyB fill:#e67e22,stroke:#333,color:#fff
style ControlPlane fill:#9b59b6,stroke:#333,color:#fff
Service Mesh가 제공하는 Ambassador 기능:
- mTLS를 통한 서비스 간 암호화
- 자동 재시도 및 서킷 브레이커
- 트래픽 라우팅 및 로드밸런싱
- 메트릭 수집 및 분산 추적
- 정책 적용 (rate limiting, auth 등)
2. 레거시 애플리케이션 현대화
Ambassador 패턴은 수정하기 어려운 레거시 애플리케이션에 현대적인 네트워킹 기능을 추가할 때 유용합니다.
| 기능 | Ambassador를 통한 추가 | 이점 |
|---|---|---|
| TLS 종료 | Nginx/Envoy Ambassador | 애플리케이션 코드 변경 불필요 |
| 모니터링 | Prometheus exporter sidecar | 기존 앱에 메트릭 추가 |
| 로깅 | Fluentd/Fluent Bit sidecar | 중앙화된 로그 수집 |
| 서킷 브레이커 | Envoy circuit breaker | 복원력 향상 |
| 인증/인가 | OAuth2 proxy | 보안 강화 |
flowchart LR
subgraph Legacy["레거시 애플리케이션 Pod"]
LegacyApp["레거시 앱<br/>(수정 불가)"]
subgraph Ambassadors["Ambassador 컨테이너들"]
TLS["TLS<br/>Ambassador"]
Metrics["Metrics<br/>Ambassador"]
Auth["Auth<br/>Ambassador"]
end
LegacyApp <--> TLS
LegacyApp <--> Metrics
LegacyApp <--> Auth
end
External["외부<br/>클라이언트"] -->|"HTTPS"| TLS
Prometheus["Prometheus"] -->|"수집"| Metrics
AuthServer["인증<br/>서버"] <--> Auth
style LegacyApp fill:#95a5a6,stroke:#333,color:#fff
style TLS fill:#e67e22,stroke:#333,color:#fff
style Metrics fill:#e67e22,stroke:#333,color:#fff
style Auth fill:#e67e22,stroke:#333,color:#fff
3. 데이터베이스 연결 관리
Cloud SQL Proxy나 AWS RDS Proxy와 같은 데이터베이스 프록시를 Ambassador로 활용할 수 있습니다.
# Cloud SQL Proxy as Ambassador
apiVersion: v1
kind: Pod
metadata:
name: app-with-cloudsql
spec:
containers:
- name: app
image: my-app:1.0
env:
- name: DATABASE_URL
value: "postgresql://user:pass@localhost:5432/dbname"
- name: cloud-sql-proxy
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
args:
- "--port=5432"
- "project:region:instance"
- "--credentials-file=/secrets/service_account.json"
volumeMounts:
- name: sa-credentials
mountPath: /secrets
이점:
- 애플리케이션은 localhost로 DB 접근
- Cloud SQL Proxy가 IAM 인증 처리
- SSL/TLS 암호화 자동 적용
- 연결 풀링 및 관리
4. Knative에서의 Ambassador 활용
Knative Serving의 queue-proxy는 Ambassador 패턴의 실제 구현입니다.
flowchart LR
subgraph KnativeService["Knative Service Pod"]
direction LR
UserContainer["사용자<br/>컨테이너"]
QueueProxy["Queue Proxy<br/>(Ambassador)"]
UserContainer <-->|"localhost"| QueueProxy
end
Activator["Activator"] -->|"요청"| QueueProxy
QueueProxy -->|"동시성 메트릭"| Autoscaler["Autoscaler"]
QueueProxy -->|"버퍼링<br/>제한 적용"| UserContainer
style QueueProxy fill:#e67e22,stroke:#333,color:#fff
style UserContainer fill:#4a90d9,stroke:#333,color:#fff
Queue Proxy의 역할:
- 요청 버퍼링 (애플리케이션 과부하 방지)
- 메트릭 수집 (동시 요청 수 등)
- Concurrency limit 강제 적용
- 헬스체크 및 라이프사이클 관리
5. 프로덕션 고려사항
| 항목 | 권장 사항 | 이유 |
|---|---|---|
| 리소스 모니터링 | Prometheus + Grafana | Ambassador 오버헤드 추적 |
| 로깅 | Structured logging | 디버깅 용이성 |
| 버전 관리 | 명시적 이미지 태그 | 재현 가능성 |
| 설정 외부화 | ConfigMap/Secret | 설정 변경 시 재배포 불필요 |
| 네트워크 정책 | NetworkPolicy 적용 | 보안 강화 |
| 메트릭 수집 | Sidecar exporter | 관찰성 향상 |
정리
| 요구사항 | 권장 패턴 | 이유 |
|---|---|---|
| 외부 서비스 접근 단순화 | Ambassador | 클라이언트 사이드 프록시 |
| 메트릭/로그 포맷 변환 | Adapter | 서버 사이드 프록시 |
| 설정 파일 동기화 | Sidecar | 양방향 협력 |
| Service Mesh 구축 | Ambassador (Envoy) | 표준 패턴 |
| 레거시 앱 현대화 | Ambassador | 코드 변경 불필요 |
Ambassador 패턴은 외부 서비스 접근을 단순화하고 관심사를 분리하는 구조적 패턴입니다.
- localhost 기반 통신의 단순함
- 환경 독립적인 애플리케이션 코드
- Native Sidecar의 시작 순서 보장
- 프로덕션 환경을 위한 복원력과 보안
'k8s > kubernetes-pattern' 카테고리의 다른 글
| Kubernetes Observability(2025) (0) | 2025.12.06 |
|---|---|
| Kubernetes Pattern: Adapter (0) | 2025.11.29 |
| Kubernetes Pattern: Sidecar (4) | 2025.11.22 |
| Kubernetes Pattern: Init Conatiner (2) | 2025.11.15 |
| Kubernetes Pattern: Self Awareness (0) | 2025.11.08 |